From 612aa03f9c074621219c4b563d6eca75984edf98 Mon Sep 17 00:00:00 2001 From: kirich1409 Date: Sat, 18 Apr 2026 06:11:10 +0300 Subject: [PATCH 1/2] Frame terminal canvas with chrome padding Wrap TerminalViewRepresentable in a clipped rounded container with DS.Spacing.md padding so the terminal no longer bleeds to the window edges. DS.Color.surfaceWindow fills the surrounding chrome. Co-Authored-By: Claude Opus 4.7 (1M context) --- MacApp/Relay/AppRootView.swift | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/MacApp/Relay/AppRootView.swift b/MacApp/Relay/AppRootView.swift index 8467e9b..0a88694 100644 --- a/MacApp/Relay/AppRootView.swift +++ b/MacApp/Relay/AppRootView.swift @@ -189,26 +189,33 @@ private struct AgentTerminalView: View { var body: some View { VStack(spacing: 0) { - // Terminal view - if let sessionID = store.terminal.sessionID { - TerminalViewRepresentable( - sessionID: sessionID, - registry: registry, - configuration: store.terminal.configuration, - reduceMotion: reduceMotion - ) - .frame(maxWidth: .infinity, maxHeight: .infinity) - } else { - // Terminal canvas background — see note above on `Color.black`. - Color.black - .frame(maxWidth: .infinity, maxHeight: .infinity) + // Terminal canvas — framed inside rounded chrome so the window's + // surface colour shows through around the edges. `Color.black` + // fallback matches the connecting terminal background; it is + // excluded from the `no_color_black` SwiftLint rule in the Relay + // target (Wave 2 rationale, retained through Wave 6). + Group { + if let sessionID = store.terminal.sessionID { + TerminalViewRepresentable( + sessionID: sessionID, + registry: registry, + configuration: store.terminal.configuration, + reduceMotion: reduceMotion + ) + } else { + Color.black + } } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .clipShape(.rect(cornerRadius: DS.Radius.md, style: .continuous)) + .padding(DS.Spacing.md) Divider() // Status bar AgentStatusBarView(store: store) } + .background(DS.Color.surfaceWindow) } } From 4c96a3ea0e5edd10796c6bcb321c7c787a4ff1da Mon Sep 17 00:00:00 2001 From: kirich1409 Date: Sat, 18 Apr 2026 06:33:54 +0300 Subject: [PATCH 2/2] Tighten terminal chrome tokens per design review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design-review feedback on PR #247: - Padding DS.Spacing.md → xs: 16pt was too generous for a content canvas. - Radius DS.Radius.md → sm: parent NSWindow rounds ~10pt; child surface reads as distinctly smaller. - Surface DS.Color.surfaceWindow → surfaceContent: windowBackgroundColor is the default fill and was near no-op; controlBackgroundColor makes the frame read as a distinct chrome band. - Drop Divider() between canvas and status bar; surface-contrast now carries the separation. - Connecting-state fallback reads from EnvironmentValues.terminalTheme instead of literal Color.black, so users on light palettes no longer see a black flash during session startup. Co-Authored-By: Claude Opus 4.7 (1M context) --- MacApp/.swiftlint.yml | 8 ++++---- MacApp/Relay/AppRootView.swift | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/MacApp/.swiftlint.yml b/MacApp/.swiftlint.yml index 89ae0ae..0df5375 100644 --- a/MacApp/.swiftlint.yml +++ b/MacApp/.swiftlint.yml @@ -142,10 +142,10 @@ custom_rules: regex: '\bColor\.black\b' message: "Use DS.Color.* semantic tokens instead of Color.black." severity: error - # Wave 2 note: the `Relay` target remains excluded because AppRootView uses - # Color.black as the terminal canvas background fallback — the canvas is - # outside the design-system semantic palette and migrates in Wave 6 - # alongside the terminal-specific theming pipeline. + # Relay target stays excluded until two further `Color.black` fallbacks + # in AppRootView (lines for the Welcome-transition canvas and the + # NoSessionPlaceholder backdrop) are replaced with theme-aware tokens. + # Tracked as a follow-up cleanup to the Wave 6 rollout. excluded: - "Packages/RemoteTerminal" - "Packages/TerminalSwiftTerm" diff --git a/MacApp/Relay/AppRootView.swift b/MacApp/Relay/AppRootView.swift index 0a88694..5c501ef 100644 --- a/MacApp/Relay/AppRootView.swift +++ b/MacApp/Relay/AppRootView.swift @@ -2,6 +2,7 @@ import AgentOrchestrator import ComposableArchitecture import DesignSystem import PaneManager +import SharedModels import SwiftUI import TerminalFeature import UniformTypeIdentifiers @@ -186,14 +187,14 @@ private struct AgentTerminalView: View { let registry: TerminalSessionRegistry @Environment(\.accessibilityReduceMotion) private var reduceMotion + @Environment(\.terminalTheme) private var terminalTheme var body: some View { VStack(spacing: 0) { - // Terminal canvas — framed inside rounded chrome so the window's - // surface colour shows through around the edges. `Color.black` - // fallback matches the connecting terminal background; it is - // excluded from the `no_color_black` SwiftLint rule in the Relay - // target (Wave 2 rationale, retained through Wave 6). + // Terminal canvas — framed inside rounded chrome so the content + // surface shows through around the edges. Connecting-state + // fallback mirrors the user's chosen terminal palette so there + // is no black flash before the palette is applied. Group { if let sessionID = store.terminal.sessionID { TerminalViewRepresentable( @@ -203,19 +204,19 @@ private struct AgentTerminalView: View { reduceMotion: reduceMotion ) } else { - Color.black + Color(nsColor: terminalTheme.background.nsColor) } } .frame(maxWidth: .infinity, maxHeight: .infinity) - .clipShape(.rect(cornerRadius: DS.Radius.md, style: .continuous)) - .padding(DS.Spacing.md) + .clipShape(.rect(cornerRadius: DS.Radius.sm, style: .continuous)) + .padding(DS.Spacing.xs) - Divider() - - // Status bar + // Status bar — no divider: colour contrast between the content + // surface chrome and the canvas beneath the chrome carries the + // separation. AgentStatusBarView(store: store) } - .background(DS.Color.surfaceWindow) + .background(DS.Color.surfaceContent) } }