From 34c002e92d9d3a4c381bd6e8bb8354d10f2391d3 Mon Sep 17 00:00:00 2001 From: Mingjing <1239443+hackergene@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:59:56 +0800 Subject: [PATCH] fix(macos): adapt Codex 26.803 theme surfaces --- CHANGELOG.md | 9 +++++++++ VERSION | 2 +- engine/assets/ai-themestore.css | 9 ++++++++- engine/scripts/codex-shell-probe.mjs | 9 +++++++++ engine/scripts/injector.mjs | 19 ++++++++++++++++++- tests/codex-shell-probe.test.mjs | 16 ++++++++++++++++ tests/run-tests.sh | 15 +++++++++++++++ 7 files changed, 76 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4be5920..42f7d78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.1.1 — 2026-08-16 + +- Restored themed composer glass on Codex 26.803 by clearing its new opaque + semantic layout layer while preserving native controls. +- Removed the new Home top spacer that could appear as a dark horizontal band + above the themed hero. +- Added live verification gates for native composer backgrounds and modern Home + top alignment on both New Chat and active task routes. + ## 0.1.0 — 2026-08-11 - Added a native, offline macOS App for applying and restoring Codex diff --git a/VERSION b/VERSION index 6e8bf73..17e51c3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0 +0.1.1 diff --git a/engine/assets/ai-themestore.css b/engine/assets/ai-themestore.css index 016e0d2..0658c73 100644 --- a/engine/assets/ai-themestore.css +++ b/engine/assets/ai-themestore.css @@ -457,6 +457,13 @@ html.ai-themestore .ai-themestore-composer-surface { overflow: visible !important; } +/* Codex 26.803 can paint an opaque layout body inside the semantic composer + surface. Keep the native controls live while letting the themed glass show. */ +html.ai-themestore .ai-themestore-composer-surface > [data-composer-layout] { + background-color: transparent !important; + background-image: none !important; +} + html.ai-themestore main.main-surface:not(.ai-themestore-home-shell) .sticky.bottom-0 > .pointer-events-none.absolute.inset-x-0.bottom-0 @@ -1219,7 +1226,7 @@ html.ai-themestore .ai-themestore-home-v2 > .ai-themestore-home-banner-slot > :f } html.ai-themestore .ai-themestore-home-v2 > .ai-themestore-home-layout { - padding-top: 15px !important; + padding-top: 0 !important; min-height: 100% !important; } diff --git a/engine/scripts/codex-shell-probe.mjs b/engine/scripts/codex-shell-probe.mjs index 22175b8..6a9b8c4 100644 --- a/engine/scripts/codex-shell-probe.mjs +++ b/engine/scripts/codex-shell-probe.mjs @@ -62,6 +62,15 @@ export function resolveComposerSurfaceDocument(documentRef, scopeRef = documentR export const COMPOSER_SURFACE_RESOLVER_EXPRESSION = `(${resolveComposerSurfaceDocument.toString()})(document)`; +export function composerNativeLayerCoveragePass(layers) { + return layers.every((layer) => + layer.backgroundAlpha <= 0.035 && + (layer.backgroundImage === "none" || layer.backgroundImage === null)); +} + +export const COMPOSER_NATIVE_LAYER_COVERAGE_EXPRESSION = + `(${composerNativeLayerCoveragePass.toString()})`; + export function resolveChatPaneDocument(documentRef) { const marked = documentRef.querySelector("aside.ai-themestore-chat-pane"); if (marked) return marked; diff --git a/engine/scripts/injector.mjs b/engine/scripts/injector.mjs index dd7f2e4..29e5d37 100644 --- a/engine/scripts/injector.mjs +++ b/engine/scripts/injector.mjs @@ -5,6 +5,7 @@ import { CHAT_PANE_DIVIDER_PARITY_EXPRESSION, CHAT_PANE_RESOLVER_EXPRESSION, CODEX_SHELL_PROBE_EXPRESSION, + COMPOSER_NATIVE_LAYER_COVERAGE_EXPRESSION, COMPOSER_SURFACE_RESOLVER_EXPRESSION, OPTIONAL_SIDEBAR_VISIBILITY_EXPRESSION, SHELL_MAIN_RESOLVER_EXPRESSION, @@ -555,11 +556,25 @@ async function verifySession(session, expected = null) { const placeholder = editor?.querySelector('.placeholder') ?? null; const composerSurfaceMetric = (node) => { const style = node ? getComputedStyle(node) : null; + const nativeLayers = node + ? [...node.children] + .filter((child) => child.matches('[data-composer-layout]')) + .map((child) => { + const childStyle = getComputedStyle(child); + return { + backgroundColor: childStyle.backgroundColor, + backgroundAlpha: backgroundAlpha(childStyle.backgroundColor), + backgroundImage: childStyle.backgroundImage, + }; + }) + : []; return { backgroundColor: style?.backgroundColor ?? null, backgroundAlpha: style ? backgroundAlpha(style.backgroundColor) : null, backdropFilter: style?.backdropFilter ?? null, borderRadius: style?.borderRadius ?? null, + nativeLayers, + nativeLayersClear: ${COMPOSER_NATIVE_LAYER_COVERAGE_EXPRESSION}(nativeLayers), pass: false, }; }; @@ -814,7 +829,8 @@ async function verifySession(session, expected = null) { metric.backgroundAlpha != null && Math.abs(metric.backgroundAlpha - expectedComposerAlpha) <= 0.035 && metric.backdropFilter?.includes('blur(18px)') && - metric.borderRadius === '21px' + metric.borderRadius === '21px' && + metric.nativeLayersClear ); result.composerSurface.pass = composerSurfacePass(result.composerSurface); result.chatPaneCoverage.composerSurface.pass = !result.chatPaneCoverage.expected || @@ -957,6 +973,7 @@ async function verifySession(session, expected = null) { const modernHomeLayoutPass = !result.modernHome || Boolean( result.homeBox?.visible && result.hero?.visible && result.composer?.visible && result.hero.y >= result.homeBox.y - 2 && + result.hero.y - result.homeBox.y <= 2 && result.hero.y + result.hero.height <= result.homeBox.y + result.homeBox.height + 2 && result.composer.y >= result.homeBox.y - 2 && result.composer.y + result.composer.height <= result.homeBox.y + result.homeBox.height + 2 && diff --git a/tests/codex-shell-probe.test.mjs b/tests/codex-shell-probe.test.mjs index 3b1323a..15370cb 100644 --- a/tests/codex-shell-probe.test.mjs +++ b/tests/codex-shell-probe.test.mjs @@ -1,6 +1,7 @@ import assert from "node:assert/strict"; import { chatPaneDividerParityPass, + composerNativeLayerCoveragePass, optionalSidebarVisibilityPass, probeCodexShellDocument, resolveChatPaneDocument, @@ -206,6 +207,21 @@ const semanticComposerScope = { assert.equal(resolveComposerSurfaceDocument(semanticComposerScope), semanticComposerSurface, "Codex 26.730 semantic composer surface must resolve through stable data attributes"); +assert.equal(composerNativeLayerCoveragePass([]), true, + "legacy composers without a semantic native body must remain supported"); +assert.equal(composerNativeLayerCoveragePass([{ + backgroundAlpha: 0, + backgroundImage: "none", +}]), true, "a transparent Codex semantic composer body must preserve theme glass"); +assert.equal(composerNativeLayerCoveragePass([{ + backgroundAlpha: 0.864706, + backgroundImage: "none", +}]), false, "an opaque Codex semantic composer body must fail verification"); +assert.equal(composerNativeLayerCoveragePass([{ + backgroundAlpha: 0, + backgroundImage: "linear-gradient(rgb(0, 0, 0), rgb(0, 0, 0))", +}]), false, "a native composer background image must fail verification"); + assert.equal(chatPaneDividerParityPass({ chatPanePresent: false }), true, "absent Ask pane must not require divider verification"); assert.equal(chatPaneDividerParityPass({ diff --git a/tests/run-tests.sh b/tests/run-tests.sh index 40b60ea..6acc9eb 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -15,6 +15,21 @@ for script in "$ROOT"/engine/scripts/*.mjs "$ROOT"/engine/assets/*.js; do "$NODE" --check "$script" >/dev/null done +/usr/bin/grep -F -q '.ai-themestore-composer-surface > [data-composer-layout]' \ + "$ROOT/engine/assets/ai-themestore.css" || { + printf 'Theme CSS must clear the opaque Codex semantic composer body.\n' >&2 + exit 1 +} +/usr/bin/grep -F -q 'metric.nativeLayersClear' "$ROOT/engine/scripts/injector.mjs" || { + printf 'Live verification must reject opaque native layers inside the composer.\n' >&2 + exit 1 +} +/usr/bin/grep -F -q 'result.hero.y - result.homeBox.y <= 2' \ + "$ROOT/engine/scripts/injector.mjs" || { + printf 'Live verification must reject the modern Home top spacer regression.\n' >&2 + exit 1 +} + "$NODE" -e ' const fs = require("node:fs"); const path = require("node:path");