cli: parse a help flag after the verb in the pm and node groups - #739
cli: parse a help flag after the verb in the pm and node groups#739colinhacks wants to merge 3 commits into
Conversation
`nub pm shim --help` installed the six package-manager shims and appended a PATH block to every shell startup file for the current shell, and `nub pm unshim --help` removed them again. `nub node shim --help` and `nub node unshim --help` behaved the same way. None of the fifteen `nub pm` / `nub node` verbs printed help for `--help` or `-h`. The top-level argument scan stops matching nub's own flags once a subcommand is seen, so `nub run build --watch` reaches the script rather than nub (the three-position rule). `pm` and `node` are non-forwarding groups that bypass clap, and their help guard only inspected argv[0]; past it the sub-verbs read no arguments at all, so the flag was dropped and the verb ran. Both groups now recognize `--help` and `-h` at any position. Neither forwards argv to a child process, and their only argument consumers take a package manager name or a version, so no help flag was ever a valid value there. The regression test asserts the predicate rather than driving `run_pm`: a test that ran the real verb would install shims into the test runner's own HOME the moment this regressed. Closes #653
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
ℹ️ No correctness issues found — one follow-up worth a decision.
Reviewed changes
group_help_requestedhelper — new predicate incrates/nub-cli/src/cli.rsmatchinghelpat argv[0] or--help/-hat any position, with a doc comment recording why the blanket scan is safe.run_node/run_pmguards — both group help guards now call the helper instead of matching on argv[0] only, sonub pm shim --helpandnub node shim --helpprint help instead of installing shims and editing shell startup files.- Unit test —
group_help_is_recognized_after_the_verbcovers the post-verb forms, the pre-existing argv[0] forms, and real verb invocations that must still run.
I reproduced the bug against published @nubjs/nub@0.7.5 to confirm the diagnosis in the PR body: nub node ls --help prints the version listing and nub pm cache --help prints the cache listing, so argv really does reach both groups with the flag intact and the argv[0]-only guard was the whole cause. I also enumerated every match arm in both groups — use takes a package-manager name, install/uninstall/pin take versions, cache takes clear, and the rest take nothing — so the blanket scan cannot swallow a legitimate value, and neither group forwards argv to a child. Clap-dispatched commands are unaffected: nub init --help already prints usage and scaffolds nothing.
ℹ️ nub agent is the third non-forwarding group and keeps the old guard
crates/nub-cli/src/agent/mod.rs:55 carries the identical argv[0]-only match, and the module doc describes it as "a non-forwarding group handled by a manual sub-verb match (like nub node / nub pm)". On 0.7.5 nub agent skill --help prints the skill and ignores the flag, while nub agent docs --help and -h fail with unexpected argument '--help'. Nothing destructive happens, so this is a follow-up rather than a blocker — but the helper's doc comment now enumerates two of the three groups it describes, which is the kind of gap that goes stale quietly.
Technical details
# Extend the group help guard to `nub agent`
## Affected sites
- `crates/nub-cli/src/agent/mod.rs:55` — `matches!(verb, None | Some("help") | Some("--help") | Some("-h"))`, the same argv[0]-only shape the PR replaces in `run_pm` / `run_node`.
- `crates/nub-cli/src/agent/mod.rs:~78` (`run_docs`) — the `other => bail!` arm is what turns a trailing `--help` into `unexpected argument '--help'`.
- `crates/nub-cli/src/cli.rs:8513-8523` — the new doc comment names `nub pm` and `nub node` as "a non-forwarding command group"; `agent` is a third one.
## Required outcome
- `nub agent docs --help` and `nub agent skill --help` print help rather than erroring or ignoring the flag, or the decision to leave `agent` alone is recorded so the next reader does not re-derive it.
## Suggested approach (optional)
- `group_help_requested` is a private `fn` in `cli.rs`; reaching it from `agent/mod.rs` needs `pub(crate)` (and arguably a home shared by all three groups).
- `agent`'s argument consumer takes a `/docs/...` slug, so the same "no help flag is valid there" reasoning holds.
## Open questions for the human
- Is keeping this PR scoped to the destructive groups deliberate, with `agent` tracked separately?ℹ️ Nitpicks
crates/nub-cli/src/cli.rs:8888— the line comment above therun_nodeguard still reads "nub node --help/-h/help: short usage listing the verbs", which describes the argv[0] forms only now that the guard fires at any position.
Claude Opus | 𝕏
`nub agent` is the third non-forwarding group that bypasses clap for a manual sub-verb match, and it carried the same argv[0]-only guard: `nub agent docs --help` failed with `unexpected argument '--help'`, and `nub agent skill --help` printed the skill markdown with the flag ignored. Neither is destructive, but both are the same defect. `group_help_requested` becomes `pub(crate)` and `agent::run` calls it, so all three groups share one definition. The `agent` argument consumer takes a `/docs/...` slug, so no help flag was a valid value there either. The agent test asserts only the `docs` form. The `skill` form returned 0 before this change too, so an exit-code assertion on it could never fail; the flag-anywhere semantics it relies on are asserted on the predicate instead. Also corrects the comment above the `run_node` guard, which still described the argv[0] forms only.
There was a problem hiding this comment.
ℹ️ No correctness issues in the new commit — one doc-comment wording nit inline.
Reviewed changes
Since the prior review (6dc7cb9), one commit extends the fix to the third non-forwarding group and tidies the surrounding comments.
nub agentnow shares the guard —agent::runcallscrate::cli::group_help_requestedinstead of matching argv[0], sonub agent docs --helpprints usage rather than failing withunexpected argument '--help', andnub agent skill --helpstops dumping the whole skill markdown.- Helper opened up and re-documented —
group_help_requestedbecamepub(crate)and its doc comment now names all three groups and restates the "safe as a blanket scan" rationale to coveragent's/docs/...slug consumer. run_nodeguard comment refreshed — it now describes the any-position semantics instead of the argv[0] forms only (the prior review's nitpick).- Wiring test added —
agent::tests::a_help_flag_after_the_verb_is_not_an_unexpected_argumentdrivesrun(&["docs", flag])and assertsOk(0); it fails without the fix becauserun_docs'sother => bail!arm makes.unwrap()panic. Thecli.rspredicate test gaineddocs --help/skill -hpositives and adocs --page /docs/runtime/jsxnegative.
I confirmed agent is in SUBCOMMANDS and is routed by dispatch_subcommand ahead of clap, so the top-level three-position scan hands the flag through untouched — the same path that made the pm/node bug reachable. I also checked the one manual group left out: run_global does its own argv[0]-only match, but it forwards to the engine config verb through parse_config_args, a clap parser that already handles --help at any position, so it has neither the bug nor the non-forwarding property the blanket scan depends on. Excluding it is correct.
Claude Opus | 𝕏
The comment claimed the sub-verbs never read past argv[0]. They do — `install <version>`, `use <pm>` and `docs --page <slug>` all take a value. It was each group's help GUARD that inspected argv[0] alone, and the flag then met whatever the verb does with its arguments, which is why the same defect surfaced three ways: ignored and the verb ran, consumed as a bad value, or rejected as an unexpected argument.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Since the prior review (981d77f), one commit changes the group_help_requested doc comment and nothing else — no code, no test, no behavior.
- Helper doc comment corrected — the middle paragraph now attributes the argv[0]-only inspection to each group's help guard rather than to the sub-verbs, and replaces the blanket "silently dropped" claim with the three symptoms the defect actually produced.
I checked each factual claim the new text makes rather than taking it at face value. no published Node version matches "--help" is the exact format string at crates/nub-core/src/version_management/manage.rs:89, so a value-taking verb really did consume the flag as a bad version. unexpected argument '--help' matches crates/nub-cli/src/agent/mod.rs:104, the other => bail! arm the new agent test asserts against. And the load-bearing "no group forwards argv to a child process" premise still holds — I re-enumerated run_pm's arms (which, use, update/up, cache, pin, shim, unshim, switch, _) and none spawns with the group's argv.
This resolves the inline thread from the prior review; I've replied and marked it resolved.
Claude Opus | 𝕏

Every
nub pmandnub nodesub-verb ignored--help/-hand ran the verb.nub pm shim --helpinstalled six shims and added a PATH block to every shell startup file;nub pm unshim --helpremoved them. The twonub nodeshim verbs behaved the same way.The top-level scan stops matching nub's own flags once a subcommand is seen, so
nub run build --watchreaches the script. Both groups bypass clap and guarded help on argv[0] only, so past it the flag was dropped.Both now recognize a help flag at any position. Neither forwards argv to a child, and their argument consumers take a package-manager name or a version, so no help flag was valid there.
Closes #653