From 473aa082f66a843edcea0d7ab9e9f94a2b585b67 Mon Sep 17 00:00:00 2001 From: "Kai (Tam Nhu) Tran" <61256810+kaitranntt@users.noreply.github.com> Date: Mon, 15 Jun 2026 23:12:52 -0400 Subject: [PATCH] fix: honor default target for Claude passthrough (#1539) Honors the configured default target in the Claude subcommand passthrough resolver. --- src/dispatcher/profile-resolver.ts | 25 ++++++++++++++----- ...le-resolver-subcommand-passthrough.test.ts | 21 ++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/dispatcher/profile-resolver.ts b/src/dispatcher/profile-resolver.ts index 9cf6d35d..6a1dfb35 100644 --- a/src/dispatcher/profile-resolver.ts +++ b/src/dispatcher/profile-resolver.ts @@ -99,11 +99,15 @@ function usesImplicitDefaultProfile(cleanArgs: string[]): boolean { * and only reached on the profile-not-found path, so a real configured profile * of the same name always wins. */ -export function isBareClaudeSubcommandPassthrough(profile: string, args: string[]): boolean { +export function isBareClaudeSubcommandPassthrough( + profile: string, + args: string[], + profileConfig?: Parameters[1] +): boolean { if (profile === 'default') return false; if (getClaudeSubcommandName([profile]) === null) return false; try { - return resolveTargetType(args) === 'claude'; + return resolveTargetType(args, profileConfig) === 'claude'; } catch { return false; } @@ -158,10 +162,19 @@ export async function resolveProfileAndTarget( } catch (profileError) { // Bare Claude subcommand passthrough: forward `ccs agents`, `ccs mcp`, ... // through the default profile instead of failing as an unknown profile. - if (isBareClaudeSubcommandPassthrough(profile, args)) { - remainingArgs = [profile, ...remainingArgs]; - profile = 'default'; - profileInfo = detector.detectProfileType(profile); + if (profile !== 'default' && getClaudeSubcommandName([profile]) !== null) { + const defaultProfileInfo = detector.detectProfileType('default'); + const defaultProfileConfig = defaultProfileInfo.target + ? { target: defaultProfileInfo.target } + : undefined; + + if (isBareClaudeSubcommandPassthrough(profile, args, defaultProfileConfig)) { + remainingArgs = [profile, ...remainingArgs]; + profile = 'default'; + profileInfo = defaultProfileInfo; + } else { + throw profileError; + } } else { throw profileError; } diff --git a/tests/unit/dispatcher/profile-resolver-subcommand-passthrough.test.ts b/tests/unit/dispatcher/profile-resolver-subcommand-passthrough.test.ts index 4a59d8f6..9fdf61fb 100644 --- a/tests/unit/dispatcher/profile-resolver-subcommand-passthrough.test.ts +++ b/tests/unit/dispatcher/profile-resolver-subcommand-passthrough.test.ts @@ -42,4 +42,25 @@ describe('isBareClaudeSubcommandPassthrough', () => { ); expect(isBareClaudeSubcommandPassthrough('mcp', ['mcp', '--target', 'codex'])).toBe(false); }); + + it('does not reroute through a default profile configured for a non-claude target', () => { + expect( + isBareClaudeSubcommandPassthrough('setup-token', ['setup-token', 'sk-secret'], { + target: 'droid', + }) + ).toBe(false); + expect(isBareClaudeSubcommandPassthrough('agents', ['agents'], { target: 'codex' })).toBe( + false + ); + }); + + it('allows explicit claude target selection to override a non-claude default profile target', () => { + expect( + isBareClaudeSubcommandPassthrough( + 'setup-token', + ['setup-token', 'sk-secret', '--target', 'claude'], + { target: 'droid' } + ) + ).toBe(true); + }); });