Skip to content

Backport rc Tier-1 fixes to main#1104

Merged
pedramamini merged 9 commits into
mainfrom
backport/rc-fixes-tier1
Jun 17, 2026
Merged

Backport rc Tier-1 fixes to main#1104
pedramamini merged 9 commits into
mainfrom
backport/rc-fixes-tier1

Conversation

@pedramamini

@pedramamini pedramamini commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Backports three isolated, tested bug fixes from `0.15.0-rc` to `main`, plus one supporting test-isolation fix.

What's included

  • fix(left-bar): keep Auto Run agents visible in the unread filter (`34b2401db`)
  • feat(process-monitor): show the remote agent command for SSH spawns (`089250c1e`)
  • fix(terminal): stop SSH/startup terminal tabs vanishing on PTY exit, add close diagnostics (`a95fe655e`)
  • test(cue): isolate cue-spawn-builder from ambient `MAESTRO_CLAUDE_BIN` (`794b19ef4`)

Dropped during backport

  • `7c4efbaa9` (test: align useCue activity-log expectation to 1000) was intentionally dropped. It is a test-only alignment for the activity-log limit bump (100 to 1000) that lives in a separate rc commit (`557013aae`) which is out of scope for this backport. Including the test without its source change broke the suite; dropping it keeps the limit at 100 on main with a green test.

Validation

  • `npm run lint` passes (all three tsconfigs).
  • Full pre-push test suite passes: 31,188 passed, 108 skipped.

Cherry-picked cleanly with no conflicts.

Summary by CodeRabbit

Release Notes

  • New Features

    • SSH spawns now display the remote agent invocation in Process Details, alongside the local SSH command.
    • Exited terminal tabs can be restarted from the terminal tab UI.
  • Improvements

    • Terminal auto-close behavior was refined to avoid closing restartable (persistent) terminals on exit.
    • Session filtering now accounts for auto-running batch sessions.
    • Theme color validation is more reliable, including optional bgTitleBar.
    • Persisted file preview content is now capped to prevent overly large saves.
  • Tests

    • Expanded regression coverage for SSH command display and terminal restart/exit handling.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR propagates a human-readable SSH remote command string from SSH command builders through the entire spawn pipeline (wrappers, IPC handlers, process manager, cue lifecycle) to a new "Remote Command" tile in the Process Monitor detail view. It also introduces a restartTerminalTab action, a TerminalCloseReason type, and persistent-vs-scratch terminal classification in TerminalView with a restart button in TerminalTabItem. Additionally, useSessionCategories gains an activeBatchSessionIds parameter to keep auto-running sessions visible under the unread-agents filter, a shared deterministic CSS color validator replaces the DOM-based validation in custom theme imports, and supporting migrations for Adaptive Mode and file persistence are refined.

Changes

SSH Remote Command in Process Monitor

Layer / File(s) Summary
SSH builder output types and remoteCommandLine construction
src/main/utils/ssh-command-builder.ts, src/main/utils/ssh-spawn-wrapper.ts, src/main/process-manager/types.ts
SshCommandResult gains remoteCommandLine computed as the bare agent invocation (excluding PATH wrapper) in both stdin and non-stdin paths. SshSpawnWrapResult and ProcessConfig/ManagedProcess gain sshRemoteCommand. wrapSpawnWithSsh propagates the value in both execution branches.
Spawn pipeline propagation
src/main/cue/cue-spawn-builder.ts, src/main/cue/cue-process-lifecycle.ts, src/main/group-chat/group-chat-moderator.ts, src/main/group-chat/spawnGroupChatAgent.ts, src/main/ipc/handlers/process.ts, src/main/process-manager/spawners/ChildProcessSpawner.ts
SpawnSpec, CueActiveProcess, CueProcessInfo, IProcessManager.spawn config, and CueProcessEntry all gain optional sshRemoteCommand. Each spawn site (buildSpawnSpec, spawnGroupChatAgent, ChildProcessSpawner, process:spawn, getActiveProcesses) threads the value through to the renderer.
Process Monitor renderer types, tree, and detail view
src/renderer/components/ProcessMonitor/types.ts, src/renderer/components/ProcessMonitor/processTree.ts, src/renderer/components/ProcessMonitor/ProcessMonitor.tsx, src/renderer/components/ProcessMonitor/ProcessDetailView.tsx
ActiveProcess, ProcessNode, and ProcessDetailData gain sshRemoteCommand. buildProcessTree populates it on all four node types. openProcessDetail copies it into detailView. ProcessDetailView renders a "Remote Command" tile with a Server icon and relabels the local tile to "SSH Command".
SSH builder and Process Monitor tests
src/__tests__/main/cue/cue-spawn-builder.test.ts, src/__tests__/main/utils/ssh-command-builder.test.ts, src/__tests__/renderer/components/ProcessMonitor/ProcessDetailView.test.tsx
Tests assert remoteCommandLine exposes only the bare invocation without PATH/cd wrappers. ProcessDetailView tests assert "Remote Command" tile visibility, "SSH Command" relabeling, and absence in non-SSH cases. cue-spawn-builder tests add MAESTRO_CLAUDE_BIN env isolation.

Terminal Restart and Persistent Terminal Lifecycle

Layer / File(s) Summary
restartTerminalTab helper, TerminalCloseReason type, and tabStore actions
src/renderer/utils/terminalTabHelpers.ts, src/renderer/stores/tabStore.ts
restartTerminalTab(session, tabId) resets pid/state/exitCode and selects the tab. Exports TerminalCloseReason union type. TabStoreActions updates closeTerminalTab to accept an optional reason and exposes restartTerminalTab. closeTerminalTab emits structured diagnostic logs; restartTerminalTab kills lingering PTY before respawn.
TerminalView persistent/scratch classification and spawn failure handling
src/renderer/components/TerminalView.tsx
Adds stable onTabStateChangeRef. Introduces handleSpawnFailure for persistent-vs-scratch recovery. isPersistent is derived from startupCommand or SSH remote session membership. Both spawn-result and spawn-exception failures delegate to handleSpawnFailure. PTY exit effect is reworked: persistent tabs get a restart notice; non-persistent tabs are closed; rapid exits trigger a toast.
TerminalTabItem restart button UI
src/renderer/components/TabBar/TerminalTabItem.tsx
Adds RotateCw icon and useTabStore. Renders a "Restart terminal" button alongside the exit-code badge when tab.state === 'exited'.
Diagnostic logging
src/main/process-listeners/exit-listener.ts, src/renderer/hooks/tabs/internal/useUnifiedTabHandlers.ts
exit-listener logs terminal PTY exits when sessionId contains -terminal-. useUnifiedTabHandlers logs tab close context before bulk-close kills.
Terminal restart and persistent lifecycle tests
src/__tests__/renderer/utils/terminalTabHelpers.test.ts, src/__tests__/renderer/stores/tabStore.test.ts, src/__tests__/renderer/components/TerminalView.test.tsx
restartTerminalTab tests cover state reset, startupCommand preservation, active-tab selection, and not-found no-op. tabStore tests cover PTY kill and no-op for missing tab. TerminalView tests add 'pty-exit' reason to existing close assertions and add two new tests confirming persistent tabs are not auto-closed.

Session List Auto-Running Filter

Layer / File(s) Summary
useSessionCategories auto-running filter
src/renderer/hooks/session/useSessionCategories.ts, src/renderer/components/SessionList/SessionList.tsx, src/__tests__/renderer/hooks/useSessionCategories.test.ts
useSessionCategories gains activeBatchSessionIds parameter. Unread-agents filter builds a Set from it, keeps sessions in the set visible as auto-running, and also keeps parent sessions whose worktree children are auto-running. SessionList passes activeBatchSessionIds. Tests cover auto-running visibility and worktree-parent retention.

CSS Color Validation Refactor

Layer / File(s) Summary
Shared CSS color validation module
src/shared/cssColor.ts
Adds deterministic CSS color validation supporting hex (3/4/6/8 digits), rgb()/rgba()/hsl()/hsla() functional notation, and CSS named colors (case-insensitive). Rejects malformed inputs and non-strings. Exports isValidCssColor(color: unknown): boolean.
CustomThemeBuilder CSS validation migration and optional bgTitleBar
src/renderer/components/CustomThemeBuilder.tsx, src/__tests__/helpers/mockTheme.ts
Replaces local DOM-based isValidColor helper with the shared isValidCssColor function. Excludes bgTitleBar from required color keys, making it optional for older theme exports. Mock theme helper adds bgTitleBar for test consistency.
CSS color validation tests
src/__tests__/shared/cssColor.test.ts, src/__tests__/renderer/components/CustomThemeBuilder.test.tsx
Comprehensive test suite for isValidCssColor covering valid hex, functional notation, and named colors, and rejecting malformed inputs. CustomThemeBuilder tests validate optional bgTitleBar handling.

Supporting Migrations and Cleanup

Layer / File(s) Summary
Adaptive mode migration refinement
src/main/stores/migrations/adaptive-mode-default.ts, src/__tests__/main/stores/migrations/adaptive-mode-default.test.ts
Migration now targets only sessions where enableMaestroP === undefined (never configured), leaving explicit false selections unchanged. Tests verify strict backfill behavior and add coverage for sessions that already have explicit API choices.
Pre-push hook delete-only detection
.husky/pre-push
Detects delete-only branch pushes by parsing stdin ref updates and checking whether all local SHAs are zero, skipping validation for such pushes.
File preview content persistence capping
src/renderer/hooks/utils/useDebouncedPersistence.ts
Adds MAX_PERSISTED_PREVIEW_CONTENT constant. prepareSessionForPersistence sanitizes filePreviewTabs by clearing oversized content to prevent large session-file growth.

Sequence Diagrams

sequenceDiagram
  rect rgba(100, 149, 237, 0.5)
    Note over buildSshCommand,wrapSpawnWithSsh: SSH Builder Layer
    buildSshCommand->>buildSshCommand: buildShellCommand(cmd, args) → remoteCommandLine
    buildSshCommand-->>wrapSpawnWithSsh: SshCommandResult { remoteCommandLine }
    wrapSpawnWithSsh-->>caller: SshSpawnWrapResult { sshRemoteCommand }
  end
  rect rgba(144, 238, 144, 0.5)
    Note over caller,ProcessDetailView: Spawn Pipeline → Renderer
    caller->>ChildProcessSpawner: spawn({ sshRemoteCommand })
    ChildProcessSpawner-->>IPC: ManagedProcess { sshRemoteCommand }
    IPC-->>Renderer: getActiveProcesses → CueProcessEntry { sshRemoteCommand }
    Renderer->>buildProcessTree: populate ProcessNode { sshRemoteCommand }
    buildProcessTree-->>ProcessMonitor: ProcessNode { sshRemoteCommand }
    ProcessMonitor->>ProcessDetailView: detailView { sshRemoteCommand }
    ProcessDetailView->>ProcessDetailView: render "Remote Command" tile
  end
