Red-team follow-up to #1341: the original fix only guarded --print but
Claude accepts -p as the short form, and CCS itself passes -p in
headless-executor.ts. Without this check the security bypass survived
via the short flag.
Added regression tests: ['-p', 'agents'], ['-p', 'doctor'], ['-p']
alone, and injector short-circuit verification for -p form.
* fix(dispatcher): treat --print as non-subcommand Claude session
* style: apply prettier formatting
* fix(dispatcher): correct return type in subcommand detector
getClaudeSubcommandName returns string | null; return false (boolean)
was invalid after dev refactored isClaudeSubcommandInvocation to
delegate to it. Change to return null to preserve the --print safety
fix intent.
`stripClaudeSubcommandSessionArgs` was unconditionally stripping
`--permission-mode`, `--dangerously-skip-permissions`, and
`--allow-dangerously-skip-permissions` from every Claude subcommand
invocation. That's correct for `auth`/`doctor`/`mcp`/etc. — their
parsers reject those flags with `error: unknown option '...'`.
But `claude agents` does accept all three (see `claude agents --help`):
they configure the default permission mode for sessions dispatched from
the agent view. As a result, `ccs <profile> agents --permission-mode
bypassPermissions` silently dropped the flag before forwarding to Claude
and the agent view kept its previous default.
Add a small per-subcommand allowlist (`SUBCOMMAND_ALLOWED_SESSION_FLAGS`)
and a `getClaudeSubcommandName(args)` helper, then branch the strip
logic on the detected subcommand. `agents` keeps the three permission
flags; every other subcommand (including unknown future ones) falls
through to the existing strip behavior. `--teammate-mode` is still
stripped for every subcommand — no upstream subcommand accepts it.
Tests cover both before- and after-position arguments, the
`--flag=value` form, the `--teammate-mode` exclusion for `agents`, and
regression coverage for non-`agents` subcommands.
Squash merge PR #1240.\n\nValidated locally from the PR head because trusted-author GitHub CI was skipped for this fork PR:\n- bun run validate\n- bun run build:all\n- bun run test:all\n- CCS_E2E_SKIP_BUILD=1 bun run test:e2e
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.