Repository navigation
Persist Codex title session resumes #3500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import Foundation | ||
|
|
||
| enum CodexSessionTitleParser { | ||
| static let launchSource = "surface-title" | ||
|
|
||
| private static let sessionSlugRegex = try! NSRegularExpression( | ||
| pattern: #"(?i)(?:^|[^A-Z0-9_-])(codex-[0-9a-f]{8,}(?:-[A-Z0-9]+)+)(?=$|[^A-Z0-9_-])"# | ||
| ) | ||
|
Comment on lines
+6
to
+8
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The regex is a compile-time-constant literal so this will never trap in practice, but |
||
|
|
||
| static func sessionId(from title: String?) -> String? { | ||
| guard let title else { return nil } | ||
| let trimmed = title.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| guard !trimmed.isEmpty else { return nil } | ||
|
|
||
| let range = NSRange(trimmed.startIndex..<trimmed.endIndex, in: trimmed) | ||
| guard let match = sessionSlugRegex.firstMatch(in: trimmed, range: range), | ||
| match.numberOfRanges > 1, | ||
| let slugRange = Range(match.range(at: 1), in: trimmed) else { | ||
| return nil | ||
| } | ||
| return String(trimmed[slugRange]) | ||
| } | ||
|
|
||
| static func restorableSnapshot( | ||
| fromTitle title: String?, | ||
| workingDirectory: String? | ||
| ) -> SessionRestorableAgentSnapshot? { | ||
| guard let sessionId = sessionId(from: title) else { return nil } | ||
| let normalizedWorkingDirectory = normalized(workingDirectory) | ||
| return SessionRestorableAgentSnapshot( | ||
| kind: .codex, | ||
| sessionId: sessionId, | ||
| workingDirectory: normalizedWorkingDirectory, | ||
| launchCommand: AgentLaunchCommandSnapshot( | ||
| launcher: "codex", | ||
| executablePath: "codex", | ||
| arguments: [ | ||
| "codex", | ||
| "--dangerously-bypass-approvals-and-sandbox", | ||
| ], | ||
| workingDirectory: normalizedWorkingDirectory, | ||
| environment: nil, | ||
| capturedAt: nil, | ||
| source: launchSource | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| static func isSurfaceTitleSnapshot(_ snapshot: SessionRestorableAgentSnapshot) -> Bool { | ||
| snapshot.kind == .codex && snapshot.launchCommand?.source == launchSource | ||
| } | ||
|
|
||
| static func snapshot(_ snapshot: SessionRestorableAgentSnapshot, matchesTitle title: String?) -> Bool { | ||
| isSurfaceTitleSnapshot(snapshot) && sessionId(from: title) == snapshot.sessionId | ||
| } | ||
|
|
||
| private static func normalized(_ value: String?) -> String? { | ||
| guard let trimmed = value?.trimmingCharacters(in: .whitespacesAndNewlines), | ||
| !trimmed.isEmpty else { | ||
| return nil | ||
| } | ||
| return trimmed | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -236,6 +236,7 @@ extension Workspace { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredTerminalScrollbackByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let normalizedCurrentDirectory = snapshot.currentDirectory.trimmingCharacters(in: .whitespacesAndNewlines) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -370,10 +371,29 @@ extension Workspace { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let effectiveRestorableAgent = restoredAgentSnapshotsByPanelId[panelId] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let panelTitle = panelTitle(panelId: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let customTitle = panelCustomTitles[panelId] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let shellActivityState = panelShellActivityStates[panelId] ?? .unknown | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if restorableAgent == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let currentSnapshot = restoredAgentSnapshotsByPanelId[panelId] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if shellActivityState == .promptIdle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let currentSnapshot, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CodexSessionTitleParser.isSurfaceTitleSnapshot(currentSnapshot) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.remove(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if shellActivityState != .promptIdle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let titleRestorableAgent = CodexSessionTitleParser.restorableSnapshot( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fromTitle: panelTitles[panelId] ?? panel.displayTitle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workingDirectory: panelDirectories[panelId] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId[panelId] = titleRestorableAgent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Title snapshot overwrites richer hook-based restored snapshotsMedium Severity When Additional Locations (1)Reviewed by Cursor Bugbot for commit 2b46dc8. Configure here. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+378
to
+395
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new File Used: .github/review-bot-rules/swift-architectural-rethink.md (source)
Comment on lines
+378
to
+395
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear stale title-derived snapshots when the live title stops matching. If hook state never comes back after restore, Suggested fix if restorableAgent == nil {
let currentSnapshot = restoredAgentSnapshotsByPanelId[panelId]
if shellActivityState == .promptIdle,
let currentSnapshot,
CodexSessionTitleParser.isSurfaceTitleSnapshot(currentSnapshot) {
restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId)
restoredAgentAutoResumePendingPanelIds.remove(panelId)
restoredAgentAutoResumeRunningPanelIds.remove(panelId)
invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId)
} else if shellActivityState != .promptIdle,
let titleRestorableAgent = CodexSessionTitleParser.restorableSnapshot(
fromTitle: panelTitles[panelId] ?? panel.displayTitle,
workingDirectory: panelDirectories[panelId]
) {
restoredAgentSnapshotsByPanelId[panelId] = titleRestorableAgent
invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId)
+ } else if let currentSnapshot,
+ CodexSessionTitleParser.isSurfaceTitleSnapshot(currentSnapshot) {
+ restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId)
+ restoredAgentAutoResumePendingPanelIds.remove(panelId)
+ restoredAgentAutoResumeRunningPanelIds.remove(panelId)
+ invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId)
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let effectiveRestorableAgent = restoredAgentSnapshotsByPanelId[panelId] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let directory = panelDirectories[panelId] ?? effectiveRestorableAgent?.workingDirectory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let isPinned = pinnedPanelIds.contains(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let isManuallyUnread = manualUnreadPanelIds.contains(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -648,13 +668,16 @@ extension Workspace { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId[terminalPanel.id] = restorableAgent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if restoredAgentResumeInput != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.insert(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.remove(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeValue(forKey: terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.remove(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applySessionPanelMetadata(snapshot, toPanelId: terminalPanel.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -7267,6 +7290,7 @@ final class Workspace: Identifiable, ObservableObject { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var restoredTerminalScrollbackByPanelId: [UUID: String] = [:] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var restoredAgentSnapshotsByPanelId: [UUID: SessionRestorableAgentSnapshot] = [:] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var restoredAgentAutoResumePendingPanelIds: Set<UUID> = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var restoredAgentAutoResumeRunningPanelIds: Set<UUID> = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var invalidatedRestoredAgentFingerprintsByPanelId: [UUID: Int] = [:] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private var pendingTerminalInputObserversByPanelId: [UUID: [WorkspacePendingTerminalInputObserver]] = [:] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -8554,15 +8578,38 @@ final class Workspace: Identifiable, ObservableObject { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| guard previousState != state else { return } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| panelShellActivityStates[panelId] = state | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if state == .commandRunning, let restoredAgent = restoredAgentSnapshotsByPanelId[panelId] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if restoredAgentAutoResumePendingPanelIds.remove(panelId) == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if restoredAgentAutoResumePendingPanelIds.remove(panelId) != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.insert(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if CodexSessionTitleParser.snapshot( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matchesTitle: panelTitles[panelId] ?? panels[panelId]?.displayTitle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.insert(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let fingerprint = TabManager.restorableAgentSnapshotFingerprint(restoredAgent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId[panelId] = fingerprint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #if DEBUG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmuxDebugLog( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "session.restore.agent.invalidate panel=\(panelId.uuidString.prefix(5)) " + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "kind=\(restoredAgent.kind.rawValue) session=\(restoredAgent.sessionId.prefix(8))" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if state == .promptIdle { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let wasAutoResume = restoredAgentAutoResumeRunningPanelIds.remove(panelId) != nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let wasPendingAutoResume = restoredAgentAutoResumePendingPanelIds.remove(panelId) != nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if let restoredAgent = restoredAgentSnapshotsByPanelId[panelId], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wasAutoResume || wasPendingAutoResume || CodexSessionTitleParser.isSurfaceTitleSnapshot(restoredAgent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #if DEBUG | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cmuxDebugLog( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "session.restore.agent.clear panel=\(panelId.uuidString.prefix(5)) " + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "kind=\(restoredAgent.kind.rawValue) session=\(restoredAgent.sessionId.prefix(8))" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -8796,6 +8843,9 @@ final class Workspace: Identifiable, ObservableObject { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds = restoredAgentAutoResumePendingPanelIds.filter { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validSurfaceIds.contains($0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds = restoredAgentAutoResumeRunningPanelIds.filter { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validSurfaceIds.contains($0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId = invalidatedRestoredAgentFingerprintsByPanelId.filter { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validSurfaceIds.contains($0.key) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -10538,6 +10588,7 @@ final class Workspace: Identifiable, ObservableObject { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pendingRemoteTerminalChildExitSurfaceIds.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pruneSurfaceMetadata(validSurfaceIds: []) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredTerminalScrollbackByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pendingTerminalInputObserversByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| terminalInheritanceFontPointsByPanelId.removeAll(keepingCapacity: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastTerminalConfigInheritancePanelId = nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -13302,6 +13353,7 @@ extension Workspace: BonsplitDelegate { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredTerminalScrollbackByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentSnapshotsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumePendingPanelIds.remove(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| restoredAgentAutoResumeRunningPanelIds.remove(panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| invalidatedRestoredAgentFingerprintsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PortScanner.shared.unregisterPanel(workspaceId: id, panelId: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| terminalInheritanceFontPointsByPanelId.removeValue(forKey: panelId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nonisolatedon pure static helpersCodexSessionTitleParseris a pure string-parsing utility with no actor-bound state. In a module with@MainActor-by-default isolation, all static members —launchSource,sessionSlugRegex,sessionId(from:),restorableSnapshot(fromTitle:workingDirectory:),isSurfaceTitleSnapshot(_:),snapshot(_:matchesTitle:), andnormalized(_:)— will be implicitly@MainActor. That unnecessarily couples calls to them through the main actor, prevents use from background contexts, and violates the actor-isolation rule that pure helpers and file-scoped constants should be explicitlynonisolated. Marking each static membernonisolated(and the enum itselfnonisolatedto make the annotation structural rather than per-member) is the fix.File Used: .github/review-bot-rules/swift-actor-isolation.md (source)