Skip to content

Fix stale SSH workspace connection status - #9085

Merged
austinywang merged 56 commits into
mainfrom
issue-9068-stale-ssh-status
Jul 30, 2026
Merged

austinywang merged 56 commits into
mainfrom
issue-9068-stale-ssh-status

Conversation

@austinywang

@austinywang austinywang commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #9068

Summary

  • distinguish a launched remote terminal wrapper from an authoritatively connected terminal
  • report terminal-connected lifecycle events from OpenSSH and persistent PTY handshakes
  • prevent auxiliary daemon/proxy retries from overwriting known-live terminal status

Test plan

  • regression coverage for unconfirmed wrappers, lifecycle RPC routing, OpenSSH startup, and persistent PTY bridge readiness
  • tagged local dogfood after CI and review are clean

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes stale SSH “Connected” states by making the terminal process the source of truth, keyed to per-process lifecycle IDs and authenticated relay/persistent PTY ownership. SSH/Mosh now register each launching attempt and only report connected after transport is proven; readiness runs off-main with a single broker-lease commit and proxy-only errors no longer claim “Connected”.

  • Bug Fixes
    • Added worker-lane RPCs workspace.remote.terminal_session_launching and workspace.remote.terminal_session_connected with per-attempt UUIDs; one main-actor mutation after off-main validation.
    • Authenticated persistent PTY readiness via broker-owned lifecycle owner and a commit lease that coalesces duplicates, reuses completed acks, and rejects stale owners at commit.
    • Exported CMUX_TERMINAL_LIFECYCLE_ID to terminal env and bootstrap; readiness carries authority (relay port or persistent transport) and attempt IDs; Mosh and restored SSH report connected only after their transport and remoteRelayPort.
    • Routed liveness to the owning Dock by presentation workspace; survives launch-workspace removal and treats surface respawns as new lifecycle generations; session-end and connected resolutions allow a missing workspace when a window-scoped Dock owns it.
    • Correlation-scoped clears cancel matching in-flight notification policy work (e.g., “Remote proxy unavailable”); unconfirmed proxy-only errors cannot set “Connected”.

Closes #9068.

Written for commit 5ac19c1. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added workspace.remote.terminal_session_connected handshake support with relay and persistent-session authority resolution.
    • Introduced per-surface remote-terminal liveness/session-phase tracking with dock-split connect/end handling.
    • Propagated terminalLifecycleId via CMUX environment and included correlation keys across notification policies and in-flight reservations.
  • Bug Fixes
    • Preserved remote-terminal session phase/authority across detachment/reattachment and corrected session-end responses when workspace ownership is unavailable.
    • Added stricter validation to reject ambiguous or mismatched terminal session ownership.
  • Tests
    • Expanded unit and integration coverage for new handshake behavior, lifecycle-liveness transitions, dock transfers, reconnection flows, and correlation-scoped clearing.

@coderabbitai

coderabbitai Bot commented Jul 28, 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

The PR adds authoritative remote-terminal connection reporting, tracks terminal liveness across workspace, dock, reconnect, and detach flows, propagates terminal lifecycle identifiers, and scopes notification correlation through policy and cleanup paths.

Changes

Remote terminal liveness

Layer / File(s) Summary
Connected-session RPC reporting
CLI/cmux.swift, Packages/macOS/CmuxControlSocket/..., Packages/macOS/CmuxRemoteWorkspace/...
SSH readiness paths emit workspace.remote.terminal_session_connected; the coordinator validates relay or persistent PTY authority and resolves the connection through workspace context and broker lifecycle ownership.
Workspace and dock lifecycle state
Sources/Workspace*, Sources/DockSplitStore*, Sources/TerminalController*, Sources/WorkspaceRemoteSessionHostAdapter.swift, cmux.xcodeproj/project.pbxproj
Workspace and dock state records launching, connected, and ended terminal phases, preserves authority through detach/reattach, handles external docks, and updates connection-state presentation.
Terminal lifecycle identity propagation
Packages/macOS/CmuxTerminal*/..., Sources/RemoteInteractiveShellBootstrapBuilder.swift, CLI/cmux.swift
Terminal surfaces generate lifecycle identifiers and propagate them through managed startup environments, bootstrap scripts, and SSH command templates.
Correlation-scoped notification cleanup
Sources/TerminalNotification*, Sources/SessionNotificationSnapshot.swift, cmuxTests/AgentNotificationMutationBoundaryTests.swift
Correlation keys flow through notification models and policy requests, and matching in-flight and stored notifications can be cleared by tab and correlation key.
Lifecycle and notification validation
cmuxTests/*, Packages/macOS/*/Tests/*
Tests cover RPC emission, authority rejection, stale generations, reconnect transitions, dock-owned transfers, notification isolation, startup identity propagation, and PTY lifecycle ownership.

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

Sequence Diagram(s)

sequenceDiagram
  participant SSHBridge
  participant ControlCommandCoordinator
  participant TerminalController
  participant Workspace
  SSHBridge->>ControlCommandCoordinator: Send workspace.remote.terminal_session_connected
  ControlCommandCoordinator->>TerminalController: Forward validated authority
  TerminalController->>Workspace: Mark terminal session connected
  Workspace-->>TerminalController: Return remote status and identifiers
  TerminalController-->>ControlCommandCoordinator: Return RPC response
Loading

Suggested reviewers: azooz2003-bit


Important

Pre-merge checks failed

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

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error WorkspaceRemoteSessionHostAdapter reads AppDelegate.shared.existingWindowDocks off-main before hopping to DispatchQueue.main; AppDelegate and that accessor are @MainActor. Move the existingWindowDocks fetch inside the main-queue hop, or add a main-actor accessor and only pass Sendable data across the background callback.
Cmux Swift Blocking Runtime ❌ Error RemotePTYLifecycleCommitLease adds OSAllocatedUnfairLock in production code; the rule bans new manual locks where actor/explicit signal should own sync. Replace the lock with actor-owned state or a non-blocking commit token/signal, and keep the validity check off the hot path.
Cmux Algorithmic Complexity ❌ Error TerminalNotificationStore.swift:1668-1675 scans all notifications, then remove(id) rescans the array twice per match, making clearNotifications(forTabId:correlationKey:) O(n*m) on a scalable notifi... Use the existing one-pass rebuild pattern from clearNotifications(forTabId:), or keep an index by tabId+correlationKey so clearing is O(k).
Cmux Swift Package Boundaries ❌ Error Pure notification policy/store logic was expanded in app-target Sources despite being data-format/persistence code that can be unit-tested without AppKit. Extract the policy/request/engine/in-flight store and correlation-key helpers into a small SwiftPM target (e.g. CmuxNotificationPolicyCore); keep only AppKit/UserNotifications glue in Sources.
Cmux Architecture Rethink ❌ Error Added a lock-backed RemotePTYLifecycleCommitLease for readiness commits, creating a new blocking repair path for PTY lifecycle races. Move lifecycle validity into the broker’s queue-owned registry and expose one synchronous commit path; avoid a separate lock-backed lease except in tests.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ 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 Browser Automation Off-Main ✅ Passed Browser wait/callback verbs stay on the socket worker router with policy tests; main-actor cases are only direct focus/open commands, not waits.
Cmux Expensive Synchronous Load ✅ Passed Patch adds lifecycle handshake/commit-lease logic only; changed files show no added RestorableAgentSessionIndex.load(), SharedLiveAgentIndex.shared, or agent-history parsing.
Cmux Cache Substitution Correctness ✅ Passed No fresh-authoritative read was replaced by an unchecked cache; restored terminal state is gated by current config/active surface checks and PTY readiness uses a commit lease.
Cmux No Hacky Sleeps ✅ Passed No changed TS/JS/shell/runtime files; the only added wait is Bun.sleep(10) in a Python test helper, which is test-only scaffolding.
Cmux Swift Concurrency ✅ Passed PASS: changes add sync authority validation and allowed main-queue callback hops; no new DispatchQueue.global, Combine, or unscoped fire-and-forget Tasks.
Cmux Swift @Concurrent ✅ Passed Changed Swift code has no nonisolated async work lacking @concurrent; new socket/network helpers use explicit DispatchQueue/Task hops and no invalid @concurrent annotations were added.
Cmux Swiftpm Lockfiles ✅ Passed Diff only changes app/runtime code and tests; no Package.swift, .gitignore, Xcode project, or Package.resolved files were modified.
Cmux Swift Logging ✅ Passed No new or modified production Swift logging appears in the diff; touched files are logic-only, and existing logs are pre-existing or allowed test/CLI output.
Cmux User-Facing Error Privacy ✅ Passed Changed user-facing messages are generic; the new RPC errors expose only public params/opaque refs, and no vendor names, secrets, or raw payloads appear.
Cmux Full Internationalization ✅ Passed PASS: The only user-facing Swift labels use L10n/String(localized:) and matching en/ja catalog entries; the rest are logic/comments/tests, not locale text.
Cmux Swiftui State Layout ✅ Passed No changed SwiftUI view/layout code: diff only touches model/controller classes; no GeometryReader, lazy row store refs, or render-time state writes were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The PR diff only touches backend/control-socket/terminal-liveness code; no new NSWindow/NSPanel/WindowGroup/NSWindowController or cmuxAuxiliaryWindowIdentifiers changes were introduced.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source/tests/config files; none are logs, caches, build output, DerivedData, or scratch artifacts.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production diff adds only functional lifecycle/RPC code; no new #if DEBUG or ForTesting/TestHook-style members or wrapper seams were added in Sources/.
Cmux No Ambient Global State ✅ Passed New behavior stays on extensions/instance types; I found no added top-level free funcs, mutable globals, or new singletons in the production diff.
Title check ✅ Passed The title is concise and accurately reflects the main fix: stale SSH workspace connection status.
Description check ✅ Passed Summary and test plan are present and aligned with the change, but the demo video, review trigger, and checklist sections are missing.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-9068-stale-ssh-status

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.

@austinywang
austinywang marked this pull request as ready for review July 28, 2026 23:04

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

🤖 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 `@CLI/cmux.swift`:
- Around line 13003-13028: Shorten the timeout for both
terminal_session_connected RPC call sites: in CLI/cmux.swift lines 13003-13028,
update sshConnectedLocalCommandScript to invoke the CLI with a short
CMUXTERM_CLI_RESPONSE_TIMEOUT_SEC override; in CLI/cmux.swift lines 12645-12653,
update runSSHPTYAttach to pass an explicit short responseTimeout to
client.sendV2. Preserve the existing discarded-result behavior.

In `@cmuxTests/WorkspaceRemoteConnectionTests.swift`:
- Around line 1783-1840: Assert that the workspace-side
workspace.markRemoteTerminalSessionEnded(surfaceId:relayPort:allowUntracked:)
call returns true, matching the existing assertions for the connected and
dock-side lifecycle transitions. Keep the subsequent ended-state assertions
unchanged.

In `@Sources/TerminalNotificationStore.swift`:
- Line 847: Update beginDesktopNotificationHookResolution so the pre-registered
policy request retains the notification’s correlation key instead of storing
nil. Ensure addNotification reuses or atomically updates that metadata when
preRegisteredPolicyRequestId is provided, allowing clearNotifications to cancel
the in-flight request through the correlation-keyed path.
🪄 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 Plus

Run ID: 89ea66e2-a0a4-48d6-9b6f-dd55af13f019

📥 Commits

Reviewing files that changed from the base of the PR and between 64ec2bb and a671d84.

📒 Files selected for processing (26)
  • CLI/cmux.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+Workspace.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceContext.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceRemoteTerminalSessionConnectedResolution.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorWorkspaceTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/FakeWorkspaceControlCommandContext.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/SessionNotificationSnapshot.swift
  • Sources/TerminalController+ControlWorkspaceContext.swift
  • Sources/TerminalController.swift
  • Sources/TerminalNotification.swift
  • Sources/TerminalNotificationLiveRetargetDelivery.swift
  • Sources/TerminalNotificationPolicy.swift
  • Sources/TerminalNotificationPolicyInFlightStore.swift
  • Sources/TerminalNotificationStore.swift
  • Sources/Workspace+DetachedSurfaceTransfer.swift
  • Sources/Workspace+RemoteTerminalLiveness.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AgentNotificationMutationBoundaryTests.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/SSHStartupManualReconnectTests.swift
  • cmuxTests/WorkspaceRemoteBadgeTruthTests.swift
  • cmuxTests/WorkspaceRemoteConnectionTests.swift

Comment thread CLI/cmux.swift Outdated
Comment thread cmuxTests/WorkspaceRemoteConnectionTests.swift
Comment thread Sources/TerminalNotificationStore.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.

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)
cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift (1)

4006-4053: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Three mock servers silently fall through to default for the new terminal_session_connected RPC.

testSSHPTYAttachBridgeEOFWhenSessionGoneClearsLocalState, testSSHPTYAttachBridgeResetWhenSessionGoneClearsLocalState, and testSSHPTYAttachSendsResizeWithoutBlockingEOFLocalCleanup all assert workspace.remote.terminal_session_connected appears in the recorded method sequence, but their mock server switch blocks have no case for it — it hits default and gets an unexpected_method error response. The tests only pass because the CLI apparently ignores this RPC's failure; unlike testSSHPTYAttachBridgeEOFWhileSessionRunsPreservesLifecycleForRetry (lines 3907-3914), none of these three validate the request params or return a genuine success response for this call.

Add a case mirroring the one already added in testSSHPTYAttachBridgeEOFWhileSessionRunsPreservesLifecycleForRetry to each of these three mock servers so the tests actually exercise (and don't accidentally rely on error-tolerance for) the new liveness RPC.

♻️ Suggested fix (apply similarly to all three mock servers)
             case "workspace.remote.pty_resize":
                 let params = payload["params"] as? [String: Any] ?? [:]
                 XCTAssertEqual(params["attachment_token"] as? String, "attach-token")
                 XCTAssertEqual(params["surface_id"] as? String, surfaceId)
                 return self.v2Response(id: id, ok: true, result: ["resized": true])
+            case "workspace.remote.terminal_session_connected":
+                let params = payload["params"] as? [String: Any] ?? [:]
+                XCTAssertEqual(params["workspace_id"] as? String, workspaceId)
+                XCTAssertEqual(params["surface_id"] as? String, surfaceId)
+                XCTAssertEqual(params["session_id"] as? String, sessionId)
+                return self.v2Response(id: id, ok: true, result: ["connected": true])
             case "workspace.remote.pty_sessions":

Also applies to: 4194-4241, 4478-4526, 3980-3980, 4079-4079, 4267-4267, 4614-4615

🤖 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 `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift` around lines 4006
- 4053, Add a workspace.remote.terminal_session_connected case to the
mock-server switch blocks used by
testSSHPTYAttachBridgeEOFWhenSessionGoneClearsLocalState,
testSSHPTYAttachBridgeResetWhenSessionGoneClearsLocalState, and
testSSHPTYAttachSendsResizeWithoutBlockingEOFLocalCleanup. Mirror the existing
successful handler in
testSSHPTYAttachBridgeEOFWhileSessionRunsPreservesLifecycleForRetry, including
parameter validation and a genuine success response, so the RPC does not fall
through to default.
Sources/Workspace+RemoteTerminalLiveness.swift (1)

33-37: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve and revalidate the lifecycle authority for pending connections.

When remoteConfiguration is nil, this accepts any TerminalPanel and stores only relayPort. For persistent PTY events, relayPort is nil, so applyPendingRemoteTerminalConnections() later replays the event without rechecking the session/lifecycle generation validated in TerminalController+ControlWorkspaceContext.swift. A stale event can therefore promote the wrong surface to .connected.

Carry the validated authority through the pending record and revalidate before applying; otherwise fail closed instead of using the panel type as proof of remote ownership. As per path instructions, correctness-critical liveness must use one authoritative structured signal and fail closed when it is unavailable.

Also applies to: 60-67

🤖 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/Workspace`+RemoteTerminalLiveness.swift around lines 33 - 37, Update
the pending remote-terminal connection flow around remoteConfiguration and
applyPendingRemoteTerminalConnections() to preserve the validated
session/lifecycle authority in PendingWorkspaceRemoteTerminalConnection,
including persistent PTY events where relayPort is nil. Revalidate that
structured authority before applying the pending state; if it is unavailable or
invalid, fail closed instead of treating a TerminalPanel as proof of remote
ownership.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/TerminalController`+ControlWorkspaceContext.swift:
- Around line 728-733: Update the remote-session connect and end flows around
dock.markRemoteTerminalSessionConnected and
workspace.markRemoteTerminalSessionConnected so the workspace is resolved and
its transition is validated before mutating Dock, or atomically roll back Dock
when the workspace update cannot apply. Do not discard the workspace transition
result; return failure instead of .resolved whenever either side cannot be
synchronized, keeping Workspace.remoteConnectionState, session phases, and
remoteStatus consistent.

---

Outside diff comments:
In `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift`:
- Around line 4006-4053: Add a workspace.remote.terminal_session_connected case
to the mock-server switch blocks used by
testSSHPTYAttachBridgeEOFWhenSessionGoneClearsLocalState,
testSSHPTYAttachBridgeResetWhenSessionGoneClearsLocalState, and
testSSHPTYAttachSendsResizeWithoutBlockingEOFLocalCleanup. Mirror the existing
successful handler in
testSSHPTYAttachBridgeEOFWhileSessionRunsPreservesLifecycleForRetry, including
parameter validation and a genuine success response, so the RPC does not fall
through to default.

In `@Sources/Workspace`+RemoteTerminalLiveness.swift:
- Around line 33-37: Update the pending remote-terminal connection flow around
remoteConfiguration and applyPendingRemoteTerminalConnections() to preserve the
validated session/lifecycle authority in
PendingWorkspaceRemoteTerminalConnection, including persistent PTY events where
relayPort is nil. Revalidate that structured authority before applying the
pending state; if it is unavailable or invalid, fail closed instead of treating
a TerminalPanel as proof of remote ownership.
🪄 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 Plus

Run ID: 97d119e7-ef90-4916-8a24-7b65f3c3538e

📥 Commits

Reviewing files that changed from the base of the PR and between a671d84 and 28e95a4.

📒 Files selected for processing (21)
  • CLI/cmux.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceContext.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceRemoteTerminalSessionConnectedResolution.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceRemoteTerminalSessionEndResolution.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorWorkspaceTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/FakeWorkspaceControlCommandContext.swift
  • Packages/macOS/CmuxRemoteSession/Tests/CmuxRemoteSessionTests/RemotePortScanGatingTests.swift
  • Packages/macOS/CmuxRemoteSession/Tests/CmuxRemoteSessionTests/RemoteSessionSSHRemoteCommandOverrideTests.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleOwnershipRegistry.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBrokering.swift
  • Packages/macOS/CmuxRemoteWorkspace/Tests/CmuxRemoteWorkspaceTests/RemoteProxyBrokerPTYLifecycleRestartTests.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/TerminalController+ControlWorkspaceContext.swift
  • Sources/Workspace+RemoteTerminalLiveness.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/SSHStartupManualReconnectTests.swift
  • cmuxTests/WorkspaceRemoteConnectionTests.swift

Comment thread Sources/TerminalController+ControlWorkspaceContext.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.

Actionable comments posted: 2

Caution

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

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

803-809: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make the Dock and workspace end transition atomic.

Line 805 ignores the workspace transition result after the Dock transfer is already marked ended. If the workspace rejects the authority, this still returns .resolved with a stale workspace remoteStatus. Validate both before mutating, or add a symmetric workspace-owned Dock-end helper that updates both states together and fails otherwise.

Based on prior review context, this is the same unresolved Dock/workspace lifecycle divergence concern.

🤖 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`+ControlWorkspaceContext.swift around lines 803 -
809, The remote-terminal end transition in the
dock.markRemoteTerminalSessionEnded callback is non-atomic because the workspace
result is ignored after Dock state changes. Update the surrounding lifecycle
flow to validate or perform both Dock and workspace transitions as one
operation, propagating failure and preventing a .resolved result when workspace
authority is rejected; preserve generation and lifecycleOnly checks.
Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift (1)

14-83: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Localize the new socket error messages.

These new control-socket responses are plain English literals. Add app-provided localized fields and catalog entries, then consume them through the context rather than calling String(localized:) from this package.

As per coding guidelines, user-facing text must use localized APIs and matching catalogs; based on learnings, CmuxControlSocket must receive localized strings through its app context.

🤖 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/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator`+WorkspaceRemoteLifecycle.swift
around lines 14 - 83, Localize the user-facing error messages in the workspace
remote lifecycle handler, including the invalid-parameter, unavailable-context,
and not-found responses. Add matching localized fields and catalog entries in
the app, expose them through the control-socket app context, and consume those
context-provided strings here instead of calling String(localized:) within
CmuxControlSocket.

Sources: Coding guidelines, Learnings

cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift (1)

4125-4125: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle the new connected-session RPC successfully in every affected mock.

The tests now expect workspace.remote.terminal_session_connected, but their corresponding mock servers still return ok: false for that method. Add a validating success branch so these tests exercise the intended lifecycle contract rather than an ignored error path.

  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift#L4125-L4125: Return a successful connected response for the EOF-when-session-gone test.
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift#L4313-L4313: Return a successful connected response for the bridge-reset test.
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift#L4660-L4660: Return a successful connected response for the resize/local-cleanup test.
🤖 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 `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift` at line 4125,
Update the mock server handlers for workspace.remote.terminal_session_connected
in cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift at lines 4125,
4313, and 4660 to validate the request and return a successful connected
response instead of ok: false; apply this consistently to the
EOF-when-session-gone, bridge-reset, and resize/local-cleanup tests.
🤖 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/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceContext.swift`:
- Around line 286-299: The controlWorkspaceRemoteTerminalSessionConnected flow
must retain the terminal session/lifecycle generation through the main-actor
commit instead of relying only on persistentTransport(transportKey). Pass the
validated session identity or broker lease from the worker into
ControlWorkspaceContext, revalidate it immediately before applying the workspace
transition, and reject stale generations so they cannot mark a replacement
connected. Add an interleaving regression test covering retirement between
worker lookup and main-actor mutation.

In `@Sources/DockSplitStore`+RemoteTerminalLiveness.swift:
- Around line 13-25: Update markRemoteTerminalSessionConnected to apply the same
authority freshness/matching guard as markRemoteTerminalSessionEnded before
mutating detachedSurfaceTransfersByPanelId. Reject stale or mismatched
authorities by returning false, while preserving the existing connected-state
update for valid authorities.

---

Outside diff comments:
In `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift`:
- Line 4125: Update the mock server handlers for
workspace.remote.terminal_session_connected in
cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift at lines 4125, 4313,
and 4660 to validate the request and return a successful connected response
instead of ok: false; apply this consistently to the EOF-when-session-gone,
bridge-reset, and resize/local-cleanup tests.

In
`@Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator`+WorkspaceRemoteLifecycle.swift:
- Around line 14-83: Localize the user-facing error messages in the workspace
remote lifecycle handler, including the invalid-parameter, unavailable-context,
and not-found responses. Add matching localized fields and catalog entries in
the app, expose them through the control-socket app context, and consume those
context-provided strings here instead of calling String(localized:) within
CmuxControlSocket.

In `@Sources/TerminalController`+ControlWorkspaceContext.swift:
- Around line 803-809: The remote-terminal end transition in the
dock.markRemoteTerminalSessionEnded callback is non-atomic because the workspace
result is ignored after Dock state changes. Update the surrounding lifecycle
flow to validate or perform both Dock and workspace transitions as one
operation, propagating failure and preventing a .resolved result when workspace
authority is rejected; preserve generation and lifecycleOnly checks.
🪄 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 Plus

Run ID: 7c36ffa9-d775-4ec1-b8dc-94c2bc229716

📥 Commits

Reviewing files that changed from the base of the PR and between 28e95a4 and 69835ec.

📒 Files selected for processing (33)
  • CLI/cmux.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/ControlCommandCoordinator+Params.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/ControlCommandCoordinator.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlRemotePTYLifecycleOwner.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceContext.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceRemoteTerminalAuthority.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Wire/ControlCommandExecutionPolicy.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandContextTestStubs.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorWorkspaceTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandExecutionPolicyTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/FakeWorkspaceControlCommandContext.swift
  • Packages/macOS/CmuxRemoteSession/Tests/CmuxRemoteSessionTests/RemotePortScanGatingTests.swift
  • Packages/macOS/CmuxRemoteSession/Tests/CmuxRemoteSessionTests/RemoteSessionSSHRemoteCommandOverrideTests.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleOwner.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleOwnershipRegistry.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBrokering.swift
  • Packages/macOS/CmuxRemoteWorkspace/Tests/CmuxRemoteWorkspaceTests/RemoteProxyBrokerPTYLifecycleRestartTests.swift
  • Sources/DockSplitStore+RemoteTerminalLiveness.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/TerminalController+ControlWorkspaceContext.swift
  • Sources/TerminalController.swift
  • Sources/TerminalNotificationStore.swift
  • Sources/Workspace+DetachedSurfaceTransfer.swift
  • Sources/Workspace+RemoteTerminalLiveness.swift
  • Sources/Workspace.swift
  • Sources/WorkspaceRemoteSessionHostAdapter.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/SSHStartupManualReconnectTests.swift
  • cmuxTests/WorkspaceRemoteBadgeTruthTests.swift
  • cmuxTests/WorkspaceRemoteConnectionTests.swift

Comment thread Sources/DockSplitStore+RemoteTerminalLiveness.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

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

⚠️ Outside diff range comments (1)
Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift (1)

41-85: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Apply the same main-actor freshness check to relay-port authority.

The coordinator treats relayPort as authorityIsCurrent = true before writing it to Workspace.markRemoteTerminalSessionConnected(...), which just rejects non-matching configurations later. If a stale terminal_session_connected event arrives after the workspace has been reconfigured to a different relay or no relay, relay-port staleness is not revalidated against the current remoteConfiguration/generation here, so it can flip the terminal to connected without the same TOCTOU protection used for persistent transport. Recheck the active authority after controlResolveOnMain, similar to the persistentTransport case.

🤖 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/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator`+WorkspaceRemoteLifecycle.swift
around lines 41 - 85, Update the relayPort branch in the authorityIsCurrent
switch within controlResolveOnMain to revalidate the relay authority against the
workspace’s current remoteConfiguration and generation, using the same
main-actor freshness protection as persistentTransport. Set authorityIsCurrent
false when the active relay no longer matches, so stale
terminal_session_connected events resolve to .notFound.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator`+WorkspaceRemoteLifecycle.swift:
- Around line 41-85: Update the relayPort branch in the authorityIsCurrent
switch within controlResolveOnMain to revalidate the relay authority against the
workspace’s current remoteConfiguration and generation, using the same
main-actor freshness protection as persistentTransport. Set authorityIsCurrent
false when the active relay no longer matches, so stale
terminal_session_connected events resolve to .notFound.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13dc5a77-0e65-4c8e-9b78-b7e48a118358

📥 Commits

Reviewing files that changed from the base of the PR and between 69835ec and f68c6e3.

📒 Files selected for processing (3)
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorWorkspaceTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/FakeWorkspaceControlCommandContext.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.

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)
Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift (1)

203-222: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make the claim and PTY retirement atomic.

Line 208 schedules acknowledgement after releasing the broker queue. A retry can register the same sessionID/lifecycleID first; Lines 211-214 then acknowledge the replacement lifecycle. Retire the tunnel/snapshot lifecycle within the same queue-critical operation as claimAfterWrapperEnd, or carry a distinct bridge-generation token into the acknowledgement.

Proposed fix
-        let claim = queue.sync {
-            ptyLifecycleOwnership.claimAfterWrapperEnd(lifecycleKey)
-        }
-        guard let claim else { return nil }
-        queue.async { [weak self] in
-            guard let self, let entry = self.entries[claim.transportKey] else { return }
+        return queue.sync {
+            guard let claim = ptyLifecycleOwnership.claimAfterWrapperEnd(lifecycleKey) else {
+                return nil
+            }
+            guard let entry = entries[claim.transportKey] else { return claim }
             if let tunnel = entry.tunnel {
                 _ = tunnel.acknowledgePTYLifecycleIfKnown(
                     sessionID: lifecycleKey.sessionID,
                     lifecycleID: lifecycleKey.lifecycleID
                 )
             } else if var snapshot = entry.ptyLifecycleSnapshot,
                       snapshot.acknowledgePTYLifecycleIfKnown(
                         sessionID: lifecycleKey.sessionID,
                         lifecycleID: lifecycleKey.lifecycleID
                       ) {
                 entry.ptyLifecycleSnapshot = snapshot
             }
+            return claim
         }
-        return claim

As per path instructions, correctness-critical lifecycle state must use one reliable source of truth with no timing-based staleness window.

🤖 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/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift`
around lines 203 - 222, Make the claim and PTY lifecycle acknowledgement atomic
in the method containing RemotePTYLifecycleKey and claimAfterWrapperEnd: perform
the tunnel or ptyLifecycleSnapshot retirement inside the same queue.sync
critical section as ptyLifecycleOwnership.claimAfterWrapperEnd, using the
claimed transport entry and lifecycle key. Remove the deferred queue.async
acknowledgement so a retry cannot register and be acknowledged as a replacement
lifecycle.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 10049-10052: Update the relay-side lifecycle RPC command in the
startup script around cmux_relay_terminal_connected to set
CMUXTERM_CLI_RESPONSE_TIMEOUT_SEC to the same short override used by the other
lifecycle-reporting paths, before invoking the relay CLI. Preserve the existing
CMUX_SOCKET environment, surface.report_tty call, output suppression, and
failure suppression.

In `@cmuxTests/GhosttyTerminalStartupEnvironmentTests.swift`:
- Around line 54-64: In the test setup around the original TerminalSurface,
install failure cleanup immediately after constructing original so a throwing
`#require` for startupEnvironmentValue does not leave it registered or active.
After the explicit unregister and teardown of original, mark that cleanup as
consumed before constructing replacement, preserving the existing teardown path.

In `@Sources/RemoteInteractiveShellBootstrapBuilder.swift`:
- Around line 248-250: Update the lifecycle initialization sequence in
RemoteInteractiveShellBootstrapBuilder so it unsets the inherited
CMUX_TERMINAL_LIFECYCLE_ID before evaluating the placeholder case, then exports
it only when a valid replacement is present. Preserve the empty and
unreplaced-placeholder branches as fail-closed behavior, and add a regression
test covering an inherited lifecycle ID with an unreplaced placeholder.

In `@Sources/TerminalController`+ControlWorkspaceContext.swift:
- Around line 8-15: The lease currently holds its unfair lock while executing
the entire workspace commit closure; change the contract and call site so the
lock only validates the current generation, then perform workspace mutation,
presentation, and notification effects after validation returns. In
Sources/TerminalController+ControlWorkspaceContext.swift#L8-L15, update
RemotePTYLifecycleCommitLease.commitIfCurrent to use the new check-then-commit
or validated-token flow without running the resolution closure under the lease
lock. In
Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleCommitLease.swift#L36-L45,
expose that enforced validation/commit API and preserve rejection of stale
generations.

---

Outside diff comments:
In
`@Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift`:
- Around line 203-222: Make the claim and PTY lifecycle acknowledgement atomic
in the method containing RemotePTYLifecycleKey and claimAfterWrapperEnd: perform
the tunnel or ptyLifecycleSnapshot retirement inside the same queue.sync
critical section as ptyLifecycleOwnership.claimAfterWrapperEnd, using the
claimed transport entry and lifecycle key. Remove the deferred queue.async
acknowledgement so a retry cannot register and be acknowledged as a replacement
lifecycle.
🪄 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 Plus

Run ID: 381d403d-c5ee-424d-9811-0d1bdc0072f6

📥 Commits

Reviewing files that changed from the base of the PR and between f68c6e3 and 0df2518.

📒 Files selected for processing (24)
  • CLI/cmux.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlCommandCoordinator+WorkspaceRemoteLifecycle.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlRemotePTYLifecycleCommitLease.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlRemotePTYLifecycleOwner.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Workspace/ControlWorkspaceRemoteTerminalAuthority.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/ControlCommandCoordinatorWorkspaceTests.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleCommitLease.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleOwner.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleOwnershipRegistry.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemotePTYLifecycleWrapperEndClaim.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBroker.swift
  • Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/Broker/RemoteProxyBrokering.swift
  • Packages/macOS/CmuxRemoteWorkspace/Tests/CmuxRemoteWorkspaceTests/RemoteProxyBrokerPTYLifecycleRestartTests.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Spawn/TerminalSurface+StartupEnvironment.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeSurfaceCreation.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift
  • Packages/macOS/CmuxTerminalCore/Sources/CmuxTerminalCore/SurfaceValues/TerminalSurfaceCmuxContextEnvironment.swift
  • Sources/DockSplitStore+RemoteTerminalLiveness.swift
  • Sources/RemoteInteractiveShellBootstrapBuilder.swift
  • Sources/TerminalController+ControlWorkspaceContext.swift
  • Sources/Workspace+RemoteTerminalLiveness.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/GhosttyTerminalStartupEnvironmentTests.swift
  • cmuxTests/TerminalControllerSocketSecurityTests.swift

Comment thread CLI/cmux.swift Outdated
Comment thread cmuxTests/GhosttyTerminalStartupEnvironmentTests.swift
Comment thread Sources/RemoteInteractiveShellBootstrapBuilder.swift
Comment thread Sources/TerminalController+ControlWorkspaceContext.swift
@cursor

cursor Bot commented Jul 29, 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.

@cursor

cursor Bot commented Jul 29, 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.

@cursor

cursor Bot commented Jul 30, 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.

cmux reload-cloud added 2 commits July 29, 2026 19:38
…-9068-stale-ssh-status

# Conflicts:
#	CLI/CMUXCLI+SSHStartupScripts.swift
#	CLI/cmux.swift
#	Sources/SSHPTYAttachStartupCommandBuilder.swift
#	Sources/SessionRemoteWorkspaceSnapshot+Restore.swift
#	cmux.xcodeproj/project.pbxproj
#	cmuxTests/SSHConfiguredRemoteCommandHostTests.swift
#	cmuxTests/SessionRemoteWorkspaceMoshRestoreTests.swift
…-9068-stale-ssh-status

# Conflicts:
#	Sources/DockSplitStore+Reset.swift
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Workspace status shows stale [ssh:connecting]/[ssh:reconnecting] even after the connection has actually recovered

1 participant