fix(cursor): fix router fall-through, add daemon marker, use random test port

- Route all `ccs cursor *` to handleCursorCommand (no profile-switching)
- Add --ccs-daemon marker to spawned process for stable PID validation
- Use random port in lifecycle integration test to prevent CI conflicts
- Remove unnecessary .toFixed(1) on integer tokenAge
This commit is contained in:
Tam Nhu Tran
2026-02-12 08:37:01 +07:00
parent 760a5c3ca4
commit bfc9361701
4 changed files with 9 additions and 15 deletions
+4 -11
View File
@@ -533,18 +533,11 @@ async function main(): Promise<void> {
}
// Special case: cursor command (Cursor IDE integration)
// Only route to command handler for known subcommands, otherwise treat as profile
// Note: Bare `ccs cursor` shows help (unlike copilot which falls through to profile)
// This is intentional — cursor has no profile-switching mode
// All `ccs cursor *` routes to cursor command handler — cursor has no profile-switching mode
if (firstArg === 'cursor') {
const { handleCursorCommand, CURSOR_SUBCOMMANDS } = await import('./commands/cursor-command');
if (
args.length === 1 ||
CURSOR_SUBCOMMANDS.includes(args[1] as (typeof CURSOR_SUBCOMMANDS)[number])
) {
const exitCode = await handleCursorCommand(args.slice(1));
process.exit(exitCode);
}
const { handleCursorCommand } = await import('./commands/cursor-command');
const exitCode = await handleCursorCommand(args.slice(1));
process.exit(exitCode);
}
// Special case: copilot command (GitHub Copilot integration)
+1 -1
View File
@@ -160,7 +160,7 @@ async function handleStatus(): Promise<number> {
console.log(`Authentication: ${authIcon} ${authText}`);
if (authStatus.authenticated && authStatus.tokenAge !== undefined) {
console.log(` Token age: ${authStatus.tokenAge.toFixed(1)} hours`);
console.log(` Token age: ${authStatus.tokenAge} hours`);
}
// Daemon status
+3 -2
View File
@@ -179,7 +179,8 @@ export async function startDaemon(
`,
];
proc = spawn(process.execPath, args, {
// Append --ccs-daemon marker for PID validation in stopDaemon
proc = spawn(process.execPath, [...args, '--ccs-daemon'], {
stdio: 'ignore',
detached: true,
});
@@ -267,7 +268,7 @@ export async function stopDaemon(): Promise<{ success: boolean; error?: string }
// Verify the PID belongs to our daemon before signaling
try {
const cmdline = fs.readFileSync(`/proc/${pid}/cmdline`, 'utf8');
if (!cmdline.includes('cursor') && !cmdline.includes('/health')) {
if (!cmdline.includes('--ccs-daemon')) {
// PID was reused by an unrelated process
removePidFile();
return { success: true };
+1 -1
View File
@@ -141,7 +141,7 @@ describe('startDaemon', () => {
it(
'starts and stops daemon successfully',
async () => {
const port = 18765;
const port = 10000 + Math.floor(Math.random() * 50000);
const result = await startDaemon({ port, model: 'test' });
expect(result.success).toBe(true);
expect(result.pid).toBeDefined();