Skip to content

feat(help): help topics, did-you-mean, humanized auth errors, command examples, completion help (PD-6074)#85

Merged
LanusseMorais merged 1 commit into
mainfrom
feature/PD-6074-cli-help-discoverability
Jun 9, 2026
Merged

feat(help): help topics, did-you-mean, humanized auth errors, command examples, completion help (PD-6074)#85
LanusseMorais merged 1 commit into
mainfrom
feature/PD-6074-cli-help-discoverability

Conversation

@LanusseMorais

@LanusseMorais LanusseMorais commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Polishes the CLI surface for discoverability and automation. Adds long-form help topics, usage examples on every mutating command, "did you mean" suggestions on typos, humanized auth errors, and a deterministic --no-input path so AI agents / CI scripts never block on interactive prompts.

Rebased onto main now that #84 (PD-6071 browser login) is merged, and squashed into a single commit. The whole diff is the review surface.

Help topics

New lsh help <topic> pages grouped under a dedicated section of lsh --help:

Help topics:
  authentication   How to sign in: tokens, profiles, env vars
  automation       Run lsh non-interactively (CI, scripts, AI agents)
  output-formats   Render results as table or JSON
  profiles         How profiles map to teams

Each topic renders as a clean documentation page (no flag dump under it).

Did-you-mean

$ lsh sever list
Error: unknown command "sever" for "lsh"

Did you mean this?
        servers

(SuggestionsMinimumDistance = 2 on rootCmd.)

Humanized auth errors

utils.PrintError rewrites 401/403 from the API into actionable guidance:

$ LATITUDESH_TOKEN=ak_invalid lsh projects list --no-input
✗ Error: Your authentication token is invalid or revoked.
Run 'lsh login' to sign in again, or see 'lsh help authentication'.

Detection (hasStatusMarker) anchors on the bracketed [<status>] marker the go-openapi runtime emits, which shows up in two real shapes:

  • [401] Unauthorized &{...} — generic response (what list endpoints return)
  • [POST /servers][401] createServerUnauthorized ... — typed response

It matches [401]/[403] only at the start of the string or right after the ] that closes the [<method> <path>] segment — so both shapes are caught while a bare [401] buried in an error payload is ignored, and loose words like unauthorized (e.g. "field 'role' has an unauthorized value") are never matched. Covered by a table-driven test in internal/utils/response_utils_test.go.

Examples on mutating commands

Every mutating command gained an Example: field (Cobra renders these before flags, matching the clig.dev recommendation): api_keys, servers (create/update/reinstall/destroy/schedule-deletion), projects, ssh_keys, tags, virtual_networks (+ assignments), plus login / auth status / auth logout / completion.

Every example was verified against the command's actual flag set — this caught and fixed real unknown flag bugs where examples used hyphens for flags that are underscore-named (--operating_system, --ssh_keys, --provisioning_type) and a stale --id on projects destroy (real flag is --id_or_slug).

SilenceUsage = true on these commands keeps errors clean (no flag dump under "Error: ...").

Cleaner flag descriptions

Removed hardcoded enum lists from generated flag descriptions (e.g. --operating_system, --plan, --site, --raid, --environment, --provisioning_type). They went stale every time the API added a SKU/region/OS. Replaced with short prose + e.g. <one-example> using the correct dash-separated plan slugs (c2-small-x86).

completion help rewrite

The generated cobra boilerplate (yourprogram, a path that fails on Homebrew) was replaced with per-shell instructions that work for any install method — a portable ~/.zsh/completions + compinit setup for zsh and a ~/.bashrc source line for bash, with Homebrew shortcuts noted alongside.

--no-input for agents and scripts

The --project prompt now respects the existing --no-input global flag. When set (or when stdin is not a TTY), commands that would otherwise open the interactive bubbletea picker exit with an actionable error:

$ lsh --no-input servers list
Error: --project is required (pass --project=<id>, --all-projects, or set LSH_PROJECT)

This matters because the bubbletea picker is not driveable by stdin strings — AI agents running inside a TTY (Claude Code, Aider, etc.) would otherwise hang on it. lsh help automation documents the full non-interactive contract.

Test plan

go build -o ./lsh-dev .

# Help topics + did-you-mean
./lsh-dev --help
./lsh-dev help authentication
./lsh-dev help automation
./lsh-dev sever list                          # → "Did you mean: servers"

# Examples render before flags, with real flag names
./lsh-dev servers create --help               # --operating_system / --ssh_keys, no Enum dump
./lsh-dev projects create --help              # --provisioning_type
./lsh-dev tags create --help

# Non-interactive mode
./lsh-dev --no-input servers list             # errors out, does not prompt
LSH_PROJECT=<id> ./lsh-dev servers list       # uses env, no prompt

# Humanized 401 (no real credentials needed)
LATITUDESH_TOKEN=ak_invalid ./lsh-dev projects list --no-input
# → "Your authentication token is invalid or revoked..."

# Control: a non-auth error is NOT humanized (passes through raw)
LATITUDESH_TOKEN=x ./lsh-dev projects list --no-input --base-path=/nonexistent
# → "[GET /projects] get-projects (status 404): {}"

Notes

  • Manual edits to generated *_operation.go files are tagged // MANUAL — keep when regenerating so a future swagger regeneration preserves them.
  • Help topic content is plain Cobra commands with a custom help template ({{.Long}}\n) — no third-party doc generator.
  • Volume commands were intentionally left untouched (handled in a separate task).

Greptile Summary

This PR polishes the CLI's discoverability surface: four long-form lsh help <topic> pages, "did you mean" suggestions on typos, humanized 401/403 errors with actionable guidance, a --no-input fast-fail path for agents/CI, and usage examples on every mutating command. It also fixes the previously-flagged tags update bug where AssignValues was called on an anonymous struct literal, causing every update to silently send empty strings.

  • Help & UX: adds help authentication|profiles|automation|output-formats topics, SuggestionsMinimumDistance=2, and SilenceUsage=true on mutating commands.
  • Auth error humanization: HumanizeAPIError detects go-openapi's [401]/[403] markers at their two known anchor positions, avoiding false positives on validation messages.
  • tags update fix: body is now a named struct passed by pointer so reflection can set fields; nil-pointer guards send only explicitly-provided attributes.

Confidence Score: 4/5

Safe to merge after correcting the invalid OS slug in the servers create example.

The servers create example uses ubuntu_22_04 which is not a recognized OS slug — the correct value is ubuntu_22_04_x64_lts. A user copying that example verbatim gets a validation error, which directly undermines the PR's goal of making examples accurate. All other changes look correct and well-tested.

cli/create_server_operation.go — the --operating_system value in the minimal deploy example needs to be corrected to ubuntu_22_04_x64_lts.

Comments Outside Diff (1)

  1. cmd/tags/update.go, line 91-101 (link)

    P1 AssignValues result is discarded — update always sends empty fields

    AssignValues is called with a pointer to an anonymous struct literal initialised from the local variables (name, description, slug, color, all ""). Reflection sets the flag values on that anonymous struct, but the local variables are never updated. When the UpdateTagTagsAttributes request is then built using &name, &description, &color, those pointers still reference the original empty strings.

    As a result, every lsh tags update call sends "" for all attributes, silently overwriting the tag's values rather than patching them. The fix is to use a named struct variable and read its fields when building the request.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: cmd/tags/update.go
    Line: 91-101
    
    Comment:
    **`AssignValues` result is discarded — update always sends empty fields**
    
    `AssignValues` is called with a pointer to an anonymous struct literal initialised from the local variables (`name`, `description`, `slug`, `color`, all `""`). Reflection sets the flag values on that anonymous struct, but the local variables are never updated. When the `UpdateTagTagsAttributes` request is then built using `&name`, `&description`, `&color`, those pointers still reference the original empty strings.
    
    As a result, every `lsh tags update` call sends `""` for all attributes, silently overwriting the tag's values rather than patching them. The fix is to use a named struct variable and read its fields when building the request.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
cli/create_server_operation.go:41
The OS slug in the minimal deploy example is `ubuntu_22_04`, but the only valid Ubuntu 22.04 slug in `SupportedOperatingSystems` (and the go-openapi enum) is `ubuntu_22_04_x64_lts`. A user copying this example verbatim would hit a validation error. The reinstall command's example already uses the correct slug for comparison.

```suggestion
    --operating_system=ubuntu_22_04_x64_lts \
```

Reviews (3): Last reviewed commit: "feat(help): improve CLI help discoverabi..." | Re-trigger Greptile

Comment thread cli/help_topics.go Outdated
Comment thread cli/create_server_operation.go Outdated
Comment thread internal/utils/response_utils.go Outdated
Base automatically changed from feature/PD-6071-cli-browser-login to main June 9, 2026 21:43
@LanusseMorais LanusseMorais force-pushed the feature/PD-6074-cli-help-discoverability branch from 6213d7f to bf3c283 Compare June 9, 2026 23:31
@LanusseMorais LanusseMorais changed the title feat(help): help topics, did-you-mean, humanized errors, automation hooks feat(help): help topics, did-you-mean, humanized auth errors, command examples, completion help (PD-6074) Jun 9, 2026
@LanusseMorais

Copy link
Copy Markdown
Collaborator Author

@greptile review

…humanized auth errors, command examples, completion help (PD-6074)
@LanusseMorais LanusseMorais force-pushed the feature/PD-6074-cli-help-discoverability branch from bf3c283 to 8a2e10a Compare June 9, 2026 23:52
@LanusseMorais

Copy link
Copy Markdown
Collaborator Author

@greptile review

@LanusseMorais LanusseMorais merged commit eef49d6 into main Jun 9, 2026
1 check passed
@LanusseMorais LanusseMorais deleted the feature/PD-6074-cli-help-discoverability branch June 10, 2026 00:00
@promptless

promptless Bot commented Jun 10, 2026

Copy link
Copy Markdown

Promptless prepared a documentation update related to this change.

Triggered by CLI PR #85

Documents CLI improvements: built-in help topics (lsh help authentication|automation|output-formats|profiles), command examples on mutating commands, did-you-mean typo suggestions, humanized auth errors, --no-input mode for CI/scripts/AI agents, and improved shell completion instructions.

Review: Add changelog entry for CLI help and discoverability improvements

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.

2 participants