From 29007437677183d856d0081a16d28461c7f4da4a Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Mon, 22 Jun 2026 11:40:10 -0400 Subject: [PATCH] fix(dispatch): route unknown bar/copilot/cursor subcommands and survive corrupt config Pre-dispatch only routed known subcommand tokens, so unknown bar/copilot/cursor subcommands never reached their handlers (no error, no non-zero exit). Route them through. Also wrap autoMigrate() so a corrupt config.yaml no longer crashes startup, and print only the first line of a best-effort recovery failure. --- src/commands/bar/index.ts | 1 + src/dispatcher/pre-dispatch.ts | 42 ++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/commands/bar/index.ts b/src/commands/bar/index.ts index 27ecb28b..f12d8cd4 100644 --- a/src/commands/bar/index.ts +++ b/src/commands/bar/index.ts @@ -66,6 +66,7 @@ export async function handleBarCommand(args: string[]): Promise { if (!handler) { console.error(`[X] Unknown bar subcommand: ${subcommand}`); console.error('[i] Usage: ccs bar [launch|serve|stop|status|install|uninstall|version|--help]'); + process.exitCode = 1; return; } diff --git a/src/dispatcher/pre-dispatch.ts b/src/dispatcher/pre-dispatch.ts index aef943c6..e5c0d4eb 100644 --- a/src/dispatcher/pre-dispatch.ts +++ b/src/dispatcher/pre-dispatch.ts @@ -68,10 +68,19 @@ export async function runPreDispatchHandlers(ctx: PreDispatchContext): Promise" and exit 1. + // Unknown tokens that are NOT subcommand-like are kept as profile passthrough. if (firstArg === 'copilot' && args.length > 1) { const copilotToken = args[1]; - const shouldRouteToCopilotCommand = isCopilotSubcommandToken(copilotToken); + const isKnownSubcommand = isCopilotSubcommandToken(copilotToken); + // Route any non-flag, non-profile-looking second token to the handler so + // the default branch fires with the correct error message. + const looksLikeCopilotSubcmd = + isKnownSubcommand || (typeof copilotToken === 'string' && !copilotToken.startsWith('-')); - if (shouldRouteToCopilotCommand) { + if (looksLikeCopilotSubcmd) { const { handleCopilotCommand } = await import('../commands/copilot-command'); const exitCode = await handleCopilotCommand(args.slice(1)); process.exit(exitCode); @@ -125,14 +142,11 @@ export async function runPreDispatchHandlers(ctx: PreDispatchContext): Promise 1) { const { handleCursorCommand } = await import('../commands/cursor-command'); - const cursorToken = args[1]; - - if (isCursorSubcommandToken(cursorToken)) { - const exitCode = await handleCursorCommand(args.slice(1)); - process.exit(exitCode); - } + const exitCode = await handleCursorCommand(args.slice(1)); + process.exit(exitCode); } // Compatibility shim: old `ccs cursor ` still forwards to the legacy bridge