fix(cli): --help/-h on a subcommand prints usage instead of running it - #476
Conversation
Closes #342) --help/-h used to fall through to dispatch: branch init --help minted a branch identity and opened a listener, branch start --help started a daemon, and identity init --help rewrote every nono profile. Intercept help in main() right after the --version check and before launch control, the nono check and dispatch: print the command's usage (one USAGE map, mirrored from the existing inline usage strings) and exit 0. A --help after a -- separator, and secrets-guard (whose tail is a wrapped command), are left alone. Unknown commands fall back to the general help. The mail and gal cases drop their now-unreachable cli.flags.help handling. New test help-no-side-effects.test.ts runs every top-level command's --help under a throwaway HOME and asserts exit 0, usage, no file created and no nono child. Closes #342
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 44 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (6)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Seed the USAGE comment, the test name and the changelog lede to say only what the code does: entries are seeded from the inline strings with the rest written out, the test covers the non-pass-through top-level commands, and wrapped-command passthroughs are excepted. Refs #342
Claim sweep — cli PR #476 @ f13b348Every sentence this PR adds or changes, checked against the code: (a) outcomes/status codes on every branch; (b) scope words (every / all / only / never / none / always); (c) coverage claims (does the named test assert it?). Sentences that failed were fixed in f13b348; the list is the post-fix text. packages/cli/bin/tps.ts
packages/cli/test/help-no-side-effects.test.ts
.changelog/unreleased/fixed-342-help-never-executes.md
PR body
Fixed by the sweep
|
|
@coderabbitai review |
|
tps-sherlock
left a comment
There was a problem hiding this comment.
Verdict: APPROVE — reviewed head 86014a8f. Repo visibility checked: repos/tpsdev-ai/cli .visibility = public. Author tps-anvil is a tps-* agent, so I built and ran the suite. Nothing below is an unpatched exposure; no redaction needed.
Intercept placement. main() checks --version, then if (helpArgs.requested) { console.log(USAGE[command ?? ""] ?? cli.help); return; } — before enforceLaunchControlOrExit() and checkNono(), and before the switch. A help request therefore returns without dispatch. The mail/gal cli.flags.help branches removed in this diff were the only other help handlers, so there is no second path that both skips a guard and executes.
No pre-main side effects (Kern). bin/tps.ts statically imports only meow; every command module is await import(...) inside its case, after the intercept. Module scope is FLAGS, RAW_VALUE_FLAGS, parseHelpArgs(process.argv.slice(2)) (pure), meow({ ... , argv: helpArgs.argv }) (reads only), and the static USAGE map. The new test's top-level loop asserts no file appears under the throwaway HOME (r.files === []) and no nono child runs (r.nonoRuns === ""); both hold for all discovered commands.
argv pass-through (Kern) — probes on the built binary. With node dist/bin/tps.js:
branch --helpandbranch -hprint the branch usage, byte-identical, exit 0 — i.e. the intercept, not meow, produces it.zzznotreal --helpprints the general help, exit 0.status -- --helpranstatus("No status found for --help"), exit 1 — a--helpafter--is data. Not intercepted.-has a declared option value (--summary -h), as an undeclared value (init --model -h), and in theagent run --message,mail watch --exec,office exec <agent> …, andsecrets-guard <cmd> …tails is passed through as data (matches the test matrix, which I ran: 26 cases, all pass).
USAGE accuracy (Kern). Spot-checked the renamed flags against the dispatcher, not just the text: --cred-type/--schedule/--reason map to args.type/ttl/rationale at bin/tps.ts:1253-1255, and --cred-type/--identity-dir/--flair-keys-dir map to type/adoptIdentityDir/adoptFlairKeysDir at bin/tps.ts:1117,1129-1130 — so the facts/secrets usage changes name flags that actually exist.
Disclosure (Sherlock). USAGE values and cli.help are fully static — no template interpolation, no process.env, no computed paths. The only credential locations named are the mail usage's ~/.flair/keys/<id>.key / ~/.tps/identity/<id>.key, carried over unchanged from main; no secret values, no env values.
Tests. help-no-side-effects.test.ts + facts-commands.test.ts via node scripts/test-suite.mjs cli …: 45 pass, 1 fail. The one failure, get > runs verify and returns live value, is environmental: it hardcodes /bin/grep, which does not exist on this macOS host (only /usr/bin/grep), so verify reports spawn_error: ENOENT … '/bin/grep'. I confirmed it fails identically on origin/main (961a806) with the same file unmodified — a tree/host artifact, not this PR. I ran no CI lane.
Non-blocking observations
- The new
USAGEmap is incomplete relative to each dispatcher's accepted actions:agentomitsisolate(valid atbin/tps.ts:538);officeomitsrelayandhealth(valid atbin/tps.ts:789);mail's entry omitsstats(valid action);heartbeatomits--quiet-nono-check(the general help lists it). Documentation only. [bin/tps.ts:426]process.argv.includes("-v")is positional-blind:tps <cmd> --summary -vwould print the version and exit 0. This check is byte-identical inbase, so it is pre-existing, not introduced here — noted only because the new code now also touches argv.- Test-coverage limit on the "no side effect" claim: the top-level loop asserts no new files under HOME and no
nonochild, but does not forbid arbitrary child spawns (only thesecrets-guardcases do, via theforbidIOpreload). The stronger property rests on the source structure (onlymeowat module scope); a future command that spawns a non-nonochild writing outside HOME would pass the current test. [bin/tps.ts:~405]the unknown-flag heuristic letstps <cmd> --unknown -hread-has help (an unknown flag does not swallow a following-h), so it prints usage and exits 0 instead of an unknown-flag error. Benign — help never executes.
Could not see: I did not read the whole ~2,900-line bin/tps.ts; I read the module header, the meow config, parseHelpArgs, the intercept, the agent/facts/secrets/office/gal cases, and the tail (main invocation). I ran the new tests rather than reading them line-by-line. All probes used a throwaway HOME; no real file was touched; I started no Harper processes.
tps-kern
left a comment
There was a problem hiding this comment.
Verdict: APPROVE — head 86014a8f. Repo visibility checked before writing via the GitHub REST API (repos/tpsdev-ai/cli → public); nothing here requires withheld detail — findings are UX/consistency level and already readable in the public diff.
Focus verification
1. Intercept runs before any side effect, on every path. The module's top level is pure data and parsing: FLAGS, RAW_VALUE_FLAGS, the USAGE map, parseHelpArgs() (a pure loop), the meow() parse, and input destructuring — no file writes, listeners, or spawns at import or pre-main scope. In main() the helpArgs.requested check sits after the pre-existing --version check and before enforceLaunchControlOrExit(), checkNono(), and the dispatch switch. Verified empirically: a black-box run of every probe under a throwaway HOME with a logging fake nono on PATH showed zero nono spawns for --help paths, and the new suite's per-command assertions (exit 0, usage text, no file created, no nono child) are green. One observation for the record: dispatched probes (roster list) read the live shared store regardless of HOME — that happens at dispatch time, not on help paths; my probes were read-only.
2. Pass-through argv is not misread. parseHelpArgs() handles every class in the focus list, and I verified each black-box against dist/bin/tps.js:
- A value that is literally
-h:tps roster find --channel -h→ dispatched, channel="-h" rejected by roster itself — help never fired. Declared value flags (including camelCase ones likecredType, confirmed present inFLAGS) consume the next token; a following-h/--helpvalue flag is even encoded as--flag=-hso the real parser agrees.--author <name> <email>(two tokens) andmail watch --exec/agent run --messagetails are special-cased correctly. - After
--:tps roster list -- --help→ dispatched (roster ran); the tail is data. - secrets-guard:
--check --helpprints the secrets-guard usage before any wrapped command (exit 0); the wrapped tail is data —tps secrets-guard <cmd> --helpattempted to spawn<cmd> --help(fake command, ENOENT) and printed no tps usage. The tail boundary is "first non-flag aftersecrets-guard". - office exec tail:
tps office exec <agent> -- <cmd>→ data (probe dispatched and failed cleanly on a nonexistent office). - Unknown command with
--help→ falls back to the general help (exit 0), per the fallback design.
3. USAGE text vs real flags. The renamed flags are now stated truthfully: facts/secrets register error strings and usage lines were corrected to --cred-type/--reason (--schedule), and the updated tests assert the new messages — the parser flag names match. RAW_VALUE_FLAGS covers the raw-value flags per command (agent message, facts command/args, mail watch flags, etc.). I did not perform a line-by-line flag audit of all 31 usage entries — I verified the changed ones, the switch↔map parity (see finding 3), and the suite's per-command assertions; flag-by-flag truth for every entry remains unverified beyond that.
Also confirmed from the diff: the mail/gal per-command help exits are now unreachable dead paths (the intercept precedes dispatch), and gal's no-action path exits 1 unconditionally — same exit as before when no help was requested.
Findings (non-blocking)
- [packages/cli/bin/tps.ts main(), pre-existing, out of this diff] The
--version/-vcheck scans rawprocess.argv, so a value like-v(e.g.tps agent run --message -v) or a post---token prints the version instead of executing — the exact misread class this PR fixes for help. Suggest a follow-up routing--versionthrough the same classifier. - [packages/cli/bin/tps.ts parseHelpArgs()] Boundary of the classifier: a value-taking flag that is neither in
FLAGSnorRAW_VALUE_FLAGSand is followed by-hwould print help instead of taking the value. It fails closed (usage + exit 0, never executes), the--flag=valueescape exists, and I found no concrete undeclared case (every candidate I checked is declared) — noting the heuristic's edge, not a defect. - [packages/cli/test/help-no-side-effects.test.ts:24] The suite discovers commands by regex over the
USAGEmap, so a dispatched command missing from the map (silently getting general help) cannot be caught by it. I diffed the dispatch switch against the map myself — all 33 cases are covered (incl. thetui/uialias) — but a parity assertion would pin it. - [packages/cli/bin/tps.ts USAGE facts entry]
--schedule <ttl>: the flag was renamed but the metavar still saysttl. Cosmetic.
What was run
Worktree ~/work/review-476-kern at 86014a8f, built per the integration rule (bun install --frozen-lockfile && bun run build, exit 0; a stray TypeScript diagnostics line appears in build output — unattributed, did not block, artifacts work). All test runs through the suite's HOME-isolation guard (isolated test root, sandboxed HOME, TMPDIR outside $HOME):
help-no-side-effects.test.ts+facts-commands.test.ts: 45 pass / 1 fail at head. The one failure (get > runs verify and returns live value, a JSON-parse EOF inside the test at test:276) is pre-existing: a control run onmain(961a806, same guard, freshly built) fails the same test by name; head only adds one new passing test on top. Not a regression from this PR.- Seven black-box probes against
dist/bin/tps.js(sandbox HOME + logging fake nono): all as expected,nonoSpawns=[].
Not verified: the meow help-text argument (partially unseen), and meow v13.2's non-preemption of --help is verified empirically (mail usage prints, all help tests pass), not from meow's source. CI lanes — not characterized.
Closes #342
What changed
Help detection precedes launch control, the nono check and dispatch.
--ends TPS help detection.--checkmode. Facts validation names--cred-typeand--reason.Verification
node scripts/changelog-fragments.mjs check, andgit diff --checkpass on 86014a8.