fix(cli): bare-namespace help for invoice / swap / group / market#38
Merged
Conversation
`sphere invoice` (no subcommand) used to fall through to the legacy
dispatcher's `Unknown command: invoice` branch, contradicting
`sphere --help` which advertises `invoice` as a valid command.
Same for `swap`, `group`, `market` — they're all routed by
buildLegacyArgv's `prefixSub` which returns just the bare namespace
when the tail is empty.
This patch adds a fall-through case in the legacy dispatcher that
synthesises a help block listing the namespace's real subcommands
(sourced from COMMAND_HELP so it stays in sync) and exits 1. Single
sentence summary per sub keeps it scannable; full help is one
`--help` away.
== Output ==
$ sphere invoice
Error: 'sphere invoice' is a namespace and needs a subcommand.
Try: sphere invoice <subcommand> [options]
Available subcommands:
auto-return Show or configure auto-return settings.
cancel Cancel an invoice (terminal state).
close Close an invoice (terminal state).
create Create a new invoice by specifying a target address ...
...
transfers List all transfers related to an invoice ...
Run 'sphere invoice <subcommand> --help' for details.
== Notes ==
- `Error:` / `Try:` deliberately replace `Usage:` as the leading
line — legacy-cli-ux.test.ts's static guard requires real
per-command usage stubs to route through `failWithHelp()`. There
is no per-namespace COMMAND_HELP entry (invoice / swap / group /
market are virtual roots synthesised by Commander's prefixSub
bridge), so the help block is rendered inline rather than via
failWithHelp. An inline comment in the code documents this.
- `Unknown command:` default branch is unchanged — actual typos
still produce the original error.
- `dm`, `nametag`, `payments`, `crypto`, `util` namespaces have
different prefixSub semantics (some collapse to a single legacy
command, some forward bare-namespace as the actual command). Out
of scope here — file follow-up issues if those UX paths are
similarly broken.
== Verification ==
- npx tsc --noEmit: clean
- npx vitest run: 126/126 pass (UX static-guard now green)
- npx tsup: ESM + CJS + DTS build clean
- Smoke: `sphere invoice` / `sphere swap` / `sphere group` /
`sphere market` each print the new namespace help; `sphere
nonsense` still hits the unknown-command path normally
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sphere invoice(andsphere swap/sphere group/sphere market) without a subcommand used to fall through to the legacy dispatcher'sUnknown command: invoicebranch — directly contradictingsphere --helpwhich listsinvoiceas a valid command. Operators hit this loop:Root cause:
buildLegacyArgv'sprefixSub('invoice-', [])returns just the bare namespace['invoice']when the tail is empty, and the legacy dispatcher has no case for the bare name (onlyinvoice-create,invoice-pay, …).Fix
Insert a fall-through case in the legacy dispatcher for the four bare namespaces. Each prints a synthesised help block listing its real subcommands, sourced from
COMMAND_HELPso future subcommand additions show up automatically.Why not
Usage:/failWithHelp()legacy-cli-ux.test.ts's static guard requires real per-command usage stubs to route throughfailWithHelp(), which expects aCOMMAND_HELPentry. There is no per-namespaceCOMMAND_HELPentry —invoice/swap/group/marketare virtual roots synthesised by the Commander prefixSub bridge — so the help block is rendered inline. TheError:/Try:framing avoids tripping theUsage:regex. Inline code comment documents the trade-off.Why these four
They share the same
prefixSub('<ns>-', tail)bridge insrc/index.ts:buildLegacyArgv. Other namespaces (dm,nametag,payments,crypto,util) have different semantics (some collapse the bare invocation to a single legacy command, some treat it as a real command). Out of scope here.Out of scope
COMMAND_HELPentries + routing throughfailWithHelp()— would also require updating the static-guard test to recognise them. Worth doing as a follow-up if more namespaces grow help.dm/nametag/payments/crypto/utilbare invocations — file separate issues if their UX paths are similarly broken.sphere invoices→Did you mean invoice?) — that's Commander's built-in behaviour, unrelated.Test plan
npx tsc --noEmit— cleannpx vitest run— 126/126 pass (UX static-guard now green; was tripping on priorUsage:draft)npx tsup— ESM + CJS + DTS build cleansphere invoice,sphere swap,sphere group,sphere marketeach print the new namespace help;sphere nonsense-cmdstill produces the originalUnknown command:error normallytest/integration/cli-invoice.integration.test.tsassertingsphere invoice(no sub) exits non-zero and matches/Available subcommands:/Closes the "totally misleading help" report — discovered while prepping for a Discord demo where the operator tried
sphere invoiceafter seeing it insphere --help.