From 4e5d8118ba34b29b629cb9810c7a3ee6ecbca20b Mon Sep 17 00:00:00 2001 From: Chris Izatt Date: Thu, 18 Jun 2026 18:49:02 +0100 Subject: [PATCH 1/2] Fix copy transcript popover contrast --- .../src/assets/css/03-composer-welcome-activity.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/src/assets/css/03-composer-welcome-activity.css b/src/renderer/src/assets/css/03-composer-welcome-activity.css index 446c7d9e..d43da311 100644 --- a/src/renderer/src/assets/css/03-composer-welcome-activity.css +++ b/src/renderer/src/assets/css/03-composer-welcome-activity.css @@ -4245,10 +4245,10 @@ display: grid; gap: 10px; padding: 12px; - border: 1px solid color-mix(in srgb, var(--border) 70%, transparent); + border: 1px solid color-mix(in srgb, var(--panel-border, var(--border)) 88%, var(--text-primary) 12%); border-radius: 10px; - background: var(--panel-bg, var(--surface-base)); - box-shadow: 0 18px 46px rgba(0, 0, 0, 0.34); + background: var(--panel-bg-solid, var(--surface-1, var(--surface-base))); + box-shadow: 0 18px 46px rgba(0, 0, 0, 0.46); color: var(--text-primary); } From 0f1c257b779988d2a1b2e83f4c16ab033b970dc3 Mon Sep 17 00:00:00 2001 From: Chris Izatt Date: Thu, 18 Jun 2026 18:57:54 +0100 Subject: [PATCH 2/2] =?UTF-8?q?fix(ios):=20grok=20composer=20keeps=20focus?= =?UTF-8?q?=20=E2=80=94=20stop=20shell=20placement=20flipping=20on=20focus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real root cause of "grok composer shows neither above rows nor telemetry when focused" (build-24's zIndex(0) treated the wrong layer). 3 independent Opus reviewers converged: The core VStack's `.composerShellIf((detached && !inputOwnsSurface) || tuckedTab)` and the outer `.composerShellIf(!detached && !tuckedTab)` toggle a ViewModifier on/off based on `tuckedTab`, which folds in `hasAboveContent` → `composerFocused`. `composerShellIf` is a @ViewBuilder if/else, so flipping it changes the subtree's STRUCTURAL IDENTITY → SwiftUI tears down + rebuilds the Composer → its @FocusState resets to false → onFocusChange(false) → composerFocused can never latch true → BOTH focus-gated halves (above rows + telemetry) collapse. grok is the only `tuckedAboveTab` shell, so it's the only one whose shell placement depends on focus; cursor et al. have focus-stable predicates, hence immune. Fix: key the two shell placements + the core zIndex off the STATIC `resolved.layout.tuckedAboveTab` (new `tuckedShell`) instead of the focus-derived `tuckedTab`. grok now always wears its shell on the core (focused or not) — no identity churn, focus latches, both halves render. `tuckedTab` still drives the focus-gated tab geometry/spacing (those don't change identity). Byte-identical for the other 12 shells (their tuckedAboveTab is false). Verified: swift build + 73 tests + iPhone-17 simulator build. Diagnosed via 3 adversarial Opus 4.8 reviewers (independent convergence, high confidence). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Sources/TaskWraithUI/ThreadDetailViews.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ios/TaskWraithKit/Sources/TaskWraithUI/ThreadDetailViews.swift b/ios/TaskWraithKit/Sources/TaskWraithUI/ThreadDetailViews.swift index cd990bb5..d7737eb5 100644 --- a/ios/TaskWraithKit/Sources/TaskWraithUI/ThreadDetailViews.swift +++ b/ios/TaskWraithKit/Sources/TaskWraithUI/ThreadDetailViews.swift @@ -849,6 +849,16 @@ struct ThreadDetailView: View { && (hasAttachedRows || card.isEnsemble || !(card.queuedComposerPrompts ?? []).isEmpty) let tuckedTab = resolved.layout.tuckedAboveTab && hasAboveContent + // SHELL PLACEMENT must be focus-INDEPENDENT. The core/outer + // `.composerShellIf` below toggle a ViewModifier on/off; because + // `composerShellIf` is a @ViewBuilder if/else, flipping it changes + // the subtree's structural identity, which tears down + rebuilds the + // Composer and RESETS its @FocusState — so for grok (the only + // tuckedAboveTab shell) focus never latched and BOTH the above rows + // and the telemetry collapsed. Key placement off the STATIC recipe + // flag, not the focus-derived `tuckedTab`. (`tuckedTab` still drives + // the focus-gated tab geometry/spacing, which don't change identity.) + let tuckedShell = resolved.layout.tuckedAboveTab VStack(spacing: tuckedTab ? -10 : (detached ? 6 : 0)) { // Above-rows group: inner VStack spacing matches the outer so // non-tuck stays identical; the grok tuck makes it the inset, @@ -1009,10 +1019,10 @@ struct ThreadDetailView: View { planLanes: card.todoLanes ?? []) } } - .composerShellIf((detached && !inputOwnsSurface) || tuckedTab, resolved) - .zIndex(tuckedTab ? 1 : 0) + .composerShellIf((detached && !inputOwnsSurface) || tuckedShell, resolved) + .zIndex(tuckedShell ? 1 : 0) } - .composerShellIf(!detached && !tuckedTab, resolved) + .composerShellIf(!detached && !tuckedShell, resolved) .task(id: composerGitWorkspaceIds(card: card).joined(separator: "\n")) { for workspaceId in composerGitWorkspaceIds(card: card) { await model.refreshGitSnapshotCache(workspaceId: workspaceId)