Skip to content

feat: enable fuzzy matching for slash commands and session filter#467

Open
felipeggv wants to merge 7 commits intoRunMaestro:mainfrom
felipeggv:feat/fuzzy-search
Open

feat: enable fuzzy matching for slash commands and session filter#467
felipeggv wants to merge 7 commits intoRunMaestro:mainfrom
felipeggv:feat/fuzzy-search

Conversation

@felipeggv
Copy link

@felipeggv felipeggv commented Feb 26, 2026

Summary

  • Enable fuzzy matching for session filter in Left Bar (previously exact prefix match only)
  • Enable fuzzy matching for slash command autocomplete in input area
  • Update test expectations to reflect new fuzzy matching behavior

Details

Previously, typing /r would only match commands starting with "r". Now it matches any command containing "r" anywhere in the name (e.g., /clear matches /r because "clear" contains "r"). Same improvement applied to the session filter in the Left Bar sidebar.

Test plan

  • Unit test updated for new fuzzy matching behavior
  • ESLint clean
  • Manual: type partial text in Left Bar filter, verify fuzzy matches appear
  • Manual: type / in input, verify fuzzy autocomplete suggestions

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Command autocomplete now uses fuzzy matching with relevance ranking (including descriptions) and respects terminal vs AI-mode visibility.
    • Session list search now uses fuzzy matching across session names, AI tabs, worktrees and branches.
    • Keyboard selection for slash commands improved to reliably pick and insert the best-matched command.
  • Tests

    • Updated tests to reflect fuzzy-match behavior for slash commands in AI mode.

Felipe Gobbi and others added 3 commits February 26, 2026 15:48
The agent filter was using exact substring matching (.includes()),
making it impossible to find agents with non-contiguous character queries.
Now uses the existing fuzzyMatch() utility for consistent behavior
with File Search Modal and Tab Switcher.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Slash command search was using startsWith() prefix matching, requiring
exact contiguous character input. Now uses fuzzyMatchWithScore() with
3-tier ranking (prefix > fuzzy name > fuzzy description) in InputArea
and fuzzyMatch() in useInputKeyDown for consistent keyboard navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update useInputKeyDown test to expect /clear fuzzy match for '/r' input
since fuzzy matching now matches 'r' anywhere in command names.

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

coderabbitai bot commented Feb 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56c64d6 and 013d812.

📒 Files selected for processing (1)
  • src/renderer/hooks/input/useInputKeyDown.ts

📝 Walkthrough

Walkthrough

Introduce a fuzzy, scored matching helper for slash commands and apply fuzzy matching to session searches. Replace local prefix-only slash filtering with filterAndSortSlashCommands; update InputArea prop types and keyboard handling; adjust tests to reflect fuzzy-match behavior.

Changes

Cohort / File(s) Summary
Slash command filtering (components & hook)
src/renderer/components/InputArea.tsx, src/renderer/hooks/input/useInputKeyDown.ts
Replaced local startsWith-based filtering with a memoized searchTerm and calls to filterAndSortSlashCommands(...). Updated InputArea prop type to SlashCommandEntry[]. Added safe index bounding when applying selected slash command on Tab/Enter.
Search utilities
src/renderer/utils/search.ts
Added SlashCommandEntry interface and exported filterAndSortSlashCommands<T extends SlashCommandEntry>(commands, searchTerm, isTerminalMode). Implements terminal/AI mode filtering, prefix scoring, fuzzy-match-with-score fallback, and sorting by descending score.
Session list fuzzy search
src/renderer/components/SessionList.tsx
Replaced ad-hoc substring/lowercase checks with fuzzyMatch for session names, AI tab names, worktree/branch names, and group matching logic.
Tests
src/__tests__/renderer/hooks/useInputKeyDown.test.ts, src/__tests__/renderer/utils/search.test.ts
Updated useInputKeyDown test expectation to reflect fuzzy matching (e.g., input '/r' now fuzzy-matches '/clear' resulting in setInputValue('/clear')). Added tests validating filterAndSortSlashCommands behavior: mode-aware filtering, prefix vs fuzzy ranking, case-insensitivity, empty-query behavior, and preservation of extra object properties.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: introducing fuzzy matching for slash commands and session filtering, which is the primary focus of all modifications across multiple components.

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

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

Copy link

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/components/SessionList.tsx (1)

1903-1940: ⚠️ Potential issue | 🟡 Minor

Inconsistent filtering logic in group expansion effect.

This useEffect still uses .toLowerCase().includes() for matching (lines 1909-1911), while the main sessionCategories memo uses fuzzyMatch. This inconsistency means:

  1. Groups may not expand for sessions that match via fuzzy logic but not substring.
  2. User experience differs between what's filtered vs. what groups auto-expand.

Consider updating this effect to use fuzzyMatch for consistency.

🔧 Proposed fix
 	useEffect(() => {
 		if (sessionFilter) {
 			// Find groups that contain matching sessions (search session name AND AI tab names)
 			const groupsWithMatches = new Set<string>();
-			const query = sessionFilter.toLowerCase();
+			const query = sessionFilter;
 			const matchingSessions = sessions.filter((s) => {
-				if (s.name.toLowerCase().includes(query)) return true;
-				if (s.aiTabs?.some((tab) => tab.name?.toLowerCase().includes(query))) return true;
+				if (fuzzyMatch(s.name, query)) return true;
+				if (s.aiTabs?.some((tab) => tab.name && fuzzyMatch(tab.name, query))) return true;
 				return false;
 			});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/SessionList.tsx` around lines 1903 - 1940, The effect
that computes matchingSessions (inside the useEffect using sessionFilter) uses
substring .toLowerCase().includes() which is inconsistent with the
sessionCategories memo that uses fuzzyMatch; replace the substring checks with
the same fuzzyMatch utility (call fuzzyMatch(sessionFilter, s.name) and
fuzzyMatch(sessionFilter, tab.name) for aiTabs) so group expansion logic matches
the main filter, and ensure matchingSessions and hasMatchingBookmarks use those
fuzzyMatch checks; also update the useEffect dependency array to include
sessionFilterOpen, sessions, and fuzzyMatch (or its module) so the effect
re-runs when those change.
🧹 Nitpick comments (1)
src/renderer/hooks/input/useInputKeyDown.ts (1)

209-219: Filtering logic duplicated between useInputKeyDown and InputArea.

This file uses a simple boolean filter (prefix OR fuzzy name OR fuzzy description), while InputArea.tsx uses a scoring-based approach with tiered ranking (prefix > fuzzy name > fuzzy description). The two implementations may produce different filtered results or ordering for the same input.

Consider extracting a shared utility function to ensure consistent slash command filtering behavior across both locations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/input/useInputKeyDown.ts` around lines 209 - 219,
Duplicate filtering logic in useInputKeyDown (filteredCommands/searchTerm) and
InputArea.tsx causes inconsistent results; extract a shared utility (e.g.,
computeSlashCommandScore or filterAndScoreSlashCommands) that accepts
allSlashCommands, inputValue, isTerminalMode and returns a scored & sorted list
using the same tiered ranking: exact/prefix match highest, fuzzy name next,
fuzzy description last, while honoring terminalOnly and aiOnly flags; replace
the inline logic in useInputKeyDown (and update InputArea to use the new
utility) so both locations call the same function (reusing fuzzyMatch) and
consume the sorted results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/renderer/components/SessionList.tsx`:
- Around line 1903-1940: The effect that computes matchingSessions (inside the
useEffect using sessionFilter) uses substring .toLowerCase().includes() which is
inconsistent with the sessionCategories memo that uses fuzzyMatch; replace the
substring checks with the same fuzzyMatch utility (call
fuzzyMatch(sessionFilter, s.name) and fuzzyMatch(sessionFilter, tab.name) for
aiTabs) so group expansion logic matches the main filter, and ensure
matchingSessions and hasMatchingBookmarks use those fuzzyMatch checks; also
update the useEffect dependency array to include sessionFilterOpen, sessions,
and fuzzyMatch (or its module) so the effect re-runs when those change.

---

Nitpick comments:
In `@src/renderer/hooks/input/useInputKeyDown.ts`:
- Around line 209-219: Duplicate filtering logic in useInputKeyDown
(filteredCommands/searchTerm) and InputArea.tsx causes inconsistent results;
extract a shared utility (e.g., computeSlashCommandScore or
filterAndScoreSlashCommands) that accepts allSlashCommands, inputValue,
isTerminalMode and returns a scored & sorted list using the same tiered ranking:
exact/prefix match highest, fuzzy name next, fuzzy description last, while
honoring terminalOnly and aiOnly flags; replace the inline logic in
useInputKeyDown (and update InputArea to use the new utility) so both locations
call the same function (reusing fuzzyMatch) and consume the sorted results.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45a90c7 and 049345a.

📒 Files selected for processing (4)
  • src/__tests__/renderer/hooks/useInputKeyDown.test.ts
  • src/renderer/components/InputArea.tsx
  • src/renderer/components/SessionList.tsx
  • src/renderer/hooks/input/useInputKeyDown.ts

@greptile-apps
Copy link

greptile-apps bot commented Feb 26, 2026

Greptile Summary

This PR successfully replaces exact prefix matching with fuzzy matching for both slash command autocomplete and session filtering, improving the search experience by matching characters that appear anywhere in the command or session name (e.g., /r now matches /clear).

Key improvements:

  • Centralized filterAndSortSlashCommands() ensures consistent sorting between the dropdown UI (InputArea.tsx) and keyboard handler (useInputKeyDown.ts), resolving the previously reported ordering mismatch
  • Added comprehensive fuzzy matching utilities with tiered scoring (prefix: 300, name fuzzy: 100+score, description: score)
  • Proper null safety guards for optional fields like tab.name and child.worktreeBranch
  • Safe index bounds checking prevents out-of-bounds access when navigating filtered results
  • Improved SessionList useEffect dependency array from [sessionFilter] to [sessionFilter, sessions, worktreeChildrenByParentId] for correct reactivity
  • Extensive test coverage including edge cases, scoring algorithms, and terminal/AI mode filtering

Confidence Score: 4/5

  • This PR is safe to merge with minor manual testing recommended
  • The implementation is solid with comprehensive unit tests, proper null safety, and correct resolution of the ordering mismatch issue. The centralized filterAndSortSlashCommands() function ensures consistency between UI and keyboard navigation. However, manual testing is still pending per the PR description, and the fuzzy matching behavior change could benefit from real-world validation before merge.
  • No files require special attention - all changes are well-tested and properly implemented

Important Files Changed

Filename Overview
src/renderer/utils/search.ts added comprehensive fuzzy matching utilities with scoring system and centralized filterAndSortSlashCommands() function that ensures consistent sorting across UI components
src/renderer/components/InputArea.tsx replaced prefix matching with filterAndSortSlashCommands() for consistent fuzzy search behavior and sorted results
src/renderer/components/SessionList.tsx replaced .includes() with fuzzyMatch() for session filtering, improved dependency tracking in useEffect
src/renderer/hooks/input/useInputKeyDown.ts replaced prefix filtering with filterAndSortSlashCommands() to fix ordering mismatch, added guard for empty results and safe index bounds checking

Sequence Diagram

sequenceDiagram
    participant User
    participant InputArea
    participant useInputKeyDown
    participant filterAndSortSlashCommands
    participant fuzzyMatchWithScore
    
    User->>InputArea: Types /r in input
    InputArea->>InputArea: Extract searchTerm = 'r'
    InputArea->>filterAndSortSlashCommands: filter(slashCommands, 'r', isTerminalMode)
    
    filterAndSortSlashCommands->>fuzzyMatchWithScore: Check /clear command
    fuzzyMatchWithScore-->>filterAndSortSlashCommands: matches=true, score=~107
    
    filterAndSortSlashCommands->>fuzzyMatchWithScore: Check /reset command
    fuzzyMatchWithScore-->>filterAndSortSlashCommands: matches=true, score=~107
    
    filterAndSortSlashCommands-->>InputArea: Sorted array [/clear, /reset, ...]
    InputArea->>InputArea: Render dropdown with sorted commands
    
    User->>useInputKeyDown: Presses ArrowDown key
    useInputKeyDown->>useInputKeyDown: Extract searchTerm = 'r'
    useInputKeyDown->>filterAndSortSlashCommands: filter(allSlashCommands, 'r', isTerminalMode)
    filterAndSortSlashCommands-->>useInputKeyDown: Same sorted array [/clear, /reset, ...]
    useInputKeyDown->>useInputKeyDown: Increment selectedIndex
    
    User->>useInputKeyDown: Presses Enter
    useInputKeyDown->>useInputKeyDown: Get command at selectedIndex
    useInputKeyDown->>InputArea: setInputValue(filteredCommands[selectedIndex])
    
    Note over InputArea,useInputKeyDown: Both use same filterAndSortSlashCommands()<br/>ensuring consistent ordering between<br/>dropdown display and keyboard selection
Loading

Last reviewed commit: 013d812

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 210 to 220
const filteredCommands = allSlashCommands.filter((cmd) => {
if ('terminalOnly' in cmd && cmd.terminalOnly && !isTerminalMode) return false;
if ('aiOnly' in cmd && cmd.aiOnly && isTerminalMode) return false;
return cmd.command.toLowerCase().startsWith(inputValue.toLowerCase());
if (!searchTerm) return true;
const cmdName = cmd.command.toLowerCase().replace(/^\//, '');
return (
cmdName.startsWith(searchTerm) ||
fuzzyMatch(cmdName, searchTerm) ||
(cmd.description ? fuzzyMatch(cmd.description, searchTerm) : false)
);
});
Copy link

Choose a reason for hiding this comment

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

Ordering mismatch causes wrong command to be selected on Enter/Tab

filteredCommands here is built with Array.filter(), which preserves the original insertion order of allSlashCommands. However, filteredSlashCommands in InputArea.tsx sorts results by fuzzy-match score (prefix match scores 300, name fuzzy match ~100+score, description match is lowest priority). Both arrays are indexed by the same selectedSlashCommandIndex from InputContext.

This means what the user sees highlighted in the dropdown (the sorted order from InputArea.tsx) will often be a different item than what filteredCommands[selectedSlashCommandIndex] resolves to in this hook. For example, with commands registered as ['/beta', '/alpha'] and a query of 'a':

  • Dropdown renders: [/alpha (score 300), /beta (score ~207)]/alpha is visually first
  • filteredCommands here: [/beta, /alpha] — original order; pressing Enter at index 0 selects /beta

The fix is to either pass the already-sorted filteredSlashCommands array into this hook (removing the duplicated filtering logic), or replicate the same sort here. The cleanest approach is to stop duplicating the filter and instead consume the array that InputArea.tsx has already computed.

…rd handler

Extract shared filterAndSortSlashCommands() utility to ensure both InputArea
(visual dropdown) and useInputKeyDown (Enter/Tab handler) produce identically
ordered command lists. Previously, InputArea sorted by relevance score while
useInputKeyDown kept original array order, causing the wrong command to be
inserted when pressing Enter/Tab.

Also fixes SessionList group auto-expansion to use fuzzyMatch() consistently
instead of substring .includes(), matching the main sessionCategories filter.

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

@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 the current code and only fix it if needed.

Inline comments:
In `@src/renderer/utils/search.ts`:
- Around line 154-158: Normalize the search term before doing the prefix check
so it matches the already-lowercased cmdName: compute a lowercase variant (e.g.
const normalizedSearchTerm = searchTerm.toLowerCase()) just before the prefix
match and use normalizedSearchTerm in the startsWith call instead of searchTerm;
leave fuzzyMatchWithScore as-is since it’s case-insensitive.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 049345a and 96f0cde.

📒 Files selected for processing (4)
  • src/renderer/components/InputArea.tsx
  • src/renderer/components/SessionList.tsx
  • src/renderer/hooks/input/useInputKeyDown.ts
  • src/renderer/utils/search.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/renderer/hooks/input/useInputKeyDown.ts
  • src/renderer/components/InputArea.tsx

Prefix match compared lowercased cmdName against potentially mixed-case
searchTerm, making it case-sensitive while fuzzyMatchWithScore was
case-insensitive. Now lowercases searchTerm once at function entry.

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

@coderabbitai review
@greptile-apps review

All issues from previous reviews have been addressed:

  • Index mismatch bug: Extracted shared filterAndSortSlashCommands() utility used by both InputArea and useInputKeyDown (commit 96f0cde)
  • Case-sensitivity: Normalized searchTerm with .toLowerCase() before prefix check (commit 2ba935c)
  • SessionList inconsistency: Group expansion useEffect now uses fuzzyMatch() instead of .includes() (commit 96f0cde)

@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

@felipeggv: Thank you for addressing the previous feedback! I'll review the changes now, including the shared utility implementation, case-sensitivity normalization, and SessionList fuzzy matching consistency.

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

- Clamp selectedSlashCommandIndex in useInputKeyDown before accessing
  filteredCommands, preventing silent no-op when index exceeds list length
  after the user continues typing
- Align SessionList group-expansion useEffect with sessionCategories memo:
  add worktree children branch/name matching and parentSessionId filtering,
  fix missing sessions and worktreeChildrenByParentId dependencies
- Add 11 tests for filterAndSortSlashCommands covering mode filtering,
  prefix vs fuzzy ranking, case insensitivity, description matching,
  empty results, and generic type preservation
- Remove duplicate SlashCommand interface from InputArea.tsx, import
  SlashCommandEntry from search.ts instead

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

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/hooks/input/useInputKeyDown.ts (1)

216-222: ⚠️ Potential issue | 🟡 Minor

Arrow navigation can still produce an invalid index on empty results.

On Line 218, when filteredCommands.length is 0, the upper bound becomes -1, so ArrowDown can set selectedSlashCommandIndex to -1.

Suggested fix
 				if (e.key === 'ArrowDown') {
 					e.preventDefault();
-					setSelectedSlashCommandIndex((prev) => Math.min(prev + 1, filteredCommands.length - 1));
+					const maxIndex = Math.max(0, filteredCommands.length - 1);
+					setSelectedSlashCommandIndex((prev) => Math.min(Math.max(0, prev + 1), maxIndex));
 				} else if (e.key === 'ArrowUp') {
 					e.preventDefault();
-					setSelectedSlashCommandIndex((prev) => Math.max(prev - 1, 0));
+					const maxIndex = Math.max(0, filteredCommands.length - 1);
+					setSelectedSlashCommandIndex((prev) => Math.min(Math.max(0, prev - 1), maxIndex));
 				} else if (e.key === 'Tab' || e.key === 'Enter') {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/input/useInputKeyDown.ts` around lines 216 - 222, In
useInputKeyDown, the ArrowUp/ArrowDown handling can set
selectedSlashCommandIndex to -1 when filteredCommands.length === 0; before
calling setSelectedSlashCommandIndex (in the ArrowDown and ArrowUp branches) add
a guard that returns early or computes the new index using a clamp that treats
an empty filteredCommands array as having no valid indices (i.e., do nothing if
filteredCommands.length === 0), ensuring setSelectedSlashCommandIndex is never
called with a negative upper bound; reference setSelectedSlashCommandIndex,
filteredCommands, and selectedSlashCommandIndex in your fix.
🧹 Nitpick comments (1)
src/renderer/components/SessionList.tsx (1)

1908-1928: Extract the session-match predicate to one shared helper.

The same fuzzy-match decision tree is duplicated in both sessionCategories and the group-expansion effect. Centralizing it will prevent future drift between visible results and expansion behavior.

Also applies to: 1756-1784

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/SessionList.tsx` around lines 1908 - 1928, Extract
the duplicated fuzzy-match logic into a single helper (e.g.,
sessionMatchesFilter) that accepts a session object, the sessionFilter string,
and access to worktreeChildrenByParentId; move the decision tree currently in
the useEffect (lines shown) and the identical logic used in sessionCategories
into that helper, then replace both places to call sessionMatchesFilter(session,
sessionFilter, worktreeChildrenByParentId) so expansion and visible-results use
the exact same predicate and keep types/signatures consistent with existing
Session and Worktree types.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/renderer/hooks/input/useInputKeyDown.ts`:
- Around line 216-222: In useInputKeyDown, the ArrowUp/ArrowDown handling can
set selectedSlashCommandIndex to -1 when filteredCommands.length === 0; before
calling setSelectedSlashCommandIndex (in the ArrowDown and ArrowUp branches) add
a guard that returns early or computes the new index using a clamp that treats
an empty filteredCommands array as having no valid indices (i.e., do nothing if
filteredCommands.length === 0), ensuring setSelectedSlashCommandIndex is never
called with a negative upper bound; reference setSelectedSlashCommandIndex,
filteredCommands, and selectedSlashCommandIndex in your fix.

---

Nitpick comments:
In `@src/renderer/components/SessionList.tsx`:
- Around line 1908-1928: Extract the duplicated fuzzy-match logic into a single
helper (e.g., sessionMatchesFilter) that accepts a session object, the
sessionFilter string, and access to worktreeChildrenByParentId; move the
decision tree currently in the useEffect (lines shown) and the identical logic
used in sessionCategories into that helper, then replace both places to call
sessionMatchesFilter(session, sessionFilter, worktreeChildrenByParentId) so
expansion and visible-results use the exact same predicate and keep
types/signatures consistent with existing Session and Worktree types.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96f0cde and 56c64d6.

📒 Files selected for processing (5)
  • src/__tests__/renderer/utils/search.test.ts
  • src/renderer/components/InputArea.tsx
  • src/renderer/components/SessionList.tsx
  • src/renderer/hooks/input/useInputKeyDown.ts
  • src/renderer/utils/search.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/components/InputArea.tsx

When filteredCommands.length === 0, ArrowDown/ArrowUp/Enter/Tab handlers
would compute invalid indices (e.g. Math.min(prev+1, -1)). Added early
return guard that only allows Escape when no commands match.

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

All review comments have been addressed and verified:

  1. CodeRabbit (case-sensitive prefix match): Fixed in commit 2ba935c5searchTerm is now lowercased to lowerSearchTerm before the startsWith check in filterAndSortSlashCommands.

  2. Greptile (ordering mismatch): Fixed in commit 96f0cdefuseInputKeyDown.ts now uses the same filterAndSortSlashCommands function as InputArea.tsx, ensuring consistent ordering between dropdown and keyboard handler.

  3. Empty-results edge case: Guarded in useInputKeyDown.ts — when filteredCommands.length === 0, arrow keys and Enter/Tab return early, preventing invalid index access.

Lint checks pass: npm run lint and npm run lint:eslint both clean.

@pedramamini pedramamini self-assigned this Feb 26, 2026
@felipeggv
Copy link
Author

All CodeRabbit and Greptile review comments have been addressed: case-insensitive prefix matching, arrow nav guard on empty results, index ordering mismatch resolved. Requesting re-review. @coderabbitai review @greptile review

@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

@felipeggv: Thank you for addressing all the feedback! I'll review the changes now, including the case-insensitive prefix matching, the arrow navigation guard for empty results, and the index ordering fix.

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

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