Loading
stateDiagram-v2
  [*] --> Spawning: spawnPtyForTab
  Spawning --> Running: PTY spawned
  Spawning --> SpawnFailed: error
  SpawnFailed --> ExitedPersistent: isPersistent → mark exited + write restart notice
  SpawnFailed --> Closed: isScratch → closeTerminalTab('pty-exit')
  Running --> PTYExited: PTY exit event
  PTYExited --> ExitedPersistent: isPersistent → write restart notice
  PTYExited --> Closed: isScratch + rapid exit → toast + closeTerminalTab('pty-exit')
  PTYExited --> Closed: isScratch + normal exit → closeTerminalTab('pty-exit')
  ExitedPersistent --> Spawning: restartTerminalTab (kill PTY + reset state)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • RunMaestro/Maestro#526: Both PRs touch the unified terminal-tab system—main PR extends TerminalView/tabStore/terminalTabHelpers terminal lifecycle (auto-close/restart and exit handling) on top of the Terminal Upgrade (#526) PTY terminal architecture.
  • RunMaestro/Maestro#1102: The main PR's CustomThemeBuilder.tsx changes specifically adjust validation/requiredness for the new bgTitleBar theme token, which directly overlaps with the retrieved PR's work adding and wiring bgTitleBar through theme types/tests and the builder UI.

Suggested labels

approved, ready to merge

Suggested reviewers

  • reachrazamair

Poem

🐇 Hopping through SSH tunnels, leaving trails of command strings,
The rabbit stamps each process with the remote line it brings.
Exited tabs now rest in peace — a restart button gleams,
While batch sessions stay visible in the unread agent streams.
No terminal lost forever; the RotateCw icon dreams! 🔄

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change—backporting bug fixes from the rc branch to main—matching the PR's core objective of integrating three key fixes and test isolation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch backport/rc-fixes-tier1

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.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR backports four isolated fixes from 0.15.0-rc to main: it stops SSH and startup terminal tabs from vanishing on PTY exit by introducing a isPersistent concept (tabs with a startup command or under an SSH session are kept as restartable husks instead of being silently closed), adds a restart button and restartTerminalTab store action so users can recover those tabs, surfaces the remote agent command in the Process Details modal for SSH spawns, and keeps Auto Run agents visible in the unread filter.

  • Terminal tab lifecycle fix (TerminalView.tsx, tabStore.ts, terminalTabHelpers.ts, TerminalTabItem.tsx): persistent tabs transition to exited with a visible notice and a restart button rather than being destroyed; closeTerminalTab now accepts a TerminalCloseReason and logs it at every close site to aid in diagnosing future vanished-terminal reports.
  • SSH process display (ssh-command-builder.ts, ssh-spawn-wrapper.ts, several propagation files): remoteCommandLine is threaded from the SSH builder through SpawnSpec/ManagedProcess/ProcessNode all the way to ProcessDetailView, which shows it above the local ssh ... invocation when present.
  • Left-bar Auto Run fix (useSessionCategories.ts, SessionList.tsx): activeBatchSessionIds is now passed to the session-category hook so idle Auto Run agents aren't dropped by the unread filter.

Confidence Score: 4/5

Safe to merge; all three source fixes are self-contained and the full test suite passes. The only substantive concern is that remoteCommandLine in buildSshCommandWithStdin is captured after the user prompt may have been appended to cmdParts, so agents that pass prompts as CLI arguments will show the full prompt text in the Process Details modal.

The terminal-tab and left-bar fixes are straightforward and well-tested. The SSH remote-command feature threads a new optional string field through many layers without touching existing behavior. The one concrete issue is the remoteCommandLine capture point in buildSshCommandWithStdin: it sits after the prompt-append block, so for any agent that receives its prompt as a CLI argument (rather than via stdin), the Process Details modal would display the full user prompt as the 'Remote Command'. This is unlikely to affect the common Claude/SSH path (which uses stdin), but it mismatches the stated intent and could expose prompt content unexpectedly for other agents. Two em-dashes in JSX comments also violate the project style guide.

src/main/utils/ssh-command-builder.ts - the remoteCommandLine capture ordering; src/renderer/components/ProcessMonitor/ProcessDetailView.tsx - em-dash style violations

Important Files Changed

Filename Overview
src/renderer/components/TerminalView.tsx Core fix for vanishing SSH/startup terminal tabs: adds isPersistent logic to keep exited tabs as restartable husks instead of silently closing them, plus diagnostic logging at every tab-close site.
src/renderer/stores/tabStore.ts Adds restartTerminalTab action and TerminalCloseReason type; closeTerminalTab now accepts an optional reason for structured diagnostic logging at every tab-destruction chokepoint.
src/renderer/utils/terminalTabHelpers.ts Adds restartTerminalTab pure helper that resets a tab to pid=0/state=idle and selects it so spawn effects in TerminalView can re-create the PTY.
src/main/utils/ssh-command-builder.ts Adds remoteCommandLine to both SSH builder results; for buildSshCommandWithStdin the capture point is after the prompt may have been appended to cmdParts, so the displayed value can include full user prompt text.
src/renderer/hooks/session/useSessionCategories.ts Adds activeBatchSessionIds parameter (default=[]) so Auto Run agents remain visible in the unread filter; worktree-child auto-run propagates to parent visibility as well.
src/renderer/components/ProcessMonitor/ProcessDetailView.tsx Shows remote agent command above the local SSH invocation for SSH spawns; two em-dashes in JSX comments violate the project no-em-dash style rule.
src/renderer/components/TabBar/TerminalTabItem.tsx Adds a restart button (RotateCw icon) visible only on exited terminal tabs, wired to the new restartTerminalTab store action.
src/main/process-listeners/exit-listener.ts Adds structured diagnostic logging for terminal PTY exits at the main-process source, pairing with renderer-side logs to trace vanished terminal reports end-to-end.
src/renderer/hooks/tabs/internal/useUnifiedTabHandlers.ts Adds diagnostic logging for bulk terminal tab closes (wizard/session close path), filling a previously untracked terminal-removal path in the vanished-terminal investigation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[PTY process exits] --> B{tab.pid != 0?}
    B -->|No - spawn failure already handled| Z[Skip duplicate handling]
    B -->|Yes| C{startupCommand OR isRemoteSession?}
    C -->|Yes - persistent| E[Write exit notice to terminal\nKeep tab for restart]
    C -->|No - scratch tab| F[closeTerminalTab with reason=pty-exit]

    A --> G{age less than 2s?}
    G -->|Yes| H[notifySpawnFailure toast]

    J[User clicks Restart button] --> K[restartTerminalTab in tabStore]
    K --> L[Kill any lingering PTY]
    K --> M[Reset tab: pid=0, state=idle]
    M --> N[Select tab, set inputMode=terminal]
    N --> O[spawn effect fires because pid===0 and state is idle]
    O --> P[spawnPtyForTab called]
    P --> Q{Spawn success?}
    Q -->|No and persistent| R[handleSpawnFailure: mark exited, write message]
    Q -->|No and scratch| S[closeTerminalTab with reason=spawn-failure]
    Q -->|Yes| T[onTabPidChange with real PID]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[PTY process exits] --> B{tab.pid != 0?}
    B -->|No - spawn failure already handled| Z[Skip duplicate handling]
    B -->|Yes| C{startupCommand OR isRemoteSession?}
    C -->|Yes - persistent| E[Write exit notice to terminal\nKeep tab for restart]
    C -->|No - scratch tab| F[closeTerminalTab with reason=pty-exit]

    A --> G{age less than 2s?}
    G -->|Yes| H[notifySpawnFailure toast]

    J[User clicks Restart button] --> K[restartTerminalTab in tabStore]
    K --> L[Kill any lingering PTY]
    K --> M[Reset tab: pid=0, state=idle]
    M --> N[Select tab, set inputMode=terminal]
    N --> O[spawn effect fires because pid===0 and state is idle]
    O --> P[spawnPtyForTab called]
    P --> Q{Spawn success?}
    Q -->|No and persistent| R[handleSpawnFailure: mark exited, write message]
    Q -->|No and scratch| S[closeTerminalTab with reason=spawn-failure]
    Q -->|Yes| T[onTabPidChange with real PID]
Loading

Comments Outside Diff (1)

  1. src/main/utils/ssh-command-builder.ts, line 451-459 (link)

    P2 remoteCommandLine is captured after the prompt may have been appended to cmdParts (lines 453-455 push shellEscape(remoteOptions.prompt) when !hasStdinInput). For agents that take the user prompt as a CLI argument rather than via stdin, the displayed "Remote Command" in Process Details will include the full prompt text, which could be arbitrarily long and expose its content unexpectedly. Moving the capture point above the prompt-append block matches the comment's stated intent of "bare agent invocation".

Reviews (1): Last reviewed commit: "fix(terminal): stop SSH/startup terminal..." | Re-trigger Greptile

Comment on lines +383 to +385
{/* Remote Command — full width. Shown only for SSH spawns: the actual agent
invocation running on the remote host, displayed above the local SSH
command line below so it's clear what is executing remotely. */}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Em-dashes in new and edited JSX comments

Both the new "Remote Command" comment (line 383) and the edited "Command Line" comment (line 414) contain (em-dash). CLAUDE.md requires: "NEVER use em-dashes anywhere ... If you catch an em-dash in anything you produce or edit, replace it." Replace both with - (spaced hyphen).

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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/SessionList.tsx (1)

720-726: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include auto-running worktree children in unread-only filtering.

Line 720-726 omits AUTO-state checks, so an auto-running worktree child can still disappear in unread mode even though its parent is kept visible.

Suggested fix
 		const worktreeChildren = showUnreadAgentsOnly
 			? allWorktreeChildren.filter(
 					(child) =>
 						child.id === activeSessionId ||
 						child.aiTabs?.some((tab) => tab.hasUnread) ||
-						child.state === 'busy'
+						child.state === 'busy' ||
+						activeBatchSessionIds.includes(child.id)
 				)
 			: allWorktreeChildren;
🤖 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/renderer/components/SessionList/SessionList.tsx` around lines 720 - 726,
The filter logic in the worktreeChildren filtering block is missing a check for
the 'auto' state, which causes auto-running worktree children to be hidden when
showUnreadAgentsOnly is true even though their parent remains visible. Add an
additional condition to the filter within the allWorktreeChildren.filter call to
also include children where the state equals 'auto', alongside the existing
check for child.state === 'busy'. This ensures auto-running children are
retained in unread-only filtering mode.
🤖 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 `@src/renderer/components/TabBar/TerminalTabItem.tsx`:
- Around line 392-398: The restart button in the TerminalTabItem component
relies only on the title attribute for accessibility, which is insufficient for
screen readers. Add an aria-label attribute to the button element with an
appropriate accessible name like "Restart terminal" to provide an explicit
accessible name alongside the existing title attribute. This ensures assistive
technologies can properly announce the button's purpose.

In `@src/renderer/stores/tabStore.ts`:
- Around line 622-632: The restartTerminalTab function resets a tab to idle and
then kills the PTY process, but if the kill operation emits an exit event after
the reset completes, the exit event listener can revert the tab back to exited
state, preventing the spawn effect from running. Add a guard mechanism (such as
a restart generation/token or one-shot exit suppression) associated with the
restarted tab/session ID to prevent stale exit events from reverting the
restart. This guard should be set when restartTerminalTab is called and checked
in the exit event listener to ignore exit events that occur during the restart
sequence.

---

Outside diff comments:
In `@src/renderer/components/SessionList/SessionList.tsx`:
- Around line 720-726: The filter logic in the worktreeChildren filtering block
is missing a check for the 'auto' state, which causes auto-running worktree
children to be hidden when showUnreadAgentsOnly is true even though their parent
remains visible. Add an additional condition to the filter within the
allWorktreeChildren.filter call to also include children where the state equals
'auto', alongside the existing check for child.state === 'busy'. This ensures
auto-running children are retained in unread-only filtering mode.
🪄 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

Run ID: c3c2f2ac-d794-4bbb-b54b-275922936d66

📥 Commits

Reviewing files that changed from the base of the PR and between 1ba41aa and 316bdd8.

📒 Files selected for processing (28)
  • src/__tests__/main/cue/cue-spawn-builder.test.ts
  • src/__tests__/main/utils/ssh-command-builder.test.ts
  • src/__tests__/renderer/components/ProcessMonitor/ProcessDetailView.test.tsx
  • src/__tests__/renderer/components/TerminalView.test.tsx
  • src/__tests__/renderer/hooks/useSessionCategories.test.ts
  • src/__tests__/renderer/stores/tabStore.test.ts
  • src/__tests__/renderer/utils/terminalTabHelpers.test.ts
  • src/main/cue/cue-process-lifecycle.ts
  • src/main/cue/cue-spawn-builder.ts
  • src/main/group-chat/group-chat-moderator.ts
  • src/main/group-chat/spawnGroupChatAgent.ts
  • src/main/ipc/handlers/process.ts
  • src/main/process-listeners/exit-listener.ts
  • src/main/process-manager/spawners/ChildProcessSpawner.ts
  • src/main/process-manager/types.ts
  • src/main/utils/ssh-command-builder.ts
  • src/main/utils/ssh-spawn-wrapper.ts
  • src/renderer/components/ProcessMonitor/ProcessDetailView.tsx
  • src/renderer/components/ProcessMonitor/ProcessMonitor.tsx
  • src/renderer/components/ProcessMonitor/processTree.ts
  • src/renderer/components/ProcessMonitor/types.ts
  • src/renderer/components/SessionList/SessionList.tsx
  • src/renderer/components/TabBar/TerminalTabItem.tsx
  • src/renderer/components/TerminalView.tsx
  • src/renderer/hooks/session/useSessionCategories.ts
  • src/renderer/hooks/tabs/internal/useUnifiedTabHandlers.ts
  • src/renderer/stores/tabStore.ts
  • src/renderer/utils/terminalTabHelpers.ts

Comment on lines +392 to +398
<button
onClick={handleRestartClick}
className="p-0.5 rounded hover:bg-white/10 transition-colors shrink-0"
title="Restart terminal"
>
<RotateCw className="w-3 h-3" style={{ color: theme.colors.accent }} />
</button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add an accessible name to the restart icon button.

The new icon-only restart button should expose an explicit accessible name (do not rely only on title).

Suggested fix
 			{tab.state === 'exited' && (
 				<button
 					onClick={handleRestartClick}
 					className="p-0.5 rounded hover:bg-white/10 transition-colors shrink-0"
 					title="Restart terminal"
+					aria-label="Restart terminal"
 				>
 					<RotateCw className="w-3 h-3" style={{ color: theme.colors.accent }} />
 				</button>
 			)}
📝 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.

Suggested change
<button
onClick={handleRestartClick}
className="p-0.5 rounded hover:bg-white/10 transition-colors shrink-0"
title="Restart terminal"
>
<RotateCw className="w-3 h-3" style={{ color: theme.colors.accent }} />
</button>
<button
onClick={handleRestartClick}
className="p-0.5 rounded hover:bg-white/10 transition-colors shrink-0"
title="Restart terminal"
aria-label="Restart terminal"
>
<RotateCw className="w-3 h-3" style={{ color: theme.colors.accent }} />
</button>
🤖 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/renderer/components/TabBar/TerminalTabItem.tsx` around lines 392 - 398,
The restart button in the TerminalTabItem component relies only on the title
attribute for accessibility, which is insufficient for screen readers. Add an
aria-label attribute to the button element with an appropriate accessible name
like "Restart terminal" to provide an explicit accessible name alongside the
existing title attribute. This ensures assistive technologies can properly
announce the button's purpose.

Comment thread src/renderer/stores/tabStore.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/__tests__/shared/cssColor.test.ts (1)

24-34: ⚡ Quick win

Add malformed functional-notation regression tests.

The suite should include explicit invalid rgb()/hsl() shapes to lock the rejection behavior and prevent permissive regex regressions.

Suggested test additions
 describe('functional notations', () => {
 	it('accepts rgb() and rgba()', () => {
 		expect(isValidCssColor('rgb(26, 26, 46)')).toBe(true);
 		expect(isValidCssColor('rgba(189, 147, 249, 0.2)')).toBe(true);
 	});

 	it('accepts hsl() and hsla()', () => {
 		expect(isValidCssColor('hsl(262, 83%, 58%)')).toBe(true);
 		expect(isValidCssColor('hsla(262, 83%, 58%, 0.5)')).toBe(true);
 	});
+
+	it('rejects malformed functional notation', () => {
+		expect(isValidCssColor('rgb(,,)')).toBe(false);
+		expect(isValidCssColor('rgba(255, 255)')).toBe(false);
+		expect(isValidCssColor('hsl(eee)')).toBe(false);
+	});
 });
