Skip to content

sphere-cli UX consistency: unified currency input, human-friendly default output, complete --help, autocomplete, auto-help on invalid input #32

@vrogojin

Description

@vrogojin

Streamline the sphere-cli command-line UX so every command, subcommand, and sub-subcommand behaves consistently in how it takes input and how it presents output. This is a follow-up to the post-#397/#401 cleanup pass; the user will pick it up after a fresh-context session, so this issue is deliberately self-contained.

Scope — five concrete consistency goals

1. Unified currency input across all commands

Canonical syntax: human-friendly fractional amount separated from the coin symbol by a space.

sphere payments send <recipient> 100.5 UCT
sphere invoice create --target @alice --asset "7 UCT" --asset "0.001 BTC"
sphere swap propose --to @bob --offer "7 UCT" --want "2 ETH"
sphere invoice return <id> --recipient @bob --asset "100000 UCT"

Today this mostly works (src/legacy/legacy-cli.ts:425 parseAssetArg already handles "<amount> <symbol>" and several commands consume it), but coverage is incomplete and the argument shape diverges:

  • payments send <recipient> <amount> <coin> uses positional amount + coin (separate tokens)
  • invoice-create --asset "<amount> <coin>" uses quoted compound form
  • swap-propose --offer "<amount> <coin>" matches invoice-create
  • invoice-return --asset "<amount> <coin>" matches invoice-create

Required: every command that takes amount-plus-coin must accept the same form. Pick one canonical syntax (recommendation: positional <amount> <coin> mirrors payments send's shape and avoids the quote-juggling), document it once, and adapt every other site to accept it. NFT (--nft <tokenId>) input rules also need to be consistent across invoice-create / swap-propose / payments send.

2. Human-friendly default output (not raw JSON)

Most commands today print a raw JSON.stringify(result, null, 2) blob. Inventory in src/legacy/legacy-cli.ts:

Line Command
3093 nametag resolve/check
3129 / 3142 identity / address inspection
4166 invoice-list
4261 invoice-status (one of two sites)
4309 invoice-import
4383 invoice-deliver
4494 / 5266 invoice-status
4618 invoice-pay
4688 invoice-return
4722 invoice-cancel / similar

…plus ~17 more JSON.stringify outputs at lines 1798, 1894, 3015, 3093, 3177, 3195, 3216, etc.

Required: default output for end-user-facing commands should be a prettified table or labelled key-value block (see invoice-status line 4446 which already does ID: ... / Status: ... labelling — that style should be the template). Raw JSON output should be opt-in via a --json flag (machine-readable mode for scripts / pipes).

Acceptance: running e.g. sphere invoice create --target @alice --asset \"7 UCT\" and sphere invoice deliver <id> --to @bob should produce a readable table by default; --json should still emit the existing structured form for backwards compatibility with anyone scripting against the CLI.

3. Help works for every command, subcommand, sub-subcommand

Today the --help / -h / help handler is wired at a single top-level entrypoint (src/legacy/legacy-cli.ts:1716 and a second branch at line 1723), but the dispatch through to specific subcommands is patchy. Symptoms:

  • sphere wallet --help may not print wallet-specific help
  • sphere invoice deliver --help may not print deliver-specific help
  • sphere swap propose --help likewise

Required: every command in the COMMANDS registry (search src/legacy/legacy-cli.ts for usage: — 57+ entries) should respond to --help / -h / help by printing its own usage + flag table + examples. Common idiom in similar CLIs: a single helper printHelpFor(commandName) that the early-dispatch path calls before any side-effecting work runs.

4. Bash/zsh autocompletion

A completion generator already exists at src/legacy/legacy-cli.ts:5599+ (sphere-cli completions bash), but the user reports autocompletion is not working at all in practice. Two likely causes, both worth verifying:

  1. The generator output may not match the actual command shape (e.g. it's stale vs the current COMMANDS table at line 533+).
  2. Installing the completion file requires a system path (/etc/bash_completion.d/sphere-cli) which needs sudo. The setup step may not be documented as part of sphere init / installation.

Required:

  • Verify the generated completion is correct against the current command/flag inventory.
  • Document the installation step in the README (sudo path) and offer a no-sudo per-user fallback (~/.bash_completion.d/ / zsh $fpath).
  • If kernel/system-level setup is required, defer the actual install step but ship the verified-correct generator so the user can do the install themselves later.

5. Auto-help on invalid input

Today, invalid input typically falls through to console.error('Usage: ...') followed by process.exit(1). The single-line usage string isn't enough — it omits flag descriptions and examples. Recommended: on any parse failure (unknown subcommand, missing required arg, bad asset spec), the CLI should:

  1. Print a one-line "Error: " message
  2. Print the full help block for the closest matching subcommand
  3. Exit non-zero

Common in modern CLIs (Cargo, kubectl, gh). Concrete example today: passing sphere invoice create with no --asset flag should print the full invoice-create help, not just the one-line usage.

Suggested phasing (for the implementer)

  1. Pass A — output: route every JSON.stringify(result, ...) site through a shared formatOutput(payload, { json }) helper. Add --json to the global flag set so it applies everywhere. Define table formatters for the common payload shapes (Invoice, InvoiceStatus, TransferResult, Asset[], Token[], PeerInfo).
  2. Pass B — input: pick the canonical <amount> <coin> syntax and write one parseAssetArg (the existing one at line 425 is a good base) that every command uses. Update help strings + examples in lockstep.
  3. Pass C — help: add printHelpFor(commandName) and a single early-dispatch shim at the top of runCli() that catches --help / -h / help <cmd> / missing-required-arg cases and prints help instead of running the command.
  4. Pass D — completion: verify generator output, document install (with sudo + no-sudo paths), add a CI smoke that diffs the generator output against a golden file so it can't drift.

Each pass is mergeable independently. Pass A delivers the most visible user win and should land first.

Out of scope

  • Cosmetic redesign (colors, ASCII art, etc.) — focus is consistency, not theming.
  • Migrating off the legacy-cli.ts monolith — that's its own refactor; this issue can land within the existing file structure.
  • Daemon-mode commands (sphere daemon ...) — separate UX surface; consistency goals apply but daemon-output formats can be tackled in a follow-up if needed.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions