Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .github/swift-file-length-budget.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
# Format: max_lines<TAB>relative path
# Reduce counts as files shrink. CI fails if tracked files exceed this budget.
34660 CLI/cmux.swift
17978 Sources/AppDelegate.swift
17960 Sources/AppDelegate.swift
16484 Sources/ContentView.swift
14293 Sources/TerminalController.swift
14214 Sources/TerminalController.swift
13071 Sources/Workspace.swift
12348 cmuxTests/AppDelegateShortcutRoutingTests.swift
12212 Sources/GhosttyTerminalView.swift
11671 Sources/Panels/BrowserPanel.swift
9497 cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
8032 Sources/Panels/BrowserPanelView.swift
8016 CLI/cmux_open.swift
7663 Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
7647 Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
7404 cmuxTests/WorkspaceUnitTests.swift
7218 cmuxTests/WorkspaceRemoteConnectionTests.swift
6359 cmuxTests/SessionPersistenceTests.swift
Expand All @@ -24,7 +24,7 @@
4487 Sources/Panels/FilePreviewPanel.swift
4483 Sources/cmuxApp.swift
4367 cmuxTests/BrowserPanelTests.swift
4257 Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift
4239 Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift
4121 Sources/BrowserWindowPortal.swift
3934 Sources/Feed/FeedPanelView.swift
3926 cmuxTests/TabManagerUnitTests.swift
Expand Down Expand Up @@ -92,21 +92,21 @@
1006 cmuxTests/CmuxSSHURLRequestTests.swift
1002 Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/PairedMacBackupTests.swift
982 Packages/Shared/CmuxAgentChat/Tests/CmuxAgentChatTests/ChatConversationStoreTests.swift
953 cmuxTests/DockSocketLifecycleTests.swift
974 Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/AppSection.swift
951 Sources/App/TerminalDirectoryOpenSupport.swift
948 Sources/App/ShortcutRoutingSupport.swift
947 Sources/TerminalNotificationPolicy.swift
945 Sources/SessionIndexRegisteredAgents.swift
944 Sources/CommandPalette/CommandPaletteSettingsToggle.swift
942 Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift
937 Sources/TextBoxMentionIndexStore.swift
933 cmuxTests/DockSocketLifecycleTests.swift
929 Sources/Panels/TerminalPanel.swift
974 Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/AppSection.swift
918 Sources/Panels/BrowserPopupWindowController.swift
905 Sources/CmuxSSHURLRequest.swift
899 Sources/Panels/MarkdownWebRenderer.swift
885 cmuxTests/SidebarWorkspaceDropPlannerTests.swift
881 Sources/DockSplitStore.swift
879 Sources/DockSplitStore.swift
871 cmuxTests/ClaudeHookSurfaceResolutionSwiftTests.swift
868 Sources/Panels/BrowserScreenshotSnapshotter.swift
864 Packages/Shared/CmuxAgentChat/Sources/CmuxAgentChat/Store/ChatConversationStore.swift
Expand Down Expand Up @@ -172,12 +172,13 @@
627 Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/KeyboardShortcutsSection.swift
620 cmuxTests/FinderFileDropRegressionTests.swift
620 cmuxTests/TerminalNotificationQueueTests.swift
617 Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellRenderGridLivenessTests.swift
617 Sources/SettingsNavigation.swift
608 Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellRenderGridLivenessTests.swift
608 cmuxUITests/FeedSidebarUITests.swift
607 Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift
607 Sources/SessionIndexModels.swift
607 Sources/SleepyFaceView.swift
605 Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellRenderGridLivenessTestSupport.swift
604 Packages/macOS/CmuxCommandPalette/Tests/CmuxCommandPaletteTests/CommandPaletteNucleoFFITests.swift
602 Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Coordinators/WorkspaceReorderCoordinator.swift
601 Packages/macOS/CMUXAgentLaunch/Sources/CMUXAgentLaunch/AgentLaunchSanitizerPrimaryPolicies.swift
Expand All @@ -189,7 +190,6 @@
590 Sources/Panels/BrowserNavigationDelegate.swift
589 Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Coordinators/WorkspaceGroupCoordinator.swift
588 cmuxTests/CommandPaletteShortcutCustomizationTests.swift
587 Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellRenderGridLivenessTestSupport.swift
586 Packages/macOS/CmuxRemoteSession/Sources/CmuxRemoteSession/Session/RemoteSessionCoordinator+PortScan.swift
586 Sources/JSONCParser.swift
585 Sources/Cloud/VMClient.swift
Expand All @@ -215,7 +215,6 @@
539 CLI/CMUXCLI+Themes.swift
539 CLI/CodexTeamsApprovalBridge.swift
538 Packages/macOS/CmuxRemoteWorkspace/Sources/CmuxRemoteWorkspace/PTYBridge/RemotePTYBridgeSession.swift
537 Sources/TerminalController+ControlSurfaceContext2.swift
536 cmuxTests/CmuxConfigContextMenuTests.swift
535 Sources/App/WorkspaceRuntimeSettings.swift
532 Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
Expand All @@ -230,6 +229,7 @@
524 CLI/CMUXCLI+AutoNaming.swift
524 Sources/TerminalPaneDropTargetView.swift
522 Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Coordinator/Surface/ControlCommandCoordinator+Surface.swift
522 Sources/TerminalController+ControlSurfaceContext2.swift
520 CLI/CMUXCLI+AmpExtension.swift
520 cmuxTests/MainWindowVisibilityControllerTests.swift
519 Packages/macOS/CmuxSwiftRender/Tests/CmuxSwiftRenderTests/Corpus/stress-two-column-cockpit-sidebar.swift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,162 @@ extension MobileShellComposite {
return true
}

func recordTerminalRenderGridDelivery(_ renderGrid: MobileTerminalRenderGridFrame) {
terminalActiveScreenBySurfaceID[renderGrid.surfaceID] = renderGrid.activeScreen
if renderGrid.activeScreen == .alternate, renderGrid.full {
terminalAlternateRenderGridBaselineSurfaceIDs.insert(renderGrid.surfaceID)
} else if renderGrid.activeScreen == .primary {
terminalAlternateRenderGridBaselineSurfaceIDs.remove(renderGrid.surfaceID)
}
}

private func renderGridEventDeliveryDecision(
_ renderGrid: MobileTerminalRenderGridFrame,
previous: MobileTerminalRenderGridFrame.Screen?
) -> (requestReplay: Bool, updateTrackedScreen: Bool, deliverViewportPolicy: Bool)? {
guard terminalOutputTransport == .hybrid,
renderGrid.activeScreen == .primary else {
return nil
}
guard previous == .alternate else {
return (requestReplay: false, updateTrackedScreen: true, deliverViewportPolicy: true)
}
guard !renderGrid.full else { return nil }
return (requestReplay: true, updateTrackedScreen: false, deliverViewportPolicy: false)
}

func deliverAuthoritativeTerminalRenderGrid(
_ renderGrid: MobileTerminalRenderGridFrame,
expectedSurfaceID: String? = nil,
source: String
) {
guard expectedSurfaceID == nil || renderGrid.surfaceID == expectedSurfaceID,
hasTerminalOutputSink(surfaceID: renderGrid.surfaceID) else {
return
}
// The stale floor is the delivered high-water mark, surviving a replay
// barrier via the pre-barrier stash: a buffered frame from before the
// barrier must not paint (and must not establish an outdated baseline)
// while the fresh authoritative replay is pending. Against the STASH
// the rejection includes EQUAL sequences — the surface already shows
// that content and render grids re-emit at unchanged byte sequences,
// so a same-seq buffered full frame must not cancel the pending
// replay. Against the live delivered mark only strictly-older frames
// are stale, so steady-state same-seq re-emits (resize repaints)
// still deliver.
let deliveredSeqValue = deliveredTerminalByteEndSeqBySurfaceID[renderGrid.surfaceID] ?? 0
let preBarrierFloorSeq = terminalPreBarrierDeliveredEndSeqBySurfaceID[renderGrid.surfaceID]
if deliveredSeqValue > renderGrid.stateSeq
|| preBarrierFloorSeq.map({ $0 >= renderGrid.stateSeq }) ?? false {
MobileDebugLog.anchormux(
"sync.render_grid_stale source=\(source) surface=\(renderGrid.surfaceID) delivered=\(max(deliveredSeqValue, preBarrierFloorSeq ?? 0)) frame=\(renderGrid.stateSeq)"
)
return
}
let hasDeliveredSeq = deliveredTerminalByteEndSeqBySurfaceID[renderGrid.surfaceID] != nil
let previousScreen = terminalActiveScreenBySurfaceID[renderGrid.surfaceID]
// The alternate baseline flag is maintained by DELIVERED frames only,
// so gating on it (in both screen directions) cannot be fooled by the
// speculative tracked-screen write below: a delta VT patch cannot
// switch screens, so it may only paint the screen the local surface
// actually shows.
let hasAlternateBaseline = terminalAlternateRenderGridBaselineSurfaceIDs.contains(renderGrid.surfaceID)
let establishesRenderGridBaseline = renderGrid.full
|| (
renderGrid.activeScreen == .primary
&& !hasAlternateBaseline
&& renderGrid.isReplaceableViewportPatchForMobileDelivery
)
let needsRenderGridBaseline = (
terminalOutputTransport == .renderGrid
&& !establishesRenderGridBaseline
&& (
!hasDeliveredSeq
|| (renderGrid.activeScreen == .alternate) != hasAlternateBaseline
)
)
|| (
terminalOutputTransport == .hybrid
&& renderGrid.activeScreen == .alternate
&& !hasAlternateBaseline
)
if source == "event", needsRenderGridBaseline, !establishesRenderGridBaseline {
if renderGrid.activeScreen == .alternate {
terminalActiveScreenBySurfaceID[renderGrid.surfaceID] = .alternate
deliverTerminalViewportPolicy(renderGrid.mobileViewportPolicy, surfaceID: renderGrid.surfaceID)
}
MobileDebugLog.anchormux("sync.render_grid_waiting_for_baseline source=\(source) surface=\(renderGrid.surfaceID) seq=\(renderGrid.stateSeq)")
if terminalReplayBarrierTokensBySurfaceID[renderGrid.surfaceID] != nil {
_ = deliverTerminalRenderGrid(renderGrid, surfaceID: renderGrid.surfaceID)
} else {
requestTerminalReplayForMissingRenderGridBaseline(surfaceID: renderGrid.surfaceID)
}
return
}
if source == "event",
let deliveryDecision = renderGridEventDeliveryDecision(renderGrid, previous: previousScreen) {
if renderGrid.full,
terminalReplayBarrierTokensBySurfaceID[renderGrid.surfaceID] == nil {
markTerminalFullReplacementObserved(
surfaceID: renderGrid.surfaceID,
seq: renderGrid.stateSeq
)
}
if deliveryDecision.updateTrackedScreen {
terminalActiveScreenBySurfaceID[renderGrid.surfaceID] = renderGrid.activeScreen
if renderGrid.activeScreen == .primary {
terminalAlternateRenderGridBaselineSurfaceIDs.remove(renderGrid.surfaceID)
}
}
if deliveryDecision.deliverViewportPolicy {
deliverTerminalViewportPolicy(renderGrid.mobileViewportPolicy, surfaceID: renderGrid.surfaceID)
}
MobileDebugLog.anchormux(
"sync.render_grid_advisory source=\(source) surface=\(renderGrid.surfaceID) screen=\(renderGrid.activeScreen.rawValue) seq=\(renderGrid.stateSeq) requestReplay=\(deliveryDecision.requestReplay) updateTrackedScreen=\(deliveryDecision.updateTrackedScreen) deliverViewportPolicy=\(deliveryDecision.deliverViewportPolicy)"
)
if deliveryDecision.requestReplay {
requestTerminalReplay(surfaceID: renderGrid.surfaceID)
}
return
}
let activeReplayBarrierToken = terminalReplayBarrierTokensBySurfaceID[renderGrid.surfaceID]
let bypassLiveBaselineBarrier = source == "event"
&& establishesRenderGridBaseline
&& activeReplayBarrierToken != nil
&& (
terminalColdAttachReplayBarrierTokensBySurfaceID[renderGrid.surfaceID] == activeReplayBarrierToken
|| terminalRenderGridBaselineReplayBarrierTokensBySurfaceID[renderGrid.surfaceID] == activeReplayBarrierToken
)
Comment thread
austinywang marked this conversation as resolved.
if bypassLiveBaselineBarrier {
terminalOutputQueuesBySurfaceID[renderGrid.surfaceID] = TerminalOutputDeliveryQueue()
terminalOutputStreamTokensBySurfaceID[renderGrid.surfaceID] = UUID()
terminalReplayBarrierAckStreamTokensBySurfaceID.removeValue(forKey: renderGrid.surfaceID)
terminalReplayBarrierAckCoveredDroppedOutputCountsBySurfaceID.removeValue(forKey: renderGrid.surfaceID)
}
guard deliverTerminalRenderGrid(
renderGrid,
surfaceID: renderGrid.surfaceID,
bypassReplayBarrier: bypassLiveBaselineBarrier
) else { return }
if bypassLiveBaselineBarrier,
terminalReplayBarrierAckStreamTokensBySurfaceID[renderGrid.surfaceID] != nil {
cancelTerminalReplayInFlight(surfaceID: renderGrid.surfaceID)
terminalReplayBarrierAckCoveredDroppedOutputCountsBySurfaceID[renderGrid.surfaceID] =
terminalReplayBarrierDroppedOutputCountsBySurfaceID[renderGrid.surfaceID] ?? 0
}
recordTerminalRenderGridDelivery(renderGrid)
markTerminalBytesDelivered(
surfaceID: renderGrid.surfaceID,
endSeq: renderGrid.stateSeq,
fullReplacement: renderGrid.full
)
}

/// Whether a surface currently has an attached output stream consumer.
func hasTerminalOutputSink(surfaceID: String) -> Bool {
terminalByteContinuationsBySurfaceID[surfaceID] != nil
}

/// Yield a raw PTY byte chunk to the surface stream, if one is attached.
@discardableResult
func deliverTerminalBytes(
Expand Down Expand Up @@ -127,6 +283,13 @@ extension MobileShellComposite {
let next = queue.completeInFlight()
terminalOutputQueuesBySurfaceID[surfaceID] = queue
if terminalReplayBarrierAckStreamTokensBySurfaceID[surfaceID] == streamToken {
let replayBarrierToken = terminalReplayBarrierTokensBySurfaceID[surfaceID]
let coldAttachReplayBarrier = replayBarrierToken.map {
terminalColdAttachReplayBarrierTokensBySurfaceID[surfaceID] == $0
} ?? false
let missingBaselineReplayBarrier = replayBarrierToken.map {
terminalRenderGridBaselineReplayBarrierTokensBySurfaceID[surfaceID] == $0
} ?? false
let coveredDroppedOutputCount =
terminalReplayBarrierAckCoveredDroppedOutputCountsBySurfaceID.removeValue(forKey: surfaceID)
let currentDroppedOutputCount = terminalReplayBarrierDroppedOutputCountsBySurfaceID[surfaceID] ?? 0
Expand All @@ -135,20 +298,37 @@ extension MobileShellComposite {
} ?? true
terminalReplayBarrierAckStreamTokensBySurfaceID.removeValue(forKey: surfaceID)
terminalReplayBarrierTokensBySurfaceID.removeValue(forKey: surfaceID)
terminalColdAttachReplayBarrierTokensBySurfaceID.removeValue(forKey: surfaceID)
terminalRenderGridBaselineReplayBarrierTokensBySurfaceID.removeValue(forKey: surfaceID)
MobileDebugLog.anchormux("terminal.output.replay_barrier_cleared surface=\(surfaceID)")
let droppedOutputDuringBarrier = terminalReplayBarrierDroppedOutputSurfaceIDs.remove(surfaceID) != nil
terminalReplayBarrierDroppedOutputCountsBySurfaceID.removeValue(forKey: surfaceID)
if droppedOutputDuringBarrier,
needsFollowUpReplay,
claimTerminalReplayBarrierFollowUp(surfaceID: surfaceID) {
let baselineReplayRequestCount = missingBaselineReplayBarrier
? terminalRenderGridBaselineReplayRequestCountsBySurfaceID[surfaceID]
: nil
let replayBarrierToken = beginTerminalReplayBarrier(
surfaceID: surfaceID,
preservingFollowUpCount: true
)
if coldAttachReplayBarrier {
terminalColdAttachReplayBarrierTokensBySurfaceID[surfaceID] = replayBarrierToken
}
if missingBaselineReplayBarrier {
if let baselineReplayRequestCount {
terminalRenderGridBaselineReplayRequestCountsBySurfaceID[surfaceID] = baselineReplayRequestCount
}
terminalRenderGridBaselineReplayBarrierTokensBySurfaceID[surfaceID] = replayBarrierToken
}
MobileDebugLog.anchormux("terminal.output.replay_followup surface=\(surfaceID)")
requestTerminalReplay(surfaceID: surfaceID, replayBarrierToken: replayBarrierToken)
return
}
// Fully resolved: a seq-less raw tail leaves no delivered sequence,
// so the floor restore is the truthful baseline hand-back.
restoreTerminalPreBarrierBaselineIfNeeded(surfaceID: surfaceID)
terminalReplayBarrierFollowUpCountsBySurfaceID.removeValue(forKey: surfaceID)
}
guard let next,
Expand Down Expand Up @@ -184,6 +364,9 @@ extension MobileShellComposite {
return
}
let replayBarrierToken = beginTerminalReplayBarrier(surfaceID: surfaceID)
// Rebuilt surface: nothing pre-barrier is visible anymore.
rebaseTerminalReplayStaleFloor(surfaceID: surfaceID)
terminalAlternateRenderGridBaselineSurfaceIDs.remove(surfaceID)
MobileDebugLog.anchormux("terminal.output.reset surface=\(surfaceID)")
requestTerminalReplay(surfaceID: surfaceID, replayBarrierToken: replayBarrierToken)
}
Expand All @@ -197,7 +380,10 @@ extension MobileShellComposite {
}
terminalOutputQueuesBySurfaceID[surfaceID] = TerminalOutputDeliveryQueue()
terminalOutputStreamTokensBySurfaceID[surfaceID] = UUID()
// Post-reset retry: rebuilt surface, so drop the floor, don't stash.
rebaseTerminalReplayStaleFloor(surfaceID: surfaceID)
deliveredTerminalByteEndSeqBySurfaceID.removeValue(forKey: surfaceID)
terminalAlternateRenderGridBaselineSurfaceIDs.remove(surfaceID)
terminalFullReplacementSeqBySurfaceID.removeValue(forKey: surfaceID)
terminalFullReplacementGenerationBySurfaceID.removeValue(forKey: surfaceID)
pendingTerminalByteEndSeqBySurfaceID.removeValue(forKey: surfaceID)
Expand Down Expand Up @@ -225,9 +411,13 @@ extension MobileShellComposite {
}

/// Ask the Mac to replay the authoritative terminal state for a surface.
/// Reached from the render-pipeline reset: the surface was rebuilt blank,
/// so (like ``terminalOutputDidReset``) no pre-barrier baseline survives.
public func terminalOutputNeedsReplay(surfaceID: String) {
guard terminalByteContinuationsBySurfaceID[surfaceID] != nil else { return }
let replayBarrierToken = beginTerminalReplayBarrier(surfaceID: surfaceID)
rebaseTerminalReplayStaleFloor(surfaceID: surfaceID)
terminalAlternateRenderGridBaselineSurfaceIDs.remove(surfaceID)
MobileDebugLog.anchormux("terminal.output.replay_requested surface=\(surfaceID)")
requestTerminalReplay(surfaceID: surfaceID, replayBarrierToken: replayBarrierToken)
}
Expand Down
Loading
Loading