feat(terminal): add cursor style setting (bar/block/underline)#908
feat(terminal): add cursor style setting (bar/block/underline)#908roberto-fernandino wants to merge 22 commits into
Conversation
feat(tabs): select tabs by index within active space
…dow-shortcut feat(shortcuts): add ai toggle mini shortcut
…nd-palette feat: terminals in command-palette
Adds a new keyboard shortcut (Cmd+Shift+G by default) that switches the
sidebar to the Files/explorer view. Pairs naturally with Cmd+G (source
control) so the user can toggle between them without touching the mouse.
The shortcut uses cycleSidebarView("explorer") — same pattern as pane.source
uses for source-control — and is fully configurable in Settings > Shortcuts.
Also exposed as "Show Files sidebar" in the command palette.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tcut feat(shortcuts): add configurable shortcut to show Files sidebar
Documents and enforces the mandatory workflow: branch → commit → dual PR (fork + upstream cross-fork) → merge fork → back to main. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New "Agents" sidebar tab lists every Claude Code, Codex, Gemini, OpenCode and Cursor agent running in terminals, with status badges (working / needs input) and one-click navigation to the terminal tab - Terminal tabs whose agent is detected by the backend now show that tool's logo (Claude, Gemini, Codex/OpenCode, or robotic fallback) instead of the generic terminal icon - "Show Agents sidebar tab" toggle in Settings > General (default on); disabling it falls back to the Files view - Merged upstream additions: Codex/Gemini notification hooks, per-agent notification bell, jump-to-attention shortcut Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-and-logos feat(sidebar): Agents tab + agent logos in terminal tabs
When an agent process starts (claude, codex, etc.) it was immediately shown as "working" even though it was just sitting at its idle prompt. Added "idle" as a third AgentStatus. The "started" signal now sets idle; only the explicit "working" signal (fired when the agent begins executing a task) promotes it to working. The sidebar badge count excludes idle sessions so the badge only lights up during real activity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(agents): show idle status when agent is at prompt, not working
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…efault feat(ai): open AI panel by default on startup
- "finished" signal now sets status back to "idle" instead of "waiting" so the badge only lights up on genuine attention requests, not routine task completions - Added a useEffect in App.tsx: when the active tab becomes a terminal that has a waiting agent, reset it to idle — the user is already looking at it so the notification is no longer relevant; covers all nav paths (tab click, keyboard shortcut, notification bell, agents panel) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…on-focus fix(agents): clear needs-input when tab focused; finished resets to idle
Ctrl+C interrupts Claude Code without firing a finished signal, leaving the status permanently stuck on "working". Extend the tab-focus effect to reset any non-idle status (waiting or working) to idle when the user navigates to the terminal. If the agent is genuinely still running, the backend will fire the next working signal and promote it back immediately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ck-on-interrupt fix(agents): reset working status to idle when terminal tab is focused
…working status Depending on tabs (not tabsRef) caused the effect to re-run on every tab title update. While the agent was working and the user was already on the terminal tab, the next title change re-ran the effect and reset working→idle, breaking real-time status display. Switching to tabsRef means the effect only fires when activeId actually changes (true navigation), not on content updates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a terminalCursorStyle preference that lets users choose between bar, block, and underline cursor shapes in the terminal, matching VS Code's terminal cursor style options. Defaults to bar (previous hardcoded value). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughIntroduces an Agents sidebar panel displaying active agent sessions with idle/working/waiting status tracking. Adds terminal cursor style as a persisted preference applied live to xterm instances. Extends the command palette with terminal tab switching and a files sidebar command. Adds ChangesAgents Panel and Status Lifecycle
Terminal Cursor Style Preference
Navigation, Shortcuts, and Command Palette
Tooling and Workflow
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/modules/agents/store/agentStore.ts (1)
33-49: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winFilter idle sessions before driving the active-agent UI.
handleSignal(..., "finished")now leaves sessions in the store as"idle", butApp.tsxstill feeds every session intoagentsByTabIdandAgentsPanel. Completed runs will keep a tab icon and stay in the sidebar until the PTY exits.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/agents/store/agentStore.ts` around lines 33 - 49, The agent store leaves finished sessions in state as "idle", but the active-agent UI still treats every session as active. Update the session-to-UI mapping in App.tsx (the agentsByTabId/AgentsPanel path) to exclude sessions whose status is "idle" so only running sessions drive the tab icon and sidebar, while keeping the existing store behavior in agentStore.start and handleSignal unchanged.
🧹 Nitpick comments (1)
src/modules/terminal/lib/useTerminalSession.ts (1)
911-914: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winHoist this global preference fanout out of
useTerminalSession.Each mounted terminal hook now subscribes to
terminalCursorStyle, butapplyCursorStyle()already scans the shared pool. Because hidden tabs stay mounted, one settings change reruns the same pool walk once per terminal tab. A single store subscription near the pool or app bootstrap avoids that multiplier. As per path instructions,src/**/*.{ts,tsx}: "Watch for performance regressions: wasted re-renders, extra IPC round-trips, eager work that should be lazy" and "Tabs are kept mounted and hidden on switch".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/modules/terminal/lib/useTerminalSession.ts` around lines 911 - 914, The cursor-style fanout in useTerminalSession is causing duplicate work because every mounted terminal hook subscribes to terminalCursorStyle and re-runs applyCursorStyle() even though it already walks the shared pool. Move the store subscription and effect out of useTerminalSession and hoist it to a single place near the terminal pool or app bootstrap so the style change is handled once per update. Keep applyCursorStyle as the shared pool updater, and ensure the new subscription still triggers it when the preference changes.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/skills/terax-pr-workflow/SKILL.md:
- Line 34: The workflow currently uses a bare TypeScript check command instead
of the project’s pnpm-based script. Update the SKILL.md instructions to use pnpm
check-types in place of npx tsc --noEmit, and keep the guidance aligned with the
established pnpm-only workflow so it references the project’s standard
type-check command.
- Line 74: Remove the robot emoji from the PR body template in the skill
documentation so it follows the no-emojis convention. Update the template text
in SKILL.md by editing the PR template section that includes the “Generated with
[Claude Code]” line, and ensure the final PR body content contains only plain
text with no emoji characters.
- Line 3: The skill description in SKILL.md still uses an em-dash, which
violates the repository convention. Update the description text to remove the
em-dash and replace it with plain ASCII punctuation while preserving the
meaning, and ensure the rest of the skill content remains unchanged. Use the
description field in SKILL.md as the target location for this cleanup.
In `@src/app/App.tsx`:
- Around line 399-415: Do not reset agent lifecycle state in the App tab-switch
effect: the logic in App.tsx useEffect that iterates over useAgentStore sessions
and calls setStatus(..., "idle") on activeId change is clearing real
running/waiting state. Remove or narrow this behavior so tab visibility only
acknowledges notifications, and if any status update is still needed, scope it
to the focused leaf and only for waiting states rather than all non-idle
sessions.
- Around line 1179-1184: The panel row click wiring in App’s AgentsPanel is
using setActiveId directly, but these rows need the leaf-aware activation path
to keep the header and split-pane state in sync across spaces. Update the
AgentsPanel usage so row clicks call activateAgentTarget instead of setActiveId,
and make sure the panel receives the existing callback that knows how to focus
the owning leaf for an agent session. Keep the change localized to the
App/AgentsPanel wiring to avoid broader regressions in global navigation state.
In `@src/modules/ai/components/AiStatusBarControls.tsx`:
- Around line 172-174: The IconBtn in AiStatusBarControls should toggle the mini
chat window instead of always opening it. Update the button’s click handler to
switch between the open and close actions based on miniOpen, using the existing
openMini/closeMini logic (or a shared toggle handler) so it matches the title
text and the ai.toggleMini shortcut.
In `@src/modules/sidebar/useSidebarPanel.ts`:
- Around line 60-62: The lazy initialization in useSidebarPanel is restoring
sidebarView from the pre-hydration default, which can briefly reopen the agents
view before preferences are loaded. Update the sidebarView initialization and
the related syncing logic in useSidebarPanel/readSidebarView so the initial
state does not come from the stale showAgentsTab default, and only apply the
persisted view once preferences are ready; also adjust the later effect around
the same sidebar state handling to avoid the visible flash.
---
Outside diff comments:
In `@src/modules/agents/store/agentStore.ts`:
- Around line 33-49: The agent store leaves finished sessions in state as
"idle", but the active-agent UI still treats every session as active. Update the
session-to-UI mapping in App.tsx (the agentsByTabId/AgentsPanel path) to exclude
sessions whose status is "idle" so only running sessions drive the tab icon and
sidebar, while keeping the existing store behavior in agentStore.start and
handleSignal unchanged.
---
Nitpick comments:
In `@src/modules/terminal/lib/useTerminalSession.ts`:
- Around line 911-914: The cursor-style fanout in useTerminalSession is causing
duplicate work because every mounted terminal hook subscribes to
terminalCursorStyle and re-runs applyCursorStyle() even though it already walks
the shared pool. Move the store subscription and effect out of
useTerminalSession and hoist it to a single place near the terminal pool or app
bootstrap so the style change is handled once per update. Keep applyCursorStyle
as the shared pool updater, and ensure the new subscription still triggers it
when the preference changes.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 841ca7e7-fddf-4eff-9a13-415158d9fec4
📒 Files selected for processing (26)
.claude/skills/terax-pr-workflow/SKILL.mdpackage.jsonsrc/app/App.tsxsrc/modules/agents-panel/AgentsPanel.tsxsrc/modules/agents-panel/index.tssrc/modules/agents/components/AgentNotificationsBridge.tsxsrc/modules/agents/components/NotificationBell.tsxsrc/modules/agents/lib/agentIcon.tsxsrc/modules/agents/lib/format.tssrc/modules/agents/lib/types.tssrc/modules/agents/store/agentStore.tssrc/modules/ai/components/AiStatusBarControls.tsxsrc/modules/ai/store/chatStore.tssrc/modules/command-palette/commands.tssrc/modules/header/Header.tsxsrc/modules/settings/store.tssrc/modules/shortcuts/shortcuts.tssrc/modules/sidebar/SidebarRail.tsxsrc/modules/sidebar/types.tssrc/modules/sidebar/useSidebarPanel.tssrc/modules/tabs/TabBar.tsxsrc/modules/tabs/lib/pickTabBySpaceIndex.test.tssrc/modules/tabs/lib/useTabs.tssrc/modules/terminal/lib/rendererPool.tssrc/modules/terminal/lib/useTerminalSession.tssrc/settings/sections/GeneralSection.tsx
| @@ -0,0 +1,112 @@ | |||
| --- | |||
| name: terax-pr-workflow | |||
| description: Use this skill whenever making ANY change to this repository — features, fixes, shortcuts, refactors, anything. It enforces the mandatory branch → commit → dual-PR (fork + upstream) → merge-fork → back-to-main workflow. Trigger on phrases like "create a PR", "add a feature", "fix this", "push this", "open a pull request", or any task that involves committing and shipping code changes. | |||
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove em-dash from skill description.
The description field contains an em-dash, which violates the project convention: "Do not use em-dash anywhere, including code, comments, commits, and docs." As per coding guidelines, no em-dashes anywhere.
🧰 Tools
🪛 SkillSpector (2.3.7)
[warning] 34: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 111: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/skills/terax-pr-workflow/SKILL.md at line 3, The skill description
in SKILL.md still uses an em-dash, which violates the repository convention.
Update the description text to remove the em-dash and replace it with plain
ASCII punctuation while preserving the meaning, and ensure the rest of the skill
content remains unchanged. Use the description field in SKILL.md as the target
location for this cleanup.
Source: Coding guidelines
| Implement the feature/fix. Type-check before committing: | ||
|
|
||
| ```bash | ||
| npx tsc --noEmit |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use pnpm check-types instead of npx tsc --noEmit.
The project defines pnpm check-types as the frontend type-check command. Using bare npx tsc bypasses pnpm, the project's package manager, and any project-level TypeScript configuration that check-types may wrap. This is inconsistent with the established workflow and could drift if the check-types script is updated. As per coding guidelines, pnpm only, never npm/npx/yarn.
🧰 Tools
🪛 SkillSpector (2.3.7)
[warning] 34: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 111: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/skills/terax-pr-workflow/SKILL.md at line 34, The workflow currently
uses a bare TypeScript check command instead of the project’s pnpm-based script.
Update the SKILL.md instructions to use pnpm check-types in place of npx tsc
--noEmit, and keep the guidance aligned with the established pnpm-only workflow
so it references the project’s standard type-check command.
Source: Coding guidelines
| ## Test plan | ||
| - [ ] item | ||
| 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove emoji from PR template.
The PR body template includes a robot emoji, which violates the project convention: "Do not use emojis anywhere." As per coding guidelines, no emojis anywhere.
🧰 Tools
🪛 SkillSpector (2.3.7)
[warning] 34: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
[warning] 111: [RP1] null: npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
Remediation: Pin the version: npx @scope/server@1.2.3
(MCP Rug Pull (RP1))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/skills/terax-pr-workflow/SKILL.md at line 74, Remove the robot emoji
from the PR body template in the skill documentation so it follows the no-emojis
convention. Update the template text in SKILL.md by editing the PR template
section that includes the “Generated with [Claude Code]” line, and ensure the
final PR body content contains only plain text with no emoji characters.
Source: Coding guidelines
|
|
||
| // When the user NAVIGATES to a terminal tab, reset any non-idle agent status | ||
| // back to idle — they are looking at it so notifications are moot, and | ||
| // Ctrl+C won't fire a finished signal so "working" would otherwise get stuck. | ||
| // Uses tabsRef (not tabs) so this only fires on activeId change, not on every | ||
| // tab title update (which would kill real-time "working" display). | ||
| useEffect(() => { | ||
| const tab = tabsRef.current.find((t) => t.id === activeId); | ||
| if (!tab || tab.kind !== "terminal") return; | ||
| const store = useAgentStore.getState(); | ||
| for (const s of Object.values(store.sessions)) { | ||
| if (s.tabId === activeId && s.status !== "idle") { | ||
| store.setStatus(s.leafId, "idle"); | ||
| } | ||
| } | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, [activeId]); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not clear agent status on tab switch.
This rewrites real lifecycle state as a visibility side effect: a running or waiting agent in the active tab becomes idle, which drops it from agentCount and the panel, and split tabs clear sibling leaves too. Keep acknowledgement separate, or at least scope this to the focused leaf and waiting. As per path instructions, focus on regressions from local fixes and the right abstraction boundary.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/App.tsx` around lines 399 - 415, Do not reset agent lifecycle state
in the App tab-switch effect: the logic in App.tsx useEffect that iterates over
useAgentStore sessions and calls setStatus(..., "idle") on activeId change is
clearing real running/waiting state. Remove or narrow this behavior so tab
visibility only acknowledges notifications, and if any status update is still
needed, scope it to the focused leaf and only for waiting states rather than all
non-idle sessions.
Source: Path instructions
| ) : sidebarView === "agents" ? ( | ||
| <AgentsPanel | ||
| sessions={agentSessions} | ||
| tabs={tabs} | ||
| onSelectTab={setActiveId} | ||
| /> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use activateAgentTarget for panel row clicks.
agentSessions spans all spaces and multiple leaves per tab, but these rows only call setActiveId, so cross-space clicks leave the header on the wrong space and split-pane clicks cannot focus the owning leaf. Pass the existing leaf-aware activation callback through the panel instead. As per path instructions, focus on blast radius and global regressions from local UI wiring.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/app/App.tsx` around lines 1179 - 1184, The panel row click wiring in
App’s AgentsPanel is using setActiveId directly, but these rows need the
leaf-aware activation path to keep the header and split-pane state in sync
across spaces. Update the AgentsPanel usage so row clicks call
activateAgentTarget instead of setActiveId, and make sure the panel receives the
existing callback that knows how to focus the owning leaf for an agent session.
Keep the change localized to the App/AgentsPanel wiring to avoid broader
regressions in global navigation state.
Source: Path instructions
| <IconBtn | ||
| title={miniOpen ? "Mini-window open" : "Open conversation"} | ||
| title={`${miniOpen ? "Close" : "Open"} AI chat window (${fmtShortcut("⇧", MOD_KEY, "I")})`} | ||
| onClick={openMini} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make this button actually toggle the mini window.
Line 173 advertises "Close AI chat window" when miniOpen is true, but Line 174 still calls openMini, so this control never performs the close action and now disagrees with the ai.toggleMini shortcut.
Suggested fix
- const openMini = useChatStore((s) => s.openMini);
+ const toggleMini = useChatStore((s) => s.toggleMini);
...
- onClick={openMini}
+ onClick={toggleMini}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <IconBtn | |
| title={miniOpen ? "Mini-window open" : "Open conversation"} | |
| title={`${miniOpen ? "Close" : "Open"} AI chat window (${fmtShortcut("⇧", MOD_KEY, "I")})`} | |
| onClick={openMini} | |
| <IconBtn | |
| title={`${miniOpen ? "Close" : "Open"} AI chat window (${fmtShortcut("⇧", MOD_KEY, "I")})`} | |
| onClick={toggleMini} |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/modules/ai/components/AiStatusBarControls.tsx` around lines 172 - 174,
The IconBtn in AiStatusBarControls should toggle the mini chat window instead of
always opening it. Update the button’s click handler to switch between the open
and close actions based on miniOpen, using the existing openMini/closeMini logic
(or a shared toggle handler) so it matches the title text and the ai.toggleMini
shortcut.
| const [sidebarView, setSidebarViewState] = useState<SidebarViewId>(() => | ||
| readSidebarView(showAgentsTab), | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not restore the agents view from the pre-hydration default.
usePreferencesStore boots with showAgentsTab: true, so this lazy initializer can reopen "agents" on first paint for users who disabled it and had that view stored. The later effect fixes it, but only after a visible flash.
Also applies to: 121-125
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/modules/sidebar/useSidebarPanel.ts` around lines 60 - 62, The lazy
initialization in useSidebarPanel is restoring sidebarView from the
pre-hydration default, which can briefly reopen the agents view before
preferences are loaded. Update the sidebarView initialization and the related
syncing logic in useSidebarPanel/readSidebarView so the initial state does not
come from the stale showAgentsTab default, and only apply the persisted view
once preferences are ready; also adjust the later effect around the same sidebar
state handling to avoid the visible flash.
Summary
barso existing users see no changeTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes