Skip to content

feat(cli): render command hints with a wrapper-passed tool name - #983

Merged
aparajon merged 6 commits into
mainfrom
armand/cli-name-config
Aug 10, 2026
Merged

feat(cli): render command hints with a wrapper-passed tool name#983
aparajon merged 6 commits into
mainfrom
armand/cli-name-config

Conversation

@aparajon

@aparajon aparajon commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Every pasteable command hint the CLI prints (Force unlock: schemabot unlock ..., use 'schemabot status ...') starts with the bare binary name. When the CLI runs behind a wrapper command, pasting a hint invokes an unconfigured bare binary that can't reach the server instead of the wrapper the operator actually uses.

A wrapper can now supply its own invocation: an exec-style wrapper passes a hidden global --cli-name flag (e.g. --cli-name "acme schemabot"), and a wrapper that embeds the command packages calls cliname.Set before parsing. All hint sites render through the new pkg/cmd/cliname package (exported so embedders can use it), and kong's usage text picks up the name too, so printed commands work as pasted. When neither is used the plain schemabot default keeps direct use unchanged.

The flag is scanned from the raw args before kong.Parse because it feeds kong's usage name; kong still declares the flag (hidden) so it's accepted at any position, a parse test pins the two spellings to each other, and the scan accepts exactly what kong's scanner accepts. Kong help tags that embed command hints interpolate the name via a cli_name kong var, and the preview usage/error/demo surfaces render through cliname too.

The companion CLI client guide (docs/cli.md, including how to wrap the CLI with --cli-name) is split out into #984.

🤖 Generated with Claude Code

Every pasteable command hint the CLI prints starts with the bare binary
name, so when the CLI runs behind a wrapper, pasting a hint invokes an
unconfigured binary that can't reach the server. A wrapper now passes
its own invocation on every call via a hidden global --cli-name flag;
every hint site and kong's usage text render through the new cliname
package, so printed commands work as pasted. The flag is scanned from
the raw args because kong's usage name must be fixed before parsing;
an absent flag keeps the default name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 9, 2026 20:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes CLI-printed “pasteable” command hints wrapper-aware by introducing a hidden global --cli-name flag that can supply the wrapper invocation (e.g. --cli-name "wrapper schemabot"). The CLI scans this flag from raw args before kong.Parse so kong’s usage header and all runtime hints consistently render the wrapper’s tool name, while preserving the default schemabot behavior when the flag is absent.

Changes:

  • Add pkg/cmd/internal/cliname to store and resolve the rendered CLI name and to pre-scan --cli-name from raw args.
  • Wire cliname.Name() into kong.Name(...) and replace hard-coded schemabot ... hints across templates and commands.
  • Declare a hidden global kong flag (cli-name) so the flag is accepted at any position.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/cmd/main.go Pre-scan --cli-name and feed wrapper-aware name into kong usage (kong.Name(cliname.Name())).
pkg/cmd/internal/templates/progress.go Replace hard-coded schemabot hints with cliname.Name() in progress/status-related output.
pkg/cmd/internal/templates/plan.go Render “re-run with --allow-unsafe” hint using cliname.Name().
pkg/cmd/internal/templates/locks.go Render unlock hints using cliname.Name() so wrapper users can paste commands.
pkg/cmd/internal/cliname/cliname.go New package providing global CLI name resolution and raw-args scanning for --cli-name.
pkg/cmd/internal/cliname/cliname_test.go Unit tests covering name lifecycle and --cli-name arg scanning behavior.
pkg/cmd/commands/watch_tui.go Make TUI exit/context command hint wrapper-aware via cliname.Name().
pkg/cmd/commands/watch_tui_view.go Update various TUI footer/reattach/proceed hints to use cliname.Name().
pkg/cmd/commands/progress.go Update validation error message to point at wrapper-aware status command.
pkg/cmd/commands/plan.go Update “no endpoint configured” guidance to use wrapper-aware configure command.
pkg/cmd/commands/login.go Update profile/endpoint configuration guidance to use wrapper-aware configure command.
pkg/cmd/commands/fixlint.go Update follow-up hint (plan) to use wrapper-aware command name.
pkg/cmd/commands/configure.go Update post-configure example commands to use wrapper-aware invocation.
pkg/cmd/commands/common.go Declare hidden global cli-name flag and update several printed hints to use cliname.Name().
pkg/cmd/commands/apply.go Update apply preflight messaging and revert-window hint to use wrapper-aware commands.
pkg/cmd/client/config.go Update token refresh/login guidance to use wrapper-aware login command.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/cmd/internal/cliname/cliname_test.go
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aparajon
aparajon marked this pull request as ready for review August 9, 2026 23:14
A wrapper that embeds the command packages in its own kong CLI (rather
than exec'ing the binary) must call cliname.Set before parsing, which an
internal/ package forbids from another module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unlock command requires -d, so the pasteable hint must carry it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Kiran01bm

Copy link
Copy Markdown
Collaborator

🤖 Review findings - created by Kiran's code review agent - for pull/983, 67527d3.

Verdict: 7 findings — 0 blocking; 4 non-blocking (live sweep gaps + hygiene), 3 suggestions. CI is fully green (32/32); merges cleanly with current main.

Non-blocking

  1. Live preview surfaces missed by the sweeppkg/cmd/commands/preview.go#L155 fmt.Errorf("unknown preview type: %s (run 'schemabot preview' for valid types)") is a live runtime error hint, and printPreviewUsage prints five pasteable schemabot preview … lines (#L165, #L334-L337). Under a wrapper, sq schemabot preview bogus tells the operator to run schemabot preview — the exact unconfigured-bare-binary paste this PR exists to eliminate, and it contradicts the body's "All hint sites render through the new pkg/cmd/cliname package". Trivial cliname.Name() conversions. (Preview is dev-only, hence non-blocking.)

  2. Kong help: tags still embed the bare namepkg/cmd/commands/apply.go#L29 help:"Defer cutover until manual trigger (use 'schemabot cutover')" and preview.go#L14. Verified live: sq schemabot apply --help renders the usage header with the wrapper name but this flag line still says schemabot cutover — inconsistent within one help screen. Struct tags are compile-time, but kong v1.16.0 supports ${var} interpolation in help text via kong.Vars — already used for ${version} at main.go#L74 — so (use '${cli_name} cutover') plus one Vars entry closes it without restructuring.

  3. The flag name is spelled independently in two places with no test pinning they matchconst flagName = "--cli-name" in cliname.go#L22 (what FromArgs scans for) vs the name:"cli-name" tag on common.go#L34 (what kong declares). A future rename of either silently desyncs them: kong rejects or misparses while FromArgs still scans the old spelling, and nothing fails until a wrapper user hits it. No test drives --cli-name through an actual kong.Parse (the body's "accepted at any position" and "kong's usage text picks up the name" claims are exercised nowhere). One small test constructing the kong app and parsing --cli-name x would pin both.

  4. "sq schemabot" as the example wrapper name — in the exported package doc (cliname.go#L27), six times in cliname_test.go, and the PR body. AGENTS.md's OSS rule (#L100: "Never reference internal company names or proprietary details in code or comments") reads as banning naming Block's internal sq CLI in this public repo. Plausible rather than clear-cut — it reads generic — but a neutral example (mycli schemabot) serves the docs equally well.

General suggestions

  1. Harden FromArgs against flag-like values: at cliname.go#L55 the space form accepts any next token, while kong rejects hyphen-leading values — so schemabot --cli-name -e staging status (value forgotten) sets the name to -e and the resulting kong error banner renders as -e: error: --cli-name: expected string value … with Usage: -e <command>. Empirically confirmed this divergence is confined to command lines kong rejects anyway (never a successful parse), so it's purely cosmetic — but skipping hyphen-prefixed space-form values would make error output clean too.

  2. Preview/demo narration in pkg/cmd/internal/templates/preview_{progress,defer,sequential,vschema}.go hardcodes schemabot … lines, so a wrapper-invoked demo mixes both names in one output (verified live: --cli-name 'sq schemabot' preview cli_locking_all shows sq schemabot unlock -d testapp next to demo lines saying schemabot cutover …). Correct-by-design for the TEMPLATES.md snapshot (regenerated without --cli-name), so cosmetic — worth a decision rather than an accident.

  3. Commit hygiene nit: fb92a0fe test(cli): … also changes production code (atomic.Valueatomic.Pointer[string], needed for the nil-reset), which the test-scoped message doesn't mention.

The one thing that could have broken, verified

Hand-scanning raw argv with a second, independent parser of the same flag kong declares — then baking the result into kong's own usage name before kong parses. If FromArgs and kong ever disagreed on a successful parse, a wrapper could steal a legit argument as the name or render a wrong name on a working invocation. Probed exhaustively with a scratch program against the pinned kong v1.16.0 mirroring the real CLI shape: every divergence case (-d --cli-name, --cli-name --force, flag-like space-form values) coincides with a kong parse error — kong's scanner rejects hyphen-leading values in space form (scanner.go:172-178), the exact set FromArgs handles differently — and on every input kong accepts (= form including hyphen-leading and empty values, space form with plain values, positions before/after subcommands, after --, last-occurrence-wins) the two agree. Multi-word kong.Name("sq schemabot") renders correctly in top-level help, subcommand help, the "Run … --help" footer, and error prefixes. And the only path into cliname.Set is os.Args in main (main.go#L67, before kong.Parse and before any goroutine) — no remote or config value can ever feed the rendered name.

Verified correct

  • TEMPLATES.md is genuinely regenerated, not hand-edited: it's produced by scripts/update-templates.sh (pre-commit hook); a finder rebuilt the PR-head binary, re-ran the generation, and diffed — byte-identical. The two changed lines are real regeneration output.
  • The lock-hint fix is correct: unlock's Database field is required:"" — bare schemabot unlock (the old hint) errors out as pasted, so adding -d <database> fixes a genuinely broken hint; all WriteLockConflict callers pass a non-empty database (config loading rejects empty).
  • End-to-end wrapper behavior verified on the built binary: with --cli-name 'sq schemabot', hints and kong usage both render the wrapper name; without it, output is byte-identical to before (default path unchanged, existing hint-string test assertions still pass).
  • Every remaining schemabot literal in pkg/cmd classified: env vars (SCHEMABOT_*), the schemabot.yaml filename, ~/.schemabot dir, package docs, and comments are all legitimately untouched; pkg/webhook's schemabot plan/apply/… strings are PR-comment bot-command syntax (server-side identity), correctly not converted.
  • Printf verb/arg counts checked on every converted site (including the 5-verb WriteStopSuccess line); log.emit in apply.go keeps its key/value shape; the To trigger cutover: alignment double-space survives.
  • Exporting pkg/cmd/cliname is justified: the binary is package main so an embedding wrapper can't import it; internal/ would forbid foreign modules from calling Set; the kong-parsed Globals.CLIName field is write-only by design (declared solely so kong accepts the flag — reading it can't work for kong.Name, which needs the value pre-parse).
  • No cross-test pollution: cliname.Set has exactly one caller in the repo (main.go); each package's tests run in their own binary; the package's own test resets the global around itself with no t.Parallel.
  • No drift hazard: merge-tree vs current main (40a505c) is clean, and none of the 4 commits main gained add new hint sites the sweep would miss.

This review was generated by Claude Code (claude-fable-5).

aparajon and others added 2 commits August 9, 2026 22:18
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Close the hint surfaces the first sweep missed: the preview usage/error
hints, the demo narration lines in preview templates (so a wrapper-invoked
demo no longer mixes tool names), and the kong help tags that embed
command hints — now interpolated via a cli_name kong var. FromArgs skips
hyphen-leading space-form values so it accepts exactly what kong's own
scanner accepts, and a parse test pins the kong flag declaration and the
raw-args scan to the same spelling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@aparajon

aparajon commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

🤖 Thanks — all addressed in a5acfc7 except the commit-message nit (that commit is now in approved history, so leaving it rather than rewriting): preview usage/error hints and the preview-template demo narration render through cliname.Name() (TEMPLATES.md regenerates byte-identical), the two kong help tags interpolate ${cli_name} via kong.Vars, FromArgs now skips hyphen-leading space-form values to match kong's scanner, and TestCLINameFlagSpelling pins the kong declaration and the raw-args scan to the same spelling. The naming finding was independently resolved earlier today — examples now use a fictional acme schemabot.

This reply was generated by Claude Code (Fable 5).

@aparajon
aparajon merged commit 40f4aba into main Aug 10, 2026
32 checks passed
@aparajon
aparajon deleted the armand/cli-name-config branch August 10, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants