fix(cli): validate common option values - #551
Conversation
`validateCliOptions` read every option through `command.opts()`, which returns
defaults for options nobody passed, and then applied the `<n>` rule to them.
`ix smells` declares `--orphan-max-connections <n>` with a default of "0",
and the rule was positive-integer -- so `ix smells`, with no arguments,
exited 1 with
Error: option '--orphan-max-connections' must be a positive integer
before its action ever ran. Verified against main, where the same command
reaches the backend. Nothing caught it because no test runs `ix smells`, and
the suite only exercised options it passed explicitly.
Two changes:
- Validate only what the caller actually typed, via commander's own
`getOptionValueSource`. A default is the command author's choice and is by
definition a value the command accepts; checking it can only ever produce a
command nobody can run. This also retires the whole class -- any future
option whose default falls outside its documented `(a|b|c)` group would
have bricked its command the same way.
- `<n>` now means a non-negative integer rather than a positive one. 0 is
documented for several of these flags -- `--offset 0`, `--weak-max-neighbors
0`, and `--orphan-max-connections 0`, which is its own default -- while every
typo this exists to catch still fails: `1e3`, `10abc`, `0x10`, `-5`, `abc`.
The flags that really do mean "at least one" declare `parsePositiveInt` as
their own commander parser (`--pick`), so commander still rejects 0 there at
parse time, ahead of this hook.
Tests: replaced the `--limit 0` case with `--limit -1` (0 is now legal, -1 is
still not), added the two `smells` zero cases, and added a case per command
asserting it survives validation on its defaults alone -- the check that would
have caught this.
Review — one blocking defect, fixed on the branch
Against Cause. .option("--orphan-max-connections <n>", "Max connections for orphan files", "0")
Nothing caught it because the suite only exercised options it passed explicitly, and no test runs I audited every option the hook polices by instantiating the program and running Fixed in 839f9ee
Tests:
Left for you — the mechanism itselfThe blocker is fixed, but I did not touch the design, and it is the part worth your eye: allowed values are inferred by regex-matching the option's help text for a parenthesised group containing const group = option.description.match(/\(([^()]*(?:\|)[^()]*)\)/)?.[1];Three consequences:
One real behaviour change it makes that I think is right, for the record: An explicit Everything else in the PR — |
|
Thanks for the fix! I kept your commit unchanged and addressed the remaining validation logic with explicit choices. CI is passing. |
Fixes #550
Summary
Validate common CLI option domains before command actions can contact the backend.
Type
Changes
ix map --format silentis now part of the visible option domain.<n>options where0is documented, while dedicated positive-integer parsers still reject0where at least one is required.parseInt.--as-ofand--min-confidenceexplicitly.Reviewer fix retained
Commit
839f9eefixes the blockingix smellsno-argument regression by validating only CLI-sourced values and separating non-negative generic options from positive-only parsers. The follow-up commit leaves that implementation intact and only replaces help-text inference with explicit Commander choices.Validation
npm test(85 files, 1473 passed, 3 skipped; parser smoke passed)npm run typechecknpm run buildnpm run knipix smells --format jsonreaches the backend instead of failing option validationix doctor --format yamlexits 1 before backend access with Commander's allowed-choice errorChecklist
Release checklist (if merging to main)
ix-cli/package.jsonversion bumpedgit tag vX.Y.Z && git push origin vX.Y.Z)ix-memory-layertagged and released firstdocker-compose.standalone.ymlchanged: verifiedcurl | shinstall works