From 60e2bfe00636d0084b90bd206a3eec305fa69a3e Mon Sep 17 00:00:00 2001 From: CHOCK1337 <122972648+CHOCK1337@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:45:57 +0800 Subject: [PATCH 1/2] fix(windows): restore skin on Codex 26.730 --- README.en.md | 4 +- README.md | 4 +- docs/release-notes/riru-v1.2.1.md | 25 ++ linux/VERSION | 2 +- linux/scripts/common-linux.sh | 2 +- linux/scripts/injector.mjs | 2 +- macos/CHANGELOG.md | 4 + macos/VERSION | 2 +- macos/assets/dream-skin.css | 124 +++++----- macos/assets/renderer-inject.js | 2 +- macos/assets/selectors.json | 10 +- macos/package.json | 2 +- macos/scripts/common-macos.sh | 2 +- macos/scripts/injector.mjs | 2 +- macos/tests/injector-bootstrap.test.mjs | 4 +- tools/renderer-runtime.test.mjs | 8 +- tools/selectors.json | 10 +- windows/CHANGELOG.md | 7 + windows/VERSION | 2 +- windows/assets/dream-skin.css | 214 +++++++++--------- windows/assets/renderer-inject.js | 19 +- windows/assets/selectors.json | 10 +- windows/scripts/injector.mjs | 2 +- windows/tests/home-responsive-css.test.mjs | 10 +- windows/tests/injector-bootstrap.test.mjs | 8 +- .../tests/injector-window-readiness.test.mjs | 4 +- windows/tests/renderer-inject.test.mjs | 8 +- windows/tests/run-tests.ps1 | 4 +- 28 files changed, 273 insertions(+), 224 deletions(-) create mode 100644 docs/release-notes/riru-v1.2.1.md diff --git a/README.en.md b/README.en.md index e08d46c..a9aad2a 100644 --- a/README.en.md +++ b/README.en.md @@ -37,14 +37,14 @@ Screenshots captured from a real Codex session are never published, preventing a Download the following from the [latest release](https://github.com/CHOCK1337/Codex-RIRU-Moonroom-Skin/releases/latest): -- `CodexDreamSkin-Setup-v1.6.0.exe` for the complete Windows UI, update guardian, performance profile, and companion. +- `CodexDreamSkin-Setup-v1.6.1.exe` for compatibility with the current Codex shell plus the complete Windows UI, update guardian, performance profile, and companion. - `RIRU-Moonroom-v1.2.0.zip` for the portable wallpaper, theme tokens, and Safe CSS. - `RIRU-Moonpup-v2.zip` for a manual companion-only install. - `SHA256SUMS.txt` for integrity verification. This personal fan build has no commercial code-signing certificate, so Setup is unsigned. Download it only from this repository's release and verify `SHA256SUMS.txt` first. -The theme ZIP contains only the portable theme. Use Setup v1.6.0 or install the repository source for the complete Windows presentation, companion, and update guardian. +The theme ZIP contains only the portable theme. Use Setup v1.6.1 or install the repository source for the complete Windows presentation, companion, and update guardian. ## Full Windows install diff --git a/README.md b/README.md index a2dd38f..deac738 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,14 @@ 从 [Latest Release](https://github.com/CHOCK1337/Codex-RIRU-Moonroom-Skin/releases/latest) 下载: -- `CodexDreamSkin-Setup-v1.6.0.exe`:完整 Windows 安装包,包含 UI、更新守护、性能优化和 RIRU 宠物。 +- `CodexDreamSkin-Setup-v1.6.1.exe`:完整 Windows 安装包,包含新版 Codex 外壳兼容、UI、更新守护、性能优化和 RIRU 宠物。 - `RIRU-Moonroom-v1.2.0.zip`:可导入的便携主题包,包含同人壁纸、颜色和 Safe CSS。 - `RIRU-Moonpup-v2.zip`:只含生成宠物图集、manifest 和权利说明的手动安装包。 - `SHA256SUMS.txt`:下载校验文件。 这是个人同人构建,没有商业代码签名证书,因此 Setup 会显示为未签名;请只从本仓库 Release 下载并先核对 `SHA256SUMS.txt`。 -主题 ZIP 适合已经安装 Codex Dream Skin `1.5.9` 或更高版本的用户。要获得完整 Windows UI、宠物与更新守护,请使用 `1.6.0` 安装包或本仓库源码;单独导入主题 ZIP 只会带入壁纸、主题颜色和 Safe CSS。 +主题 ZIP 适合已经安装 Codex Dream Skin `1.5.9` 或更高版本的用户。要获得完整 Windows UI、宠物与更新守护,请使用 `1.6.1` 安装包或本仓库源码;单独导入主题 ZIP 只会带入壁纸、主题颜色和 Safe CSS。 ## Windows 完整安装 diff --git a/docs/release-notes/riru-v1.2.1.md b/docs/release-notes/riru-v1.2.1.md new file mode 100644 index 0000000..0172d44 --- /dev/null +++ b/docs/release-notes/riru-v1.2.1.md @@ -0,0 +1,25 @@ +# RIRU · MOONROOM v1.2.1 + +这是一次 Windows 兼容性热修复。RIRU 壁纸和 Moonpup 宠物素材没有变化。 + +## 修复 + +- 适配 Codex `26.730.8199.0` 的新版应用外壳。 +- 主表面同时识别旧版 `main-surface` 类名与新版 `data-app-shell-main-surface` 稳定属性。 +- 标题栏同时识别旧版 `app-header-tint` 类名与新版 `data-app-shell-header-edge-scroll` 稳定属性。 +- 启动验证、背景 CSS、任务氛围层和运行时分类使用同一份兼容选择器,避免注入后被误判失败并回滚到官方外观。 + +## 安装包 + +- `CodexDreamSkin-Setup-v1.6.1.exe`:完整 Windows 体验与本次兼容修复。 +- `RIRU-Moonroom-v1.2.0.zip`:未变化的便携主题。 +- `RIRU-Moonpup-v2.zip`:未变化的宠物包。 +- `SHA256SUMS.txt`:发布文件的 SHA-256。 + +Setup 是未签名的个人同人构建;请只使用本仓库 Release,并在运行前核对 SHA-256。 + +## 验证边界 + +- 回归测试覆盖旧版类名和 Codex 26.730+ 的稳定属性选择器。 +- Windows 全量测试、双端 payload 同步检查与 renderer 性能基准会在发布前执行。 +- 公开仓库不包含真实 Codex 会话截图、账号名称、会话标题、本机路径或对话内容。 diff --git a/linux/VERSION b/linux/VERSION index dc1e644..9c6d629 100644 --- a/linux/VERSION +++ b/linux/VERSION @@ -1 +1 @@ -1.6.0 +1.6.1 diff --git a/linux/scripts/common-linux.sh b/linux/scripts/common-linux.sh index 22c98ae..0e173ae 100755 --- a/linux/scripts/common-linux.sh +++ b/linux/scripts/common-linux.sh @@ -5,7 +5,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" INJECTOR="$SCRIPT_DIR/injector.mjs" -SKIN_VERSION="1.6.0" +SKIN_VERSION="1.6.1" INSTALL_ROOT="$HOME/.codex/codex-dream-skin-linux" STATE_ROOT="${XDG_STATE_HOME:-$HOME/.local/state}/CodexDreamSkin" THEME_DIR="$STATE_ROOT/theme" diff --git a/linux/scripts/injector.mjs b/linux/scripts/injector.mjs index 393a3a7..a1dd242 100644 --- a/linux/scripts/injector.mjs +++ b/linux/scripts/injector.mjs @@ -39,7 +39,7 @@ const stableTestidLiteral = (testid) => { } return JSON.stringify(`[data-testid="${testid}"]`); }; -const SKIN_VERSION = "1.6.0"; +const SKIN_VERSION = "1.6.1"; const INTERNET_ANGEL_EXTENSION_THEME_IDS = new Set([ "preset-internet-angel", "preset-internet-angel-default", diff --git a/macos/CHANGELOG.md b/macos/CHANGELOG.md index bbc14f2..811eb9f 100644 --- a/macos/CHANGELOG.md +++ b/macos/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.6.1 — 2026-08-06 + +- 同步 Codex `26.730.8199.0` 的稳定 `data-app-shell-*` 选择器与背景 CSS 兼容层;旧版类名继续受支持。 + ## 1.6.0 — 2026-08-05 ### 更新 diff --git a/macos/VERSION b/macos/VERSION index dc1e644..9c6d629 100644 --- a/macos/VERSION +++ b/macos/VERSION @@ -1 +1 @@ -1.6.0 +1.6.1 diff --git a/macos/assets/dream-skin.css b/macos/assets/dream-skin.css index 96601eb..962e91a 100644 --- a/macos/assets/dream-skin.css +++ b/macos/assets/dream-skin.css @@ -289,7 +289,7 @@ html[data-dream-skin="active"] aside.app-shell-left-panel [aria-current="page"] color: var(--ds-accent) !important; } -html[data-dream-skin="active"] main.main-surface { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]) { position: relative !important; isolation: isolate; overflow: hidden !important; @@ -301,7 +301,7 @@ html[data-dream-skin="active"] main.main-surface { box-shadow: -8px 0 28px rgb(var(--ds-bg-rgb) / .18) !important; } -html[data-dream-skin="active"] main.main-surface:not(:has([role="main"]))::before { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { content: ""; position: absolute; inset: 0; @@ -314,12 +314,12 @@ html[data-dream-skin="active"] main.main-surface:not(:has([role="main"]))::befor opacity: .78; } -html[data-dream-skin="active"][data-dream-shell="light"] main.main-surface:not(:has([role="main"]))::before { +html[data-dream-skin="active"][data-dream-shell="light"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { opacity: .72; } html[data-dream-skin="active"]:is([data-dream-art-wide="true"], [data-dream-art-aspect="wide"], [data-dream-art-aspect="ultrawide"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { background-position: center, center, var(--ds-art-position); background-size: 100% 100%, 100% 100%, cover; } @@ -328,7 +328,7 @@ html[data-dream-skin="active"]:is([data-dream-art-wide="true"], [data-dream-art- baseline readability veil. Ambient mode deliberately uses the heavier task fade/shade below, while off removes the artwork entirely. */ html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { inset: 0; height: auto; background-image: var(--ds-task-full-veil), var(--dream-skin-art); @@ -338,12 +338,12 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { inset: 0; height: auto; } -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) body { +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) body { background-image: var(--dream-skin-art) !important; background-position: var(--ds-art-position) !important; background-size: cover !important; @@ -351,7 +351,7 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- background-attachment: fixed !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) body { +html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) body { background-image: var(--dream-skin-art) !important; background-position: var(--ds-art-position) !important; background-size: cover !important; @@ -359,7 +359,7 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art background-attachment: fixed !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) +html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) aside.app-shell-left-panel { background: linear-gradient(90deg, var(--ds-immersive-sidebar), @@ -370,13 +370,13 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art backdrop-filter: none !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) +html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) aside.app-shell-left-panel::after { background: transparent !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) - main.main-surface:not(:has([role="main"])) { +html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) { background: linear-gradient(90deg, var(--ds-immersive-edge), var(--ds-immersive-mid) 64%, @@ -387,11 +387,11 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art } html[data-dream-skin="active"]:is([data-dream-task-mode="full"], [data-dream-art-task-mode="full"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { content: none; } -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) aside.app-shell-left-panel { background: linear-gradient(90deg, var(--ds-task-immersive-sidebar), @@ -404,13 +404,13 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- /* Native sidebar resize chrome inherits the sidebar background and extends 20px into the main surface. Keeping it clear preserves one continuous image. */ -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) aside.app-shell-left-panel::after { background: transparent !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) - main.main-surface:not(:has([role="main"])) { +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) { background: linear-gradient(90deg, var(--ds-task-immersive-edge), var(--ds-task-immersive-mid) 64%, @@ -421,11 +421,11 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { content: none; } -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) .composer-surface-chrome { background: var(--ds-immersive-composer-solid) !important; border: 0 !important; @@ -436,8 +436,8 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- backdrop-filter: none !important; } -html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) - main.main-surface > header.app-header-tint { +html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface])):not(:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"])) + main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { background: transparent !important; border-bottom: 0 !important; box-shadow: none !important; @@ -445,7 +445,7 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) [class*="_markdown"] { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) [class*="_markdown"] { color: var(--ds-text) !important; text-shadow: 0 1px 2px rgb(var(--ds-bg-rgb) / .82), @@ -453,14 +453,14 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- } html[data-dream-skin="active"][data-dream-shell="light"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) [class*="_markdown"] { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) [class*="_markdown"] { text-shadow: 0 1px 2px rgb(var(--ds-panel-rgb) / .92), 0 0 10px rgb(var(--ds-panel-rgb) / .72); } html[data-dream-skin="active"]:is([data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { inset: 0 0 auto; height: clamp(280px, 46vh, 520px); background-position: center top, center top, var(--ds-art-position); @@ -468,7 +468,7 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="banner"], [data-dream-a } html[data-dream-skin="active"]:is([data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"]):is([data-dream-art-wide="true"], [data-dream-art-aspect="wide"], [data-dream-art-aspect="ultrawide"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { inset: 0; height: auto; background-position: center, center, var(--ds-art-position); @@ -476,16 +476,16 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="banner"], [data-dream-a } html[data-dream-skin="active"]:is([data-dream-task-mode="off"], [data-dream-art-task-mode="off"]) - main.main-surface:not(:has([role="main"]))::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"]))::before { content: none; } -html[data-dream-skin="active"] main.main-surface:not(:has([role="main"])) > :not(header.app-header-tint) { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) > :not(header:is(.app-header-tint, [data-app-shell-header-edge-scroll])) { position: relative; z-index: 1; } -html[data-dream-skin="active"] main.main-surface:not(:has([role="main"])) [role="main"] { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) [role="main"] { background: transparent !important; color: var(--ds-text) !important; text-shadow: @@ -493,7 +493,7 @@ html[data-dream-skin="active"] main.main-surface:not(:has([role="main"])) [role= 0 0 10px rgb(var(--ds-bg-rgb) / .46); } -html[data-dream-skin="active"][data-dream-shell="light"] main.main-surface:not(:has([role="main"])) [role="main"] { +html[data-dream-skin="active"][data-dream-shell="light"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) [role="main"] { text-shadow: none; } @@ -503,35 +503,35 @@ html[data-dream-skin="active"][data-dream-shell="light"] main.main-surface:not(: transparency is deliberately not gated on the home-route selector. The nested surfaces all carry the same token, so they are cleared everywhere and the translucent pane tint is painted once, on the bordered outer wrapper. */ -html[data-dream-skin="active"] main.main-surface +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]) :is(div, section, aside)[class~="bg-token-main-surface-primary"] { background: transparent !important; } -html[data-dream-skin="active"] main.main-surface +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]) div[class~="bg-token-main-surface-primary"][class~="border-l"] { background: rgb(var(--ds-panel-rgb) / .62) !important; backdrop-filter: blur(10px) saturate(106%) !important; } -html[data-dream-skin="active"] main.main-surface:not(:has([role="main"])) article { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) article { border: 1px solid rgb(var(--ds-muted-rgb) / .12); background: rgb(var(--ds-panel-rgb) / .44); box-shadow: 0 8px 24px rgb(var(--ds-bg-rgb) / .10); backdrop-filter: blur(7px) saturate(105%); } -html[data-dream-skin="active"][data-dream-shell="light"] main.main-surface:not(:has([role="main"])) article { +html[data-dream-skin="active"][data-dream-shell="light"] main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) article { background: rgb(var(--ds-panel-rgb) / .72); } html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:has([role="main"])::after, + main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"])::after, html[data-dream-skin="active"][data-dream-shell="light"] [role="main"]:has([data-testid="home-icon"]) [data-feature="game-source"]::before { text-shadow: none; } -html[data-dream-skin="active"] main.main-surface > header.app-header-tint { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { /* Preserve Codex's native fixed header geometry and side-panel controls. */ background: rgb(var(--ds-panel-rgb) / .90) !important; border-bottom: 1px solid var(--ds-line) !important; @@ -540,7 +540,7 @@ html[data-dream-skin="active"] main.main-surface > header.app-header-tint { /* Decorative chrome lives on the native shell; no injected positioning host is needed. */ html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::before { content: var(--dream-skin-name, "Codex Dream Skin") " · " var(--dream-skin-brand-subtitle, "CODEX DREAM SKIN"); position: absolute; @@ -559,7 +559,7 @@ html[data-dream-skin="active"] } html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::after { content: var(--dream-skin-status, "DREAM SKIN ONLINE"); position: absolute; right: 84px; @@ -577,7 +577,7 @@ html[data-dream-skin="active"] } html[data-dream-skin="active"] - main.main-surface:has([role="main"])::after { + main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"])::after { content: var(--dream-skin-quote, "MAKE SOMETHING WONDERFUL"); position: absolute; right: 28px; @@ -592,9 +592,9 @@ html[data-dream-skin="active"] } html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before, + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::before, html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::after { text-shadow: none; } @@ -614,7 +614,7 @@ html[data-dream-skin="active"][data-dream-shell="dark"] text-shadow: 0 1px 2px rgb(var(--ds-bg-rgb) / .82) !important; } -html[data-dream-skin="active"] main.main-surface [role="main"] { +html[data-dream-skin="active"] main:is(.main-surface, [data-app-shell-main-surface]) [role="main"] { background: transparent !important; scrollbar-color: rgb(var(--ds-accent-rgb) / .38) transparent; } @@ -901,7 +901,7 @@ html[data-dream-skin="active"] .composer-surface-chrome::before { content: none /* A wide image can carry the home screen too. The native hero remains live, but the artwork is painted once on the window instead of repeated in a card. */ -html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main.main-surface [role="main"]) body { +html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"]) body { background-image: var(--dream-skin-art) !important; background-position: var(--ds-art-position) !important; background-size: cover !important; @@ -909,7 +909,7 @@ html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main.main-surface background-attachment: fixed !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main.main-surface [role="main"]) +html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"]) aside.app-shell-left-panel { background: linear-gradient(90deg, var(--ds-immersive-sidebar), @@ -920,12 +920,12 @@ html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main.main-surface backdrop-filter: none !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main.main-surface [role="main"]) +html[data-dream-skin="active"][data-dream-art-wide="true"]:has(main:is(.main-surface, [data-app-shell-main-surface]) [role="main"]) aside.app-shell-left-panel::after { background: transparent !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has([role="main"]) { +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"]) { background: linear-gradient(90deg, var(--ds-immersive-edge), var(--ds-immersive-mid) 64%, @@ -935,29 +935,29 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has box-shadow: none !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has([role="main"]) - > header.app-header-tint { +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"]) + > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { background: transparent !important; border-bottom: 0 !important; box-shadow: none !important; backdrop-filter: none !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface - > header.app-header-tint { +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]) + > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { color: var(--ds-text) !important; text-shadow: 0 1px 2px rgb(var(--ds-bg-rgb) / .86), 0 0 8px rgb(var(--ds-bg-rgb) / .52) !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface - > header.app-header-tint svg { +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]) + > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) svg { color: rgb(var(--ds-muted-rgb) / .96) !important; filter: drop-shadow(0 1px 2px rgb(var(--ds-bg-rgb) / .72)); } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has([role="main"]) +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"]) [role="main"]:has([data-testid="home-icon"]) > div:first-child > div:first-child > div:first-child { border: 0 !important; border-radius: 0 !important; @@ -965,12 +965,12 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has box-shadow: none !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has([role="main"]) +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"]) [role="main"]:has([data-testid="home-icon"]) > div:first-child > div:first-child > div:first-child::before { content: none !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has([role="main"]) +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"]) [role="main"]:has([data-testid="home-icon"]) .group\/home-suggestions button { background: rgb(var(--ds-panel-rgb) / .56) !important; box-shadow: @@ -1088,17 +1088,17 @@ html[data-dream-skin="active"] .composer-surface-chrome p.placeholder::after { /* Search routes ship an opaque sticky band and input surface. Keep the control legible while allowing the selected image to remain continuous. */ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) div.sticky:has(input[type="text"]) { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) div.sticky:has(input[type="text"]) { background: transparent !important; } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) div.sticky:has(input[type="text"])::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) div.sticky:has(input[type="text"])::after { background: transparent !important; } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) div.no-drag:has(> input[type="text"]) { + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) div.no-drag:has(> input[type="text"]) { background: var(--ds-immersive-composer) !important; border: 0 !important; box-shadow: @@ -1110,17 +1110,17 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- /* Pull Requests and similar utility routes wrap their content in a native full-size opaque surface. Only clear full-window wrappers, not cards. */ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"])[data-dream-art-wide="true"] - main.main-surface:not(:has([role="main"])) + main:is(.main-surface, [data-app-shell-main-surface]):not(:has([role="main"])) [class~="bg-token-main-surface-primary"][class~="h-full"][class~="w-full"] { background: transparent !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]) .app-shell-main-content-frame { border-top: 0 !important; } -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]) .app-shell-main-content-top-fade { display: none !important; background: transparent !important; @@ -1129,7 +1129,7 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface /* Codex paints a second opaque fade behind the sticky composer. The composer already owns its readable surface, so retaining this layer creates a false bottom panel and makes the control look duplicated. */ -html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface +html[data-dream-skin="active"][data-dream-art-wide="true"] main:is(.main-surface, [data-app-shell-main-surface]) .thread-scroll-container .bg-gradient-to-t.from-token-main-surface-primary { background: transparent !important; } @@ -1178,7 +1178,7 @@ html[data-dream-skin="active"] [data-message-author-role] { border-radius: 16px; @media (max-width: 1120px) { html[data-dream-skin="active"] - main.main-surface:has([role="main"])::after { content: none; } + main:is(.main-surface, [data-app-shell-main-surface]):has([role="main"])::after { content: none; } html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) { --thread-content-max-width: min(940px, calc(100cqw - 30px)) !important; } html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) > div:first-child > div:first-child > div:first-child { width: calc(100% - 28px) !important; } } diff --git a/macos/assets/renderer-inject.js b/macos/assets/renderer-inject.js index 2e3bc55..33eddb6 100644 --- a/macos/assets/renderer-inject.js +++ b/macos/assets/renderer-inject.js @@ -1,6 +1,6 @@ // Canonical cross-platform renderer. Run tools/sync-runtime-assets.mjs after editing. ((cssText, artDataUrl, themeConfig) => { - const SELECTOR_CONTRACT = {"schema":"codex-dream-skin-selectors/1","selectors":[{"key":"shell-main","selector":"main.main-surface","tier":"L1","scope":"all","required":true},{"key":"left-panel","selector":"aside.app-shell-left-panel","tier":"L1","scope":"all","required":true},{"key":"header-tint","selector":"header.app-header-tint","tier":"L1","scope":"all","required":true},{"key":"home-icon","selector":"[data-testid=\"home-icon\"]","tier":"L1","scope":"home","required":true},{"key":"home-route","selector":"[role=\"main\"]:has([data-testid=\"home-icon\"])","tier":"L1","scope":"home","required":true},{"key":"home-route-css","selector":"[role=\"main\"]","tier":"L1","scope":"home","required":true},{"key":"home-banners","selector":".home-banners","tier":"L2","scope":"home","required":false},{"key":"composer-chrome","selector":".composer-surface-chrome","tier":"L2","scope":"home+thread","required":false},{"key":"composer-toolbar","selector":".composer-surface-chrome [class*=\"_footer_\"]","tier":"L2","scope":"home+thread","required":false},{"key":"home-utility","selector":"[class*=\"_homeUtilityBar_\"]","tier":"L2","scope":"home","required":false},{"key":"game-source","selector":"[data-feature=\"game-source\"]","tier":"L2","scope":"home","required":false},{"key":"home-suggestions","selector":".group\\/home-suggestions","tier":"L2","scope":"home","required":false},{"key":"project-selector","selector":".group\\/project-selector","tier":"L2","scope":"home config","required":false},{"key":"markdown","selector":"[class*=\"_markdown\"]","tier":"L2","scope":"thread","required":false},{"key":"thread-surface","selector":".thread-scroll-container","tier":"L2","scope":"thread","required":false},{"key":"message","selector":"[data-message-author-role]","tier":"L2","scope":"thread","required":false},{"key":"appearance-radio","selector":"input[name=\"appearance-theme\"]","tier":"L2","scope":"settings","required":false},{"key":"overlay-menu","selector":"[role=\"menu\"]","tier":"L2","scope":"overlay","required":false},{"key":"overlay-dialog","selector":"[role=\"dialog\"]","tier":"L2","scope":"overlay","required":false},{"key":"overlay-popper","selector":"[data-radix-popper-content-wrapper]","tier":"L2","scope":"overlay","required":false}],"stableTestids":["app-shell-header-context-menu-surface","home-icon","theme-preview"]}; + const SELECTOR_CONTRACT = {"schema":"codex-dream-skin-selectors/1","selectors":[{"key":"shell-main","selector":"main:is(.main-surface, [data-app-shell-main-surface])","tier":"L1","scope":"all","required":true},{"key":"left-panel","selector":"aside.app-shell-left-panel","tier":"L1","scope":"all","required":true},{"key":"header-tint","selector":"header:is(.app-header-tint, [data-app-shell-header-edge-scroll])","tier":"L1","scope":"all","required":true},{"key":"home-icon","selector":"[data-testid=\"home-icon\"]","tier":"L1","scope":"home","required":true},{"key":"home-route","selector":"[role=\"main\"]:has([data-testid=\"home-icon\"])","tier":"L1","scope":"home","required":true},{"key":"home-route-css","selector":"[role=\"main\"]","tier":"L1","scope":"home","required":true},{"key":"home-banners","selector":".home-banners","tier":"L2","scope":"home","required":false},{"key":"composer-chrome","selector":".composer-surface-chrome","tier":"L2","scope":"home+thread","required":false},{"key":"composer-toolbar","selector":".composer-surface-chrome [class*=\"_footer_\"]","tier":"L2","scope":"home+thread","required":false},{"key":"home-utility","selector":"[class*=\"_homeUtilityBar_\"]","tier":"L2","scope":"home","required":false},{"key":"game-source","selector":"[data-feature=\"game-source\"]","tier":"L2","scope":"home","required":false},{"key":"home-suggestions","selector":".group\\/home-suggestions","tier":"L2","scope":"home","required":false},{"key":"project-selector","selector":".group\\/project-selector","tier":"L2","scope":"home config","required":false},{"key":"markdown","selector":"[class*=\"_markdown\"]","tier":"L2","scope":"thread","required":false},{"key":"thread-surface","selector":".thread-scroll-container","tier":"L2","scope":"thread","required":false},{"key":"message","selector":"[data-message-author-role]","tier":"L2","scope":"thread","required":false},{"key":"appearance-radio","selector":"input[name=\"appearance-theme\"]","tier":"L2","scope":"settings","required":false},{"key":"overlay-menu","selector":"[role=\"menu\"]","tier":"L2","scope":"overlay","required":false},{"key":"overlay-dialog","selector":"[role=\"dialog\"]","tier":"L2","scope":"overlay","required":false},{"key":"overlay-popper","selector":"[data-radix-popper-content-wrapper]","tier":"L2","scope":"overlay","required":false}],"stableTestids":["app-shell-header-context-menu-surface","home-icon","theme-preview"]}; const STATE_KEY = "__CODEX_DREAM_SKIN_STATE__"; const DISABLED_KEY = "__CODEX_DREAM_SKIN_DISABLED__"; const STYLE_REGISTRY_KEY = "__CODEX_DREAM_SKIN_STYLE_SHEETS__"; diff --git a/macos/assets/selectors.json b/macos/assets/selectors.json index 06e2223..3147031 100644 --- a/macos/assets/selectors.json +++ b/macos/assets/selectors.json @@ -2,10 +2,10 @@ "schema": "codex-dream-skin-selectors/1", "description": "双端统一选择器契约(初稿)。scope 与 required 均来自 2026-07-21 双端 DOM 快照实测,非猜测。doctor / CI 应逐条 querySelector 并按 tier 判级:L1 缺失=皮肤主行为受损,L2 缺失=精修静默降级。", "verifiedAgainst": { - "date": "2026-07-21", - "chromium": "150.0.7871.124", + "date": "2026-08-06", + "chromium": "150.0.7871.124 and 151.0.7922.71", "codexVersionMac": "26.715.61943", - "codexVersionWindows": "版本号未记录;bundle hash 与 mac 不同(ModelPickerTrigger mac=1fm6a win=1w4ob),确认存在版本错位", + "codexVersionWindows": "26.730.8199.0:主表面改为 data-app-shell-main-surface,标题栏改为 data-app-shell-header-edge-scroll;保留旧版类名作为兼容分支", "fixtures": [ "runtime/dom-fixtures/codex-dom-fixture-darwin-watch.json (15 状态)", "runtime/dom-fixtures/codex-dom-fixture-win32-watch.json (7 状态)" @@ -26,9 +26,9 @@ "config": "依赖用户配置才出现(如未配置项目则无项目选择器)" }, "selectors": [ - { "key": "shell-main", "selector": "main.main-surface", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。mac 设置页缺失(win 存在),缺失时整页仅 L0" }, + { "key": "shell-main", "selector": "main:is(.main-surface, [data-app-shell-main-surface])", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。26.730+ 使用稳定 data-app-shell-main-surface;旧版保留 main-surface。使用 :is() 让同一契约安全用于 querySelector 与 CSS 模板。mac 设置页缺失时整页仅 L0" }, { "key": "left-panel", "selector": "aside.app-shell-left-panel", "tier": "L1", "scope": "all", "required": true, "notes": "左侧栏;收起/重建时会移除节点,勿在其消失时清皮" }, - { "key": "header-tint", "selector": "header.app-header-tint", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;皮肤不得覆盖其 position/z-index(既有回归约束)" }, + { "key": "header-tint", "selector": "header:is(.app-header-tint, [data-app-shell-header-edge-scroll])", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;26.730+ 使用稳定 data-app-shell-header-edge-scroll。使用 :is() 避免 CSS 模板中的逗号并集逃逸根作用域;皮肤不得覆盖其 position/z-index(既有回归约束)" }, { "key": "home-icon", "selector": "[data-testid=\"home-icon\"]", "tier": "L1", "scope": "home", "required": true, "notes": "首页判定信号,双端一致" }, { "key": "home-route", "selector": "[role=\"main\"]:has([data-testid=\"home-icon\"])", "tier": "L1", "scope": "home", "required": true, "notes": "首页容器。实测 [role=main] 仅存在于首页——它不是通用路由锚点,thread 页没有" }, { "key": "home-route-css", "selector": "[role=\"main\"]", "tier": "L1", "scope": "home", "required": true, "notes": "home-route 的 CSS 可组合别名:不含 :has()。CSS 禁止 :has() 嵌套,home-route 原选择器一旦写进 :has()/:not(:has()) 整条规则会被解析器丢弃(v1.3.1 全窗口首页与任务页氛围背景因此失效)。依据与 home-route 相同的实测:[role=main] 仅存在于首页;该锚点缺失时 CSS 路由门控整体失效,故必须按 L1 必需项监控" }, diff --git a/macos/package.json b/macos/package.json index 143909b..ced270d 100644 --- a/macos/package.json +++ b/macos/package.json @@ -1,6 +1,6 @@ { "name": "codex-dream-skin-studio", - "version": "1.6.0", + "version": "1.6.1", "private": true, "type": "module", "scripts": { diff --git a/macos/scripts/common-macos.sh b/macos/scripts/common-macos.sh index f7ebfba..4c9abea 100755 --- a/macos/scripts/common-macos.sh +++ b/macos/scripts/common-macos.sh @@ -29,7 +29,7 @@ CODEX_APP_JOB_LABEL="com.openai.codex-dream-skin-studio.app" INJECTOR_JOB_LABEL="com.openai.codex-dream-skin-studio.injector" EXPECTED_CODEX_TEAM_ID="2DC432GLL2" EXPECTED_CODEX_REQUIREMENT="anchor apple generic and certificate leaf[subject.OU] = \"$EXPECTED_CODEX_TEAM_ID\"" -SKIN_VERSION="1.6.0" +SKIN_VERSION="1.6.1" DREAM_SKIN_VALIDATED_RUNTIME_PID="" DREAM_SKIN_VALIDATED_RUNTIME_BUNDLE="" DREAM_SKIN_VALIDATED_RUNTIME_EXE="" diff --git a/macos/scripts/injector.mjs b/macos/scripts/injector.mjs index 106916f..fb419da 100644 --- a/macos/scripts/injector.mjs +++ b/macos/scripts/injector.mjs @@ -43,7 +43,7 @@ const stableTestidLiteral = (testid) => { } return JSON.stringify(`[data-testid="${testid}"]`); }; -const SKIN_VERSION = "1.6.0"; +const SKIN_VERSION = "1.6.1"; const INTERNET_ANGEL_EXTENSION_THEME_IDS = new Set([ "preset-internet-angel", "preset-internet-angel-default", diff --git a/macos/tests/injector-bootstrap.test.mjs b/macos/tests/injector-bootstrap.test.mjs index 0a8a6b1..f7e30ce 100644 --- a/macos/tests/injector-bootstrap.test.mjs +++ b/macos/tests/injector-bootstrap.test.mjs @@ -24,7 +24,9 @@ function createFixture() { get documentElement() { return root; }, addEventListener(type, callback) { if (type === "DOMContentLoaded") domReady.push(callback); }, querySelector(selector) { - if (selector === "main.main-surface") return markers.shell ? {} : null; + if (selector === "main:is(.main-surface, [data-app-shell-main-surface])") { + return markers.shell ? {} : null; + } if (selector === "aside.app-shell-left-panel") return markers.sidebar ? {} : null; if (selector === "[role=\"main\"]") return markers.main ? {} : null; if (selector.includes("appearance-theme") || selector.includes("theme-preview")) { diff --git a/tools/renderer-runtime.test.mjs b/tools/renderer-runtime.test.mjs index 294cd8c..96c1623 100644 --- a/tools/renderer-runtime.test.mjs +++ b/tools/renderer-runtime.test.mjs @@ -118,8 +118,8 @@ function makeFixture({ nativeAppearance = "dark", settings = false, adopted = tr partFixtures.composer = makeDomNode("composer", partFixtures.main); partFixtures.composerToolbar = makeDomNode("composer-toolbar", partFixtures.composer); register("aside.app-shell-left-panel", partFixtures.sidebar); - register("main.main-surface", partFixtures.main); - register("header.app-header-tint", partFixtures.header); + register("main:is(.main-surface, [data-app-shell-main-surface])", partFixtures.main); + register("header:is(.app-header-tint, [data-app-shell-header-edge-scroll])", partFixtures.header); register('[data-testid="home-icon"]', partFixtures.homeIcon); register('[role="main"]:has([data-testid="home-icon"])', partFixtures.home); register('[role="main"]', partFixtures.home); @@ -295,8 +295,8 @@ export async function runRendererRuntimeTest(assetRoot) { // Home gating must stay single-level: CSS forbids :has() inside :has(), // and Chromium drops any rule that nests it (the v1.3.1 regression). The // canonical CSS therefore gates on the :has()-free home-route-css alias. - assert.match(css, /main\.main-surface:has\(\[role="main"\]\)/); - assert.match(css, /main\.main-surface:not\(:has\(\[role="main"\]\)\)/); + assert.match(css, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\):has\(\[role="main"\]\)/); + assert.match(css, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\):not\(:has\(\[role="main"\]\)\)/); assert.doesNotMatch(css, /:has\([^()]*:has\(/); assert.match(css, /content:\s*var\(--dream-skin-name[\s\S]{0,180}var\(--dream-skin-brand-subtitle/); assert.match(css, /content:\s*var\(--dream-skin-status/); diff --git a/tools/selectors.json b/tools/selectors.json index 06e2223..3147031 100644 --- a/tools/selectors.json +++ b/tools/selectors.json @@ -2,10 +2,10 @@ "schema": "codex-dream-skin-selectors/1", "description": "双端统一选择器契约(初稿)。scope 与 required 均来自 2026-07-21 双端 DOM 快照实测,非猜测。doctor / CI 应逐条 querySelector 并按 tier 判级:L1 缺失=皮肤主行为受损,L2 缺失=精修静默降级。", "verifiedAgainst": { - "date": "2026-07-21", - "chromium": "150.0.7871.124", + "date": "2026-08-06", + "chromium": "150.0.7871.124 and 151.0.7922.71", "codexVersionMac": "26.715.61943", - "codexVersionWindows": "版本号未记录;bundle hash 与 mac 不同(ModelPickerTrigger mac=1fm6a win=1w4ob),确认存在版本错位", + "codexVersionWindows": "26.730.8199.0:主表面改为 data-app-shell-main-surface,标题栏改为 data-app-shell-header-edge-scroll;保留旧版类名作为兼容分支", "fixtures": [ "runtime/dom-fixtures/codex-dom-fixture-darwin-watch.json (15 状态)", "runtime/dom-fixtures/codex-dom-fixture-win32-watch.json (7 状态)" @@ -26,9 +26,9 @@ "config": "依赖用户配置才出现(如未配置项目则无项目选择器)" }, "selectors": [ - { "key": "shell-main", "selector": "main.main-surface", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。mac 设置页缺失(win 存在),缺失时整页仅 L0" }, + { "key": "shell-main", "selector": "main:is(.main-surface, [data-app-shell-main-surface])", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。26.730+ 使用稳定 data-app-shell-main-surface;旧版保留 main-surface。使用 :is() 让同一契约安全用于 querySelector 与 CSS 模板。mac 设置页缺失时整页仅 L0" }, { "key": "left-panel", "selector": "aside.app-shell-left-panel", "tier": "L1", "scope": "all", "required": true, "notes": "左侧栏;收起/重建时会移除节点,勿在其消失时清皮" }, - { "key": "header-tint", "selector": "header.app-header-tint", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;皮肤不得覆盖其 position/z-index(既有回归约束)" }, + { "key": "header-tint", "selector": "header:is(.app-header-tint, [data-app-shell-header-edge-scroll])", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;26.730+ 使用稳定 data-app-shell-header-edge-scroll。使用 :is() 避免 CSS 模板中的逗号并集逃逸根作用域;皮肤不得覆盖其 position/z-index(既有回归约束)" }, { "key": "home-icon", "selector": "[data-testid=\"home-icon\"]", "tier": "L1", "scope": "home", "required": true, "notes": "首页判定信号,双端一致" }, { "key": "home-route", "selector": "[role=\"main\"]:has([data-testid=\"home-icon\"])", "tier": "L1", "scope": "home", "required": true, "notes": "首页容器。实测 [role=main] 仅存在于首页——它不是通用路由锚点,thread 页没有" }, { "key": "home-route-css", "selector": "[role=\"main\"]", "tier": "L1", "scope": "home", "required": true, "notes": "home-route 的 CSS 可组合别名:不含 :has()。CSS 禁止 :has() 嵌套,home-route 原选择器一旦写进 :has()/:not(:has()) 整条规则会被解析器丢弃(v1.3.1 全窗口首页与任务页氛围背景因此失效)。依据与 home-route 相同的实测:[role=main] 仅存在于首页;该锚点缺失时 CSS 路由门控整体失效,故必须按 L1 必需项监控" }, diff --git a/windows/CHANGELOG.md b/windows/CHANGELOG.md index f0ad1a9..8b77593 100644 --- a/windows/CHANGELOG.md +++ b/windows/CHANGELOG.md @@ -1,5 +1,12 @@ # Windows Changelog +## 1.6.1 — 2026-08-06 + +### 兼容性修复 + +- 适配 Codex `26.730.8199.0` 的稳定主表面与标题栏属性;新版不再因旧 `main-surface` / `app-header-tint` 类名消失而误判启动失败、回滚注入或丢失 RIRU 背景。 +- 背景、任务氛围层、侧栏与标题栏 CSS 同时兼容旧类名和新版 `data-app-shell-*` 属性,并保留旧版本支持。 + ## 1.6.0 — 2026-08-05 ### 新增 diff --git a/windows/VERSION b/windows/VERSION index dc1e644..9c6d629 100644 --- a/windows/VERSION +++ b/windows/VERSION @@ -1 +1 @@ -1.6.0 +1.6.1 diff --git a/windows/assets/dream-skin.css b/windows/assets/dream-skin.css index 0c3af12..51f4b25 100644 --- a/windows/assets/dream-skin.css +++ b/windows/assets/dream-skin.css @@ -111,7 +111,7 @@ html.codex-dream-skin aside.app-shell-left-panel [class*="text-token"] { color: currentColor; } -html.codex-dream-skin main.main-surface { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) { position: relative; isolation: isolate; overflow: hidden !important; @@ -121,7 +121,7 @@ html.codex-dream-skin main.main-surface { box-shadow: inset 0 1px color-mix(in oklab, var(--dream-surface-raised) 72%, transparent) !important; } -html.codex-dream-skin main.main-surface > header.app-header-tint { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { /* Preserve Codex's native fixed header geometry and side-panel controls. */ color: var(--dream-text) !important; background: color-mix(in oklab, var(--dream-surface) 94%, transparent) !important; @@ -221,7 +221,7 @@ html.codex-dream-skin.dream-task-off .dream-task::before { display: none; } -html.codex-dream-skin .dream-task > :not(header.app-header-tint) { +html.codex-dream-skin .dream-task > :not(header:is(.app-header-tint, [data-app-shell-header-edge-scroll])) { position: relative; z-index: 1; } @@ -458,8 +458,8 @@ html.codex-dream-skin article { /* A 16:9 or wider image is painted once on the native window. The sidebar, title bar and route surface become coordinated readability layers instead of repeating or cropping the image inside individual panels. */ -html.codex-dream-skin.dream-art-wide:has(main.main-surface.dream-home-shell) body, -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) body { +html.codex-dream-skin.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) body, +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) body { background-color: var(--dream-canvas) !important; background-image: var(--dream-art) !important; background-position: var(--dream-art-position) !important; @@ -468,9 +468,9 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) background-attachment: fixed !important; } -html.codex-dream-skin.dream-art-wide:has(main.main-surface.dream-home-shell) +html.codex-dream-skin.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) aside.app-shell-left-panel, -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) aside.app-shell-left-panel { background: linear-gradient(90deg, var(--dream-immersive-sidebar), @@ -481,22 +481,22 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) backdrop-filter: none !important; } -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) aside.app-shell-left-panel { background: linear-gradient(90deg, var(--dream-task-immersive-sidebar), var(--dream-task-immersive-edge)) !important; } -html.codex-dream-skin.dream-art-wide:has(main.main-surface.dream-home-shell) +html.codex-dream-skin.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) aside.app-shell-left-panel::after, -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) aside.app-shell-left-panel::after { background: transparent !important; } -html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell, -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) main.main-surface:not(.dream-home-shell) { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell, +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) { background: linear-gradient(90deg, var(--dream-immersive-edge), var(--dream-immersive-mid) 64%, @@ -506,7 +506,7 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) box-shadow: none !important; } -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) main.main-surface:not(.dream-home-shell) { +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) { background: linear-gradient(90deg, var(--dream-task-immersive-edge), var(--dream-task-immersive-mid) 64%, @@ -521,7 +521,7 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) content: none !important; } -html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { background: transparent !important; border-bottom: 0 !important; box-shadow: none !important; @@ -530,15 +530,15 @@ html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint 0 0 8px color-mix(in oklab, var(--dream-canvas) 58%, transparent) !important; } -html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint svg { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) svg { filter: drop-shadow(0 1px 2px color-mix(in oklab, var(--dream-canvas) 72%, transparent)); } -html.codex-dream-skin.dream-art-wide main.main-surface [role="main"] { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) [role="main"] { background: transparent !important; } -html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell .dream-home > div:first-child > div:first-child > div:first-child { border: 0 !important; border-radius: 0 !important; @@ -546,12 +546,12 @@ html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell box-shadow: none !important; } -html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell .dream-home > div:first-child > div:first-child > div:first-child::before { content: none !important; } -html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell .dream-home .group\/home-suggestions button { background: color-mix(in oklab, var(--dream-surface-raised) 58%, transparent) !important; box-shadow: 0 8px 22px color-mix(in oklab, var(--dream-canvas) 18%, transparent), @@ -596,14 +596,14 @@ html.codex-dream-skin .dream-home:has(.dream-home-utility) .composer-surface-chr Clear only full-window or sticky route chrome, leaving functional cards and their hover states intact. */ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) div.sticky:has(input[type="text"]), + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) div.sticky:has(input[type="text"]), html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) div.sticky:has(input[type="text"])::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) div.sticky:has(input[type="text"])::after { background: transparent !important; } html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) div.no-drag:has(> input[type="text"]) { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) div.no-drag:has(> input[type="text"]) { background: var(--dream-immersive-composer) !important; border: 0 !important; box-shadow: inset 0 0 0 1px var(--dream-immersive-line) !important; @@ -611,21 +611,21 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) } html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) [class~="bg-token-main-surface-primary"][class~="h-full"][class~="w-full"] { background: transparent !important; } -html.codex-dream-skin.dream-art-wide main.main-surface .app-shell-main-content-frame { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) .app-shell-main-content-frame { border-top: 0 !important; } -html.codex-dream-skin.dream-art-wide main.main-surface .app-shell-main-content-top-fade { +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) .app-shell-main-content-top-fade { display: none !important; background: transparent !important; } -html.codex-dream-skin.dream-art-wide main.main-surface +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) .thread-scroll-container .bg-gradient-to-t.from-token-main-surface-primary { background: transparent !important; } @@ -729,16 +729,16 @@ html.codex-dream-skin.dream-reduced-motion #codex-dream-skin-chrome .dream-angel /* The native header is fixed by Tailwind. The atmospheric task layer now excludes it, so this block only keeps box sizing predictable and leaves all native position, z-index and window controls untouched. */ -html.codex-dream-skin main.main-surface > header.app-header-tint { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { box-sizing: border-box !important; } -html.codex-dream-skin main.main-surface > header.app-header-tint > * { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) > * { min-width: 0; } -html.codex-dream-skin main.main-surface.dream-route-task > header.app-header-tint, -html.codex-dream-skin main.main-surface.dream-route-utility > header.app-header-tint { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-task > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { padding-inline: 8px !important; background: linear-gradient(90deg, @@ -861,9 +861,9 @@ html.codex-dream-skin .dream-permission-banner svg { /* Utility routes use an opaque indigo console canvas instead of inheriting the task wallpaper wash. Their route-specific tag is decorative and inert. */ -html.codex-dream-skin main.main-surface.dream-route-utility, +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility, html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface.dream-route-utility { + main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility { isolation: isolate; color: var(--dream-text) !important; background: @@ -873,7 +873,7 @@ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) color-mix(in oklab, var(--dream-surface) 92%, var(--angel-violet) 8%)) !important; } -html.codex-dream-skin main.main-surface.dream-route-utility::before { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility::before { content: ""; position: absolute; z-index: 0; @@ -888,7 +888,7 @@ html.codex-dream-skin main.main-surface.dream-route-utility::before { mask-image: linear-gradient(to bottom, #000 0 58%, transparent 100%); } -html.codex-dream-skin main.main-surface.dream-route-utility::after { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility::after { position: absolute; z-index: 4; top: 58px; @@ -904,19 +904,19 @@ html.codex-dream-skin main.main-surface.dream-route-utility::after { letter-spacing: .08em; } -html.codex-dream-skin main.main-surface.dream-route-sites::after { content: "♡ WEB STUDIO // SITES"; } -html.codex-dream-skin main.main-surface.dream-route-pulls::after { content: "♡ REPOSITORY LINK // PR"; } -html.codex-dream-skin main.main-surface.dream-route-scheduled::after { content: "♡ AUTOMATION // SCHEDULE"; } -html.codex-dream-skin main.main-surface.dream-route-plugins::after { content: "◇ SIGNAL MODULES // PLUGINS"; } +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-sites::after { content: "♡ WEB STUDIO // SITES"; } +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-pulls::after { content: "♡ REPOSITORY LINK // PR"; } +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-scheduled::after { content: "♡ AUTOMATION // SCHEDULE"; } +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-plugins::after { content: "◇ SIGNAL MODULES // PLUGINS"; } -html.codex-dream-skin main.main-surface.dream-route-utility > :not(header.app-header-tint) { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility > :not(header:is(.app-header-tint, [data-app-shell-header-edge-scroll])) { position: relative; z-index: 1; } -html.codex-dream-skin main.main-surface.dream-route-sites +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-sites [class~="bg-token-main-surface-primary"][class~="h-full"], -html.codex-dream-skin main.main-surface.dream-route-pulls +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-pulls [class~="bg-token-main-surface-primary"] { background-color: color-mix(in oklab, var(--dream-surface) 92%, var(--angel-violet) 8%) !important; background-image: @@ -925,26 +925,26 @@ html.codex-dream-skin main.main-surface.dream-route-pulls color-mix(in oklab, var(--angel-pink) 3%, transparent)) !important; } -html.codex-dream-skin main.main-surface.dream-route-pulls [class~="border-token-border-default"] { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-pulls [class~="border-token-border-default"] { border-color: color-mix(in oklab, var(--angel-cyan) 34%, var(--dream-line)) !important; } -html.codex-dream-skin main.main-surface.dream-route-utility h1, -html.codex-dream-skin main.main-surface.dream-route-utility h2, -html.codex-dream-skin main.main-surface.dream-route-utility [role="heading"] { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility h1, +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility h2, +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility [role="heading"] { color: var(--dream-text) !important; text-shadow: 2px 2px 0 color-mix(in oklab, var(--angel-violet) 36%, transparent); } -html.codex-dream-skin main.main-surface.dream-route-utility input[type="text"], -html.codex-dream-skin main.main-surface.dream-route-utility input[type="search"] { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility input[type="text"], +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility input[type="search"] { border-width: 1px !important; box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--angel-blue) 42%, transparent) !important; } /* The home route gains a lightweight broadcast HUD without introducing fake controls or obscuring the wallpaper subject. */ -html.codex-dream-skin main.main-surface.dream-home-shell::before { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell::before { content: ""; position: absolute; z-index: 0; @@ -956,7 +956,7 @@ html.codex-dream-skin main.main-surface.dream-home-shell::before { repeating-linear-gradient(0deg, transparent 0 5px, color-mix(in oklab, var(--angel-cyan) 3.5%, transparent) 5px 6px); } -html.codex-dream-skin main.main-surface.dream-home-shell::after { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell::after { content: "◇ LIVE // CONNECTION: STABLE // RIRU CHANNEL 07"; position: absolute; z-index: 4; @@ -973,7 +973,7 @@ html.codex-dream-skin main.main-surface.dream-home-shell::after { letter-spacing: .07em; } -html.codex-dream-skin main.main-surface.dream-home-shell > :not(header.app-header-tint) { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell > :not(header:is(.app-header-tint, [data-app-shell-header-edge-scroll])) { position: relative; z-index: 1; } @@ -1471,8 +1471,8 @@ html.codex-dream-skin.dream-safe-none #codex-dream-skin-chrome .dream-angel-webc } @media (max-width: 900px) { - html.codex-dream-skin main.main-surface.dream-route-utility::after, - html.codex-dream-skin main.main-surface.dream-home-shell::after { + html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility::after, + html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell::after { display: none; } @@ -1960,7 +1960,7 @@ html.codex-dream-skin aside.app-shell-left-panel button[class~="group/section-to /* In wide-wallpaper mode the hero art lives on the window, so its old clipping box is unnecessary. Releasing it reveals Codex's native suggestion grid, which is intentionally positioned just below that box. */ -html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell .dream-home > div:first-child > div:first-child > div:first-child { overflow: visible !important; } @@ -2092,8 +2092,8 @@ html.codex-dream-skin :focus-visible { /* Sidebar: a broadcast control deck with pixel selection states. */ html.codex-dream-skin aside.app-shell-left-panel, -html.codex-dream-skin.dream-art-wide:has(main.main-surface.dream-home-shell) aside.app-shell-left-panel, -html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) aside.app-shell-left-panel { +html.codex-dream-skin.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) aside.app-shell-left-panel, +html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) aside.app-shell-left-panel { border-right: 2px solid var(--angel-blue) !important; background: linear-gradient(180deg, @@ -2324,8 +2324,8 @@ html.codex-dream-skin aside.app-shell-left-panel [role="list"] > [role="listitem } /* Header and native app bar: translucent, but visibly part of the same system. */ -html.codex-dream-skin main.main-surface > header.app-header-tint, -html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint, +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), html.codex-dream-skin [class~="group/application-menu-top-bar"] { border-bottom: 2px solid color-mix(in oklab, var(--angel-blue) 72%, transparent) !important; background: @@ -2340,8 +2340,8 @@ html.codex-dream-skin [class~="group/application-menu-top-bar"] { /* The previously empty native toolbar now reads as the title strip of a streaming desktop. The pattern is decorative and never intercepts native window controls. */ -html.codex-dream-skin main.main-surface > header.app-header-tint, -html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), +html.codex-dream-skin.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { background: repeating-linear-gradient(90deg, transparent 0 23px, @@ -2352,7 +2352,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface > header.app-header-tint color-mix(in oklab, var(--dream-surface) 90%, var(--angel-pink) 10%)) !important; } -html.codex-dream-skin main.main-surface.dream-home-shell > header.app-header-tint::before { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::before { content: ""; position: absolute; z-index: 2; @@ -2371,7 +2371,7 @@ html.codex-dream-skin main.main-surface.dream-home-shell > header.app-header-tin filter: drop-shadow(1px 1px 0 var(--angel-ink)); } -html.codex-dream-skin main.main-surface.dream-home-shell > header.app-header-tint::after { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::after { content: "LIVE // RIRU DESKTOP 07"; position: absolute; z-index: 1; @@ -2578,16 +2578,16 @@ html.codex-dream-skin button[class~="bg-token-foreground"]:hover { /* Task routes prioritize sustained reading over wallpaper visibility. */ html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface.dream-task:not(.dream-home-shell), + main:is(.main-surface, [data-app-shell-main-surface]).dream-task:not(.dream-home-shell), html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) [role="main"].dream-task { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) [role="main"].dream-task { background: var(--dream-surface) !important; } html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface.dream-task:not(.dream-home-shell)::after, + main:is(.main-surface, [data-app-shell-main-surface]).dream-task:not(.dream-home-shell)::after, html.codex-dream-skin.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) .dream-task::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) .dream-task::after { content: ""; position: absolute; z-index: 0; @@ -3977,7 +3977,7 @@ html.codex-dream-skin aside[class~="relative"][class~="isolate"][class~="rounded token-coloured shell, then mounts its tab bar and xterm descendants. Paint the shell itself so the very first expanded frame cannot expose the native olive surface while the renderer classifier is still waiting on children. */ -html.codex-dream-skin main.main-surface +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) [class~="relative"][class~="z-30"][class~="min-h-0"][class~="w-full"][class~="shrink-0"][class~="overflow-visible"] > [class~="absolute"][class~="inset-0"][class~="min-h-0"][class~="overflow-hidden"] > [class~="absolute"][class~="inset-x-0"][class~="top-0"][class~="min-h-0"][class~="border-t"][class~="bg-token-main-surface-primary"] { @@ -4213,8 +4213,8 @@ html.codex-dream-skin .dream-side-workspace kbd { panel into a compact CHOTEN relay deck without inventing controls. */ html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) { position: relative !important; isolation: isolate; @@ -4244,8 +4244,8 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) > * { position: relative; z-index: 1; @@ -4253,16 +4253,16 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) [class~="bg-token-main-surface-primary"] { background: transparent !important; } html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) )::before { content: "\25C7 SIDE CHANNEL // RIRU RELAY"; position: absolute; @@ -4286,8 +4286,8 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) )::after { content: "LIVE 88% SIGNAL 072"; position: absolute; @@ -4314,8 +4314,8 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) :is(button:has(kbd), ul button[class~="bg-token-bg-fog"]) { position: relative; min-height: 50px; @@ -4332,8 +4332,8 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) :is(button:has(kbd), ul button[class~="bg-token-bg-fog"]):hover { border-color: var(--angel-cyan) !important; translate: -2px -1px; @@ -4347,8 +4347,8 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-workspace, - main.main-surface aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), - main.main-surface [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd), + main:is(.main-surface, [data-app-shell-main-surface]) [class~="isolate"][class~="h-full"][class~="min-h-0"][class~="flex-col"][class*="contain:layout_paint"]:not(:has(.xterm)):not(:has(.thread-scroll-container)):has(button kbd) ) :where(kbd, svg) { color: var(--angel-cyan) !important; } @@ -4427,7 +4427,7 @@ html.codex-dream-skin .dream-side-workspace-brand > em { receives its broadcast surface on the very first painted frame. */ html.codex-dream-skin :where( .dream-side-chat-panel, - main.main-surface aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) ) { position: relative !important; isolation: isolate; @@ -4447,14 +4447,14 @@ html.codex-dream-skin :where( html.codex-dream-skin :where( .dream-side-chat-panel, - main.main-surface aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) ) :where([class~="bg-token-main-surface-primary"], .thread-scroll-container) { background: transparent !important; } html.codex-dream-skin :where( .dream-side-chat-panel, - main.main-surface aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) + main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome) ) > [class~="bg-token-main-surface-primary"] { border-top: 1px solid color-mix(in oklab, var(--angel-cyan) 44%, transparent) !important; } @@ -4825,8 +4825,8 @@ html.codex-dream-skin [class~="group/application-menu-top-bar"] button[data-stat box-shadow: inset 0 -2px var(--angel-cyan), 2px 2px 0 color-mix(in oklab, var(--angel-pink) 42%, transparent) !important; } -html.codex-dream-skin main.main-surface > header.app-header-tint button[aria-pressed="true"], -html.codex-dream-skin main.main-surface > header.app-header-tint button[data-state="on"] { +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) button[aria-pressed="true"], +html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) button[data-state="on"] { color: var(--angel-cyan) !important; border-color: color-mix(in oklab, var(--angel-cyan) 66%, transparent) !important; background: color-mix(in oklab, var(--angel-blue) 22%, var(--dream-surface-raised)) !important; @@ -4862,7 +4862,7 @@ html.codex-dream-skin ::-webkit-scrollbar-track { margin-left: 36px !important; } - html.codex-dream-skin main.main-surface.dream-home-shell > header.app-header-tint::after { + html.codex-dream-skin main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::after { content: "LIVE // RIRU 07"; min-width: 164px; } @@ -4877,7 +4877,7 @@ html.codex-dream-skin ::-webkit-scrollbar-track { } html.codex-dream-skin aside.app-shell-left-panel, - html.codex-dream-skin.dream-art-wide:has(main.main-surface.dream-home-shell) aside.app-shell-left-panel { + html.codex-dream-skin.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) aside.app-shell-left-panel { box-shadow: inset -1px 0 var(--angel-cyan) !important; } } @@ -6498,8 +6498,8 @@ html.codex-dream-skin.dream-riru-art ::selection { /* Matte fabric sidebar with one scalloped ribbon seam. */ html.codex-dream-skin.dream-riru-art aside.app-shell-left-panel, -html.codex-dream-skin.dream-riru-art.dream-art-wide:has(main.main-surface.dream-home-shell) aside.app-shell-left-panel, -html.codex-dream-skin.dream-riru-art.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell)) aside.app-shell-left-panel { +html.codex-dream-skin.dream-riru-art.dream-art-wide:has(main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell) aside.app-shell-left-panel, +html.codex-dream-skin.dream-riru-art.dream-art-wide:is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell)) aside.app-shell-left-panel { border-right: 0 !important; background: radial-gradient(circle at 22px 18px, color-mix(in oklab, var(--riru-blush) 5%, transparent) 0 1px, transparent 1.5px) 0 0 / 22px 22px, @@ -6614,8 +6614,8 @@ html.codex-dream-skin.dream-riru-art .dream-sidebar-packet { } /* Quiet app bar and reading plane: no console rails or telemetry labels. */ -html.codex-dream-skin.dream-riru-art main.main-surface > header.app-header-tint, -html.codex-dream-skin.dream-riru-art.dream-art-wide main.main-surface > header.app-header-tint { +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), +html.codex-dream-skin.dream-riru-art.dream-art-wide main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) { border: 0 !important; border-bottom: 1px dashed color-mix(in oklab, var(--riru-blush) 22%, transparent) !important; background: color-mix(in oklab, var(--riru-moon-ink) 93%, transparent) !important; @@ -6623,17 +6623,17 @@ html.codex-dream-skin.dream-riru-art.dream-art-wide main.main-surface > header.a backdrop-filter: blur(10px) saturate(.9) !important; } -html.codex-dream-skin.dream-riru-art main.main-surface > header.app-header-tint::before, -html.codex-dream-skin.dream-riru-art main.main-surface > header.app-header-tint::after, -html.codex-dream-skin.dream-riru-art main.main-surface.dream-route-utility::before, -html.codex-dream-skin.dream-riru-art main.main-surface.dream-route-utility::after, -html.codex-dream-skin.dream-riru-art main.main-surface.dream-home-shell::before, -html.codex-dream-skin.dream-riru-art main.main-surface.dream-home-shell::after { +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::before, +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])::after, +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility::before, +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]).dream-route-utility::after, +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell::before, +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]).dream-home-shell::after { display: none !important; } html.codex-dream-skin.dream-riru-art.dream-art-wide:is(.dream-task-ambient, .dream-task-banner) - main.main-surface:not(.dream-home-shell) { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) { background: linear-gradient(90deg, color-mix(in oklab, var(--riru-moon-ink) 76%, transparent) 0%, @@ -6647,16 +6647,16 @@ html.codex-dream-skin.dream-riru-art.dream-art-wide:is(.dream-task-ambient, .dre still owns the wallpaper. Moonroom keeps one directional reading scrim above instead: dark under the left text column and open over the character. */ html.codex-dream-skin.dream-riru-art - main.main-surface.dream-task:not(.dream-home-shell)::after, + main:is(.main-surface, [data-app-shell-main-surface]).dream-task:not(.dream-home-shell)::after, html.codex-dream-skin.dream-riru-art - main.main-surface:not(.dream-home-shell) .dream-task::after { + main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell) .dream-task::after { content: none !important; display: none !important; backdrop-filter: none !important; } html.codex-dream-skin.dream-riru-art - main.main-surface.dream-route-task .thread-scroll-container { + main:is(.main-surface, [data-app-shell-main-surface]).dream-route-task .thread-scroll-container { text-shadow: 0 1px 2px var(--riru-moon-ink), 0 0 10px color-mix(in oklab, var(--riru-moon-ink) 88%, transparent); @@ -7005,14 +7005,14 @@ html.codex-dream-skin.dream-riru-art :where( display: none !important; } -html.codex-dream-skin.dream-riru-art main.main-surface aside { +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) aside { border-left: 1px dashed color-mix(in oklab, var(--riru-blush) 18%, transparent) !important; background: color-mix(in oklab, var(--riru-sweater) 78%, transparent) !important; box-shadow: -12px 0 32px color-mix(in oklab, #05040c 24%, transparent) !important; backdrop-filter: blur(4px) saturate(.92) !important; } -html.codex-dream-skin.dream-riru-art main.main-surface aside :where( +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) aside :where( [class~="bg-token-main-surface-primary"], [class~="bg-token-main-surface-secondary"] ) { @@ -7027,7 +7027,7 @@ html.codex-dream-skin.dream-riru-art .dream-side-workspace-brand { box-shadow: none !important; } -html.codex-dream-skin.dream-riru-art main.main-surface > header.app-header-tint button { +html.codex-dream-skin.dream-riru-art main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]) button { border-color: color-mix(in oklab, var(--riru-blush) 18%, transparent) !important; border-radius: 12px !important; box-shadow: none !important; @@ -7164,7 +7164,7 @@ html.codex-dream-skin.dream-riru-art :where( removing GPU-heavy glass and decorative motion. */ html.codex-dream-skin.dream-performance-lite.dream-riru-art :where( aside.app-shell-left-panel, - main.main-surface > header.app-header-tint, + main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll]), .composer-surface-chrome, .dream-home-utility, .dream-settings-surface, diff --git a/windows/assets/renderer-inject.js b/windows/assets/renderer-inject.js index fd1ef4d..ec1f14d 100644 --- a/windows/assets/renderer-inject.js +++ b/windows/assets/renderer-inject.js @@ -2,7 +2,7 @@ const STATE_KEY = "__CODEX_DREAM_SKIN_STATE__"; const STYLE_ID = "codex-dream-skin-style"; const PART_ATTR = "data-ds-part"; - const STYLE_REVISION = "9"; + const STYLE_REVISION = "10"; const SKIN_VERSION = __DREAM_SKIN_VERSION_JSON__; const PAYLOAD_REVISION = __DREAM_SKIN_PAYLOAD_REVISION_JSON__; const CHROME_ID = "codex-dream-skin-chrome"; @@ -11,6 +11,11 @@ const SIDE_WORKSPACE_BRAND_ID = "codex-dream-side-workspace-brand"; const NEW_TASK_CLASS = "dream-new-task-button"; const RIRU_UI_REVISION = "moonroom-2"; + const SHELL_MAIN_SELECTOR = "main:is(.main-surface, [data-app-shell-main-surface])"; + const SHELL_MAIN_ASIDE_SELECTOR = + "main:is(.main-surface, [data-app-shell-main-surface]) aside"; + const HEADER_SELECTOR = + "header:is(.app-header-tint, [data-app-shell-header-edge-scroll])"; const ROOT_CLASSES = [ "codex-dream-skin", "dream-theme-light", @@ -801,8 +806,8 @@ }; add("root", [document.documentElement]); add("sidebar", all("aside.app-shell-left-panel")); - add("main", all("main.main-surface")); - add("header", all("header.app-header-tint")); + add("main", all(SHELL_MAIN_SELECTOR)); + add("header", all(HEADER_SELECTOR)); add("home", all('[role="main"]:has([data-testid="home-icon"])')); add("project-list", all(".group\\/project-selector")); add("thread", all(".thread-scroll-container")); @@ -833,7 +838,7 @@ // it, and clearing the skin there flashes native colors over the active theme. // True auxiliary windows (pets, blank targets) still have no main surface, so // they continue to clear residual skin state. - const shellMain = document.querySelector("main.main-surface") || + const shellMain = document.querySelector(SHELL_MAIN_SELECTOR) || document.querySelector("main") || document.querySelector('[role="main"]'); const shellSidebar = document.querySelector("aside.app-shell-left-panel"); @@ -1283,7 +1288,7 @@ target.classList.toggle("dream-home-dual-panel", sideOpen && bottomOpen); } - const sideChatAside = [...document.querySelectorAll("main.main-surface aside")] + const sideChatAside = [...document.querySelectorAll(SHELL_MAIN_ASIDE_SELECTOR)] .find((candidate) => candidate.querySelector?.(".thread-scroll-container") && candidate.querySelector?.(".composer-surface-chrome")); const sideChatPanel = sideChatAside?.querySelector?.(':scope > [class*="contain:layout_paint"]') @@ -1582,7 +1587,7 @@ observer.disconnect(); const root = document.documentElement; const body = document.body; - const shellMain = document.querySelector("main.main-surface") || document.querySelector("main"); + const shellMain = document.querySelector(SHELL_MAIN_SELECTOR) || document.querySelector("main"); const attributeOptions = { attributes: true, attributeOldValue: true, @@ -1807,7 +1812,7 @@ if (geometryScheduler.frame) return; const sync = () => { geometryScheduler.frame = null; - const shellMain = document.querySelector("main.main-surface") || document.querySelector("main"); + const shellMain = document.querySelector(SHELL_MAIN_SELECTOR) || document.querySelector("main"); const home = shellMain?.classList?.contains?.("dream-home-shell") ? document.querySelector('[role="main"].dream-home') || shellMain : null; diff --git a/windows/assets/selectors.json b/windows/assets/selectors.json index 06e2223..3147031 100644 --- a/windows/assets/selectors.json +++ b/windows/assets/selectors.json @@ -2,10 +2,10 @@ "schema": "codex-dream-skin-selectors/1", "description": "双端统一选择器契约(初稿)。scope 与 required 均来自 2026-07-21 双端 DOM 快照实测,非猜测。doctor / CI 应逐条 querySelector 并按 tier 判级:L1 缺失=皮肤主行为受损,L2 缺失=精修静默降级。", "verifiedAgainst": { - "date": "2026-07-21", - "chromium": "150.0.7871.124", + "date": "2026-08-06", + "chromium": "150.0.7871.124 and 151.0.7922.71", "codexVersionMac": "26.715.61943", - "codexVersionWindows": "版本号未记录;bundle hash 与 mac 不同(ModelPickerTrigger mac=1fm6a win=1w4ob),确认存在版本错位", + "codexVersionWindows": "26.730.8199.0:主表面改为 data-app-shell-main-surface,标题栏改为 data-app-shell-header-edge-scroll;保留旧版类名作为兼容分支", "fixtures": [ "runtime/dom-fixtures/codex-dom-fixture-darwin-watch.json (15 状态)", "runtime/dom-fixtures/codex-dom-fixture-win32-watch.json (7 状态)" @@ -26,9 +26,9 @@ "config": "依赖用户配置才出现(如未配置项目则无项目选择器)" }, "selectors": [ - { "key": "shell-main", "selector": "main.main-surface", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。mac 设置页缺失(win 存在),缺失时整页仅 L0" }, + { "key": "shell-main", "selector": "main:is(.main-surface, [data-app-shell-main-surface])", "tier": "L1", "scope": "all", "required": true, "notes": "全局主表面。26.730+ 使用稳定 data-app-shell-main-surface;旧版保留 main-surface。使用 :is() 让同一契约安全用于 querySelector 与 CSS 模板。mac 设置页缺失时整页仅 L0" }, { "key": "left-panel", "selector": "aside.app-shell-left-panel", "tier": "L1", "scope": "all", "required": true, "notes": "左侧栏;收起/重建时会移除节点,勿在其消失时清皮" }, - { "key": "header-tint", "selector": "header.app-header-tint", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;皮肤不得覆盖其 position/z-index(既有回归约束)" }, + { "key": "header-tint", "selector": "header:is(.app-header-tint, [data-app-shell-header-edge-scroll])", "tier": "L1", "scope": "all", "required": true, "notes": "顶栏;26.730+ 使用稳定 data-app-shell-header-edge-scroll。使用 :is() 避免 CSS 模板中的逗号并集逃逸根作用域;皮肤不得覆盖其 position/z-index(既有回归约束)" }, { "key": "home-icon", "selector": "[data-testid=\"home-icon\"]", "tier": "L1", "scope": "home", "required": true, "notes": "首页判定信号,双端一致" }, { "key": "home-route", "selector": "[role=\"main\"]:has([data-testid=\"home-icon\"])", "tier": "L1", "scope": "home", "required": true, "notes": "首页容器。实测 [role=main] 仅存在于首页——它不是通用路由锚点,thread 页没有" }, { "key": "home-route-css", "selector": "[role=\"main\"]", "tier": "L1", "scope": "home", "required": true, "notes": "home-route 的 CSS 可组合别名:不含 :has()。CSS 禁止 :has() 嵌套,home-route 原选择器一旦写进 :has()/:not(:has()) 整条规则会被解析器丢弃(v1.3.1 全窗口首页与任务页氛围背景因此失效)。依据与 home-route 相同的实测:[role=main] 仅存在于首页;该锚点缺失时 CSS 路由门控整体失效,故必须按 L1 必需项监控" }, diff --git a/windows/scripts/injector.mjs b/windows/scripts/injector.mjs index 72d80a3..8bfd343 100644 --- a/windows/scripts/injector.mjs +++ b/windows/scripts/injector.mjs @@ -40,7 +40,7 @@ const stableTestidLiteral = (testid) => { } return JSON.stringify(`[data-testid="${testid}"]`); }; -const SKIN_VERSION = "1.6.0"; +const SKIN_VERSION = "1.6.1"; const INTERNET_ANGEL_EXTENSION_THEME_IDS = new Set([ "preset-internet-angel", "preset-internet-angel-default", diff --git a/windows/tests/home-responsive-css.test.mjs b/windows/tests/home-responsive-css.test.mjs index af2b411..e7fd879 100644 --- a/windows/tests/home-responsive-css.test.mjs +++ b/windows/tests/home-responsive-css.test.mjs @@ -61,10 +61,10 @@ assert.match(moonroom, /dream-angel-stage > :not\(\.dream-riru-room\)[\s\S]*?dis assert.match(moonroom, /dream-home-shell \.dream-riru-room\s*\{[\s\S]*?display:\s*block/); assert.match(moonroom, /@container angel-stage \(max-width: 900px\)[\s\S]*?dream-riru-room-note[\s\S]*?display:\s*none\s*!important/); assert.match(moonroom, /@media \(prefers-reduced-motion: reduce\)[\s\S]*?dream-riru-ribbon-loop[\s\S]*?animation:\s*none\s*!important/); -assert.match(moonroom, /main\.main-surface:not\(\.dream-home-shell\)\s*\{[\s\S]*?linear-gradient\(90deg[\s\S]*?var\(--riru-moon-ink\) 76%, transparent[\s\S]*?var\(--riru-moon-ink\) 8%, transparent/); -assert.match(moonroom, /main\.main-surface\.dream-task:not\(\.dream-home-shell\)::after,[\s\S]*?content:\s*none\s*!important[\s\S]*?display:\s*none\s*!important[\s\S]*?backdrop-filter:\s*none\s*!important/); -assert.match(moonroom, /main\.main-surface\.dream-route-task \.thread-scroll-container\s*\{[\s\S]*?text-shadow:/); -assert.match(moonroom, /main\.main-surface aside\s*\{[\s\S]*?var\(--riru-sweater\) 78%, transparent[\s\S]*?backdrop-filter:\s*blur\(4px\) saturate\(\.92\)/); +assert.match(moonroom, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\):not\(\.dream-home-shell\)\s*\{[\s\S]*?linear-gradient\(90deg[\s\S]*?var\(--riru-moon-ink\) 76%, transparent[\s\S]*?var\(--riru-moon-ink\) 8%, transparent/); +assert.match(moonroom, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\)\.dream-task:not\(\.dream-home-shell\)::after,[\s\S]*?content:\s*none\s*!important[\s\S]*?display:\s*none\s*!important[\s\S]*?backdrop-filter:\s*none\s*!important/); +assert.match(moonroom, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\)\.dream-route-task \.thread-scroll-container\s*\{[\s\S]*?text-shadow:/); +assert.match(moonroom, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\) aside\s*\{[\s\S]*?var\(--riru-sweater\) 78%, transparent[\s\S]*?backdrop-filter:\s*blur\(4px\) saturate\(\.92\)/); assert.match(moonroom, /#codex-dream-skin-presets\s*\{[\s\S]*?top:\s*100px\s*!important[\s\S]*?left:\s*20px\s*!important[\s\S]*?width:\s*min\(480px, calc\(100% - 40px\)\)\s*!important/); assert.match(moonroom, /\.dream-presets-grid\s*\{[\s\S]*?grid-template-columns:\s*repeat\(2, minmax\(0, 1fr\)\)\s*!important/); assert.match(moonroom, /\.group\\\/home-suggestions\s*\{[\s\S]*?width:\s*min\(480px, calc\(100% - 40px\)\)\s*!important[\s\S]*?margin-left:\s*20px\s*!important/); @@ -78,7 +78,7 @@ assert.notEqual(fallbackStart, -1, "side-workspace first-frame fallback marker i assert.notEqual(fallbackEnd, -1, "side-workspace fallback section has no stable end marker"); const fallbackSection = css.slice(fallbackStart, fallbackEnd); -assert.match(fallbackSection, /main\.main-surface aside > \[class\*="contain:layout_paint"\][\s\S]*?:has\(button kbd\)/); +assert.match(fallbackSection, /main:is\(\.main-surface, \[data-app-shell-main-surface\]\) aside > \[class\*="contain:layout_paint"\][\s\S]*?:has\(button kbd\)/); assert.match(fallbackSection, /:not\(:has\(\.xterm\)\):not\(:has\(\.thread-scroll-container\)\)/); assert.match(fallbackSection, /SIDE CHANNEL \/\/ RIRU RELAY/); assert.match(fallbackSection, /SIGNAL\s+072/); diff --git a/windows/tests/injector-bootstrap.test.mjs b/windows/tests/injector-bootstrap.test.mjs index 6bef5fc..725b010 100644 --- a/windows/tests/injector-bootstrap.test.mjs +++ b/windows/tests/injector-bootstrap.test.mjs @@ -33,8 +33,12 @@ function createFixture() { get body() { return body; }, addEventListener(type, callback) { if (type === "DOMContentLoaded") domReady.push(callback); }, querySelector(selector) { - if (selector === "main.main-surface") return markers.shell ? {} : null; - if (selector === "header.app-header-tint") return markers.header ? {} : null; + if (selector === "main:is(.main-surface, [data-app-shell-main-surface])") { + return markers.shell ? {} : null; + } + if (selector === "header:is(.app-header-tint, [data-app-shell-header-edge-scroll])") { + return markers.header ? {} : null; + } if (selector === "aside.app-shell-left-panel") return markers.sidebar ? {} : null; if (selector === ".composer-surface-chrome") return markers.composer ? {} : null; if (selector.includes("[role=\"main\"]")) return markers.main ? {} : null; diff --git a/windows/tests/injector-window-readiness.test.mjs b/windows/tests/injector-window-readiness.test.mjs index 2ac0252..b1a0ebe 100644 --- a/windows/tests/injector-window-readiness.test.mjs +++ b/windows/tests/injector-window-readiness.test.mjs @@ -17,7 +17,7 @@ const win32WindowEvidence = { }; const selectors = { - shell: "main.main-surface", + shell: "main:is(.main-surface, [data-app-shell-main-surface])", sidebar: "aside.app-shell-left-panel", composer: ".composer-surface-chrome", home: '[role="main"]:has([data-testid="home-icon"])', @@ -90,7 +90,7 @@ function makeDomFixture({ }; const window = { __CODEX_DREAM_SKIN_STATE__: { - version: "1.6.0", + version: "1.6.1", themeId: "fixture-theme", revision: "fixture-revision", styleMode: "style", diff --git a/windows/tests/renderer-inject.test.mjs b/windows/tests/renderer-inject.test.mjs index ee5691d..8fecb54 100644 --- a/windows/tests/renderer-inject.test.mjs +++ b/windows/tests/renderer-inject.test.mjs @@ -124,7 +124,7 @@ for (const panelClass of ["dream-terminal-panel", "dream-side-workspace", "dream ); } else if (panelClass === "dream-side-chat-panel") { assert.ok( - css.includes('main.main-surface aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome)'), + css.includes('main:is(.main-surface, [data-app-shell-main-surface]) aside > [class*="contain:layout_paint"]:has(.thread-scroll-container):has(.composer-surface-chrome)'), "A newly mounted side conversation must receive its background before renderer classification.", ); } else if (panelClass === "dream-summary-panel") { @@ -304,7 +304,7 @@ assert.ok(template.includes("const classifyRuntimeSurfaces = (records)") && template.includes("dream-composer-palette") && template.includes("dream-settings-menu"), "New portal surfaces must receive local first-frame classification without a full DOM scan."); -assert.ok(template.includes('const STYLE_REVISION = "9"') +assert.ok(template.includes('const STYLE_REVISION = "10"') && template.includes('existingStyle.dataset.dreamVersion = STYLE_REVISION') && !template.includes('existingStyle.dataset.dreamVersion = "3"'), "Reinjection must not parse and apply the full stylesheet twice for one refresh."); @@ -708,7 +708,9 @@ function createFixture({ }, getElementById(id) { return nodes.get(id) ?? null; }, querySelector(selector) { - if (selector === "main.main-surface") return hasMain ? shellMain : null; + if (selector === "main:is(.main-surface, [data-app-shell-main-surface])") { + return hasMain ? shellMain : null; + } if (selector === "main") return hasMain ? shellMain : null; if (selector === "aside.app-shell-left-panel") return hasSidebar ? {} : null; if (selector === '[role="main"]:has([data-testid="home-icon"])') { diff --git a/windows/tests/run-tests.ps1 b/windows/tests/run-tests.ps1 index 7e6041e..5c6942d 100644 --- a/windows/tests/run-tests.ps1 +++ b/windows/tests/run-tests.ps1 @@ -1197,7 +1197,7 @@ args = [ $css = Read-DreamSkinUtf8File -Path (Join-Path $Root 'assets\dream-skin.css') foreach ($requiredCss in @( 'background-image: var(--dream-art)', - 'main.main-surface > header.app-header-tint', + 'main:is(.main-surface, [data-app-shell-main-surface]) > header:is(.app-header-tint, [data-app-shell-header-edge-scroll])', '[class~="group/application-menu-top-bar"]', '.app-shell-main-content-top-fade', '.thread-scroll-container .bg-gradient-to-t.from-token-main-surface-primary', @@ -1209,7 +1209,7 @@ args = [ '.dream-summary-panel', '.xterm-selection-layer', ':has(.dream-home-utility) .composer-surface-chrome', - ':is(.dream-task-ambient, .dream-task-banner):has(main.main-surface:not(.dream-home-shell))' + ':is(.dream-task-ambient, .dream-task-banner):has(main:is(.main-surface, [data-app-shell-main-surface]):not(.dream-home-shell))' )) { if (-not $css.Contains($requiredCss)) { throw "Windows immersive CSS is missing: $requiredCss" } } From 9db91422b36bca04582f1195f05e25c8bb938290 Mon Sep 17 00:00:00 2001 From: CHOCK1337 <122972648+CHOCK1337@users.noreply.github.com> Date: Thu, 6 Aug 2026 02:58:59 +0800 Subject: [PATCH 2/2] fix(windows): preserve guardian state paths cross-platform --- windows/scripts/injector.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/scripts/injector.mjs b/windows/scripts/injector.mjs index 8bfd343..e980cd0 100644 --- a/windows/scripts/injector.mjs +++ b/windows/scripts/injector.mjs @@ -305,7 +305,7 @@ export function buildUpdateGuardianLaunch(options, environment = process.env) { "-File", path.join(root, "scripts", "update-guardian.ps1"), "-StatePath", - path.resolve(options.stateFile), + path.win32.resolve(options.stateFile), "-ExpectedBrowserId", options.browserId, "-Port",