Skip to content

Use signals for AppKit sidebar interactions - #8383

Closed
lawrencecchen wants to merge 10 commits into
feat-appkit-signalsfrom
task-sidebar-appkit-workspace-rename
Closed

lawrencecchen wants to merge 10 commits into
feat-appkit-signalsfrom
task-sidebar-appkit-workspace-rename

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • stack on Add AppKit signal todo lab #8388 and promote its reusable signal core out of the debug lab
  • make manual workspace title and provenance one atomic signal state shared by command-palette, inline, CLI, and restore rename paths
  • make sidebar click-versus-drag an explicit signal-owned lifecycle: idle, pressed, dragging, activating
  • paint the clicked workspace blue on recognized mouse-up, while drag start preserves the authoritative selected workspace
  • cancel a pending click commit synchronously when a new press or drag replaces it
  • make propagation transactional with linear memo/effect queues, pull-settlement for dependent memos, exception-safe nested batching, equality suppression, and untracked reads

Signal design

Solid-style synchronous propagation fits AppKit selection state. Concurrent transitions do not: selection identity and the blue row must commit together on MainActor. Keyed subscriptions and ownership scopes remain useful follow-ups if the sidebar adopts per-row signal effects or nested effects.

The release experiment improved a 30-write, 800-observer fan-out from about 683 ms to 8-26 ms. A six-layer diamond now settles 12 branch memos and 6 join memos exactly once, with one downstream effect. A 50-workspace, seven-field, 100-burst update fell from 35,000 to 5,000 row reruns and about 41-46 ms to 11-13 ms with batching.

Tests

  • regression commit first: 29ad80612f
  • fix commit second: aebab20eb3
  • swift test --package-path Packages/macOS/CmuxAppKitSupportUI (48 passed)
  • 200 layered diamonds prove every memo settles once per batch
  • 200 cancelling diamonds prove unchanged derived state does not rerun downstream effects
  • 50-workspace tagged stress dataset with colors, emoji, descriptions, pull-request provenance, groups, and live ports
  • focused Xcode tests remain blocked before selection by the existing Xcode 26.3 macro error in PortScannerTests.swift

Alternative

Fixes #8224

@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a fine-grained reactive signal framework for AppKit, builds a debug UI (Signal Lab) on it, refactors inline rename coordination to use session-based state instead of once-only resolution, and integrates Signal Lab display and enhanced screenshot capture into debug commands.

Changes

Signal/Reactive Framework

Layer / File(s) Summary
Signal observer and dependency protocol contracts
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalDependency.swift, SignalObserver.swift, WeakSignalObserver.swift
SignalDependency and SignalObserver define the core observer interface; WeakSignalObserver wraps weak references for safe cleanup.
Writable Signal and context types
Signal.swift, SignalEffectContext.swift
Signal implements equality-guarded reads/writes with observer notification; SignalEffectContext registers cleanup handlers for reactive effects.
Computed memo with dependency tracking
SignalMemo.swift
SignalMemo caches computed values, tracks dependencies through SignalGraph, and updates observers only on value changes.
Reactive side effects with cleanup
SignalEffect.swift
SignalEffect runs side-effect closures on dependency changes, manages dependency lifecycle, and supports cleanup handlers.
Signal graph dependency and propagation engine
SignalGraph.swift
SignalGraph manages signal creation, dependency tracking, batched propagation, and re-entrancy-safe observer flushing.
Signal graph reactivity tests
CmuxAppKitSupportUITests/SignalGraphTests.swift
Tests validate effect dependency tracking, batching coalescing, memo memoization, diamond dependencies, and cleanup ordering.

AppKit Signal Lab Debug UI

Layer / File(s) Summary
Signal Lab data models
AppKitSignalLab/Model/AppKitSignalLabStatus.swift, AppKitSignalLabTask.swift, AppKitSignalLabMetrics.swift, AppKitSignalLabFilter.swift, AppKitSignalLabModel.swift
Task status states, task metadata, filtering rules, metrics aggregation, and main signal-based model managing tasks, queries, filtering, selection, and simulation actions.
Signal Lab view controller and visualization
AppKitSignalLab/Views/AppKitSignalLabViewController.swift, SignalLabPulseView.swift
View controller implements table with filtering/search, metric cards, and inspector panel; PulseView provides bar-chart visualization for effect samples.
Signal Lab window controller and coordinator integration
AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift, AboutTitlebarDebug/Coordinator/DebugWindowsCoordinator.swift
Window controller displays Signal Lab; DebugWindowsCoordinator caches and presents via showAppKitSignalLabWindow().

