fix: purple dot, path display, shortcut symbols, tab flash#117
fix: purple dot, path display, shortcut symbols, tab flash#117
Conversation
- Fix #116: session status scan failed silently when JSONL tail exceeded execFile maxBuffer (1MB). Reduced tail from 50 to 15 lines + raised maxBuffer to 5MB. - Display ~/ instead of /Users/<user>/ in project paths - Search supports ~/ prefix and full path matching - Shortcut uses macOS symbols (⌃⌘R not Cmd+Ctrl+R) - Click shortcut in title bar → Settings Shortcuts tab - Add debug logging to session detection + status scan Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a home-dir IPC and renderer API, popup wiring to open specific Settings tabs, macOS accelerator→symbol rendering, project-path ~/ normalization/search and highlighting, reduces tail read and increases execFile maxBuffer for session-status scanning, and adds logging/error reporting across session detection and status I/O. Changes
Sequence Diagram(s)mermaid Renderer->>Preload: window.electronAPI.getHomeDir() Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
The actual formatOptionLabel is inline in the Select JSX prop, not the module-scope function. Applied shortenPath() to the inline version and removed the unused module-scope function. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Needs-attention dot: #FFA726 (orange) → #F06856 (warm red) for clearer distinction from working (#E8956A orange) - Working pulse animation: 2s → 2.5s (slower, more distinct) - Full path search now highlights in shortened ~/ display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
2 issues found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/session-status-hooks.ts">
<violation number="1" location="src/session-status-hooks.ts:276">
P3: Stale comments still reference "50 lines" after reducing `tail` to 15 lines. The function docstring (`Reads last ~50 lines`) and the inline comment at line 297 (`// Read last 50 lines`) should be updated to match.</violation>
</file>
<file name="src/preload.ts">
<violation number="1" location="src/preload.ts:7">
P2: `sendSync` blocks the renderer's main thread until the main process responds. Use `ipcRenderer.invoke` instead, which is async and consistent with every other getter in this file (e.g., `getAppVersion`, `getIDEPreference`). The home directory value doesn't change at runtime, so it could also be fetched once on startup and cached.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/session-status-hooks.ts (1)
262-299:⚠️ Potential issue | 🟡 MinorUpdate stale comments to match the new
tail -n 15behavior.The function docs/comments still mention reading ~50 lines, but implementation now reads 15. Please align comments to prevent future confusion.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/session-status-hooks.ts` around lines 262 - 299, Update the function comment/docstring for scanInitialStatuses and the inline comment above tailFile to reflect that we now read the last 15 lines (not ~50); edit the header comment that currently says "Reads last ~50 lines..." and the inline note "// Use 15 lines (not 50) — ..." so both clearly state "15 lines" and keep the existing rationale about large assistant messages and maxBuffer/timeouts; reference the tailFile helper and the scanInitialStatuses function when making the change.
🧹 Nitpick comments (3)
src/claude-session-utility.ts (1)
895-946: Gate new session-detection logs behind debug mode (and avoid raw cwd in normal runs).These logs are useful for diagnosis, but they currently run unconditionally and include session identifiers/path data. Consider routing them through a debug logger and redacting cwd outside debug builds.
Also applies to: 966-967
src/preload.ts (1)
7-7: MigrategetHomeDirto async IPC pattern for consistency.While the
get-home-dirhandler is trivial and the blocking risk is minimal, this should useipcRenderer.invoke+ipcMain.handleto align with the established async pattern used throughout the codebase (40+ other IPC operations). All similar getter methods already use this pattern.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/preload.ts` at line 7, Change the synchronous getHomeDir export to use the async IPC pattern: replace the use of ipcRenderer.sendSync('get-home-dir') in the getHomeDir export with ipcRenderer.invoke('get-home-dir') and ensure the main-process handler uses ipcMain.handle('get-home-dir', ...) instead of a synchronous listener; also update any callers of getHomeDir to await the returned Promise so they continue to receive the home directory string asynchronously.src/switcher-ui.tsx (1)
962-968: Use a real button for the shortcut badge.This new affordance is mouse-only right now. A clickable
<span>won't receive keyboard focus or Enter/Space activation, so keyboard users can't use the shortcut-to-settings path.♿ Suggested fix
- <span + <button + type='button' onClick={() => setSettingsOpenToTab('shortcuts')} - title="Click to customize shortcuts" - style={{ fontSize: '10px', color: '#555', cursor: 'pointer' }} + title='Click to customize shortcuts' + style={{ + fontSize: '10px', + color: '#555', + cursor: 'pointer', + background: 'none', + border: 'none', + padding: 0, + }} onMouseEnter={(e) => { e.currentTarget.style.color = '#888'; }} onMouseLeave={(e) => { e.currentTarget.style.color = '#555'; }} > {quickSwitcherShortcut} - </span> + </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/switcher-ui.tsx` around lines 962 - 968, Replace the non-interactive <span> used as the "shortcuts" badge with a proper interactive element: change the span to a <button type="button"> (or a styled Button component) and keep the existing click handler setSettingsOpenToTab('shortcuts'), title, inline styles (or move to CSS class), and hover color changes; ensure the element has an accessible name (aria-label or visible text) so it receives keyboard focus and is activatable via Enter/Space, and remove any custom onKey handlers since a native button handles keyboard activation.
🤖 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/switcher-ui.tsx`:
- Around line 1484-1490: searchWords currently turns a full/home-relative path
query like "~/work/codev" into a single token which doesn't match either the
name or path Highlighter because the UI renders them separately; fix by deriving
two arrays: nameSearchWords (use the last path segment for tokens containing '/'
or starting with '~/') and pathSearchWords (use the leading path portion for
those tokens, keeping original tokens for pure-name queries), then pass
nameSearchWords to the project-name Highlighter and pathSearchWords to the path
Highlighter; implement this near where searchWords is computed (referencing
getHomeDir, searchWords, nameSearchWords, pathSearchWords, shortenPath, label)
so full-path or home-relative queries highlight correctly across the split
name/path layout.
---
Outside diff comments:
In `@src/session-status-hooks.ts`:
- Around line 262-299: Update the function comment/docstring for
scanInitialStatuses and the inline comment above tailFile to reflect that we now
read the last 15 lines (not ~50); edit the header comment that currently says
"Reads last ~50 lines..." and the inline note "// Use 15 lines (not 50) — ..."
so both clearly state "15 lines" and keep the existing rationale about large
assistant messages and maxBuffer/timeouts; reference the tailFile helper and the
scanInitialStatuses function when making the change.
---
Nitpick comments:
In `@src/preload.ts`:
- Line 7: Change the synchronous getHomeDir export to use the async IPC pattern:
replace the use of ipcRenderer.sendSync('get-home-dir') in the getHomeDir export
with ipcRenderer.invoke('get-home-dir') and ensure the main-process handler uses
ipcMain.handle('get-home-dir', ...) instead of a synchronous listener; also
update any callers of getHomeDir to await the returned Promise so they continue
to receive the home directory string asynchronously.
In `@src/switcher-ui.tsx`:
- Around line 962-968: Replace the non-interactive <span> used as the
"shortcuts" badge with a proper interactive element: change the span to a
<button type="button"> (or a styled Button component) and keep the existing
click handler setSettingsOpenToTab('shortcuts'), title, inline styles (or move
to CSS class), and hover color changes; ensure the element has an accessible
name (aria-label or visible text) so it receives keyboard focus and is
activatable via Enter/Space, and remove any custom onKey handlers since a native
button handles keyboard activation.
🪄 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: 0809adcd-3f87-4907-96dc-0b7974777158
📒 Files selected for processing (9)
CHANGELOG.mdpackage.jsonsrc/claude-session-utility.tssrc/electron-api.d.tssrc/main.tssrc/popup.tsxsrc/preload.tssrc/session-status-hooks.tssrc/switcher-ui.tsx
- cubic P2: sendSync → ipcRenderer.invoke (async) for getHomeDir - cubic P3: update stale comments "50 lines" → "15 lines" - CodeRabbit: split searchWords into nameSearchWords/pathSearchWords so full-path queries highlight correctly in split name/path layout Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pathSearchWords was cutting at lastIndexOf('/'), causing partial
highlight (e.g. ~/git/fred/packages only highlighted ~/git/fred).
Now path Highlighter uses full searchWords for correct substring
match, name Highlighter uses nameSearchWords (last segment only).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/switcher-ui.tsx`:
- Around line 961-967: Replace the non-focusable span used to open the Shortcuts
tab with a real button element in switcher-ui.tsx: swap the <span> into a
<button type="button"> and keep the existing onClick that calls
setSettingsOpenToTab('shortcuts'), title and visual styling, and remove the
mouse-only onMouseEnter/onMouseLeave color tweaks (instead use CSS :hover/:focus
or onFocus/onBlur to provide the same visual feedback) so the control is
keyboard-focusable and activatable while preserving the look and behavior.
- Around line 171-179: The module-global _homeDir/_homePrefix cache is updated
asynchronously via window.electronAPI.getHomeDir() so components won't rerender
when it resolves; move this lookup into React component state instead: call
window.electronAPI.getHomeDir() inside a useEffect, store the result in useState
(e.g. homeDir and homePrefix) and replace usages of the module-level
getHomeDir/_homePrefix with the state values so the UI updates when the async
IPC resolves (update any helper functions or consumers that reference
getHomeDir() to accept the state or read the state directly).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/switcher-ui.tsx">
<violation number="1">
P2: Path highlighting regresses for full-path search terms. When the user types `~/git/codev`, `searchWords` is `["~/git/codev"]` which is longer than the displayed path (`~/git`), so the path Highlighter finds no substring match. The removed `pathSearchWords` handled this by stripping the trailing segment. Consider keeping a `pathSearchWords` derivation or splitting each search word into both its full form and its directory prefix so the path Highlighter can still match.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
- Split path tokens into all segments for both Highlighters - Strip trailing / from search input - Normalize /Users/<user> (without trailing /) to ~ - Deduplicate highlight words Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use localStorage to track if the banner has been shown. Subsequent launches skip the "drag to reposition" banner. Mode-switch banners still show every time (intentional). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/switcher-ui.tsx (2)
171-179:⚠️ Potential issue | 🟡 MinorMake the home-dir lookup reactive.
_homeDir/_homePrefixare filled asynchronously outside React state, so the first render can stay on/Users/...and~/search/highlighting won't update until some unrelated rerender happens. Move this into component state viauseEffect, then haveshortenPathand the filter/highlighter read that state.As per coding guidelines, "Use async/await for asynchronous operations."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/switcher-ui.tsx` around lines 171 - 179, The code currently populates module-level vars _homeDir/_homePrefix asynchronously causing non-reactive UI; move this into React state by adding a useState (e.g., const [homeDir, setHomeDir] = useState('')) and call window.electronAPI?.getHomeDir with an async function inside useEffect (use async/await) to setHomeDir and compute a derived homePrefix state or memo; then update getHomeDir usages (or remove module-level getHomeDir) and make shortenPath and any filter/highlighter read the new homeDir/homePrefix state or derived value so the UI updates immediately when the async lookup completes.
961-967:⚠️ Potential issue | 🟡 MinorUse a real button for the shortcut affordance.
This opens Settings but is still a mouse-only
<span>, so it cannot be focused or activated from the keyboard. A styledbutton type="button"keeps the same look without dropping accessibility.Suggested fix
- <span + <button + type="button" onClick={() => setSettingsOpenToTab('shortcuts')} + aria-label="Customize shortcuts" title="Click to customize shortcuts" - style={{ fontSize: '10px', color: '#555', cursor: 'pointer' }} + style={{ + fontSize: '10px', + color: '#555', + cursor: 'pointer', + background: 'transparent', + border: 'none', + padding: 0, + }} onMouseEnter={(e) => { e.currentTarget.style.color = '#888'; }} onMouseLeave={(e) => { e.currentTarget.style.color = '#555'; }} + onFocus={(e) => { e.currentTarget.style.color = '#888'; }} + onBlur={(e) => { e.currentTarget.style.color = '#555'; }} > {quickSwitcherShortcut} - </span> + </button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/switcher-ui.tsx` around lines 961 - 967, The clickable span used to open Settings should be replaced with a real, focusable button to restore keyboard accessibility: change the element using setSettingsOpenToTab('shortcuts') from a <span> to a <button type="button">, keep the existing title, style, onClick, onMouseEnter and onMouseLeave handlers, and add an accessible name (aria-label or visible text) if the visual content is non-descriptive so the control can be focused and activated via keyboard; ensure button styling preserves the same visual appearance and cursor behavior as before.
🤖 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/switcher-ui.tsx`:
- Around line 865-879: The filter fails when tokens end with a trailing slash
because expanded tokens keep the slash while target contains slashless paths;
update the matching logic in the block that builds inputArray/subInput/expanded
(uses getHomeDir and the expanded variable) to normalize expanded by removing
any trailing slashes (and then lowercasing) before the target?.includes check so
tokens like "~/work/codev/" match "/Users/me/work/codev". Ensure the trimming
happens after the '~' expansion and before the includes call so expanded is the
canonical, slashless token used for matching.
- Around line 162-169: The acceleratorToSymbols function currently maps modifier
names by simple string replacement and doesn't enforce macOS modifier order;
update it to split the accelerator string on '+' (case-insensitive), normalize
tokens, collect modifier tokens into a map, then emit modifiers in the macOS
display order Shift (⇧), Control (⌃), Option/Alt (⌥), Command (⌘) followed by
the non-modifier key; ensure acceleratorToSymbols handles different casings and
preserves the final key token unchanged while joining the symbol modifiers
before it.
---
Duplicate comments:
In `@src/switcher-ui.tsx`:
- Around line 171-179: The code currently populates module-level vars
_homeDir/_homePrefix asynchronously causing non-reactive UI; move this into
React state by adding a useState (e.g., const [homeDir, setHomeDir] =
useState('')) and call window.electronAPI?.getHomeDir with an async function
inside useEffect (use async/await) to setHomeDir and compute a derived
homePrefix state or memo; then update getHomeDir usages (or remove module-level
getHomeDir) and make shortenPath and any filter/highlighter read the new
homeDir/homePrefix state or derived value so the UI updates immediately when the
async lookup completes.
- Around line 961-967: The clickable span used to open Settings should be
replaced with a real, focusable button to restore keyboard accessibility: change
the element using setSettingsOpenToTab('shortcuts') from a <span> to a <button
type="button">, keep the existing title, style, onClick, onMouseEnter and
onMouseLeave handlers, and add an accessible name (aria-label or visible text)
if the visual content is non-descriptive so the control can be focused and
activated via keyboard; ensure button styling preserves the same visual
appearance and cursor behavior as before.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
localStorage doesn't reliably persist across yarn start restarts in dev mode. Use electron-settings (file-based) instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass default-switcher-mode via URL hash from main process
to renderer, so useState initializes with the correct tab
immediately. No more projects→sessions flash.
Previously: useState('projects') + async IPC to get default
mode → visible tab switch after IPC round trip.
Now: main reads setting before createSwitcherWindow, appends
#mode=sessions to loadURL, renderer parses hash synchronously.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- filterOptions: strip trailing / from search tokens for defensive matching (mirrors highlight searchWords logic) - CHANGELOG: add tab flash fix, banner, and all style changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="CHANGELOG.md">
<violation number="1" location="CHANGELOG.md:10">
P3: Modifier symbol order `⌘⌃R` doesn't match Apple's standard order or the actual UI output. The code (switcher-ui.tsx:162, 675) renders `⌃⌘R` (Control before Command), which follows Apple's HIG. The changelog should match.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| - Reduced to 15 lines + raised maxBuffer to 5MB | ||
| - Fix: eliminate tab flash on startup (default tab now passed via URL hash) | ||
| - Style: project paths display `~/` instead of `/Users/<user>/` | ||
| - Style: shortcut display uses macOS symbols (`⌘⌃R` instead of `Cmd+Ctrl+R`) |
There was a problem hiding this comment.
P3: Modifier symbol order ⌘⌃R doesn't match Apple's standard order or the actual UI output. The code (switcher-ui.tsx:162, 675) renders ⌃⌘R (Control before Command), which follows Apple's HIG. The changelog should match.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At CHANGELOG.md, line 10:
<comment>Modifier symbol order `⌘⌃R` doesn't match Apple's standard order or the actual UI output. The code (switcher-ui.tsx:162, 675) renders `⌃⌘R` (Control before Command), which follows Apple's HIG. The changelog should match.</comment>
<file context>
@@ -5,12 +5,14 @@
+- Fix: eliminate tab flash on startup (default tab now passed via URL hash)
- Style: project paths display `~/` instead of `/Users/<user>/`
-- Style: shortcut display uses macOS symbols (`⌃⌘R` instead of `Cmd+Ctrl+R`)
+- Style: shortcut display uses macOS symbols (`⌘⌃R` instead of `Cmd+Ctrl+R`)
+- Style: needs-attention dot changed from orange `#FFA726` to warm red `#F06856`
+- Style: working pulse animation slowed from 2s to 2.5s
</file context>
| - Style: shortcut display uses macOS symbols (`⌘⌃R` instead of `Cmd+Ctrl+R`) | |
| - Style: shortcut display uses macOS symbols (`⌃⌘R` instead of `Cmd+Ctrl+R`) |
Summary
Mixed fix + polish PR covering several improvements.
Fix: purple dot for sessions with large responses (#116)
scanInitialStatuses()usedtail -n 50viaexecFilewith defaultmaxBufferof 1 MB. For sessions with large assistant responses, the last 50 lines exceeded 1 MB (observed: 2.1 MB), causing silent failure → no status file → purple dot forever.Fix: Reduced to
tail -n 15+ raisedmaxBufferto 5 MB + added error logging.Fix: tab flash on startup
Previously
useState('projects')+ async IPC to get default mode → visible tab switch. Now the default mode is passed via URL hash from main process, parsed synchronously by renderer.Style: project paths display
~/Replace
/Users/<username>/with~/in the Projects tab. Reduces visual noise.Feat: project search supports
~/and full path~/git/codevexpands~to home dir for matching~/-shortened path are both searchableStyle: shortcut uses macOS symbols
Title bar:
Cmd+Ctrl+R→⌘⌃R. Uses standard macOS modifier symbols.Feat: click shortcut → Settings Shortcuts tab
Clicking the shortcut text opens Settings directly on the Shortcuts tab.
Style: needs-attention dot + working pulse
#FFA726→ warm red#F06856Style: normal mode banner only on first launch
Uses
electron-settingsto persist the "banner seen" flag.Debug logging
Added
console.log/console.error(behindisDebugin main.ts, error-path-only elsewhere) to session detection, cleanup, and scan. Allcatch {}blocks now log errors.Test plan
~/git/...~/gitmatches and highlights/Users/grimmer/gitfilters and highlights correctly~/git/)⌘⌃R⌘⌃Ropens Settings → Shortcuts tabyarn make)🤖 On behalf of @grimmerk — generated with Claude Code