Skip to content

feat: fuzzy substring search with ranked scoring for slash commands#384

Open
felipeggv wants to merge 3 commits intoRunMaestro:mainfrom
felipeggv:feature/fuzzy-search-only
Open

feat: fuzzy substring search with ranked scoring for slash commands#384
felipeggv wants to merge 3 commits intoRunMaestro:mainfrom
felipeggv:feature/fuzzy-search-only

Conversation

@felipeggv
Copy link

Summary

Replaces the prefix-only slash command filter with ranked substring matching. Users can now find commands by typing any part of the command name or description — similar to VS Code's Command Palette.

Problem

The slash command dropdown only matched commands that started with the typed text. With growing numbers of custom commands (Spec-Kit, OpenSpec, user-defined), users had to remember exact command prefixes to find anything.

Example: typing /prd returned nothing, even though /GLOBAL:agents:prd-creator exists.

Solution

Three-tier ranked scoring system applied to both InputArea.tsx (dropdown render) and App.tsx (keyboard handler):

Score Match Type Example (input: hist)
3 Prefix on command name /history → appears first
2 Substring in command name /command-history-viewer → appears second
1 Substring in description /clear (if description mentions "history") → appears last

Results are sorted descending by score. The leading / is stripped from both input and command name before comparison to avoid false negatives.

Before / After

User types Before After
/prd No results /GLOBAL:agents:prd-creator (score 2)
/synopsis No results /history (description contains "synopsis", score 1)
/ard No results /wizard (name contains "ard", score 2)
/hist /history only /history (score 3, prefix) + description matches (score 1)
/clear /clear only /clear (score 3, prefix) — same behavior, backwards compatible

How This Helps Users

  • Discoverability — Find commands by what they do, not just their exact name
  • Partial recall — Don't need to remember full command prefixes
  • Scales with custom commands — As users add Spec-Kit, OpenSpec, and custom slash commands, search stays useful
  • No noise — Ranked scoring ensures prefix matches always appear above description-only matches

Files Changed

File Change
src/renderer/components/InputArea.tsx Dropdown filter: startsWith → scored includes on name + description
src/renderer/App.tsx Keyboard handler filter: same scoring logic

Implementation Details

// Scoring logic (same in both files)
const cmdName = cmd.command.toLowerCase().replace(/^\//, '');
if (cmdName.startsWith(searchTerm))   score 3 (prefix match)
if (cmdName.includes(searchTerm))     score 2 (substring in name)
if (description.includes(searchTerm))  score 1 (substring in description)
// No match → excluded from results
  • searchTerm strips the leading / from user input
  • cmd.description is guarded with && (some custom commands may not have descriptions)
  • useMemo dependency updated from inputValueLower to searchTerm in InputArea

Test Plan

  • Type / — all commands appear (empty search term = score 0, all included)
  • Type /prdprd-creator command appears
  • Type /synopsis/history appears (description match)
  • Type /hist/history appears first (prefix match before description matches)
  • Type /s — prefix matches (e.g., /status) appear above description-only matches
  • Arrow keys navigate filtered list correctly
  • Enter/Tab selects the highlighted command
  • Escape closes the dropdown
  • Terminal-only commands don't appear in AI mode (mode filtering unchanged)
  • npm run lint — zero new errors
  • npm test -- --run — all tests pass (5 pre-existing failures in symphony.test.ts)
  • npm run build — clean production build

🤖 Generated with Claude Code

Felipe Gobbi and others added 3 commits February 15, 2026 18:45
…iption

Replace prefix-only filtering (startsWith) with substring matching (includes)
on both command name and description fields. Users can now find commands by
typing any part of the name or description text (e.g., "synopsis" finds /history).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous includes() change still compared "/prd" against "/GLOBAL:...",
which never matched. Now both input and command name have the leading /
stripped before comparison, so typing "prd" correctly finds "/GLOBAL:agents:prd-creator".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Results are now sorted by match quality:
- Score 3: command name starts with search term (prefix match)
- Score 2: command name contains search term (substring match)
- Score 1: description contains search term
This prevents low-relevance description matches from burying exact name matches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@pedramamini
Copy link
Collaborator

@CodeRabbit review

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Feb 17, 2026

Warning

Rate limit exceeded

@pedramamini has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 54 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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

Comments