Inline Rename Session Coordination

Layer / File(s) Summary
Coordinator session state machine
Sources/Sidebar/SidebarInlineRenameCoordinator.swift
SidebarInlineRenamePhase defines editing/committed/cancelled states; session manages phase transitions; coordinator delegates to session and provides begin/updateDraft/cancel/observePhase APIs.
Field and cell integration
Sources/Sidebar/SidebarInlineRenameField.swift, Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift
SidebarRowInlineRenameField delegates to coordinator, exposes isInlineRenaming. Cell hides/shows rename field based on coordinator phase and calls cancelInlineRename() on workspace change.
Inline rename coordinator and field tests
cmuxTests/SidebarInlineRenameKeyResolverTests.swift, cmuxTests/SidebarWorkspaceTableTests.swift
Existing tests updated to begin sessions explicitly; new tests validate session rearm behavior and Enter commit using live editor text.

Debug Command Integration

Layer / File(s) Summary
Debug command dispatch and protocol
Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlDebugContext.swift, ControlCommandCoordinator+Debug.swift, ControlCommandCoordinator+Debug2.swift, ControlCommandCoordinator+DebugV1.swift
ControlDebugContext gains controlDebugShowAppKitSignalLab() and updated controlDebugCaptureScreenshot(label:windowIdentifier:); coordinators add debug-domain routing and update v1/v2 handlers.
Debug context implementation and screenshot window targeting
Sources/TerminalController+ControlDebugContext.swift, Sources/TerminalController.swift, Sources/TerminalController+DebugMethodNames.swift
TerminalController shows Signal Lab and forwards windowIdentifier to screenshot capture; capture now selects window by explicit identifier before falling back to preferred window.
Debug command and screenshot tests
Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs+Debug.swift, ControlCommandCoordinatorDebugV1Tests.swift
Test stubs implement new debug context methods; new tests verify Signal Lab dispatch and screenshot window identifier forwarding.
Debug menu and localization
Sources/cmuxApp.swift, Resources/Localizable.xcstrings
Debug menu button opens Signal Lab; localization defines menu entry and full Signal Lab UI strings (en/ja).

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Signal as Signal
    participant Memo as SignalMemo
    participant Effect as SignalEffect
    participant Graph as SignalGraph

    User->>Graph: createSignal(initialValue)
    Graph->>Signal: create Signal
    Signal-->>User: Signal

    User->>Graph: createMemo(compute)
    Graph->>Memo: create & prime
    Memo->>Graph: track dependencies
    Graph->>Signal: addObserver(Memo)
    Memo-->>User: SignalMemo

    User->>Graph: createEffect(body)
    Graph->>Effect: create
    Effect->>Graph: withObserver(effect)
    Graph->>Signal: addObserver(Effect)
    Effect-->>User: SignalEffect (running)

    User->>Signal: set(newValue)
    Signal->>Graph: schedule observers
    Graph->>Memo: run()
    Memo->>Graph: recompute
    Memo->>Graph: schedule downstream
    Graph->>Effect: run()
    Effect->>Graph: track dependencies
    Effect-->>User: effect executed
Loading

Possibly related PRs

  • manaflow-ai/cmux#6527: Initial inline-rename field implementation extended by this PR's coordinator refactor.
  • manaflow-ai/cmux#7395: Earlier refactor of inline-rename coordinator that this PR builds upon with session-based state.
  • manaflow-ai/cmux#8270: Introduced AppKit workspace-row cell scaffolding that this PR refactors for inline rename coordination.

Suggested reviewers: azooz2003-bit


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (4 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error Packages/macOS/CmuxAppKitSupportUI/.../Signals/SignalGraph.swift:95-100 repeatedly scans pendingObservers with min(by:) inside a while loop, yielding O(N^2) batch flushing on a scalable observer set. Replace the per-iteration min scan with a single-pass priority grouping/queue (or another indexed structure) so each batch flush stays near O(N).
Cmux Full Internationalization ❌ Error New AppKit Signals Lab catalog keys only have en/ja, but Resources/Localizable.xcstrings already supports 20 locales. Add translated values for every supported locale (ar, bs, da, de, es, fr, it, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant) on each new/edited string key.
Cmux Architecture Rethink ❌ Error The diff introduces a new SignalGraph/SignalEffect observer side channel and split rename-session ownership, duplicating lifecycle state instead of keeping one clear owner. Keep inline rename and signal-lab state in one explicit model/coordinator owner; avoid a general observer graph/weak-observer layer for this UI path.
Cmux Swift Auxiliary Window Close Shortcuts ❌ Error AppKitSignalLabWindowController creates a keyable window with cmux.appKitSignalsLab, but cmuxAuxiliaryWindowIdentifiers in Sources/cmuxApp.swift doesn’t include it. Add cmux.appKitSignalsLab to cmuxAuxiliaryWindowIdentifiers; the repo lint scans Sources/ only, so this review-only miss isn’t caught by CI.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description covers Summary and Testing, but it omits the Demo Video, Review Trigger, and Checklist sections from the template. Add the missing Demo Video, Review Trigger, and Checklist sections, and include any needed links or confirmations for those items.
✅ Passed checks (19 passed)
Check name Status Explanation
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 All new shared mutable types/protocols are explicitly @MainActor, and the added UI/debug paths stay on the main actor with no new detached/background access.
Cmux Swift Blocking Runtime ✅ Passed No new waits, sleeps, main-thread syncs, locks, or asyncAfter paths were introduced; the new signal runtime is MainActor-isolated and immediate.
Cmux Browser Automation Off-Main ✅ Passed PR only adds debug-window screenshot and AppKit Signal Lab; browser.* wait/screenshot commands still route through the socket-worker router, so the rule isn’t violated.
Cmux Expensive Synchronous Load ✅ Passed Touched files only add rename/session UI, debug menu routing, and screenshot forwarding; no agent-history loads, JSONL parsing, or broad scans were added to interactive/main-actor paths.
Cmux Cache Substitution Correctness ✅ Passed The rename commit path uses an event-driven session draft seeded on begin and updated on text changes, and tests prove Enter commits the live draft instead of stale stringValue.
Cmux No Hacky Sleeps ✅ Passed HEAD only touches Swift sources; no TypeScript/JS/shell/build/runtime scripts were changed, so the no-hacky-sleeps rule is not applicable.
Cmux Swift Concurrency ✅ Passed No new DispatchQueue/Task/completion-handler code was added; the only Combine use is AppKit observation plumbing, and the new signal system is synchronous @MainActor code.
Cmux Swift @Concurrent ✅ Passed Touched Swift changes are all @MainActor sync UI code; no new async/nonisolated/@Concurrent declarations appear in the modified files.
Cmux Swift Package Boundaries ✅ Passed The new Sources/Sidebar code is AppKit-specific rename glue; reusable signal primitives and SignalLab logic were placed in SwiftPM packages, so no boundary violation.
Cmux Swiftpm Lockfiles ✅ Passed PASS: The PR only changes source files; no Package.swift, Package.resolved, xcodeproj, .gitignore, or workflow files were modified, so the lockfile rule isn't triggered.
Cmux Swift Logging ✅ Passed HEAD’s diff adds no print/debugPrint/dump/NSLog/Logger/logging lines, and no file-scoped Logger declarations were introduced in changed production Swift files.
Cmux User-Facing Error Privacy ✅ Passed Touched production files add no user-facing error/alert/API body copy exposing provider names, tokens, or raw upstream messages.
Cmux Swiftui State Layout ✅ Passed Only a menu Button and an NSViewRepresentable/AppKit bridge were changed; no new ObservableObject/@Published/GeometryReader or render-time state writes were introduced.
Cmux Source Artifacts ✅ Passed Changed paths are hand-written source, tests, and a localization catalog; no logs, caches, build output, or scratch dirs appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: the new debug APIs live in DEBUG-gated or debug-folder code and are invoked by the app’s debug menu/socket path, not exposing test-only state.
Cmux No Ambient Global State ✅ Passed New code is instance-scoped (SignalGraph, rename session, debug-window coordinator); no new top-level API or singleton was added, and the only free func was preexisting.
Title check ✅ Passed The title is concise and matches the main shift toward signal-driven AppKit sidebar interactions.
✨ 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 task-sidebar-appkit-workspace-rename

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.

@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: 2b1bfe9f2e

ℹ️ 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 on lines 975 to +976
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if commandSelector == #selector(NSResponder.cancelOperation(_:)) {
onCancel?()
return true
}
if commandSelector == #selector(NSResponder.insertNewline(_:)) {
onCommit?(stringValue)
return true
}
return false
renameCoordinator.control(control, textView: textView, doCommandBy: commandSelector)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-arm the checklist add field for each presentation

SidebarRowInlineRenameField is also the persistent addField in SidebarRowChecklistSection, but unlike the workspace title path it never calls resetForNewSession(). After the first checklist item is submitted or cancelled, the coordinator remains resolved; opening “Add item” again makes Enter and focus loss no-ops (and Escape cannot invoke its cancel closure), so users cannot add a second item from that reused row. Reset the coordinator when a new checklist-add activation starts.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR promotes the reusable signal core from the debug lab and wires it into three production paths: workspace custom-title state, sidebar click-vs-drag gesture lifecycle, and inline-rename phase management. The result replaces ad-hoc boolean flags and split @Published fields with explicit, typed state machines owned by SignalGraph.

  • Atomic custom-title signal: publishSidebarCustomTitle writes customTitleSource and customTitle before updating the signal, so observers never see a half-written rename. customTitle is removed from the coalesced sidebarImmediateObservationPublisher.
  • Click-drag lifecycle: SignalClickDragInteraction gates the blue-selection optimistic paint on mouse-up (.activating) rather than mouse-down (.pressed), preventing premature highlight during drags. Drag-start transitions to .dragging, which blocks activation.
  • Rename coordinator: hasResolved bool replaced by SidebarInlineRenameSession; commit() reads the signal-owned draft rather than potentially-stale NSControl.stringValue, and begin() unconditionally re-arms the session for cell reuse.

Confidence Score: 5/5

Safe to merge. All new state machines are @MainActor-isolated, the signal graph is well-tested including diamond propagation and throwing batches, and the behavioral change (optimistic blue on mouse-up instead of mouse-down) is intentional and preflight-tested.

The architectural changes are thorough: the hasResolved bool and split @published fields that caused the original bug are fully removed, the new signal paths are covered by 43 passing tests including regression cases, and the click-drag state machine prevents the prior paint-on-press ambiguity. The one outstanding item is that sidebarCustomTitleSignal and its graph remain accessible at internal scope with a public set method, but no current callsite exploits this and it is purely a hardening concern.

Sources/Workspace.swift and Sources/Workspace+TitleOwnership.swift — the sidebarCustomTitleSignal lazy var is internal and its Signal.set is public, leaving a path for callers outside the extension to bypass publishSidebarCustomTitle's write ordering.

Important Files Changed