🤖 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/__tests__/shared/cssColor.test.ts` around lines 24 - 34, Add regression
tests within the 'functional notations' describe block to verify that
isValidCssColor properly rejects malformed rgb()/rgba()/hsl()/hsla() formats.
Create additional test cases that check invalid variations such as rgb values
outside the 0-255 range, missing parameters, incorrect separator usage, invalid
alpha values, malformed percentage syntax, and other common mistakes. These
tests should use expect().toBe(false) to ensure the validation function
correctly rejects these invalid formats and prevent future permissive regex
regressions.
🤖 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 `@src/shared/cssColor.ts`:
- Around line 18-19: The `RGB_COLOR` and `HSL_COLOR` regex patterns are too
permissive and accept malformed strings like `rgb(,,)` and `hsl(eee)` due to
their loose character class matching with the plus quantifier. Tighten these
regex patterns to properly validate the structure of functional color notation
by requiring properly formatted numeric or percentage values (potentially with
units like deg) separated by commas or slashes, rather than just matching any
sequence of allowed characters. The patterns should reject sequences of only
commas, spaces, or invalid characters to ensure only valid color values pass
validation.

---

Nitpick comments:
In `@src/__tests__/shared/cssColor.test.ts`:
- Around line 24-34: Add regression tests within the 'functional notations'
describe block to verify that isValidCssColor properly rejects malformed
rgb()/rgba()/hsl()/hsla() formats. Create additional test cases that check
invalid variations such as rgb values outside the 0-255 range, missing
parameters, incorrect separator usage, invalid alpha values, malformed
percentage syntax, and other common mistakes. These tests should use
expect().toBe(false) to ensure the validation function correctly rejects these
invalid formats and prevent future permissive regex regressions.
🪄 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

Run ID: 66396f79-127c-4d8c-af51-a4ab7521047f

📥 Commits

Reviewing files that changed from the base of the PR and between 316bdd8 and 35e8e45.

📒 Files selected for processing (3)
  • src/__tests__/shared/cssColor.test.ts
  • src/renderer/components/CustomThemeBuilder.tsx
  • src/shared/cssColor.ts

Comment thread src/shared/cssColor.ts
Comment on lines +18 to +19
const RGB_COLOR = /^rgba?\(\s*[0-9.,%\s/]+\)$/i;
const HSL_COLOR = /^hsla?\(\s*[0-9.,%\s/deg]+\)$/i;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten functional color regexes to reject malformed values.

RGB_COLOR/HSL_COLOR currently accept malformed strings like rgb(,,) and hsl(eee). That lets invalid imported theme files pass validation and then fail at render time.

Proposed fix
-const RGB_COLOR = /^rgba?\(\s*[0-9.,%\s/]+\)$/i;
-const HSL_COLOR = /^hsla?\(\s*[0-9.,%\s/deg]+\)$/i;
+const NUMBER = String.raw`\d+(?:\.\d+)?`;
+const PERCENT = String.raw`${NUMBER}%`;
+const ALPHA = String.raw`(?:0|1|0?\.\d+|${PERCENT})`;
+
+const RGB_CHANNEL = String.raw`\d{1,3}%?`;
+const RGB_COLOR = new RegExp(
+	`^rgba?\\(\\s*${RGB_CHANNEL}\\s*,\\s*${RGB_CHANNEL}\\s*,\\s*${RGB_CHANNEL}(?:\\s*,\\s*${ALPHA})?\\s*\\)$`,
+	'i'
+);
+
+const HUE = String.raw`${NUMBER}(?:deg|grad|rad|turn)?`;
+const HSL_COLOR = new RegExp(
+	`^hsla?\\(\\s*${HUE}\\s*,\\s*${PERCENT}\\s*,\\s*${PERCENT}(?:\\s*,\\s*${ALPHA})?\\s*\\)$`,
+	'i'
+);
📝 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.

Suggested change
const RGB_COLOR = /^rgba?\(\s*[0-9.,%\s/]+\)$/i;
const HSL_COLOR = /^hsla?\(\s*[0-9.,%\s/deg]+\)$/i;
const NUMBER = String.raw`\d+(?:\.\d+)?`;
const PERCENT = String.raw`${NUMBER}%`;
const ALPHA = String.raw`(?:0|1|0?\.\d+|${PERCENT})`;
const RGB_CHANNEL = String.raw`\d{1,3}%?`;
const RGB_COLOR = new RegExp(
`^rgba?\\(\\s*${RGB_CHANNEL}\\s*,\\s*${RGB_CHANNEL}\\s*,\\s*${RGB_CHANNEL}(?:\\s*,\\s*${ALPHA})?\\s*\\)$`,
'i'
);
const HUE = String.raw`${NUMBER}(?:deg|grad|rad|turn)?`;
const HSL_COLOR = new RegExp(
`^hsla?\\(\\s*${HUE}\\s*,\\s*${PERCENT}\\s*,\\s*${PERCENT}(?:\\s*,\\s*${ALPHA})?\\s*\\)$`,
'i'
);
🤖 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/shared/cssColor.ts` around lines 18 - 19, The `RGB_COLOR` and `HSL_COLOR`
regex patterns are too permissive and accept malformed strings like `rgb(,,)`
and `hsl(eee)` due to their loose character class matching with the plus
quantifier. Tighten these regex patterns to properly validate the structure of
functional color notation by requiring properly formatted numeric or percentage
values (potentially with units like deg) separated by commas or slashes, rather
than just matching any sequence of allowed characters. The patterns should
reject sequences of only commas, spaces, or invalid characters to ensure only
valid color values pass validation.

The spec env spreads process.env, so an ambient MAESTRO_CLAUDE_BIN (leaked when
the suite runs inside a maestro/claude agent, e.g. the pre-push hook) bled into
specs and tripped the 'maestro-p disabled -> undefined' assertion. Clear it per
test via vi.stubEnv so the suite asserts only what the builder injects.
The unread filter only kept busy or unread-tab agents, so an AUTO-badge
agent idling between prompts was dropped. Thread activeBatchSessionIds
(the same source driving the AUTO badge) into useSessionCategories and
treat batch-running agents and their worktree children as visible.
Surface the actual agent invocation running on an SSH remote in the
Process Details modal, displayed above the local SSH wrapper (which is
relabeled "SSH Command"). Previously only the opaque
`ssh ... /bin/bash --norc --noprofile -s` wrapper was visible.

The bare invocation is captured at the SSH command builders
(buildSshCommand, buildSshCommandWithStdin) as `remoteCommandLine`,
stripped of the PATH bootstrap, cd/env prefix, and exec wrapper, then
threaded through ProcessConfig/ManagedProcess, getActiveProcesses,
group-chat spawns, and Cue runs to ProcessDetailData. Local processes
are unchanged.
…add close diagnostics

Terminal tabs with a startup command or running under an SSH/remote session
were silently destroyed when their PTY exited (e.g. a dropped SSH transport),
discarding the tab and its config. Such "persistent" tabs are now kept as a
restartable exited husk with a visible notice and a one-click restart; plain
scratch shells still auto-close on exit.

Adds structured logging at every terminal close and PTY-exit decision so a
vanished terminal can be explained from the logs:
- exit-listener.ts: "Terminal PTY process exited" at the main-process source
- TerminalView.tsx: "Terminal PTY exited" with keep/close decision; spawn-failure log
- tabStore.ts: TerminalCloseReason threaded through closeTerminalTab
- useUnifiedTabHandlers.ts: same log shape on the bulk-close path

Adds restartTerminalTab helper + store action and tests.
isValidColor relied on a jsdom DOM round-trip (new Option().style.color),
which is non-deterministic across environments: it accepts valid colors
locally but intermittently rejects them under load on CI, causing the
CustomThemeBuilder import tests to fail (a pre-existing flake on main).

Replace it with a pure, environment-independent validator in a new shared
module (isValidCssColor) covering hex, rgb/rgba, hsl/hsla, and CSS named
colors, plus a dedicated unit test.
…on bloat

File-preview tabs stored the full file in tab.content; the viewer only
renders a truncated slice and re-reads from disk on activation, so the
full bytes were never needed at rest. A 500k-line .jsonl persisted 363MB
in one tab, ballooning maestro-sessions.json to 531MB and OOM-ing the
main process at startup (it JSON.parses the whole store on boot).

prepareSessionForPersistence now drops content (and stale editContent)
for any preview tab over 256KB, mirroring the existing fileTree and
filePreviewHistory stripping. Small files still persist so unsaved edit
state survives a restart.
Backfill the never-configured state (enableMaestroP === undefined) only.
An explicit false means the user deliberately picked the API token
source; forcing Adaptive Mode back on would silently revert their choice
to Dynamic on the next launch. The previous !== true check wrongly caught
both.
A push that only deletes refs has no new commits to lint or test. Detect
the all-zero local sha git feeds on stdin and exit early so branch
deletions don't trigger the full validate:push suite.
The CustomThemeBuilder import tests failed on CI (a pre-existing flake on
main) for two independent reasons, both fixed here:

1. Import validation required the optional bgTitleBar color key. The
   ThemeColors type marks bgTitleBar as optional and the UI falls back to
   bgMain, but handleImport listed it in the required-key check, so any
   theme exported without it (and the test fixture) was rejected. It is now
   excluded from the required set while still being value-validated when
   present.

2. Color validation used a DOM round-trip (new Option().style.color), which
   is non-deterministic: a sibling test spies on document.createElement, and
   the round-trip then rejected every color when tests ran together. Replaced
   with a pure, environment-independent validator in a new shared module
   (isValidCssColor) covering hex, rgb/rgba, hsl/hsla, and CSS named colors.

Adds a unit test for isValidCssColor and regression tests covering import
with a missing optional bgTitleBar and an invalid bgTitleBar value.
@pedramamini
pedramamini force-pushed the backport/rc-fixes-tier1 branch from 35e8e45 to 4b15231 Compare June 17, 2026 03:19

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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/renderer/components/TerminalView.tsx (1)

328-333: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Spawn the active tab after an in-place restart.

When the already active exited tab is restarted, restartTerminalTab keeps the same tab ID and only resets pid/state to 0/idle; this effect won’t rerun because its deps only observe activeTab?.id. Include pid and state so the active tab actually respawns after restart.

🐛 Proposed fix
 		useEffect(() => {
 			if (!activeTab || activeTab.pid !== 0 || activeTab.state === 'exited') {
 				return;
 			}
 			spawnPtyForTab(activeTab);
-		}, [activeTab?.id, spawnPtyForTab]);
+		}, [activeTab?.id, activeTab?.pid, activeTab?.state, spawnPtyForTab]);
🤖 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/renderer/components/TerminalView.tsx` around lines 328 - 333, The
useEffect hook in the TerminalView component has an incomplete dependency array
that only watches activeTab?.id and spawnPtyForTab. When restartTerminalTab
resets the pid and state properties to 0 and 'idle' while keeping the same tab
ID, the effect doesn't rerun because the ID hasn't changed. Add activeTab?.pid
and activeTab?.state to the dependency array so the effect will properly trigger
when these properties are reset during a restart, ensuring spawnPtyForTab is
called to respawn the terminal.
🤖 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 `@src/renderer/hooks/utils/useDebouncedPersistence.ts`:
- Around line 168-171: The size check in the cleanedFilePreviewTabs mapping only
verifies tab.content.length against MAX_PERSISTED_PREVIEW_CONTENT, but does not
account for tab.editContent which can also be very large. Modify the condition
to also check if tab.editContent exists and its length exceeds
MAX_PERSISTED_PREVIEW_CONTENT, then clear both content and editContent when
either exceeds the size limit to prevent large session startup pressure.

---

Outside diff comments:
In `@src/renderer/components/TerminalView.tsx`:
- Around line 328-333: The useEffect hook in the TerminalView component has an
incomplete dependency array that only watches activeTab?.id and spawnPtyForTab.
When restartTerminalTab resets the pid and state properties to 0 and 'idle'
while keeping the same tab ID, the effect doesn't rerun because the ID hasn't
changed. Add activeTab?.pid and activeTab?.state to the dependency array so the
effect will properly trigger when these properties are reset during a restart,
ensuring spawnPtyForTab is called to respawn the terminal.
🪄 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

Run ID: ebd5c54c-2601-40a6-b44a-9787ddf1a33b

📥 Commits

Reviewing files that changed from the base of the PR and between 35e8e45 and 4b15231.

📒 Files selected for processing (37)
  • .husky/pre-push
  • src/__tests__/helpers/mockTheme.ts
  • src/__tests__/main/cue/cue-spawn-builder.test.ts
  • src/__tests__/main/stores/migrations/adaptive-mode-default.test.ts
  • src/__tests__/main/utils/ssh-command-builder.test.ts
  • src/__tests__/renderer/components/CustomThemeBuilder.test.tsx
  • src/__tests__/renderer/components/ProcessMonitor/ProcessDetailView.test.tsx
  • src/__tests__/renderer/components/TerminalView.test.tsx
  • src/__tests__/renderer/hooks/useSessionCategories.test.ts
  • src/__tests__/renderer/stores/tabStore.test.ts
  • src/__tests__/renderer/utils/terminalTabHelpers.test.ts
  • src/__tests__/shared/cssColor.test.ts
  • src/main/cue/cue-process-lifecycle.ts
  • src/main/cue/cue-spawn-builder.ts
  • src/main/group-chat/group-chat-moderator.ts
  • src/main/group-chat/spawnGroupChatAgent.ts
  • src/main/ipc/handlers/process.ts
  • src/main/process-listeners/exit-listener.ts
  • src/main/process-manager/spawners/ChildProcessSpawner.ts
  • src/main/process-manager/types.ts
  • src/main/stores/migrations/adaptive-mode-default.ts
  • src/main/utils/ssh-command-builder.ts
  • src/main/utils/ssh-spawn-wrapper.ts
  • src/renderer/components/CustomThemeBuilder.tsx
  • src/renderer/components/ProcessMonitor/ProcessDetailView.tsx
  • src/renderer/components/ProcessMonitor/ProcessMonitor.tsx
  • src/renderer/components/ProcessMonitor/processTree.ts
  • src/renderer/components/ProcessMonitor/types.ts
  • src/renderer/components/SessionList/SessionList.tsx
  • src/renderer/components/TabBar/TerminalTabItem.tsx
  • src/renderer/components/TerminalView.tsx
  • src/renderer/hooks/session/useSessionCategories.ts
  • src/renderer/hooks/tabs/internal/useUnifiedTabHandlers.ts
  • src/renderer/hooks/utils/useDebouncedPersistence.ts
  • src/renderer/stores/tabStore.ts
  • src/renderer/utils/terminalTabHelpers.ts
  • src/shared/cssColor.ts
✅ Files skipped from review due to trivial changes (2)
  • src/tests/helpers/mockTheme.ts
  • src/main/process-listeners/exit-listener.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • src/renderer/components/ProcessMonitor/ProcessMonitor.tsx
  • src/tests/shared/cssColor.test.ts
  • src/renderer/components/ProcessMonitor/processTree.ts
  • src/tests/renderer/utils/terminalTabHelpers.test.ts
  • src/renderer/components/ProcessMonitor/ProcessDetailView.tsx
  • src/tests/main/cue/cue-spawn-builder.test.ts
  • src/tests/main/utils/ssh-command-builder.test.ts
  • src/main/cue/cue-process-lifecycle.ts
  • src/renderer/components/SessionList/SessionList.tsx
  • src/renderer/hooks/session/useSessionCategories.ts
  • src/main/process-manager/types.ts
  • src/tests/renderer/stores/tabStore.test.ts
  • src/renderer/utils/terminalTabHelpers.ts
  • src/main/ipc/handlers/process.ts
  • src/tests/renderer/hooks/useSessionCategories.test.ts
  • src/shared/cssColor.ts
  • src/renderer/stores/tabStore.ts
  • src/tests/renderer/components/TerminalView.test.tsx

Comment on lines +168 to +171
const cleanedFilePreviewTabs = (session.filePreviewTabs || []).map((tab) =>
tab.content && tab.content.length > MAX_PERSISTED_PREVIEW_CONTENT
? { ...tab, content: '', editContent: undefined }
: tab

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Include editContent in the oversize guard.

At Line 169, only tab.content.length is checked. A tab can still persist a very large editContent while content is small, which bypasses this cap and can reintroduce large-session startup pressure.

Suggested fix
-const cleanedFilePreviewTabs = (session.filePreviewTabs || []).map((tab) =>
-	tab.content && tab.content.length > MAX_PERSISTED_PREVIEW_CONTENT
-		? { ...tab, content: '', editContent: undefined }
-		: tab
-);
+const cleanedFilePreviewTabs = (session.filePreviewTabs || []).map((tab) => {
+	const contentLength = tab.content.length;
+	const editContentLength = tab.editContent?.length ?? 0;
+	const exceedsCap =
+		contentLength > MAX_PERSISTED_PREVIEW_CONTENT ||
+		editContentLength > MAX_PERSISTED_PREVIEW_CONTENT;
+
+	return exceedsCap ? { ...tab, content: '', editContent: undefined } : tab;
+});
📝 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.

Suggested change
const cleanedFilePreviewTabs = (session.filePreviewTabs || []).map((tab) =>
tab.content && tab.content.length > MAX_PERSISTED_PREVIEW_CONTENT
? { ...tab, content: '', editContent: undefined }
: tab
const cleanedFilePreviewTabs = (session.filePreviewTabs || []).map((tab) => {
const contentLength = tab.content?.length ?? 0;
const editContentLength = tab.editContent?.length ?? 0;
const exceedsCap =
contentLength > MAX_PERSISTED_PREVIEW_CONTENT ||
editContentLength > MAX_PERSISTED_PREVIEW_CONTENT;
return exceedsCap ? { ...tab, content: '', editContent: undefined } : tab;
});
🤖 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/renderer/hooks/utils/useDebouncedPersistence.ts` around lines 168 - 171,
The size check in the cleanedFilePreviewTabs mapping only verifies
tab.content.length against MAX_PERSISTED_PREVIEW_CONTENT, but does not account
for tab.editContent which can also be very large. Modify the condition to also
check if tab.editContent exists and its length exceeds
MAX_PERSISTED_PREVIEW_CONTENT, then clear both content and editContent when
either exceeds the size limit to prevent large session startup pressure.

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.

1 participant