Skip to content

feat(mail): unknown-flag fuzzy-match for lark-cli mail domain#806

Open
xzcong0820 wants to merge 1 commit into
larksuite:mainfrom
xzcong0820:harness/01kr5edze944jyrxcn6m99jcd1
Open

feat(mail): unknown-flag fuzzy-match for lark-cli mail domain#806
xzcong0820 wants to merge 1 commit into
larksuite:mainfrom
xzcong0820:harness/01kr5edze944jyrxcn6m99jcd1

Conversation

@xzcong0820
Copy link
Copy Markdown
Collaborator

@xzcong0820 xzcong0820 commented May 11, 2026

Generated by the harness-coding skill.

  • Task ID: 01KR5EDZE944JYRXCN6M99JCD1-9
  • Branch: harness/01kr5edze944jyrxcn6m99jcd1
  • Target: main

Summary

Adds mail-domain unknown-flag fuzzy-match → JSON ErrorEnvelope with did-you-mean candidates for lark-cli mail. Strictly scoped to shortcuts/mail/ + a 1-line branch in shortcuts/register.go; non-mail domains are untouched. Exit code is unchanged (still 1 via ExitAPI, not ExitValidation) — no breaking change to callers parsing exit codes.

3 files changed, 508 insertions:

  • shortcuts/mail/flag_suggest.go — implementation (InstallOnMail, parseUnknownToken, collectFlags, suggest w/ prefix + Levenshtein DP, suggestShorthand, buildHint).
  • shortcuts/mail/flag_suggest_test.go — 12 table-driven tests covering prefix / Levenshtein / hidden-skipped / top-N stable sort / shorthand exact + prefix fallback / parse regex / errorFunc pass-through / exit-code regression.
  • shortcuts/register.go — +3 lines: if service == "mail" { mail.InstallOnMail(svc) } after the mount loop.

Sprints

ID Title Status Commit
S1 Synthesize transport contract for larksuite/cli (mail flag_suggest) passed
S2 Implement mail-domain unknown-flag fuzzy match + ErrorEnvelope passed 5ae9c2d

Source specs

  • V5 tech-design
  • /tmp/harness-agent/coding-dev/01KR5EDZE944JYRXCN6M99JCD1/01KR5EDZE944JYRXCN6M99JCD1-9/input/tech-design.md

This MR was created autonomously. Quality gates were enforced by the repo's own pre-commit hooks.

Summary by CodeRabbit

  • New Features

    • Mail commands now offer intelligent unknown-flag suggestions with up to several curated candidates and a concise hint to correct or view available flags.
  • Behavior

    • Mail service registration now installs the mail-specific flag-suggestion logic so unknown-flag errors produce structured, user-friendly hints.
  • Tests

    • Added extensive tests covering suggestion ranking, shorthand handling, hidden-flag exclusion, parsing edge cases, and error-to-exit formatting.

Review Change Stack

@github-actions github-actions Bot added domain/mail PR touches the mail domain size/L Large or sensitive change across domains or core paths labels May 11, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

📝 Walkthrough

Walkthrough

Adds mail-specific unknown-flag error detection and suggestion generation. A new InstallOnMail function registers a custom error handler on the mail Cobra command that detects unknown-flag errors, parses the problematic token, collects available flags, generates prefix-based and edit-distance-based suggestions, builds a user hint, and returns a structured ExitError with candidate details. Integration occurs in the shortcut registration flow.

Changes

Mail Flag Suggestion Error Handler

Layer / File(s) Summary
Candidate Type
shortcuts/mail/flag_suggest.go
Introduces Candidate struct representing suggested flags with long name, optional shorthand, edit distance, and reason (prefix or edit_distance).
Public API
shortcuts/mail/flag_suggest.go
Exports InstallOnMail(*cobra.Command) which installs a custom FlagErrorFunc on the command.
Error Handler & Support Functions
shortcuts/mail/flag_suggest.go
Implements flagSuggestErrorFunc that detects unknown-flag errors and dispatches to parseUnknownToken, rawUnknownToken, collectFlags, suggest (for long flags with prefix + Levenshtein matching), and suggestShorthand (exact shorthand or long-flag prefix fallback). Includes buildHint, levThreshold, and levenshtein helpers. Returns *output.ExitError with Detail.Type == "unknown_flag" and populated detail payload (unknown token, command path, candidates).
Integration
shortcuts/register.go, shortcuts/register_test.go
Calls mail.InstallOnMail(svc) during RegisterShortcutsWithContext when mounting the mail service and adds registration tests asserting mail-only installation and isolation for other services.
Tests
shortcuts/mail/flag_suggest_test.go
Tests suggest for prefix/edit-distance ranking and hidden flag exclusion; suggestShorthand for exact and fallback matching; parseUnknownToken for long/short flag parsing and malformed cases; flagSuggestErrorFunc for error conversion, detail payload, exit code (output.ExitAPI), and pass-through behavior. Includes newFakeMailCmd test helper.

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers:

  • liangshuo-1

🐰 Flag hints bloom like carrots in spring,
Unknown flags caught, suggestions they bring,
Edit distance measures, prefix paths show,
Better UX for mail, our CLI aglow!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the main objective and changes, but lacks a formal Test Plan section required by the template; it includes custom metadata instead. Add a Test Plan section documenting how the changes were verified (unit tests, manual testing) to match the repository template.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding unknown-flag fuzzy-matching for the mail domain in lark-cli.
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.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 91.04478% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.82%. Comparing base (4d62542) to head (d271bf3).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/mail/flag_suggest.go 90.90% 7 Missing and 5 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #806      +/-   ##
==========================================
+ Coverage   65.46%   65.82%   +0.36%     
==========================================
  Files         510      514       +4     
  Lines       47129    48020     +891     
==========================================
+ Hits        30851    31608     +757     
- Misses      13607    13689      +82     
- Partials     2671     2723      +52     

☔ 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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

🚀 PR Preview Install Guide

🧰 CLI update

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

🧩 Skill update

npx skills add xzcong0820/larksuite-cli#harness/01kr5edze944jyrxcn6m99jcd1 -y -g

Comment thread shortcuts/mail/flag_suggest.go Outdated
m = c
}
return m
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Issue: Go 1.23 (per go.mod) supports the built-in variadic min(). The custom min3 helper can be replaced with min(a, b, c) — one fewer function to maintain.

Severity: 💡 Suggestion

Suggested Fix:

curr[j] = min(curr[j-1]+1, prev[j]+1, prev[j-1]+cost)

Then remove min3.

if err == nil {
return nil
}
token, isShorthand, ok := parseUnknownToken(err.Error())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Issue: flagSuggestErrorFunc is set on the mail parent svc and cobra walks up the parent chain for the nearest non-nil hook — this works correctly. However, there's no integration-level test that exercises the full path: RegisterShortcutsInstallOnMail → unknown flag on a real mail subcommand → structured ExitError. The 12 unit tests cover the internal logic well, but a single end-to-end test in register_test.go would guard against the wiring breaking silently (e.g., if the if service == "mail" branch is accidentally removed or the package import changes).

Severity: 💡 Suggestion

Suggested Fix: Add a test similar to TestRegisterShortcutsMountsBaseCommands that calls RegisterShortcuts, looks up a mail subcommand, sets FlagErrorFunc to fire via an invalid flag, and asserts the returned error is an *output.ExitError with Type: "unknown_flag".

Adds shortcuts/mail/flag_suggest.go (~120 LOC) implementing a cobra
FlagErrorFunc hook for the mail subcommand tree. On 'unknown flag: --X'
or 'unknown shorthand flag: "X" in -X', it collects flags from the
current command via cmd.Flags().VisitAll, runs bidirectional prefix
match + Levenshtein DP (threshold=max(1,len/3+1), cap 4), and returns
top-5 candidates inside the existing ErrorEnvelope JSON:

  error.type = "unknown_flag"
  error.detail.{unknown, command_path, candidates}
  error.detail.candidates[*] = {flag, shorthand, distance, reason}

Exit code stays 1 (ExitAPI), not ExitValidation - no breaking change for
CI/agent scripts that check non-zero exit. stderr switches from plain
'Error: unknown flag: --X' to JSON envelope, aligning with the existing
'errors = JSON envelope on stderr' convention; mail unknown-flag was the
last gap.

Scope is strictly the mail subcommand tree: shortcuts/register.go gains
a single 'if service == "mail" { mail.InstallOnMail(svc) }' branch
after the existing Mount loop. Other domains (calendar / im / api /
auth / ...) keep cobra's default FlagErrorFunc and unchanged plain-text
stderr behavior.

Covers:
- shortcuts/mail/flag_suggest.go      (new, ~120 LOC)
- shortcuts/mail/flag_suggest_test.go (new, 12 table-driven tests)
- shortcuts/register.go               (+3 lines after mail Mount loop)

No changes to cmd/root.go or internal/output/* - ErrDetail.Detail is
already interface{}, handleRootError already routes *ExitError via
WriteErrorEnvelope.
@xzcong0820 xzcong0820 force-pushed the harness/01kr5edze944jyrxcn6m99jcd1 branch from 5ae9c2d to d271bf3 Compare May 11, 2026 12:37
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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@shortcuts/register_test.go`:
- Around line 357-363: The test currently only checks that returned error isn't
an *output.ExitError; additionally assert that the FlagErrorFunc is identity by
verifying the exact pointer is returned: call baseCmd.FlagErrorFunc()(baseCmd,
in) (already assigned to got) and assert got == in (pointer equality) to ensure
pass-through; update the test around the variables got and in (and the
FlagErrorFunc invocation) to include this equality check so any
wrapper/regression will fail.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d918f259-9a3a-4b2d-ab83-caca250b3df7

📥 Commits

Reviewing files that changed from the base of the PR and between 5ae9c2d and d271bf3.

📒 Files selected for processing (4)
  • shortcuts/mail/flag_suggest.go
  • shortcuts/mail/flag_suggest_test.go
  • shortcuts/register.go
  • shortcuts/register_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • shortcuts/register.go
  • shortcuts/mail/flag_suggest.go

Comment on lines +357 to +363
got := baseCmd.FlagErrorFunc()(baseCmd, in)
// Default cobra hook is identity — anything else means the mail hook
// leaked across domains.
var exitErr *output.ExitError
if errors.As(got, &exitErr) {
t.Fatalf("base service unexpectedly produced *output.ExitError: %#v", exitErr)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert true pass-through identity for non-mail errors

This test currently proves only “not an *output.ExitError”. To lock the default Cobra contract, also assert got == in (same pointer), otherwise wrappers/regressions could slip through.

Suggested test hardening
  in := errors.New("unknown flag: --bogus")
  got := baseCmd.FlagErrorFunc()(baseCmd, in)
  // Default cobra hook is identity — anything else means the mail hook
  // leaked across domains.
  var exitErr *output.ExitError
  if errors.As(got, &exitErr) {
    t.Fatalf("base service unexpectedly produced *output.ExitError: %#v", exitErr)
  }
+ if got != in {
+   t.Fatalf("base service should pass through original error pointer, got %T (%v)", got, got)
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
got := baseCmd.FlagErrorFunc()(baseCmd, in)
// Default cobra hook is identity — anything else means the mail hook
// leaked across domains.
var exitErr *output.ExitError
if errors.As(got, &exitErr) {
t.Fatalf("base service unexpectedly produced *output.ExitError: %#v", exitErr)
}
got := baseCmd.FlagErrorFunc()(baseCmd, in)
// Default cobra hook is identity — anything else means the mail hook
// leaked across domains.
var exitErr *output.ExitError
if errors.As(got, &exitErr) {
t.Fatalf("base service unexpectedly produced *output.ExitError: %#v", exitErr)
}
if got != in {
t.Fatalf("base service should pass through original error pointer, got %T (%v)", got, got)
}
🤖 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 `@shortcuts/register_test.go` around lines 357 - 363, The test currently only
checks that returned error isn't an *output.ExitError; additionally assert that
the FlagErrorFunc is identity by verifying the exact pointer is returned: call
baseCmd.FlagErrorFunc()(baseCmd, in) (already assigned to got) and assert got ==
in (pointer equality) to ensure pass-through; update the test around the
variables got and in (and the FlagErrorFunc invocation) to include this equality
check so any wrapper/regression will fail.

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

Labels

domain/mail PR touches the mail domain 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