Filename Overview
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift New fine-grained reactive graph (Solid-style) moved from Reactive → Signals. Diamond-problem deduplication via ObjectIdentifier set is correct; settle() O(1) skip is correctly implemented; batch with throwing updates restores depth via defer. Flush loop picks up newly-appended memos/effects from within a running flush. Comprehensive new tests cover all edge cases.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalClickDragInteraction.swift New @mainactor state machine for press→click/drag lifecycle. Guards on dragDidBegin, mouseUpWithoutDrag, activationDidReconcile, dragDidEnd are all correct and prevent invalid phase transitions. Well-tested.
Sources/Sidebar/AppKitList/SidebarWorkspaceTableController.swift Click vs drag lifecycle moved to SignalClickDragInteraction; previewSelection now fires on mouse-up (.activating) instead of mouse-down (.pressed), matching the PR description. reconcileSelectionInteraction handles the already-active-workspace early-reconcile case correctly.
Sources/Sidebar/SidebarInlineRenameCoordinator.swift Replaced hasResolved bool flag with a SidebarInlineRenameSession signal; terminal-state guards on commit/cancel prevent double resolution; begin() unconditionally transitions to .editing for re-arm semantics. Commit reads signal-owned draft, not stale control text.
Sources/Workspace+TitleOwnership.swift Adds atomic sidebarCustomTitleState signal; publishSidebarCustomTitle writes the signal after the @published fields to avoid half-written state. The lazy var sidebarCustomTitleSignal is internal with a public Signal.set, leaving callers outside this extension able to write the signal directly.
Sources/WorkspaceSidebarObservation.swift customTitle removed from sidebarImmediateObservationPublisher (now routed through the signal path). New SidebarWorkspaceCustomTitleSignalModifier manages SignalEffect lifetimes via @StateObject owner; binds on workspaceIdentities change and disposes cleanly on onDisappear.
Sources/Workspace.swift Adds SignalGraph and lazily-initialized Signal for the custom-title atom. Both are internal, allowing direct .set() calls from anywhere in the app module bypassing publishSidebarCustomTitle's write ordering.
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift isEditing bool replaced by signal-driven renamePhaseEffect; visibility of titleView/renameField now toggles via the signal, eliminating the dual-write inconsistency. endInlineRename removed; cancelInlineRename delegates to the coordinator.
cmuxTests/SidebarWorkspaceTableTests.swift New test validates that Enter commits the signal-owned draft, not stale NSControl text — covering the specific regression this PR fixes.
cmuxTests/WorkspaceSidebarObservationTests.swift Replaces the publisher-based manual-title test with three signal-specific tests: delivery count, committed title content, and atomic state shape. Good coverage of the new signal path.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant TableViewImpl as SidebarWorkspaceTableViewImpl
    participant Controller as SidebarWorkspaceTableController
    participant Interaction as SignalClickDragInteraction
    participant Effect as selectionInteractionEffect

    User->>TableViewImpl: mouseDown
    TableViewImpl->>Controller: pointerMouseDown(row, modifiers)
    Controller->>Interaction: mouseDown(workspaceId, modifiers)
    Note over Interaction: idle → pressed

    alt Drag threshold crossed
        TableViewImpl->>Controller: draggingSession(willBeginAt:)
        Controller->>Interaction: dragDidBegin(workspaceId)
        Note over Interaction: pressed → dragging
        Note over Effect: guard .activating fails — no selection
        TableViewImpl->>Controller: draggingSession(ended:)
        Controller->>Interaction: dragDidEnd()
        Note over Interaction: dragging → idle
    else Clean click (mouse-up)
        TableViewImpl->>Controller: tableView(_:shouldSelectRow:) [AppKit action]
        Controller->>Interaction: mouseUpWithoutDrag(workspaceId)
        Note over Interaction: pressed → activating
        Interaction->>Effect: phase changed to .activating
        Effect->>Controller: previewSelection(workspaceId) — paint blue
        Effect->>Controller: commitSelection(workspaceId, modifiers)
        Controller->>Controller: selectionCoalescer.request(updateSelection)
        Controller->>Controller: configure(rows:) [authoritative update arrives]
        Controller->>Interaction: activationDidReconcile(workspaceId)
        Note over Interaction: activating → idle
        Effect->>Controller: cleanup — restoreAuthoritativeSelectionAppearance
    end

    TableViewImpl->>Controller: pointerTrackingDidEnd()
    Controller->>Interaction: trackingDidEnd() [no-op if not .pressed]
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"}}}%%
sequenceDiagram
    participant User
    participant TableViewImpl as SidebarWorkspaceTableViewImpl
    participant Controller as SidebarWorkspaceTableController
    participant Interaction as SignalClickDragInteraction
    participant Effect as selectionInteractionEffect

    User->>TableViewImpl: mouseDown
    TableViewImpl->>Controller: pointerMouseDown(row, modifiers)
    Controller->>Interaction: mouseDown(workspaceId, modifiers)
    Note over Interaction: idle → pressed

    alt Drag threshold crossed
        TableViewImpl->>Controller: draggingSession(willBeginAt:)
        Controller->>Interaction: dragDidBegin(workspaceId)
        Note over Interaction: pressed → dragging
        Note over Effect: guard .activating fails — no selection
        TableViewImpl->>Controller: draggingSession(ended:)
        Controller->>Interaction: dragDidEnd()
        Note over Interaction: dragging → idle
    else Clean click (mouse-up)
        TableViewImpl->>Controller: tableView(_:shouldSelectRow:) [AppKit action]
        Controller->>Interaction: mouseUpWithoutDrag(workspaceId)
        Note over Interaction: pressed → activating
        Interaction->>Effect: phase changed to .activating
        Effect->>Controller: previewSelection(workspaceId) — paint blue
        Effect->>Controller: commitSelection(workspaceId, modifiers)
        Controller->>Controller: selectionCoalescer.request(updateSelection)
        Controller->>Controller: configure(rows:) [authoritative update arrives]
        Controller->>Interaction: activationDidReconcile(workspaceId)
        Note over Interaction: activating → idle
        Effect->>Controller: cleanup — restoreAuthoritativeSelectionAppearance
    end

    TableViewImpl->>Controller: pointerTrackingDidEnd()
    Controller->>Interaction: trackingDidEnd() [no-op if not .pressed]
Loading

