Skip to content

Commit 85b397c

Browse files
feat: add 'did you mean' suggestions for unknown commands
Implements a Levenshtein distance-based suggestion mechanism for the sfw CLI. When a user types an unknown command (e.g., 'chek' instead of 'check'), the tool now suggests the closest valid command. DX Improvement: - Adds immediate feedback for typos. - Reduces friction by suggesting the intended command. - Preserves existing help output.
1 parent 573e079 commit 85b397c

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

.Jules/palette.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
## 2024-05-20 - Palette's Initial Thoughts

cmd/sfw/main.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,61 @@ Workflows:
291291
}
292292
default:
293293
fmt.Fprintf(os.Stderr, "unknown command: %s\n", cmd)
294+
if suggestion := suggestCommand(cmd); suggestion != "" {
295+
fmt.Fprintf(os.Stderr, "Did you mean '%s'?\n\n", suggestion)
296+
}
294297
flag.Usage()
295298
os.Exit(1)
296299
}
297300
}
298301

302+
func levenshtein(s1, s2 string) int {
303+
r1, r2 := []rune(s1), []rune(s2)
304+
n, m := len(r1), len(r2)
305+
if n > m {
306+
r1, r2 = r2, r1
307+
n, m = m, n
308+
}
309+
current := make([]int, n+1)
310+
for i := 0; i <= n; i++ {
311+
current[i] = i
312+
}
313+
for j := 1; j <= m; j++ {
314+
previous := current[0]
315+
current[0] = j
316+
for i := 1; i <= n; i++ {
317+
temp := current[i]
318+
cost := 0
319+
if r1[i-1] != r2[j-1] {
320+
cost = 1
321+
}
322+
current[i] = min(min(current[i-1]+1, current[i]+1), previous+cost)
323+
previous = temp
324+
}
325+
}
326+
return current[n]
327+
}
328+
329+
func suggestCommand(cmd string) string {
330+
commands := []string{"check", "diff", "index", "scan", "migrate", "stats"}
331+
bestMatch := ""
332+
minDist := 100 // Arbitrary high number
333+
334+
for _, c := range commands {
335+
dist := levenshtein(cmd, c)
336+
if dist < minDist {
337+
minDist = dist
338+
bestMatch = c
339+
}
340+
}
341+
342+
// Only suggest if distance is small (e.g. <= 2) and less than half the command length
343+
if minDist <= 2 {
344+
return bestMatch
345+
}
346+
return ""
347+
}
348+
299349
// SYNERGY: Unified Pipeline - Integrity Check + Security Scanning
300350
func runCheck(target string, strictMode bool, enableScan bool, dbPath string) error {
301351
info, err := os.Stat(target)

0 commit comments

Comments
 (0)