Why this issue exists
Pinned commander at 12.1.0 (current resolved) in PR fix/macos-tui-hardening to lock the supply chain. commander is 2 majors behind (latest 14.0.3). Bumping is non-trivial — opening this issue to track the migration as a focused PR.
How we use it
Blast radius: 61 files import commander. Top API surface across the codebase:
| Method |
Calls |
.option(...) |
451 |
.command(...) |
219 |
.description(...) |
220 |
.action(...) |
192 |
Two import shapes only:
import type { Command } from 'commander';
import { Command } from 'commander';
This is core CLI plumbing — every genie sec, genie agent, genie task, genie team, etc. registers via program.command(...).option(...).action(...) chains in src/genie.ts and src/term-commands/**.
What's changed (12.1.0 → 14.0.3)
v13.0.0 — breaking
- Excess command-arguments now error by default (
allowExcessArguments: false). A command with program.option('-p, --port <number>') and no declared positional args will reject node example.js a b c with "too many arguments. Expected 0 arguments but got 3."
- Throw during
Option construction for unsupported flag formats (e.g. multiple chars after a single -).
- Throw on multiple
.parse() calls when storeOptionsAsProperties: true.
Help.wrap() removed (refactored into formatItem() and boxWrap()).
v13.1.0 — features (non-breaking)
- Help styling routines (
styleTitle(), displayWidth(), boxWrap(), preformatted()) for color/wrap control.
getOutHasColors() / getErrHasColors() / stripColor() in configureOutput().
v14.0.0 — breaking
- Requires Node.js v20+ (we're on Node 24, Bun 1.3 — fine).
Help class internal refactor (formatItemList(), groupItems()).
v14.0.0 — features
- Option/command grouping in help via
.helpGroup(), .optionsGroup(), .commandsGroup() — would clean up the sprawling genie sec, genie agent subcommand listings.
- Unescaped negative numbers as option-arguments (e.g.
--threshold -5 works).
What we gain
- Help UX overhaul. Group
genie agent {spawn,kill,stop,resume,list,...} and genie sec {scan,remediate,fix,verify-install,quarantine,...} into named sections instead of one flat dump. Big DX win for new users.
- Color-aware help formatting for terminals that support it (without our own ANSI hacks).
- Catches accidental excess-arg invocations that today silently pass — fewer "why did my flag get ignored?" reports.
Migration cost estimate
- Audit phase: grep every
.command() chain for missing program.argument(...) declarations, then either declare the args or call .allowExcessArguments() to preserve current behavior. Most of our 219 commands already declare positional args via .argument() or in the command(<name> <arg>) sugar — but each needs verification.
- Help refactor: opt-in feature; could land in same PR or separate.
- Test impact: any test that asserts on
genie <cmd> <unexpected-arg> exit codes/error messages will need updating.
- Risk: medium-high — 61 files touched, but mostly mechanical. The "excess args" change is the gotcha: silent acceptance becomes explicit error, which IS the value but has to be audited everywhere.
Acceptance criteria
Context
- Followup from PR
fix/macos-tui-hardening (pinned packages for supply-chain hygiene post-CanisterWorm)
- Companion follow-ups: zod v4, inquirer v8, uuid v14
Why this issue exists
Pinned
commanderat12.1.0(current resolved) in PRfix/macos-tui-hardeningto lock the supply chain.commanderis 2 majors behind (latest14.0.3). Bumping is non-trivial — opening this issue to track the migration as a focused PR.How we use it
Blast radius: 61 files import
commander. Top API surface across the codebase:.option(...).command(...).description(...).action(...)Two import shapes only:
This is core CLI plumbing — every
genie sec,genie agent,genie task,genie team, etc. registers viaprogram.command(...).option(...).action(...)chains insrc/genie.tsandsrc/term-commands/**.What's changed (12.1.0 → 14.0.3)
v13.0.0 — breaking
allowExcessArguments: false). A command withprogram.option('-p, --port <number>')and no declared positional args will rejectnode example.js a b cwith "too many arguments. Expected 0 arguments but got 3."Optionconstruction for unsupported flag formats (e.g. multiple chars after a single-)..parse()calls whenstoreOptionsAsProperties: true.Help.wrap()removed (refactored intoformatItem()andboxWrap()).v13.1.0 — features (non-breaking)
styleTitle(),displayWidth(),boxWrap(),preformatted()) for color/wrap control.getOutHasColors()/getErrHasColors()/stripColor()inconfigureOutput().v14.0.0 — breaking
Helpclass internal refactor (formatItemList(),groupItems()).v14.0.0 — features
.helpGroup(),.optionsGroup(),.commandsGroup()— would clean up the sprawlinggenie sec,genie agentsubcommand listings.--threshold -5works).What we gain
genie agent {spawn,kill,stop,resume,list,...}andgenie sec {scan,remediate,fix,verify-install,quarantine,...}into named sections instead of one flat dump. Big DX win for new users.Migration cost estimate
.command()chain for missingprogram.argument(...)declarations, then either declare the args or call.allowExcessArguments()to preserve current behavior. Most of our 219 commands already declare positional args via.argument()or in thecommand(<name> <arg>)sugar — but each needs verification.genie <cmd> <unexpected-arg>exit codes/error messages will need updating.Acceptance criteria
commanderto14.0.3inpackage.json(exact pin).command()chains; declare positional args or.allowExcessArguments()per intended behavior.optionsGroup()/.commandsGroup()for the largest namespaces (agent,sec,task,team)bun testcleanContext
fix/macos-tui-hardening(pinned packages for supply-chain hygiene post-CanisterWorm)