Reduce GPU memory growth and UI sluggishness#39
Conversation
Occlude surfaces in non-selected workspaces so libghostty stops their DisplayLink and redraw loops. All split panes in the active workspace remain live regardless of focus; only workspace switches toggle occlusion. Occlusion is applied reactively via SwiftUI re-renders on selectedWorkspaceId change — no manual recompute needed. Also fixes several secondary contributors: - refreshGitBranch: cancel-and-replace per surface to prevent git subprocess pile-up on rapid tab cycling - AgentCompletionEventMonitor: batch all log-line events into one MainActor task per file read instead of one strong-self task per line - CoalescingWorkspacePersistence.save(): async instead of sync so the main thread is never blocked scheduling debounced workspace saves - WorkspacePersistence: reuse JSONEncoder instance - deleteWorkspace: call clearProgressReport for released surfaces - Codex monitor poll loop: cap at 300 iterations (150 s) to prevent orphaned monitors after abrupt close
|
Warning Review limit reached
More reviews will be available in 42 minutes and 31 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR adds workspace-selection-driven Ghostty surface occlusion to stop render loops on non-visible workspaces, consolidates agent event dispatch into a single weak-capturing ChangesGhostty Surface Occlusion for Workspace Selection
Agent Infrastructure Fixes
Workspace Service Hardening
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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: 2
🤖 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 `@Sources/Shellraiser/Features/Terminal/GhosttyTerminalView.swift`:
- Around line 199-203: The code unconditionally sets occluded: true when calling
runtime.setSurfaceOcclusion() during the detach operations at both locations
(around the runtime.detachHost call and at the second location mentioned). In a
reparent scenario where a surface can be temporarily mounted in multiple
containers, this premature occlusion stalls redraws. Instead of always setting
occluded: true when detaching, first check if the surface (identified by
mountedSurfaceId) has any other active mounts remaining in the runtime, and only
set occluded: true when removing the last mount for that surface. Apply this
conditional logic to both detach flow locations in the code.
In `@Sources/Shellraiser/Services/Workspaces/WorkspaceManager`+GitBranches.swift:
- Around line 43-53: The code checks Task.isCancelled before the MainActor.run
block, but the task can be cancelled between this check and the actual write to
gitStatesBySurfaceId on line 52. Add a second cancellation guard at the
beginning of the MainActor.run closure (after the guard let self check and
before the workspace/surface validation checks) to re-check if Task.isCancelled
and return early if true. This prevents stale git state from being written when
the task is cancelled during the actor hop.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 14f474ca-2d5e-4fc4-98cf-765f64b9adc0
📒 Files selected for processing (11)
Sources/Shellraiser/Features/Terminal/GhosttyTerminalView.swiftSources/Shellraiser/Features/WorkspaceDetail/PaneLeafView.swiftSources/Shellraiser/Infrastructure/Agents/AgentCompletionEventMonitor.swiftSources/Shellraiser/Infrastructure/Agents/AgentRuntimeBridge.swiftSources/Shellraiser/Infrastructure/Ghostty/GhosttyRuntime.swiftSources/Shellraiser/Services/Persistence/WorkspacePersistence.swiftSources/Shellraiser/Services/Workspaces/WorkspaceManager+GitBranches.swiftSources/Shellraiser/Services/Workspaces/WorkspaceManager+WorkspaceLifecycle.swiftSources/Shellraiser/Services/Workspaces/WorkspaceManager.swiftTests/ShellraiserTests/AgentRuntimeBridgeTests.swiftTests/ShellraiserTests/GhosttyTerminalViewTests.swift
Guard setSurfaceOcclusion(occluded:true) in both detach sites behind a mountedHostCount check so a reparent-in-progress surface is not stalled while a second container still shows it. Reorder dismantleContainerView to decrement first, then check. Add a second Task.isCancelled guard inside the MainActor.run closure in refreshGitBranch to prevent stale git state from landing after a replacement task cancels the in-flight one during the actor hop.
Occlude surfaces in non-selected workspaces so libghostty stops their DisplayLink and redraw loops. All split panes in the active workspace remain live regardless of focus; only workspace switches toggle occlusion. Occlusion is applied reactively via SwiftUI re-renders on selectedWorkspaceId change — no manual recompute needed.
Also fixes several secondary contributors:
Summary by CodeRabbit
Bug Fixes
Performance Improvements
Improvements