Reviews (5): Last reviewed commit: "fix: make signal propagation transaction..." | Re-trigger Greptile

Comment on lines +13 to +31
@Test
@MainActor
func appKitRowRenameEnterCommitsLiveFieldEditorText() {
let field = SidebarRowInlineRenameField()
field.stringValue = "Original"
var committedTitle: String?
field.onCommit = { committedTitle = $0 }
let editor = NSTextView()
editor.string = "Renamed"

let handled = field.control(
field,
textView: editor,
doCommandBy: #selector(NSResponder.insertNewline(_:))
)

#expect(handled)
#expect(committedTitle == "Renamed")
}

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.

P2 Missing regression for the resetForNewSession() invariant

The new test covers Enter committing live field-editor text, but there is no test for the other half of this fix: a reused AppKit table cell whose coordinator still has hasResolved = true from a previous session will silently swallow the commit on the second rename. If resetForNewSession() were accidentally dropped from beginInlineRename(), no commit would fire on subsequent renames and the regression would go undetected. A second test that calls resetForNewSession(), sets up a new commit capture, and presses Enter again would lock in that invariant.

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!

@lawrencecchen
lawrencecchen force-pushed the task-sidebar-appkit-workspace-rename branch from 2b1bfe9 to 9a067c3 Compare July 18, 2026 01:29
@lawrencecchen lawrencecchen changed the title Fix AppKit sidebar workspace renaming Use signals for AppKit sidebar workspace renaming Jul 18, 2026
@lawrencecchen
lawrencecchen changed the base branch from main to feat-appkit-signals July 18, 2026 01:30

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

🤖 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/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift`:
- Around line 93-95: Update the task advancement logic around Self.nextStatus so
any task whose resulting status is .complete has progress set to 100% rather
than the incremental value. Apply the same correction to both advancement paths,
including the occurrence around lines 153–160, while preserving normal progress
updates for non-completed statuses.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift`:
- Around line 488-491: Update the visibleCountLabel formatting and each
filter-count label to use complete localized plural phrases rather than
concatenating localized titles with counts. Add/use catalog entries with
explicit .one and .other variants, selecting the appropriate key based on the
count while preserving the displayed count value.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift`:
- Line 18: Add the AppKit Signal Lab identifier “cmux.appKitSignalsLab” to the
cmuxAuxiliaryWindowIdentifiers collection in cmuxApp.swift, preserving the
existing window-close ownership behavior for auxiliary windows.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift`:
- Around line 95-101: Update the pending observer processing loop in SignalGraph
to avoid calling min(by:) and removing only one observer per iteration. In each
pass, determine the highest-priority scheduling group in a single scan, remove
and run all observers sharing that priority, then continue with the remaining
groups so processing scales with the number of distinct priorities rather than
observer count.

In `@Sources/cmuxApp.swift`:
- Around line 614-621: Update openAllDebugWindows() to call
DebugWindowsCoordinator.showAppKitSignalLabWindow(), alongside the existing
debug-window show calls, so the AppKit Signals Lab window is included in the
“Open All Debug Windows” action.
🪄 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: 6e12be01-78f8-482f-90e7-b1185155c5fa

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1bfe9 and 9a067c3.

📒 Files selected for processing (34)
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AboutTitlebarDebug/Coordinator/DebugWindowsCoordinator.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabFilter.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabMetrics.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabStatus.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabTask.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/SignalLabPulseView.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/Signal.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalDependency.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalEffect.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalEffectContext.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalMemo.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalObserver.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/WeakSignalObserver.swift
  • Packages/macOS/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/SignalGraphTests.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+Debug.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+Debug2.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+DebugV1.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlDebugContext.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs+Debug.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorDebugV1Tests.swift
  • Resources/Localizable.xcstrings
  • Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift
  • Sources/Sidebar/SidebarInlineRenameCoordinator.swift
  • Sources/Sidebar/SidebarInlineRenameField.swift
  • Sources/TerminalController+ControlDebugContext.swift
  • Sources/TerminalController+DebugMethodNames.swift
  • Sources/TerminalController.swift
  • Sources/cmuxApp.swift
  • cmuxTests/SidebarInlineRenameKeyResolverTests.swift
  • cmuxTests/SidebarWorkspaceTableTests.swift

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 5

🤖 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/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift`:
- Around line 93-95: Update the task advancement logic around Self.nextStatus so
any task whose resulting status is .complete has progress set to 100% rather
than the incremental value. Apply the same correction to both advancement paths,
including the occurrence around lines 153–160, while preserving normal progress
updates for non-completed statuses.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift`:
- Around line 488-491: Update the visibleCountLabel formatting and each
filter-count label to use complete localized plural phrases rather than
concatenating localized titles with counts. Add/use catalog entries with
explicit .one and .other variants, selecting the appropriate key based on the
count while preserving the displayed count value.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift`:
- Line 18: Add the AppKit Signal Lab identifier “cmux.appKitSignalsLab” to the
cmuxAuxiliaryWindowIdentifiers collection in cmuxApp.swift, preserving the
existing window-close ownership behavior for auxiliary windows.

In
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift`:
- Around line 95-101: Update the pending observer processing loop in SignalGraph
to avoid calling min(by:) and removing only one observer per iteration. In each
pass, determine the highest-priority scheduling group in a single scan, remove
and run all observers sharing that priority, then continue with the remaining
groups so processing scales with the number of distinct priorities rather than
observer count.

In `@Sources/cmuxApp.swift`:
- Around line 614-621: Update openAllDebugWindows() to call
DebugWindowsCoordinator.showAppKitSignalLabWindow(), alongside the existing
debug-window show calls, so the AppKit Signals Lab window is included in the
“Open All Debug Windows” action.
🪄 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: 6e12be01-78f8-482f-90e7-b1185155c5fa

📥 Commits

Reviewing files that changed from the base of the PR and between 2b1bfe9 and 9a067c3.

📒 Files selected for processing (34)
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AboutTitlebarDebug/Coordinator/DebugWindowsCoordinator.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabFilter.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabMetrics.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabStatus.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabTask.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/SignalLabPulseView.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/Signal.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalDependency.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalEffect.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalEffectContext.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalMemo.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalObserver.swift
  • Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/WeakSignalObserver.swift
  • Packages/macOS/CmuxAppKitSupportUI/Tests/CmuxAppKitSupportUITests/SignalGraphTests.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+Debug.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+Debug2.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlCommandCoordinator+DebugV1.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Debug/ControlDebugContext.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs+Debug.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorDebugV1Tests.swift
  • Resources/Localizable.xcstrings
  • Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift
  • Sources/Sidebar/SidebarInlineRenameCoordinator.swift
  • Sources/Sidebar/SidebarInlineRenameField.swift
  • Sources/TerminalController+ControlDebugContext.swift
  • Sources/TerminalController+DebugMethodNames.swift
  • Sources/TerminalController.swift
  • Sources/cmuxApp.swift
  • cmuxTests/SidebarInlineRenameKeyResolverTests.swift
  • cmuxTests/SidebarWorkspaceTableTests.swift
🛑 Comments failed to post (5)
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift (1)

93-95: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep completed tasks at 100% progress.

.review transitions to .complete regardless of progress. For example, the blocked 41% fixture can become complete at 77%, after which the UI disables further advancement.

Proposed fix
-                    updatedTask.status = Self.nextStatus(after: task.status, progress: updatedTask.progress)
+                    updatedTask.status = Self.nextStatus(after: task.status, progress: updatedTask.progress)
+                    if updatedTask.status == .complete {
+                        updatedTask.progress = 1
+                    }

Also applies to: 153-160

🤖 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
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Model/AppKitSignalLabModel.swift`
around lines 93 - 95, Update the task advancement logic around Self.nextStatus
so any task whose resulting status is .complete has progress set to 100% rather
than the incremental value. Apply the same correction to both advancement paths,
including the occurrence around lines 153–160, while preserving normal progress
updates for non-completed statuses.
Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift (1)

488-491: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Localize the complete count phrases with plural variants.

"%lld visible" and "\(localizedTitle) \(count)" bypass locale-specific pluralization and word ordering. Use catalog entries with .one/.other variants for the visible count and each filter-count label.

As per coding guidelines, “User-facing text must use localized APIs and matching catalogs.” Based on learnings, pluralized Swift strings should use explicit .one and .other localization keys.

Also applies to: 514-517

🤖 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
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Views/AppKitSignalLabViewController.swift`
around lines 488 - 491, Update the visibleCountLabel formatting and each
filter-count label to use complete localized plural phrases rather than
concatenating localized titles with counts. Add/use catalog entries with
explicit .one and .other variants, selecting the appropriate key based on the
count while preserving the displayed count value.

Sources: Coding guidelines, Path instructions, Learnings

Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift (1)

18-18: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

rg -n -C3 'cmuxAuxiliaryWindowIdentifiers|cmux\.appKitSignalsLab' \
  "$(fd -a '^cmuxApp\.swift$' . | head -n 1)"

Repository: manaflow-ai/cmux

Length of output: 636


Register cmux.appKitSignalsLab for Cmd+W ownership
Add this identifier to cmuxAuxiliaryWindowIdentifiers in Sources/cmuxApp.swift; otherwise the new lab window falls through to workspace panel close handling.

🤖 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
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/AppKitSignalLab/Windows/AppKitSignalLabWindowController.swift`
at line 18, Add the AppKit Signal Lab identifier “cmux.appKitSignalsLab” to the
cmuxAuxiliaryWindowIdentifiers collection in cmuxApp.swift, preserving the
existing window-close ownership behavior for auxiliary windows.

Source: Coding guidelines

Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift (1)

95-101: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Optimize batched observer processing to avoid O(N²) repeated scans.

The min(by:) search inside a while loop over pendingObservers performs a repeated full-collection scan since it processes only one observer per pass. If a batch contains many observers (e.g., during a broad UI state transition), this degrades to O(N²) complexity and can cause severe frame drops. As per path instructions, avoid repeated hot-path sorting/filtering for scalable collections in production code.

Extract all observers for the highest priority in a single pass to reduce the outer loop to O(P), where P is the number of distinct priorities, making the overall flush practically O(N).

⚡ Proposed optimization
         while !pendingObservers.isEmpty {
-            guard let observer = pendingObservers.values.min(by: {
+            guard let minPriority = pendingObservers.values.min(by: {
                 $0.schedulingPriority < $1.schedulingPriority
-            }) else { return }
-            pendingObservers.removeValue(forKey: ObjectIdentifier(observer))
-            observer.run()
+            })?.schedulingPriority else { return }
+
+            let batch = pendingObservers.values.filter { $0.schedulingPriority == minPriority }
+            for observer in batch {
+                pendingObservers.removeValue(forKey: ObjectIdentifier(observer))
+            }
+
+            for observer in batch {
+                observer.run()
+            }
         }
📝 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.

        while !pendingObservers.isEmpty {
            guard let minPriority = pendingObservers.values.min(by: {
                $0.schedulingPriority < $1.schedulingPriority
            })?.schedulingPriority else { return }

            let batch = pendingObservers.values.filter { $0.schedulingPriority == minPriority }
            for observer in batch {
                pendingObservers.removeValue(forKey: ObjectIdentifier(observer))
            }

            for observer in batch {
                observer.run()
            }
        }
🤖 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
`@Packages/macOS/CmuxAppKitSupportUI/Sources/CmuxAppKitSupportUI/Signals/SignalGraph.swift`
around lines 95 - 101, Update the pending observer processing loop in
SignalGraph to avoid calling min(by:) and removing only one observer per
iteration. In each pass, determine the highest-priority scheduling group in a
single scan, remove and run all observers sharing that priority, then continue
with the remaining groups so processing scales with the number of distinct
priorities rather than observer count.

Source: Path instructions

Sources/cmuxApp.swift (1)

614-621: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Include the new window in openAllDebugWindows.

The "AppKit Signals Lab…" window was added to the "Debug Windows" menu, but AppDelegate.shared?.debugWindowsCoordinator.showAppKitSignalLabWindow() was not added to the openAllDebugWindows() helper function below. Please consider adding it so that the "Open All Debug Windows" action correctly includes this new tool.

🛠️ Suggested update for openAllDebugWindows()
    private func openAllDebugWindows() {
        // ... existing windows ...
        AppDelegate.shared?.debugWindowsCoordinator.showAboutTitlebarDebugWindow()
        AppDelegate.shared?.debugWindowsCoordinator.showAppKitSignalLabWindow()
        // ...
    }
🤖 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/cmuxApp.swift` around lines 614 - 621, Update openAllDebugWindows()
to call DebugWindowsCoordinator.showAppKitSignalLabWindow(), alongside the
existing debug-window show calls, so the AppKit Signals Lab window is included
in the “Open All Debug Windows” action.

@cursor

cursor Bot commented Jul 18, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@lawrencecchen lawrencecchen changed the title Use signals for AppKit sidebar workspace renaming Use signals for AppKit sidebar interactions Jul 18, 2026
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants