Skip to content

feat(cmdutil): add did-you-mean suggestions for unknown flags#768

Open
xzcong0820 wants to merge 1 commit intolarksuite:mainfrom
xzcong0820:feature/cli-flag-did-you-mean
Open

feat(cmdutil): add did-you-mean suggestions for unknown flags#768
xzcong0820 wants to merge 1 commit intolarksuite:mainfrom
xzcong0820:feature/cli-flag-did-you-mean

Conversation

@xzcong0820
Copy link
Copy Markdown
Collaborator

@xzcong0820 xzcong0820 commented May 7, 2026

Summary

Wire cmdutil.UnknownFlagHandler onto the root command via
SetFlagErrorFunc so that unknown CLI flags produce the structured
ExitError envelope with an optional hint field (e.g.
"did you mean --max?"). AI agents that consume lark-cli output via
AGENTS.md pattern-match error.hint to recover from typos; today an
unknown flag yields a generic message and the agent has no signal for
what to retry with. cobra walks up to the root for FlagErrorFunc, so
a single install on rootCmd applies CLI-wide.

Changes

  • Add internal/cmdutil/flag_suggest.go with UnknownFlagHandler and
    SuggestFlag. Two-layer matching: a curated synonym map (other-CLI
    conventions agents commonly reach for, e.g. --limit -> --max,
    --folder -> --filter) followed by a Levenshtein fallback with
    threshold max(2, len/3). Hidden flags excluded; ties broken
    alphabetically.
  • Synonym layer only fires when the canonical target flag is registered
    on the invoked command, so we don't mislead users on commands that
    don't define it.
  • Short flags get a plain "unknown flag" message — pflag's short-flag
    namespace is separate from long flags and 1-char Levenshtein matches
    would be near-meaningless.
  • Other flag-error types (required missing, type mismatch, etc.) pass
    through unchanged so cobra's default semantics apply.
  • Wire the handler in cmd/build.go via rootCmd.SetFlagErrorFunc.

Behavior reference

Input Output hint
--limit 5 did you mean --max?
--folder INBOX did you mean --filter? pass folder via --filter '{"folder":"..."}'
--maxx 5 did you mean --max?
--halp did you mean --help?
-Z (no hint — short-flag namespace is separate)
--totally-bogus-xyz (no hint — beyond threshold)

Test Plan

  • Unit tests pass: go test ./internal/cmdutil/... covers
    flag_suggest_test.go (14 funcs incl. synonym hit/fallthrough,
    edit-distance, hidden-flag exclusion, tiebreaker, nil-defense,
    pflag message parsing, handler pass-through).
  • E2E regression: go test ./tests/cli_e2e/... runs
    flag_suggest_regression_test.go (5 hit cases + pass-through).
  • Manual smoke confirms lark-cli mail +triage --limit 5 --dry-run
    and equivalents across calendar, drive, im, okr
    subcommands all return the structured envelope with the expected
    hint.

Summary by CodeRabbit

  • New Features
    • Added intelligent flag suggestions for unrecognized command-line flags, including "did you mean?" hints for typos and suggestions based on common flag name synonyms to improve CLI usability.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 84f533cc-d876-40c4-9349-416da74760be

📥 Commits

Reviewing files that changed from the base of the PR and between 89bd750 and 7f84817.

📒 Files selected for processing (4)
  • cmd/build.go
  • internal/cmdutil/flag_suggest.go
  • internal/cmdutil/flag_suggest_test.go
  • tests/cli_e2e/flag_suggest_regression_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • cmd/build.go
  • internal/cmdutil/flag_suggest.go
  • tests/cli_e2e/flag_suggest_regression_test.go
  • internal/cmdutil/flag_suggest_test.go

📝 Walkthrough

Walkthrough

This PR adds a structured CLI flag suggestion system with "did you mean" hints for unknown flags. It introduces UnknownFlagHandler and SuggestFlag in internal/cmdutil, implements synonym-first and Levenshtein-based suggestions, wires the handler at the root cobra command, and adds unit and end-to-end tests.

Changes

CLI Flag Suggestion with "Did You Mean" Hints

Layer / File(s) Summary
Flag Name Parsing & Suggestion
internal/cmdutil/flag_suggest.go
parseUnknownFlagName extracts flag names from pflag error messages; SuggestFlag picks synonyms or falls back to Levenshtein distance over non-hidden flags.
Handler Implementation & Signature
internal/cmdutil/flag_suggest.go
UnknownFlagHandler intercepts "unknown flag" errors, skips shorthand suggestions, and wraps into ExitError with validation type and optional Detail.Hint; includes compile-time signature assertion.
Command Integration
cmd/build.go
Root cobra command is wired to use UnknownFlagHandler via SetFlagErrorFunc, routing unknown-flag errors through suggestion system.
Unit Tests
internal/cmdutil/flag_suggest_test.go
Comprehensive unit tests for synonyms, edit-distance corrections (including transposition), hidden-flag exclusion, deterministic tie-breaking, parsing, handler wrapping, shorthand handling, and levenshtein.
End-to-End Tests
tests/cli_e2e/flag_suggest_regression_test.go
E2E regression tests validate JSON-wrapped validation errors with hint envelopes for unknown flags and ensure non-unknown errors pass through without hint envelopes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

size/L

Suggested reviewers

  • liangshuo-1

Poem

🐰 I hop through flags with a curious grin,
I sniff for typos and point where to begin.
"Did you mean --max?" I whisper light,
A hint, a hop — the CLI set right.
Tiny rabbit, smart assist, in moonlit code tonight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main feature added: structured did-you-mean suggestions for unknown CLI flags.
Description check ✅ Passed The description comprehensively covers all required template sections: Summary explains motivation and scope, Changes lists implementation details and wiring, Test Plan documents unit/E2E/manual verification with checkmarks.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label May 7, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 7, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@7f84817aba8e858cbdcad46fb7071199ebb527e2

🧩 Skill update

npx skills add xzcong0820/larksuite-cli#feature/cli-flag-did-you-mean -y -g

@xzcong0820 xzcong0820 force-pushed the feature/cli-flag-did-you-mean branch from 770da89 to 89bd750 Compare May 7, 2026 07:46
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/cmdutil/flag_suggest_test.go (1)

20-31: ⚡ Quick win

Use the repo-standard test factory helper for unit tests.

Please replace the ad-hoc command builder with the standardized factory path to keep test setup consistent across the suite.

As per coding guidelines: "**/*_test.go: Use cmdutil.TestFactory(t, config) for test factories in unit tests".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cmdutil/flag_suggest_test.go` around lines 20 - 31, Replace the
ad-hoc builder newTriageLikeCmd used in the test with the repository-standard
test factory by calling cmdutil.TestFactory(t, config) (i.e., TestFactory(t,
config)) and configuring the returned factory/command to expose the same
structure and flags: ensure the root persistent "format" flag exists and that a
child command "+triage" is added with flags "max", "filter", "page-size" and the
hidden "internal" flag (MarkHidden("internal")). Remove newTriageLikeCmd and
adapt the test to use the factory-provided command/runner so the test setup
follows the repo convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/cmdutil/flag_suggest_test.go`:
- Around line 20-31: Replace the ad-hoc builder newTriageLikeCmd used in the
test with the repository-standard test factory by calling cmdutil.TestFactory(t,
config) (i.e., TestFactory(t, config)) and configuring the returned
factory/command to expose the same structure and flags: ensure the root
persistent "format" flag exists and that a child command "+triage" is added with
flags "max", "filter", "page-size" and the hidden "internal" flag
(MarkHidden("internal")). Remove newTriageLikeCmd and adapt the test to use the
factory-provided command/runner so the test setup follows the repo convention.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 720942a2-99be-4c52-8f64-659976d06478

📥 Commits

Reviewing files that changed from the base of the PR and between 770da89 and 89bd750.

📒 Files selected for processing (4)
  • cmd/build.go
  • internal/cmdutil/flag_suggest.go
  • internal/cmdutil/flag_suggest_test.go
  • tests/cli_e2e/flag_suggest_regression_test.go
✅ Files skipped from review due to trivial changes (1)
  • tests/cli_e2e/flag_suggest_regression_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/build.go

@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

❌ Patch coverage is 93.54839% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.45%. Comparing base (c3756f3) to head (7f84817).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
internal/cmdutil/flag_suggest.go 93.47% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #768      +/-   ##
==========================================
+ Coverage   65.21%   65.45%   +0.24%     
==========================================
  Files         504      509       +5     
  Lines       46673    46888     +215     
==========================================
+ Hits        30437    30692     +255     
+ Misses      13597    13551      -46     
- Partials     2639     2645       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Wire UnknownFlagHandler onto the root command via SetFlagErrorFunc.
cobra walks up to the root for FlagErrorFunc, so a single install on
rootCmd applies CLI-wide.

The handler covers two layers:
  - synonym map for cross-CLI conventions agents reach for first
    (--limit -> --max, --folder -> --filter with extra hint, etc.).
    Only fires when the canonical target flag is registered on the
    invoked command.
  - Levenshtein fallback with threshold max(2, len/3); hidden flags
    excluded; ties broken alphabetically.

Short flags get a plain "unknown flag" message -- pflag's short-flag
namespace is separate from long flags and 1-char Levenshtein matches
would be near-meaningless.

Other flag-error types (required missing, type mismatch, etc.) pass
through unchanged so cobra's default semantics apply. Output is the
structured ExitError envelope from output.ErrValidation, satisfying
the AGENTS.md contract for AI agents to pattern-match `error.hint`.
@xzcong0820 xzcong0820 force-pushed the feature/cli-flag-did-you-mean branch from 89bd750 to 7f84817 Compare May 7, 2026 10:09
@liangshuo-1
Copy link
Copy Markdown
Collaborator

Thanks for the thoughtful work here — the architecture choice (single-point install via cobra's FlagErrorFunc walk-up) and the test
coverage are both solid.

Heads-up: we're currently working on a broader refactor of the global hint / error-message system across the CLI, which overlaps
with this PR. We'll keep you posted on progress and share the new extension point once it lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants