diff --git a/Sources/Workspace+Persistence.swift b/Sources/Workspace+Persistence.swift index 461b2ff9..23651c08 100644 --- a/Sources/Workspace+Persistence.swift +++ b/Sources/Workspace+Persistence.swift @@ -471,6 +471,7 @@ extension Workspace { private func applySessionPanelMetadata(_ snapshot: SessionPanelSnapshot, toPanelId panelId: UUID) { if let title = snapshot.title?.trimmingCharacters(in: .whitespacesAndNewlines), !title.isEmpty { panelTitles[panelId] = title + panelsWithLiveTitle.insert(panelId) } setPanelCustomTitle(panelId: panelId, title: snapshot.customTitle) diff --git a/Sources/Workspace+SidebarTelemetry.swift b/Sources/Workspace+SidebarTelemetry.swift index a14640c4..b9c837f7 100644 --- a/Sources/Workspace+SidebarTelemetry.swift +++ b/Sources/Workspace+SidebarTelemetry.swift @@ -219,6 +219,7 @@ extension Workspace { panelTitles[panelId] = trimmed didMutate = true } + panelsWithLiveTitle.insert(panelId) // Update bonsplit tab title only when this panel's title changed. if didMutate, @@ -251,10 +252,13 @@ extension Workspace { /// Re-derive the workspace title from the focused panel's last known /// title. Called on pane-focus changes so the sidebar follows the active - /// pane without waiting for it to emit a new OSC title. + /// pane without waiting for it to emit a new OSC title. Only titles that + /// arrived through a real update qualify; creation-time displayTitle + /// seeds must not overwrite the workspace's default title. func refreshWorkspaceTitleFromFocusedPanel() { guard customTitle == nil, let panelId = focusedPanelId, + panelsWithLiveTitle.contains(panelId), let stored = panelTitles[panelId] else { return } if title != stored { title = stored } if processTitle != stored { processTitle = stored } @@ -263,6 +267,7 @@ extension Workspace { func pruneSurfaceMetadata(validSurfaceIds: Set) { panelDirectories = panelDirectories.filter { validSurfaceIds.contains($0.key) } panelTitles = panelTitles.filter { validSurfaceIds.contains($0.key) } + panelsWithLiveTitle = panelsWithLiveTitle.filter { validSurfaceIds.contains($0) } panelCustomTitles = panelCustomTitles.filter { validSurfaceIds.contains($0.key) } pinnedPanelIds = pinnedPanelIds.filter { validSurfaceIds.contains($0) } manualUnreadPanelIds = manualUnreadPanelIds.filter { validSurfaceIds.contains($0) } diff --git a/Sources/Workspace.swift b/Sources/Workspace.swift index 8be3a172..cbb79183 100644 --- a/Sources/Workspace.swift +++ b/Sources/Workspace.swift @@ -84,6 +84,10 @@ final class Workspace: Identifiable, ObservableObject { /// Published directory for each panel @Published var panelDirectories: [UUID: String] = [:] @Published var panelTitles: [UUID: String] = [:] + /// Panels whose `panelTitles` entry came from a real title update (OSC or + /// session restore), as opposed to the displayTitle placeholder seeded at + /// panel creation. Only these titles may be promoted to the workspace title. + var panelsWithLiveTitle: Set = [] @Published var panelCustomTitles: [UUID: String] = [:] @Published var pinnedPanelIds: Set = [] @Published var manualUnreadPanelIds: Set = []