Skip to content

Sync settings sidebar and open notifications at turn start - #5528

Open
duroey wants to merge 10 commits into
manaflow-ai:mainfrom
duroey:codex/notification-turn-anchor
Open

duroey wants to merge 10 commits into
manaflow-ai:mainfrom
duroey:codex/notification-turn-anchor

Conversation

@duroey

@duroey duroey commented Jun 6, 2026 •

Copy link
Copy Markdown

Summary

  • Sync the Settings sidebar selection with the section currently visible while the user scrolls the settings content.
  • Change terminal notification reopen behavior so clicking a notification returns to the start of the agent turn that produced it instead of jumping to the live bottom of the surface.
  • Add focused regression coverage for both behaviors.

Testing

  • git diff --check
  • cd Packages/CmuxSettingsUI && swift test (22 tests passed)
  • CMUX_SKIP_ZIG_BUILD=1 xcodebuild test -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -only-testing:cmuxTests/GhosttySurfaceOverlayTests/testNotificationOpenAnchorCapturesTurnStartInsteadOfViewportTop -only-testing:cmuxTests/TerminalNotificationSocketActionTests/testPromptSubmitWithoutSurfaceIdRecordsAnchorForFocusedTerminalNotification
  • CMUX_SKIP_ZIG_BUILD=1 ./scripts/reload.sh --tag notification-turn-anchor

Full non-skip Zig validation was attempted with verified Zig 0.15.2 at /Users/duroy/.local/opt/zig/0.15.2/zig, but this local macOS 26.5.1 / Xcode 26.5 environment fails before cmux tests run while linking Zig's zig build build-runner (undefined symbol: __availability_version_check, _dispatch_queue_create, _abort, etc.). A minimal /tmp Zig build project reproduces the same linker failure, so this appears to be a local Zig 0.15.2 + Xcode 26.x SDK compatibility issue rather than a cmux code failure.

Demo Video

  • Video URL or attachment: Not included; both changes are covered by focused tests, and local full app reload was verified with CMUX_SKIP_ZIG_BUILD=1.

Review Trigger (Copy/Paste as PR comment)

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

Checklist

  • I tested the change locally
  • I added or updated tests for behavior changes
  • I updated docs/changelog if needed (not needed)
  • I requested bot reviews after my latest commit (copy/paste block above or equivalent)
  • All code review bot comments are resolved
  • All human review comments are resolved

Summary by CodeRabbit

  • New Features

    • Notifications capture a reopen anchor (terminal scroll position), persist in session snapshots, and restore that position immediately when a notification is opened.
    • Prompt submissions record/apply reopen anchors for relevant panels/surfaces; queued anchors are applied once the terminal scrollbar/view is available.
    • Settings sidebar syncs selection to the visible section and includes improved accessibility identifiers/selection traits.
  • Tests

    • Added extensive tests covering anchor capture, conversion, queuing, persistence, payload inclusion, clearing/dispatch behavior, and settings-visible-section logic.

@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

@duroey is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR captures prompt-submit terminal scrollbar offsets, records them per (tab,surface), persists them with notifications and session snapshots, and replays the scroll position when opening notifications (deferring until Ghostty scrollbar state is ready); it also adds settings-section visibility measurement and sidebar sync.

Changes

Notification Open Anchor Feature

