Add CLI input tolerance with fuzzy flag/command matching
Agent-friendly argument normalization that auto-corrects common CLI syntax mistakes before cobra parses them: - Single-dash long flags: -zip -> --zip - Bare key=value: zip=33101 -> --zip=33101 - Typos via Levenshtein distance (max 2): --ziip -> --zip - Command typos: categoriess -> categories - Flag aliases: --zipcode, --dept, --search -> canonical names Corrections emit a "note:" line to stderr showing what was rewritten. Positional arguments for completion/help subcommands are preserved (e.g., "completion zsh" is not rewritten). Integration tests verify end-to-end behavior including tolerance notes, double-dash boundaries, and help output for rewritten args.
This commit is contained in:
73
cmd/cli_tolerance_test.go
Normal file
73
cmd/cli_tolerance_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNormalizeCLIArgs_RewritesCommonFlagSyntax(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"-zip", "33101", "json"})
|
||||
|
||||
assert.Equal(t, []string{"--zip", "33101", "--json"}, args)
|
||||
assert.NotEmpty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_RewritesTypoFlag(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"--ziip", "33101"})
|
||||
|
||||
assert.Equal(t, []string{"--zip", "33101"}, args)
|
||||
assert.NotEmpty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_RewritesCommandTypo(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"categoriess", "--zip", "33101"})
|
||||
|
||||
assert.Equal(t, []string{"categories", "--zip", "33101"}, args)
|
||||
assert.NotEmpty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_DoesNotRewriteCompletionPositionalArgs(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"completion", "zsh"})
|
||||
|
||||
assert.Equal(t, []string{"completion", "zsh"}, args)
|
||||
assert.Empty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_DoesNotRewriteHelpCommandArgAsFlag(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"help", "stores"})
|
||||
|
||||
assert.Equal(t, []string{"help", "stores"}, args)
|
||||
assert.Empty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_RespectsDoubleDashBoundary(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"stores", "--", "zip", "33101"})
|
||||
|
||||
assert.Equal(t, []string{"stores", "--", "zip", "33101"}, args)
|
||||
assert.Empty(t, notes)
|
||||
}
|
||||
|
||||
func TestNormalizeCLIArgs_LeavesKnownShorthandUntouched(t *testing.T) {
|
||||
args, notes := normalizeCLIArgs([]string{"-z", "33101", "-n", "5"})
|
||||
|
||||
assert.Equal(t, []string{"-z", "33101", "-n", "5"}, args)
|
||||
assert.Empty(t, notes)
|
||||
}
|
||||
|
||||
func TestExplainCLIError_UnknownFlagIncludesSuggestionAndExamples(t *testing.T) {
|
||||
msg := explainCLIError(errors.New("unknown flag: --ziip"))
|
||||
|
||||
assert.Contains(t, msg, "Try `--zip`.")
|
||||
assert.Contains(t, msg, "pubcli --zip 33101")
|
||||
assert.Contains(t, msg, "pubcli --store 1425 --bogo")
|
||||
}
|
||||
|
||||
func TestExplainCLIError_UnknownCommandIncludesSuggestionAndExamples(t *testing.T) {
|
||||
msg := explainCLIError(errors.New("unknown command \"stors\" for \"pubcli\""))
|
||||
|
||||
assert.Contains(t, msg, "Did you mean `stores`?")
|
||||
assert.Contains(t, msg, "pubcli stores --zip 33101")
|
||||
assert.Contains(t, msg, "pubcli categories --zip 33101")
|
||||
}
|
||||
Reference in New Issue
Block a user