feat(dispatcher): pass through Claude subcommands without interactive-session args

Closes #1218.

When the user invokes `ccs <profile> agents` (and other Claude subcommands
like `mcp`, `doctor`, `plugin`, ...), CCS was unconditionally injecting
session-only Claude flags (`--append-system-prompt`, `--disallowedTools`,
`--settings`, official-channels plugin specs) and forwarding the
`DISABLE_TELEMETRY=1` env var from profile settings. Each of those
either errored out the subcommand (`error: unknown option
'--append-system-prompt'`) or silently flipped Claude into
non-interactive list mode, so the new `claude agents` agent view never
opened under CCS.

Add a small `claude-subcommand-detector` that recognizes the documented
Claude subcommand set after skipping known value-taking flags, then have
the three steering-prompt injectors (websearch, image-analysis, browser),
the cliproxy and settings launchers, and the official-channels plan
short-circuit when a subcommand invocation is detected. Also strip
`DISABLE_TELEMETRY` from the spawned env only for subcommand
invocations — upstream Claude Code uses that var as a kill switch for
the subcommand TUIs, and the user's telemetry preference still applies
to every normal interactive session.

Verified end-to-end against `ccs glm agents` and `ccs ck agents`: the
agent view opens correctly, no `unknown option` error, and all 1938
existing tests pass.
This commit is contained in:
Tam Nhu Tran committed 2026-05-12 16:35:37 -04:00
1 parent 72f2f9993d
commit c2b00b7ad6
9 files changed
+299 -17

No files matched your search

+17 -10
View File
@@ -44,6 +44,7 @@ import {
normalizeDeprecatedGlmtEnv,
} from '../../utils/glmt-deprecation';
import { createOpenAICompatLaunchSettings } from '../../utils/openai-compat-launch-settings';
import { isClaudeSubcommandInvocation } from '../../utils/claude-subcommand-detector';
import {
resolveDroidProvider,
evaluateTargetRuntimeCompatibility,
@@ -367,11 +368,16 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
delete proxyEnv.ANTHROPIC_API_KEY;
const launchSettings = createOpenAICompatLaunchSettings(expandedSettingsPath, settings);
const launchArgs = [
'--settings',
launchSettings.settingsPath,
...appendThirdPartyWebSearchToolArgs(browserArgs),
];
// Claude subcommands reject `--settings` (it flips `agents` to list mode).
// Routing env vars still flow via proxyEnv. Issue #1218.
const isSubcommand = isClaudeSubcommandInvocation(browserArgs);
const launchArgs = isSubcommand
? appendThirdPartyWebSearchToolArgs(browserArgs)
: [
'--settings',
launchSettings.settingsPath,
...appendThirdPartyWebSearchToolArgs(browserArgs),
];
const traceEnv = createWebSearchTraceContext({
launcher: 'ccs.settings-profile.proxy',
args: launchArgs,
@@ -384,11 +390,12 @@ export async function runSettingsFlow(ctx: ProfileDispatchContext): Promise<void
return;
}
const launchArgs = [
'--settings',
expandedSettingsPath,
...appendThirdPartyWebSearchToolArgs(browserArgs),
];
// Skip `--settings` for Claude subcommands so the interactive agent view
// works; env vars from the settings file still flow via envVars. Issue #1218.
const isSubcommand = isClaudeSubcommandInvocation(browserArgs);
const launchArgs = isSubcommand
? appendThirdPartyWebSearchToolArgs(browserArgs)
: ['--settings', expandedSettingsPath, ...appendThirdPartyWebSearchToolArgs(browserArgs)];
const traceEnv = createWebSearchTraceContext({
launcher: 'ccs.settings-profile',
args: launchArgs,