Layer / File(s) Summary
Anchor data model & snapshot wiring
Sources/TerminalNotificationStore.swift, Sources/SessionPersistence.swift
Adds TerminalNotificationOpenAnchor, adds openAnchor to TerminalNotification and SessionNotificationSnapshot, and preserves it during snapshot round-trips.
Prompt-submit anchor recording
Sources/WorkspacePromptSubmit.swift, Sources/TerminalController.swift
TabManager.handlePromptSubmit accepts an optional surfaceId; recordPromptSubmitOpenAnchors(in:surfaceId:) records anchors for affected panels and alias contexts.
Anchor store APIs and lifecycle
Sources/PromptSubmitOpenAnchorStore.swift, Sources/TerminalNotificationStore.swift
Implements PromptSubmitOpenAnchorStore, integrates promptSubmitOpenAnchorStore into TerminalNotificationStore, adds record/query/rebind/remove APIs and pruning during clears/restore.
Ghostty capture and deferred restore
Sources/GhosttyTerminalView.swift, Sources/Panels/TerminalPanel.swift
notificationOpenAnchor() captures absolute scrollbar offsets; conversion helper produces Ghostty scroll_to_row indices; scrollToNotificationOpenAnchor(_:) queues when scrollbar state absent and applies queued anchors on scrollbar updates; TerminalPanel delegates and respects hibernation.
AppDelegate open flow and scroll replay
Sources/AppDelegate.swift
openNotification(...) accepts/resolve openAnchor (from call-site or store), threads it into context and fallback paths, invokes scrollToNotificationOpenAnchor(...) after focus and before marking read, and includes open_anchor in desktop/socket payloads.
Socket & integration tests
cmuxTests/*
Adds tests for snapshot restore of openAnchor, socket open payload includes open_anchor, prompt-submit focused-terminal anchor recording, Ghostty deferred emission and retry behavior, and store clearing/rebind behavior.

Settings visible-section resolver & sync

Layer / File(s) Summary
Visibility infrastructure
Packages/CmuxSettingsUI/.../SettingsSectionVisibilityCoordinateSpace.swift, SettingsSectionFramePreferenceKey.swift, SettingsSectionVisibilityMarker.swift
Adds a named coordinate space, a PreferenceKey to aggregate per-section frames, a GeometryReader-based marker, and a view modifier to publish frames.
Visible-section resolver & tests
Packages/CmuxSettingsUI/.../SettingsVisibleSectionResolver.swift, Packages/CmuxSettingsUI/Tests/*
Adds SettingsVisibleSectionResolver which selects the active section using activationY heuristics and nearest-frame tie-breaking, with unit tests including inline browserImport handling and configurable activationY.
SettingsWindowRoot integration
Packages/CmuxSettingsUI/.../SettingsWindowScene.swift
Tracks latest section frames, suppresses visible-section-to-sidebar sync during programmatic navigation, yields to async timing in guarded scroll tasks, and syncs sidebar selection on preference changes and search reset.
Sidebar accessibility & browser subsection marker
Packages/CmuxSettingsUI/.../SettingsSidebarEntryRow.swift, Packages/CmuxSettingsUI/.../Sections/BrowserSection.swift
Adds id/isSelected inputs and accessibilityIdentifier/traits on sidebar rows; marks the inline browser-import subsection with .settingsSectionVisibility(.browserImport).

Sequence Diagram(s)

sequenceDiagram
  participant Prompt as WorkspacePromptSubmit
  participant Store as TerminalNotificationStore
  participant App as AppDelegate
  participant Panel as TerminalPanel
  participant View as GhosttySurfaceScrollView
  Prompt->>Store: recordPromptSubmitOpenAnchor(tabId,surfaceId,anchor)
  Store-->>App: promptSubmitOpenAnchor(panelId/surfaceId)?
  App->>Panel: openNotification(..., openAnchor)
  Panel->>View: scrollToNotificationOpenAnchor(anchor)
  View->>View: queue or emit binding scroll_to_row:N when scrollbar ready
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#4982: Related TerminalNotificationStore restore/rebind changes that overlap with notification replacement/restore logic.

🐰 I tucked a scrollbar offset in a tiny note,

saved where the prompt made the cursor float.
When the bell rings and you open the view,
the terminal hops back to the row it knew.
A rabbit’s tap, and your place is home anew.

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the two main changes: syncing settings sidebar during scroll and restoring notifications to turn start.
Description check ✅ Passed The description follows the template with all major sections completed: clear summary of changes, comprehensive testing details, explanation of local issues encountered, and a fully checked checklist.
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.
Cmux Swift Actor Isolation ✅ Passed New models properly isolated: Sendable value types, @MainActor ownership, no mutable reference types without isolation, no background context access violations found.
Cmux Swift Blocking Runtime ✅ Passed No new blocking synchronization patterns (Task.sleep, DispatchQueue.main.sync, semaphores, locks) introduced. Task.yield() is properly async. Pre-existing NSLocks unrelated to PR changes.
Cmux Expensive Synchronous Load ✅ Passed PR adds no expensive synchronous loaders (RestorableAgentSessionIndex.load, file I/O, sysctl) to main/interactive paths; uses lightweight property reads and in-memory storage only.
Cmux Cache Substitution Correctness ✅ Passed PromptSubmitOpenAnchorStore is transient in-memory cache with graceful degradation; scrollToNotificationOpenAnchor failure is ignored, allowing notification opening to complete successfully.
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift files and Xcode project config; check applies to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts only per rule scope.
Cmux Algorithmic Complexity ✅ Passed No algorithmic complexity violations: panel iterations bounded to ~20, anchor store uses O(1) operations, existing notification lookup pattern used defensively without worsening hot paths.
Cmux Swift Concurrency ✅ Passed PR adds no problematic legacy async patterns; Task { @MainActor } in SettingsWindowScene is proper structured concurrency for SwiftUI boundary.
Cmux Swift @Concurrent ✅ Passed PR introduces only synchronous helper functions for notification scrolling and settings UI; no async functions, @concurrent annotations, or UI-isolation isolation violations found.
Cmux Swift File And Package Boundaries ✅ Passed New 93-line PromptSubmitOpenAnchorStore.swift has clear responsibility. All oversized-file additions stay below 250-line threshold (AppDelegate +84, TerminalController +8, GhosttyTerminalView +71).
Cmux Swift Logging ✅ Passed No new logging violations found; all production code additions comply with swift-logging.md rules (no print/NSLog/debugPrint/dump in app code, no ad hoc logging, no problematic Logger declarations).
Cmux User-Facing Error Privacy ✅ Passed Notification turn-anchor feature and settings sidebar changes contain no vendor names, credentials, tokens, or unredacted payloads in user-facing text or socket responses.
Cmux Full Internationalization ✅ Passed PR makes technical changes to notification handling and settings UI without adding new user-facing strings or modifying localization catalogs; no full-internationalization violations found.
Cmux Swiftui State Layout ✅ Passed Sidebar rows receive value snapshots only; List avoids store refs; GeometryReader for measurement only; @State appropriate; new stores are value types; no body state mutations.
Cmux Architecture Rethink ✅ Passed PR introduces required SwiftUI platform bridge code; Task.yield()+flag timing coordination has documented invariants and clear state ownership; not a symptom patch.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR introduces SettingsWindowScene.swift with SwiftUI Window(id: "cmux.settings"), which is already registered in cmuxAuxiliaryWindowIdentifiers; no unregistered auxiliary windows created.
Cmux Source Artifacts ✅ Passed All 21 changed files are intentional source files, tests, or configs with no prohibited artifacts (logs, build output, caches, DerivedData, etc.) in source control.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 6, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds two behaviors: (1) the Settings sidebar now syncs its selection to the section visible in the scroll view as the user scrolls, and (2) clicking a terminal notification jumps to the start of the agent turn that produced it rather than the live bottom of the surface.

  • Settings sidebar sync: new SettingsSectionVisibilityMarker/SettingsSectionFramePreferenceKey machinery reports per-section frames via SwiftUI preferences; SettingsVisibleSectionResolver picks the active section; visibleSectionSyncSuppressed guards against the sync racing programmatic navigation.
  • Notification reopen anchor: TerminalNotificationOpenAnchor captures scrollbar.total at prompt-submit time, persists in TerminalNotification and session snapshots, and is restored by GhosttySurfaceScrollView.scrollToNotificationOpenAnchor (queuing when Ghostty's scrollbar isn't yet available).
  • PromptSubmitOpenAnchorStore tracks anchors keyed by (tab, surface), with full lifecycle management across clear/rebind/restore paths and comprehensive test coverage.

Confidence Score: 4/5

The notification anchor machinery and anchor store lifecycle are solid; the one issue worth addressing before merge is the settings sidebar sync guard in SettingsWindowScene.swift.

The Task.yield() used to re-enable sidebar sync after proxy.scrollTo will almost always fire before SwiftUI has propagated updated geometry frames, causing the sidebar to snap back to the wrong section immediately after any programmatic navigation (e.g., search-result click or window restore). All other changed paths — anchor capture, queuing, persistence, clear/rebind lifecycle, and surface_id resolution — look correct and are well-covered by tests.

Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift — the Task.yield() / visibleSectionSyncSuppressed interaction in scrollToNavigationTarget.

Important Files Changed

Filename Overview
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift Adds sidebar↔scroll sync with visibleSectionSyncSuppressed flag and Task.yield() used as a timing guard to let proxy.scrollTo settle before re-enabling sync — fragile timing assumption.
Sources/PromptSubmitOpenAnchorStore.swift New pure-value store for prompt-submit anchors keyed by (tab, surface); clean CRUD with rebind/remove semantics and no shared state.
Sources/GhosttyTerminalView.swift Adds scrollToNotificationOpenAnchor with proper signal-driven queuing via pendingNotificationOpenAnchor cleared on ghosttyDidUpdateScrollbar; no timing hacks introduced here.
Sources/TerminalNotificationStore.swift Adds openAnchor field to TerminalNotification, delegates anchor lifecycle to PromptSubmitOpenAnchorStore, and exposes userInfo(for:) as a static method for testability.
Sources/WorkspacePromptSubmit.swift Adds recordPromptSubmitOpenAnchors to capture turn-start anchor per panel at prompt-submit time; correctly handles panel/surface ID resolution and bonsplit aliases.
Sources/AppDelegate.swift Routes openAnchor from notification user-info and store through openNotification/scrollToNotificationOpenAnchor; uses panelId ?? surfaceId for stable routing.
Sources/SessionPersistence.swift Adds openAnchor to SessionNotificationSnapshot for round-trip persistence; straightforward Codable field addition.
Sources/TerminalController.swift Fixes surface_id resolution (drops tab_id fallback, adds comment) and exposes open_anchor in notification.open response payload.
Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsVisibleSectionResolver.swift New pure, Sendable resolver that picks the visible section from a frame map; three-tier priority logic (containing → crossed → nearest) with deterministic tie-breaking.
Sources/Panels/TerminalPanel.swift Thin delegation of notificationOpenAnchor() and scrollToNotificationOpenAnchor to the hosted scroll view, guarded by isAgentHibernated.

Sequence Diagram

sequenceDiagram
    participant User
    participant TerminalController
    participant TabManager
    participant TerminalNotificationStore
    participant GhosttySurfaceScrollView
    participant AppDelegate
    participant UNNotificationCenter

    User->>TerminalController: workspace.prompt_submit (surface_id?)
    TerminalController->>TabManager: handlePromptSubmit(workspaceId, surfaceId)
    TabManager->>GhosttySurfaceScrollView: notificationOpenAnchor()
    GhosttySurfaceScrollView-->>TabManager: TerminalNotificationOpenAnchor(scrollbar.total)
    TabManager->>TerminalNotificationStore: recordPromptSubmitOpenAnchor(anchor, tabId, panelId)

    Note over TerminalNotificationStore: Agent runs…

    TerminalNotificationStore->>TerminalNotificationStore: addNotification → reads anchor → attaches to TerminalNotification
    TerminalNotificationStore->>UNNotificationCenter: deliver with userInfo (includes scrollbar_offset)

    User->>AppDelegate: userNotificationCenter didReceive (clicks notification)
    AppDelegate->>AppDelegate: openNotification(tabId, surfaceId, openAnchor)
    AppDelegate->>GhosttySurfaceScrollView: scrollToNotificationOpenAnchor(anchor)
    alt scrollbar available
        GhosttySurfaceScrollView->>GhosttySurfaceScrollView: performBindingAction("scroll_to_row:N")
    else scrollbar nil
        GhosttySurfaceScrollView->>GhosttySurfaceScrollView: queue pendingNotificationOpenAnchor
        Note over GhosttySurfaceScrollView: ghosttyDidUpdateScrollbar fires → applyPendingNotificationOpenAnchorIfPossible
    end
Loading

Reviews (9): Last reviewed commit: "fix(settings): replace visibility namesp..." | Re-trigger Greptile

Comment thread Sources/AppDelegate.swift Outdated
Comment on lines +16246 to +16250
if !didScroll {
DispatchQueue.main.async { [weak terminalPanel] in
_ = terminalPanel?.scrollToNotificationOpenAnchor(openAnchor)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Timing-based retry for scrollbar readiness

When scrollToNotificationOpenAnchor returns false (either because isAgentHibernated is true or Ghostty's scrollbar is still nil), a one-shot DispatchQueue.main.async re-try is enqueued hoping the state will have advanced by the next run-loop cycle. There is no real signal from the owning subsystem — if the scrollbar is still nil on the next tick (e.g., Ghostty hasn't delivered its first scroll-state update after focus), the anchor scroll is silently dropped. Similarly, a hibernated agent will not un-hibernate in one run-loop, so the retry for that case also no-ops silently. This matches the blocked pattern in the cmux-swift-blocking-runtime rule (delayed dispatch used as synchronization) and the cmux-swift-architectural-rethink rule (timing repair that leaves bad state reachable). The fix should subscribe to a real readiness signal — e.g., observe the scrollbar property becoming non-nil and deliver the scroll then — rather than hoping a deferred queue hop is sufficient.

Rule Used: Flag new blocking or timing-based synchronization ... (source)

Comment thread Sources/TerminalController.swift Outdated
}
}
let message = messageKeys.lazy.compactMap { self.v2RawString(params, $0) }.first
let surfaceId = v2UUID(params, "surface_id") ?? v2UUID(params, "tab_id")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 tab_id fallback makes surfaceId always non-nil, silently bypassing the "all panels" anchor path

v2UUID(params, "tab_id") will succeed for every valid prompt_submit request (the workspace UUID is always present). This means surfaceId is never nil when it reaches handlePromptSubmit, so recordPromptSubmitOpenAnchors can never take the surfaceId == nil branch that records anchors for all panels in the workspace. When an agent sends prompt_submit with tab_id but no surface_id, the workspace UUID is forwarded as the surfaceId; workspace.panels[workspace_uuid] and panelIdFromSurfaceId(TabID(uuid: workspace_uuid)) both return nil, leaving panelIds = [] and recording no anchor at all. The notification will fire but clicking it won't scroll to the prompt start. To restore the intended fallback, drop the ?? v2UUID(params, "tab_id") so that a missing surface_id properly propagates as nil and triggers the "record for all panels" path.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 6, 2026

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
Sources/TerminalController.swift (1)

4789-4804: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not use tab_id as a fallback for surfaceId.

On Line 4789, v2UUID(params, "tab_id") can be a workspace/tab UUID, not a surface UUID. Passing that into handlePromptSubmit(... surfaceId:) on Line 4803 can mis-scope (or skip) anchor capture and break reopen-to-turn-start for callers that omit surface_id.

Suggested fix
-        let surfaceId = v2UUID(params, "surface_id") ?? v2UUID(params, "tab_id")
+        let surfaceId = v2UUID(params, "surface_id")

Based on learnings, keep tab/surface identifiers from a consistent origin and avoid panel/surface route fallback patterns that introduce active-context bias or wrong-ID routing.

🤖 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 `@Sources/TerminalController.swift` around lines 4789 - 4804, The code
currently falls back to v2UUID(params, "tab_id") when computing surfaceId which
can be a workspace/tab UUID and mis-scope anchor capture; change the surfaceId
calculation to use only v2UUID(params, "surface_id") (no fallback to "tab_id")
and let handlePromptSubmit receive nil when no surface_id is present so
anchor/surface routing remains correct; update any related logic that assumed a
non-nil surfaceId and add a comment by surfaceId, v2UUID, and handlePromptSubmit
to explain why "tab_id" must never be used as a surface fallback.

Source: Learnings

🤖 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/AppDelegate.swift`:
- Around line 16245-16250: Add a one-line comment above the
DispatchQueue.main.async retry that explains the rationale: note that
scrollToNotificationOpenAnchor can return false if
GhosttyTerminalView.surfaceView.scrollbar/state hasn't been delivered yet
because scrollbar updates are flushed to the main queue asynchronously, so
deferring to the next runloop gives Ghostty time to populate scrollbar
state/view geometry before retrying the scroll (reference terminalPanel and
scrollToNotificationOpenAnchor).

In `@Sources/GhosttyTerminalView.swift`:
- Around line 15277-15280: The code sets userScrolledAwayFromBottom,
allowExplicitScrollbarSync and lastSentRow before calling
surfaceView.performBindingAction("scroll_to_row:\(row)"), which can fail and
leave state stale; change the flow to first call performBindingAction(...) and
only if it succeeds update userScrolledAwayFromBottom,
allowExplicitScrollbarSync and lastSentRow (or roll back on failure). Locate the
call to surfaceView.performBindingAction("scroll_to_row:\(row)") and ensure you
inspect its return/throw value (handle Bool/Result/try) and move the state
mutations (userScrolledAwayFromBottom, allowExplicitScrollbarSync, lastSentRow)
to the success path, preserving existing behavior on failure.

In `@Sources/TerminalNotificationStore.swift`:
- Around line 824-833: The struct TerminalNotificationOpenAnchor has an explicit
memberwise init(scrollbarOffset:) which Swift synthesizes (triggering a
SwiftLint redundancy warning); remove the redundant initializer and move the
existing initializer documentation to the scrollbarOffset property comment so
the documentation is preserved (keep the struct declaration and conformances
Codable/Hashable/Sendable intact and ensure the scrollbarOffset property's
docstring describes the "Absolute top-row offset reported by Ghostty at prompt
submit time").
- Line 926: promptSubmitOpenAnchors is never pruned and should be cleaned up
when surfaces/workspaces close; inside clearNotifications(forTabId:) iterate
promptSubmitOpenAnchors and remove any entries whose key.tabId matches the
provided tabId, and inside clearNotifications(forTabId:surfaceId:) remove
entries whose key.tabId and key.surfaceId match the provided tabId and
surfaceId; update both methods (the ones at clearNotifications(forTabId:) and
clearNotifications(forTabId:surfaceId:)) to perform this removal in the same
style as lastNotificationDateByCooldownKey cleanup so stale anchors do not
accumulate.

---

Outside diff comments:
In `@Sources/TerminalController.swift`:
- Around line 4789-4804: The code currently falls back to v2UUID(params,
"tab_id") when computing surfaceId which can be a workspace/tab UUID and
mis-scope anchor capture; change the surfaceId calculation to use only
v2UUID(params, "surface_id") (no fallback to "tab_id") and let
handlePromptSubmit receive nil when no surface_id is present so anchor/surface
routing remains correct; update any related logic that assumed a non-nil
surfaceId and add a comment by surfaceId, v2UUID, and handlePromptSubmit to
explain why "tab_id" must never be used as a surface fallback.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: b013fef5-ca9e-446d-bc15-afc09de04f36

📥 Commits

Reviewing files that changed from the base of the PR and between 5302202 and 4787b51.

📒 Files selected for processing (11)
  • Sources/AppDelegate.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/TerminalPanel.swift
  • Sources/SessionPersistence.swift
  • Sources/TerminalController.swift
  • Sources/TerminalNotificationStore.swift
  • Sources/WorkspacePromptSubmit.swift
  • cmuxTests/SessionPersistenceTests.swift
  • cmuxTests/TerminalAndGhosttyTests.swift
  • cmuxTests/TerminalNotificationSocketActionTests.swift
  • cmuxTests/WorkspacePromptSubmitTests.swift

Comment thread Sources/AppDelegate.swift Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread Sources/TerminalNotificationStore.swift
Comment thread Sources/TerminalNotificationStore.swift Outdated

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

Caution

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

⚠️ Outside diff range comments (3)
Sources/TerminalNotificationStore.swift (3)

1848-1872: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear promptSubmitOpenAnchors when restoring session notifications.

restoreSessionNotifications replaces notifications for a tab but does not clear promptSubmitOpenAnchors entries for that tab. Stale runtime anchors from the previous session will accumulate, potentially causing incorrect scroll positions if the same surface IDs are reused.

🧹 Proposed fix
 func restoreSessionNotifications(_ restoredNotifications: [TerminalNotification], forTabId tabId: UUID) {
     TerminalMutationBus.shared.discardPendingNotifications(forTabId: tabId)

     let removedIds = notifications
         .filter { $0.tabId == tabId }
         .map { $0.id.uuidString }
+    promptSubmitOpenAnchors = promptSubmitOpenAnchors.filter { entry in
+        entry.key.tabId != tabId
+    }
     var usedNotificationIds = Set(notifications.filter { $0.tabId != tabId }.map(\.id))
     let restoredForTab = restoredNotifications
         .filter { $0.tabId == tabId }
🤖 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 `@Sources/TerminalNotificationStore.swift` around lines 1848 - 1872,
restoreSessionNotifications replaces notifications for a tab but doesn't clear
stale promptSubmitOpenAnchors entries, so update restoreSessionNotifications to
also remove any promptSubmitOpenAnchors entries associated with the given tabId
(e.g. clear or filter promptSubmitOpenAnchors for keys/values tied to tabId)
before or after clearing focused read indicator; reference the
promptSubmitOpenAnchors storage and the restoreSessionNotifications method so
the anchors for the previous session don't persist when notifications are
restored.

1905-1923: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear promptSubmitOpenAnchors when clearing all notifications.

clearAll() removes all notifications and workspace unread state but does not clear promptSubmitOpenAnchors. This leaves stale anchor entries that could be incorrectly attached to new notifications if the same tabId/surfaceId is reused (e.g., after workspace close and recreation).

🛠️ Proposed fix
 func clearAll(discardQueuedNotifications: Bool = true) {
     if discardQueuedNotifications { TerminalMutationBus.shared.discardPendingNotifications() }
     guard !notifications.isEmpty ||
         !focusedReadIndicatorByTabId.isEmpty ||
         !manualUnreadWorkspaceIds.isEmpty ||
         !panelDerivedUnreadWorkspaceIds.isEmpty ||
         !restoredUnreadWorkspaceIds.isEmpty else { return }
     let tabIdsToClearPanelUnread = panelDerivedUnreadWorkspaceIds.union(notifications.map(\.tabId))
     let ids = notifications.map { $0.id.uuidString }
     replaceNotificationsForClear([])
+    promptSubmitOpenAnchors.removeAll()
     clearWorkspaceManualUnread()
     clearAllWorkspacePanelUnread(forTabIds: tabIdsToClearPanelUnread)
🤖 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 `@Sources/TerminalNotificationStore.swift` around lines 1905 - 1923, In
clearAll() inside TerminalNotificationStore, also clear the
promptSubmitOpenAnchors state to avoid stale anchors being reused; locate the
clearAll method and add a step to remove or reset promptSubmitOpenAnchors (e.g.,
call whatever clearPromptSubmitOpenAnchors() or
promptSubmitOpenAnchors.removeAll()) alongside the other clear* calls (before
publishing CmuxEventBus.shared.publishNotificationCleared and removing
notifications from UNUserNotificationCenter) so anchors are fully reset when
notifications and workspace unread state are cleared.

1961-1996: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rebind promptSubmitOpenAnchors entry when moving surface notifications.

rebindSurfaceNotifications moves notifications and the focused-read indicator from sourceTabId to destinationTabId, but it does not move the promptSubmitOpenAnchors entry. After a surface is detached from one workspace and reattached to another, future notifications on that surface will not include the saved anchor (unless a new prompt-submit happens), breaking the "return to prompt start" feature.

🔧 Proposed fix
 func rebindSurfaceNotifications(fromTabId sourceTabId: UUID, toTabId destinationTabId: UUID, surfaceId: UUID) {
     guard sourceTabId != destinationTabId else { return }
     TerminalMutationBus.shared.discardPendingNotifications(forTabId: sourceTabId, surfaceId: surfaceId)

     var didMoveNotification = false
     let updated = notifications.map { notification -> TerminalNotification in
         guard notification.matches(tabId: sourceTabId, surfaceId: surfaceId) else {
             return notification
         }
         didMoveNotification = true
         return TerminalNotification(
             id: notification.id,
             tabId: destinationTabId,
             surfaceId: notification.surfaceId,
             panelId: notification.panelId,
             title: notification.title,
             subtitle: notification.subtitle,
             body: notification.body,
             createdAt: notification.createdAt,
             isRead: notification.isRead,
             paneFlash: notification.paneFlash,
             clickAction: notification.clickAction,
             openAnchor: notification.openAnchor
         )
     }
     if didMoveNotification {
         notifications = updated
     }

+    if let anchor = promptSubmitOpenAnchors[TabSurfaceKey(tabId: sourceTabId, surfaceId: surfaceId)] {
+        promptSubmitOpenAnchors.removeValue(forKey: TabSurfaceKey(tabId: sourceTabId, surfaceId: surfaceId))
+        promptSubmitOpenAnchors[TabSurfaceKey(tabId: destinationTabId, surfaceId: surfaceId)] = anchor
+    }
+
     if focusedReadIndicatorByTabId[sourceTabId] == surfaceId {
         focusedReadIndicatorByTabId.removeValue(forKey: sourceTabId)
         if focusedReadIndicatorByTabId[destinationTabId] == nil {
             focusedReadIndicatorByTabId[destinationTabId] = surfaceId
         }
     }
 }
🤖 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 `@Sources/TerminalNotificationStore.swift` around lines 1961 - 1996,
rebindSurfaceNotifications currently moves notifications and
focusedReadIndicatorByTabId but forgets to rebind promptSubmitOpenAnchors;
update rebindSurfaceNotifications to check promptSubmitOpenAnchors for an entry
for sourceTabId that equals surfaceId, remove it from sourceTabId, and set it on
destinationTabId if destination has no entry (mirror the
focusedReadIndicatorByTabId logic). Refer to rebindSurfaceNotifications,
promptSubmitOpenAnchors, sourceTabId, destinationTabId, and surfaceId when
making the change.
🤖 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.

Outside diff comments:
In `@Sources/TerminalNotificationStore.swift`:
- Around line 1848-1872: restoreSessionNotifications replaces notifications for
a tab but doesn't clear stale promptSubmitOpenAnchors entries, so update
restoreSessionNotifications to also remove any promptSubmitOpenAnchors entries
associated with the given tabId (e.g. clear or filter promptSubmitOpenAnchors
for keys/values tied to tabId) before or after clearing focused read indicator;
reference the promptSubmitOpenAnchors storage and the
restoreSessionNotifications method so the anchors for the previous session don't
persist when notifications are restored.
- Around line 1905-1923: In clearAll() inside TerminalNotificationStore, also
clear the promptSubmitOpenAnchors state to avoid stale anchors being reused;
locate the clearAll method and add a step to remove or reset
promptSubmitOpenAnchors (e.g., call whatever clearPromptSubmitOpenAnchors() or
promptSubmitOpenAnchors.removeAll()) alongside the other clear* calls (before
publishing CmuxEventBus.shared.publishNotificationCleared and removing
notifications from UNUserNotificationCenter) so anchors are fully reset when
notifications and workspace unread state are cleared.
- Around line 1961-1996: rebindSurfaceNotifications currently moves
notifications and focusedReadIndicatorByTabId but forgets to rebind
promptSubmitOpenAnchors; update rebindSurfaceNotifications to check
promptSubmitOpenAnchors for an entry for sourceTabId that equals surfaceId,
remove it from sourceTabId, and set it on destinationTabId if destination has no
entry (mirror the focusedReadIndicatorByTabId logic). Refer to
rebindSurfaceNotifications, promptSubmitOpenAnchors, sourceTabId,
destinationTabId, and surfaceId when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1f479b8e-94f0-4ada-91b2-aa28b8e85485

📥 Commits

Reviewing files that changed from the base of the PR and between 2de6880 and aa76e99.

📒 Files selected for processing (5)
  • Sources/GhosttyTerminalView.swift
  • Sources/TerminalController.swift
  • Sources/TerminalNotificationStore.swift
  • cmuxTests/TerminalAndGhosttyTests.swift
  • cmuxTests/WorkspacePromptSubmitTests.swift

@lawrencecchen
lawrencecchen dismissed coderabbitai[bot]’s stale review June 6, 2026 11:33

CodeRabbit now posts non-blocking comment reviews (request_changes_workflow=false, #5538).

@duroey duroey changed the title Fix notification opens returning to prompt start Sync settings sidebar and open notifications at turn start Jun 9, 2026
@duroey

duroey commented Jun 9, 2026

Copy link
Copy Markdown
Author

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@cubic-dev-ai

cubic-dev-ai Bot commented Jun 9, 2026

Copy link
Copy Markdown

@codex review
@coderabbitai review
@greptile-apps review
@cubic-dev-ai review

@duroey I can't start this review because your workspace has reached its free monthly review limit. Reviews resume at the start of your next billing cycle. Paid plans include much higher monthly review limits. Upgrade now to resume reviews.

To help optimise your usage, you can tune cubic to get the most out of your usage limits:

Learn more →

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

@duroey I’ll review the changes in this PR.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cb3dc5f9c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Sources/AppDelegate.swift
Comment on lines +16026 to +16028
let resolvedOpenAnchor = openAnchor ?? notificationId.flatMap { id in
notificationStore?.notifications.first(where: { $0.id == id })?.openAnchor
}

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 Badge Preserve anchors for unrecorded desktop notifications

When a notification policy sets effects.record=false while leaving desktop=true, applyNotification computes an openAnchor but deliberately skips recordNotification, and scheduleUserNotification only puts IDs in the delivered notification payload. On a Notification Center click, handleNotificationResponse calls openNotification without an anchor, so this store lookup cannot find the unrecorded notification and the click still opens at the live bottom instead of the turn start. Serialize the anchor into the UN notification userInfo or fall back to the prompt-submit anchor for the tab/surface.

Useful? React with 👍 / 👎.

@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 (2)
Sources/TerminalNotificationStore.swift (2)

1235-1282: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Extract prompt-submit anchor lifecycle out of this store.

TerminalNotificationStore.swift is already far beyond the file-size limit, and this PR adds more lifecycle/state logic into it. Please move anchor record/lookup/prune behavior into a focused type (and file) to keep this class maintainable.

As per coding guidelines: “Flag Swift production files that exceed 400 lines without a clear single responsibility, or exceed 800 lines even with mostly coherent responsibility.”

🤖 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 `@Sources/TerminalNotificationStore.swift` around lines 1235 - 1282, The
prompt-submit anchor lifecycle logic (recordPromptSubmitOpenAnchor,
promptSubmitOpenAnchor, removePromptSubmitOpenAnchors and the
promptSubmitOpenAnchors storage using
TabSurfaceKey/TerminalNotificationOpenAnchor) should be extracted into a focused
type and file: create a new AnchorStore (or PromptSubmitAnchorStore) that
encapsulates the dictionary and the three methods (record, lookup, prune) with
the same signatures/semantics, update TerminalNotificationStore to hold an
instance of that new type and forward calls to it, and move unit tests or add
new ones for the new type; ensure TabSurfaceKey and
TerminalNotificationOpenAnchor remain usable (move or import them if needed) and
update any callers to use the new store instance instead of the in-file
dictionary and methods.

Source: Coding guidelines


1925-1943: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

clearAll leaves stale prompt-submit anchors behind.

Global clear does not clear promptSubmitOpenAnchors, and the guard can early-return when only anchors remain. That lets old anchors leak into future notifications and reopen at the wrong turn position.

🛠️ Proposed fix
 func clearAll(discardQueuedNotifications: Bool = true) {
     if discardQueuedNotifications { TerminalMutationBus.shared.discardPendingNotifications() }
     guard !notifications.isEmpty ||
         !focusedReadIndicatorByTabId.isEmpty ||
         !manualUnreadWorkspaceIds.isEmpty ||
         !panelDerivedUnreadWorkspaceIds.isEmpty ||
-        !restoredUnreadWorkspaceIds.isEmpty else { return }
+        !restoredUnreadWorkspaceIds.isEmpty ||
+        !promptSubmitOpenAnchors.isEmpty else { return }
     let tabIdsToClearPanelUnread = panelDerivedUnreadWorkspaceIds.union(notifications.map(\.tabId))
     let ids = notifications.map { $0.id.uuidString }
     replaceNotificationsForClear([])
+    promptSubmitOpenAnchors.removeAll()
     clearWorkspaceManualUnread()
     clearAllWorkspacePanelUnread(forTabIds: tabIdsToClearPanelUnread)
     clearPanelDerivedWorkspaceUnread()
     clearWorkspaceRestoredUnread()
🤖 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 `@Sources/TerminalNotificationStore.swift` around lines 1925 - 1943, The
clearAll method currently can early-return while leaving promptSubmitOpenAnchors
populated; modify clearAll (the function named clearAll) to clear
promptSubmitOpenAnchors before the guard early-return (or include
promptSubmitOpenAnchors.empty in the guard check) so anchors never persist
across a global clear; specifically ensure promptSubmitOpenAnchors is emptied
(e.g. call the existing clear/close routine for promptSubmitOpenAnchors or
remove all entries) before or as part of the
replaceNotificationsForClear/clearWorkspace* sequence (refer to
replaceNotificationsForClear, clearWorkspaceManualUnread,
clearAllWorkspacePanelUnread, clearPanelDerivedWorkspaceUnread,
clearWorkspaceRestoredUnread and focusedReadIndicatorByTabId) so no stale
anchors remain after a global clear.
🤖 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
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsVisibleSectionResolver.swift`:
- Around line 4-45: This file declares multiple top-level major types; split
each major type into its own file so the package follows “one major type per
file”: create separate files containing
SettingsSectionVisibilityCoordinateSpace, SettingsSectionFramePreferenceKey,
SettingsSectionVisibilityMarker, and keep SettingsVisibleSectionResolver in its
original file; move the corresponding type declarations into those new files
(preserve their exact names, visibility, and code), update the original file to
remove the moved declarations and import/compile in the same module, and ensure
any references to SettingsSectionVisibilityCoordinateSpace.name,
SettingsSectionFramePreferenceKey, SettingsSectionVisibilityMarker, and the View
extension settingsSectionVisibility(_:) remain unchanged and compile.

---

Outside diff comments:
In `@Sources/TerminalNotificationStore.swift`:
- Around line 1235-1282: The prompt-submit anchor lifecycle logic
(recordPromptSubmitOpenAnchor, promptSubmitOpenAnchor,
removePromptSubmitOpenAnchors and the promptSubmitOpenAnchors storage using
TabSurfaceKey/TerminalNotificationOpenAnchor) should be extracted into a focused
type and file: create a new AnchorStore (or PromptSubmitAnchorStore) that
encapsulates the dictionary and the three methods (record, lookup, prune) with
the same signatures/semantics, update TerminalNotificationStore to hold an
instance of that new type and forward calls to it, and move unit tests or add
new ones for the new type; ensure TabSurfaceKey and
TerminalNotificationOpenAnchor remain usable (move or import them if needed) and
update any callers to use the new store instance instead of the in-file
dictionary and methods.
- Around line 1925-1943: The clearAll method currently can early-return while
leaving promptSubmitOpenAnchors populated; modify clearAll (the function named
clearAll) to clear promptSubmitOpenAnchors before the guard early-return (or
include promptSubmitOpenAnchors.empty in the guard check) so anchors never
persist across a global clear; specifically ensure promptSubmitOpenAnchors is
emptied (e.g. call the existing clear/close routine for promptSubmitOpenAnchors
or remove all entries) before or as part of the
replaceNotificationsForClear/clearWorkspace* sequence (refer to
replaceNotificationsForClear, clearWorkspaceManualUnread,
clearAllWorkspacePanelUnread, clearPanelDerivedWorkspaceUnread,
clearWorkspaceRestoredUnread and focusedReadIndicatorByTabId) so no stale
anchors remain after a global clear.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: b4416d34-1292-48d6-8115-97b07e9f9c79

📥 Commits

Reviewing files that changed from the base of the PR and between aa76e99 and cb3dc5f.

📒 Files selected for processing (12)
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSidebarEntryRow.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsVisibleSectionResolver.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/BrowserSection.swift
  • Packages/CmuxSettingsUI/Tests/CmuxSettingsUITests/SettingsVisibleSectionResolverTests.swift
  • Sources/AppDelegate.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/TerminalPanel.swift
  • Sources/TerminalNotificationStore.swift
  • cmuxTests/TerminalAndGhosttyTests.swift
  • cmuxTests/TerminalNotificationSocketActionTests.swift
  • cmuxTests/WorkspacePromptSubmitTests.swift

@duroey

duroey commented Jun 9, 2026

Copy link
Copy Markdown
Author

Addressed the latest review feedback in cdf51a424.

Changes included:

  • Split the settings visible-section helper types into separate package files.
  • Extracted prompt-submit anchor lifecycle into PromptSubmitOpenAnchorStore and kept TerminalNotificationStore as the forwarding owner.
  • Cleared prompt-submit anchors on clearAll, session restore, tab clear, and surface rebind paths to avoid stale anchors.
  • Serialized notification openAnchor into delivered system notification userInfo, then parsed it in AppDelegate so desktop-only/unrecorded notifications can still reopen at the agent response start.

Validation:

  • git diff --check
  • swift test in Packages/CmuxSettingsUI
  • CMUX_SKIP_ZIG_BUILD=1 xcodebuild test -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination platform=macOS -derivedDataPath /tmp/cmux-notification-turn-anchor-review-fixes-test with 10 targeted notification/settings tests
  • CMUX_SKIP_ZIG_BUILD=1 ./scripts/reload.sh --tag notification-turn-anchor

Current PR checks: Socket passes, CodeRabbit/Greptile are still processing the new commit, Cubic is skipped due review limit, and Vercel still requires Manaflow team deploy authorization.

@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

🤖 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
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSectionVisibilityCoordinateSpace.swift`:
- Around line 1-2: The enum SettingsSectionVisibilityCoordinateSpace is being
used purely as a namespace for the static constant name; replace the no-case
enum with a concrete non-enum type (e.g., a struct) to comply with the “no
namespace-enums” rule: locate the SettingsSectionVisibilityCoordinateSpace
declaration and change it to a struct (or another appropriate type) while
preserving the static let name = "SettingsSectionVisibilityCoordinateSpace"
member and any access level.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: d41fff17-658e-487c-952c-02597304ae60

📥 Commits

Reviewing files that changed from the base of the PR and between cb3dc5f and cdf51a4.

📒 Files selected for processing (9)
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSectionFramePreferenceKey.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSectionVisibilityCoordinateSpace.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSectionVisibilityMarker.swift
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsVisibleSectionResolver.swift
  • Sources/AppDelegate.swift
  • Sources/PromptSubmitOpenAnchorStore.swift
  • Sources/TerminalNotificationStore.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/WorkspacePromptSubmitTests.swift
💤 Files with no reviewable changes (1)
  • Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsVisibleSectionResolver.swift

@teamleaderleo teamleaderleo added the S3: minor Wrong behavior with a workaround label Sep 30, 2026
@teamleaderleo teamleaderleo added area: settings Settings UI and the config file area: notifications Notifications, banners, badges, the bell labels Sep 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: notifications Notifications, banners, badges, the bell area: settings Settings UI and the config file S3: minor Wrong behavior with a workaround

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants