fix(cursor): guard raw-settings save race and enforce daemon preconditions

This commit is contained in:
Tam Nhu Tran committed 2026-02-14 07:11:02 +07:00
1 parent 0e55db88a5
commit 9a76f866b0
5 files changed
+157 -3

No files matched your search

+53
View File
@@ -20,6 +20,44 @@ import cursorSettingsRoutes from './cursor-settings-routes';
const router = Router();
interface DaemonStartPreconditionInput {
enabled: boolean;
authenticated: boolean;
tokenExpired?: boolean;
}
interface DaemonStartPreconditionError {
status: number;
error: string;
}
export function getDaemonStartPreconditionError(
input: DaemonStartPreconditionInput
): DaemonStartPreconditionError | null {
if (!input.enabled) {
return {
status: 400,
error: 'Cursor integration is disabled. Enable it before starting daemon.',
};
}
if (!input.authenticated) {
return {
status: 401,
error: 'Cursor authentication required. Import credentials before starting daemon.',
};
}
if (input.tokenExpired) {
return {
status: 401,
error: 'Cursor credentials expired. Re-authenticate before starting daemon.',
};
}
return null;
}
// Mount settings sub-routes
router.use('/settings', cursorSettingsRoutes);
@@ -125,6 +163,21 @@ router.get('/models', async (_req: Request, res: Response): Promise<void> => {
router.post('/daemon/start', async (_req: Request, res: Response): Promise<void> => {
try {
const cursorConfig = getCursorConfig();
const authStatus = checkAuthStatus();
const preconditionError = getDaemonStartPreconditionError({
enabled: cursorConfig.enabled,
authenticated: authStatus.authenticated,
tokenExpired: authStatus.expired ?? false,
});
if (preconditionError) {
res.status(preconditionError.status).json({
success: false,
error: preconditionError.error,
});
return;
}
const result = await startDaemon({
port: cursorConfig.port,
ghost_mode: cursorConfig.ghost_mode,
@@ -162,9 +162,17 @@ router.put('/raw', (req: Request, res: Response): void => {
const settingsPath = path.join(getCcsDir(), 'cursor.settings.json');
// Check for conflict if file exists and expectedMtime provided
if (fs.existsSync(settingsPath) && expectedMtime) {
// For existing files, expectedMtime is required to prevent blind overwrite races.
if (fs.existsSync(settingsPath)) {
const stat = fs.statSync(settingsPath);
if (typeof expectedMtime !== 'number' || !Number.isFinite(expectedMtime)) {
res.status(409).json({
error: 'File metadata not loaded. Refresh and retry.',
mtime: stat.mtimeMs,
});
return;
}
if (Math.abs(stat.mtimeMs - expectedMtime) > 1000) {
res.status(409).json({ error: 'File modified externally', mtime: stat.mtimeMs });
return;