Skip to content

Commit 4423fe9

Browse files
committed
Merge main and resolve conflicts
2 parents 829896b + e776fa6 commit 4423fe9

15 files changed

Lines changed: 886 additions & 76 deletions

File tree

.github/workflows/ci.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,25 @@ jobs:
114114
- name: Run Windows regression suite
115115
shell: cmd
116116
run: ${{ matrix.executable }} -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\windows\tests\run-tests.ps1
117+
118+
macos-tests:
119+
name: macOS repository regressions
120+
runs-on: macos-latest
121+
steps:
122+
- uses: actions/checkout@v4
123+
- uses: actions/setup-node@v4
124+
with:
125+
node-version: "22"
126+
127+
- name: Locate runner Node.js
128+
id: node
129+
shell: bash
130+
run: echo "path=$(command -v node)" >> "$GITHUB_OUTPUT"
131+
132+
- name: Run macOS regressions without installed-app checks
133+
shell: bash
134+
env:
135+
NODE: ${{ steps.node.outputs.path }}
136+
CODEX_DREAM_SKIN_SKIP_SIGNED_RUNTIME_TESTS: "1"
137+
CODEX_DREAM_SKIN_SKIP_DOCTOR: "1"
138+
run: ./macos/tests/run-tests.sh

docs/platforms.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ Windows 启动、失败回滚与恢复重开均从已注册的 `OpenAI.Codex`
7575
### 平台差异
7676

7777
- macOS 的选图脚本会把这些字段写入主题库,可通过 `--appearance``--focus-x``--focus-y``--safe-area``--task-mode` 设置。
78-
- Windows 安装会把运行所需的 `assets/``scripts/` 原子复制到 `%LOCALAPPDATA%\CodexDreamSkin\engine`,所有快捷方式均指向该受管副本,因此安装后可移动或删除源码目录。安装还会初始化 `active-theme``themes``images`,并把「桥本有菜」同时设为首次默认和可切换的已保存主题。系统托盘支持更换背景、保存当前主题、从「已保存主题」切换、暂停和恢复;图片与 `theme.json` 保存在主题仓库中,不写进 Codex 的 `config.toml`。安装会保留用户已有的 `appearanceTheme`;仅在识别到旧版精确托管的浅色三元组时按备份迁移。
78+
- Windows 安装会把运行所需的 `assets/``scripts/` 原子复制到 `%LOCALAPPDATA%\CodexDreamSkin\engine`,所有快捷方式均指向该受管副本,因此安装后可移动或删除源码目录。安装还会初始化 `active-theme``themes``images`,并把「桥本有菜」设为首次默认活动主题,同时把「桥本有菜」与「Gothic Void Crusade / 哥特虚空远征」播种为可切换的已保存主题。系统托盘支持更换背景、保存当前主题、从「已保存主题」切换、暂停和恢复;图片与 `theme.json` 保存在主题仓库中,不写进 Codex 的 `config.toml`。安装会保留用户已有的 `appearanceTheme`;仅在识别到旧版精确托管的浅色三元组时按备份迁移。
7979
- Windows 渲染器仍支持在注入前用 `window.__CODEX_DREAM_SKIN_CONFIG__` 提供内存级可选覆盖(形状同上,颜色覆盖使用 `palette.accent`),但普通用户应优先使用持久化主题仓库与托盘。
8080

8181
## 预设与图片类型
8282

8383
- `macos/presets/preset-arina-hashimoto/` 是置顶的实测精选主题「桥本有菜 / Arina Hashimoto」。macOS 安装后用 `switch-theme-macos.sh --id preset-arina-hashimoto` 切换。
8484
- 该 preset pack 中只有 `background.jpg``2560 × 1440`、16:9、纯背景)和 `theme.json` 会被播种;它由用户提供的 `1672 × 941` 源 PNG 标准化导出,不代表增加了源图细节。Byte-identical 源图归档在 `docs/images/presets/arina-hashimoto-source.png`,不会随 preset 播种;`arina-hashimoto-light.jpg``arina-hashimoto-dark.jpg``2308 × 1572` Retina 浅/暗真实首页截图,未发送输入仅在截图时用临时本地样式遮蔽,只作效果预览,绝不能当背景导入。
8585
- `macos/presets/preset-gothic-void-crusade/` 是社区作者贡献的原创哥特科幻主题;macOS 没有活动主题时默认启用它。升级只清理固定的旧内置预设 ID,不删除 `custom-*` 或当前活动主题副本。
86-
- Windows 自带与 macOS byte-identical 的 `windows/assets/dream-reference.jpg` 纯背景,并在首次初始化时播种「桥本有菜」;可直接从「已保存主题 → 桥本有菜」切换。README 实机截图仍只作预览,绝不能作为背景导入。
86+
- Windows 自带与 macOS byte-identical 的 `windows/assets/dream-reference.jpg` 纯背景,并在首次初始化时播种「桥本有菜」与「Gothic Void Crusade」;可直接从「已保存主题」切换。README 实机截图仍只作预览,绝不能作为背景导入。
8787
- Windows 导入和 macOS 快速加载入口会拒绝空文件或超过 16 MB 的输入;macOS 主定制入口可接收最高 50 MB 的源图,但转换后的主题文件必须不超过 16 MB。两端 payload 构建还会拒绝任一边超过 16384px 或总像素超过 50MP 的声明尺寸;Windows 在复制导入图前复用 Node 元数据解析器执行同一限制。Windows 注入器用图片与主题内容的 SHA-256 修订值识别热更新,并在构建首帧 payload 前同步读取图片比例。
8888
- 自定义生图优先使用 `2560 × 1440`(16:9):左侧约 50%~58% 保持低信息、低对比,主体放在右侧约 58%~88%。输出必须是连续铺满画布的纯背景,禁止窗口、侧栏、卡片、输入框、文字、Logo 和水印。
8989
- 可直接复制的无人物、右侧成年人物与参考图编辑模板见 `docs/reference-background-prompt-guide.md`;公共默认提示词不指定真人或名人。

macos/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### 改进
6+
7+
- 菜单栏在 `paused` 状态显示「继续显示皮肤」(调用现有应用入口),与 Windows 托盘暂停/继续文案和语义对齐;运行中仍为「重新应用皮肤」+「暂停皮肤」。
8+
39
## 1.2.0 — 2026-07-17
410

511
### 新增

macos/menubar/codex_dream_skin.10s.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,14 @@ case "$OPERATION_LINE" in
129129
*)
130130
case "$SESSION_LINE" in
131131
active)
132+
# Same pair as Windows tray when running: re-apply + pause (live remove).
132133
echo "重新应用皮肤 | bash=\"$APPLY\" terminal=false refresh=true"
133134
echo "暂停皮肤 | bash=\"$PAUSE\" terminal=false refresh=true"
134135
;;
136+
paused)
137+
# Same resume affordance as Windows tray "继续显示皮肤": clear pause and apply.
138+
echo "继续显示皮肤 | bash=\"$APPLY\" terminal=false refresh=true"
139+
;;
135140
stale|unknown)
136141
echo "修复并应用 | bash=\"$APPLY\" terminal=false refresh=true"
137142
;;

macos/tests/run-tests.sh

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -201,34 +201,42 @@ fi
201201
[ "$seeded" -eq 2 ] || exit 1
202202
' _ "$ROOT"
203203

204-
# Theme switches stage files and publish theme.json last, preserving a complete
205-
# active pack while the watcher is running.
206-
SWITCH_HOME="$TMP/switch-home"
207-
SWITCH_STATE="$SWITCH_HOME/Library/Application Support/CodexDreamSkinStudio"
208-
/bin/mkdir -p "$SWITCH_STATE/themes/preset-switch-fixture" "$SWITCH_STATE/theme"
209-
/bin/cp "$ROOT/assets/portal-hero.png" "$SWITCH_STATE/themes/preset-switch-fixture/background.png"
210-
/usr/bin/printf '%s\n' \
211-
'{"schemaVersion":1,"id":"preset-switch-fixture","name":"切换测试","image":"background.png"}' \
212-
> "$SWITCH_STATE/themes/preset-switch-fixture/theme.json"
213-
/usr/bin/printf '%s\n' '{"schemaVersion":1,"id":"old","name":"旧主题","image":"old.png"}' \
214-
> "$SWITCH_STATE/theme/theme.json"
215-
: > "$SWITCH_STATE/theme/old.png"
216-
if /usr/bin/env HOME="$SWITCH_HOME" NODE="$NODE" \
217-
"$ROOT/scripts/switch-theme-macos.sh" --id '../escape' --no-apply >/dev/null 2>&1; then
218-
printf 'switch-theme unexpectedly accepted a path traversal theme id.\n' >&2
219-
exit 1
204+
run_signed_runtime_switch_test() {
205+
local switch_home="$TMP/switch-home"
206+
local switch_state="$switch_home/Library/Application Support/CodexDreamSkinStudio"
207+
/bin/mkdir -p "$switch_state/themes/preset-switch-fixture" "$switch_state/theme"
208+
/bin/cp "$ROOT/assets/portal-hero.png" "$switch_state/themes/preset-switch-fixture/background.png"
209+
/usr/bin/printf '%s\n' \
210+
'{"schemaVersion":1,"id":"preset-switch-fixture","name":"切换测试","image":"background.png"}' \
211+
> "$switch_state/themes/preset-switch-fixture/theme.json"
212+
/usr/bin/printf '%s\n' '{"schemaVersion":1,"id":"old","name":"旧主题","image":"old.png"}' \
213+
> "$switch_state/theme/theme.json"
214+
: > "$switch_state/theme/old.png"
215+
if /usr/bin/env HOME="$switch_home" NODE="$NODE" \
216+
"$ROOT/scripts/switch-theme-macos.sh" --id '../escape' --no-apply >/dev/null 2>&1; then
217+
printf 'switch-theme unexpectedly accepted a path traversal theme id.\n' >&2
218+
exit 1
219+
fi
220+
/usr/bin/env HOME="$switch_home" NODE="$NODE" \
221+
"$ROOT/scripts/switch-theme-macos.sh" --id preset-switch-fixture --no-apply >/dev/null
222+
/usr/bin/cmp -s "$switch_state/theme/background.png" \
223+
"$switch_state/themes/preset-switch-fixture/background.png"
224+
[ ! -e "$switch_state/theme/old.png" ]
225+
"$NODE" -e '
226+
const fs = require("fs");
227+
const theme = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
228+
if (theme.id !== "preset-switch-fixture" || theme.name !== "切换测试") process.exit(1);
229+
' "$switch_state/theme/theme.json"
230+
[ -z "$(/usr/bin/find "$switch_state" -maxdepth 1 -name '.theme-switch.*' -print -quit)" ]
231+
}
232+
233+
if [ "${CODEX_DREAM_SKIN_SKIP_SIGNED_RUNTIME_TESTS:-0}" = "1" ]; then
234+
printf 'SKIP: switch-theme integration requires an installed, signed Codex app.\n'
235+
SWITCH_RUNTIME_RESULT="skipped"
236+
else
237+
run_signed_runtime_switch_test
238+
SWITCH_RUNTIME_RESULT="passed"
220239
fi
221-
/usr/bin/env HOME="$SWITCH_HOME" NODE="$NODE" \
222-
"$ROOT/scripts/switch-theme-macos.sh" --id preset-switch-fixture --no-apply >/dev/null
223-
/usr/bin/cmp -s "$SWITCH_STATE/theme/background.png" \
224-
"$SWITCH_STATE/themes/preset-switch-fixture/background.png"
225-
[ ! -e "$SWITCH_STATE/theme/old.png" ]
226-
"$NODE" -e '
227-
const fs = require("fs");
228-
const theme = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
229-
if (theme.id !== "preset-switch-fixture" || theme.name !== "切换测试") process.exit(1);
230-
' "$SWITCH_STATE/theme/theme.json"
231-
[ -z "$(/usr/bin/find "$SWITCH_STATE" -maxdepth 1 -name '.theme-switch.*' -print -quit)" ]
232240

233241
RUNTIME_HOME="$TMP/runtime-home"
234242
RUNTIME_STATE_ROOT="$RUNTIME_HOME/Library/Application Support/CodexDreamSkinStudio"
@@ -296,6 +304,7 @@ UNTRUSTED_TEAM_ID="TEAM'ID"
296304
if pid_is_codex_executable "$$" || pid_is_codex_descendant "$$"; then exit 1; fi
297305
' _ "$ROOT"
298306

307+
run_signed_runtime_state_tests() {
299308
# A reused live PID must never be killed or treated as a successfully stopped
300309
# injector when its command identity does not match the recorded watcher.
301310
STOP_HOME="$TMP/stop-home"
@@ -488,6 +497,15 @@ for state_payload in '{' '{}'; do
488497
' _ "$ROOT" "$TEST_INJECTOR_JOB_LABEL"
489498
/usr/bin/cmp -s "$STOP_STATE_ROOT/state.json" "$STOP_STATE_ROOT/state.original"
490499
done
500+
}
501+
502+
if [ "${CODEX_DREAM_SKIN_SKIP_SIGNED_RUNTIME_TESTS:-0}" = "1" ]; then
503+
printf 'SKIP: runtime-state integration requires an installed, signed Codex app.\n'
504+
RUNTIME_STATE_RESULT="skipped"
505+
else
506+
run_signed_runtime_state_tests
507+
RUNTIME_STATE_RESULT="passed"
508+
fi
491509

492510
/bin/mkdir -p "$TMP/theme"
493511
/bin/cp "$ROOT/assets/portal-hero.png" "$TMP/theme/background.png"
@@ -821,6 +839,14 @@ CRLF_BACKUP="$TMP/config-crlf-backup.json"
821839
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$CRLF_CONFIG" "$CRLF_BACKUP" >/dev/null
822840
/usr/bin/cmp -s "$CRLF_CONFIG" "$TMP/original-crlf.toml"
823841

824-
/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "$(/bin/cat "$ROOT/VERSION" 2>/dev/null | /usr/bin/tr -d '\''\n\r'\'')" ]' _ "$ROOT""$ROOT/scripts/doctor-macos.sh" >/dev/null
842+
/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "$(/bin/cat "$ROOT/VERSION" 2>/dev/null | /usr/bin/tr -d '\''\n\r'\'')" ]' _ "$ROOT"
843+
if [ "${CODEX_DREAM_SKIN_SKIP_DOCTOR:-0}" = "1" ]; then
844+
printf 'SKIP: Doctor requires an installed, signed Codex app.\n'
845+
DOCTOR_RESULT="skipped"
846+
else
847+
"$ROOT/scripts/doctor-macos.sh" >/dev/null
848+
DOCTOR_RESULT="passed"
849+
fi
825850

826-
printf 'PASS: syntax, payload, bundled presets, preset seeding, runtime-state safety, custom-theme, config round-trips, HOME recovery, signature, and doctor checks.\n'
851+
printf 'PASS: syntax, payload, bundled presets, preset seeding, runtime-state safety, custom-theme, config round-trips, HOME recovery, signature, switch-theme signed runtime %s, runtime-state integration %s, and Doctor %s.\n' \
852+
"$SWITCH_RUNTIME_RESULT" "$RUNTIME_STATE_RESULT" "$DOCTOR_RESULT"

windows/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Windows Changelog
22

3+
## Unreleased
4+
5+
### 修复
6+
7+
- 收起或重建左侧栏时不再因找不到 `aside.app-shell-left-panel` 而整页卸掉皮肤;只要主内容壳层仍在就继续应用当前主题,避免闪回 Codex 原生配色。透明辅助窗口仍会清理残留样式。
8+
- 托盘「暂停皮肤」现在与 macOS 一致:写入暂停标记后立刻通过 CDP 执行 `injector --remove` 卸下当前窗口皮肤,不再只等 watcher 轮询;「继续显示皮肤」会清除暂停并重新应用。
9+
- Windows 注入器补齐与 macOS 相同的窗口内操作浮层(loading / 成功 / 失败);暂停、继续与重新应用时在 Codex 主区显示「正在暂停皮肤…」「正在应用皮肤…」等进度,不再只有托盘气泡。
10+
- 安装/主题库初始化会把 macOS 同款「Gothic Void Crusade / 哥特虚空远征」播种到已保存主题(`presets/preset-gothic-void-crusade`),可与「桥本有菜」一并在托盘切换;默认活动主题仍为桥本有菜。
11+
312
## 1.2.0 — 2026-07-17
413

514
### 新增

windows/assets/renderer-inject.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,15 @@
326326
const root = document.documentElement;
327327
if (!root || !document.body) return;
328328

329-
const shellMain = document.querySelector("main.main-surface");
330-
const shellSidebar = document.querySelector("aside.app-shell-left-panel");
331-
if (!shellMain || !shellSidebar) {
329+
// Main Codex shell is the content surface. The left rail is optional: Codex
330+
// removes or rebuilds aside.app-shell-left-panel while collapsing/expanding
331+
// it, and clearing the skin there flashes native colors over the active theme.
332+
// True auxiliary windows (pets, blank targets) still have no main surface, so
333+
// they continue to clear residual skin state.
334+
const shellMain = document.querySelector("main.main-surface") ||
335+
document.querySelector("main") ||
336+
document.querySelector('[role="main"]');
337+
if (!shellMain) {
332338
clearSkinDom();
333339
return;
334340
}
@@ -348,7 +354,9 @@
348354
}
349355

350356
const home = document.querySelector('[role="main"]:has([data-testid="home-icon"])');
351-
for (const candidate of document.querySelectorAll('[role="main"]')) {
357+
const mainCandidates = [...document.querySelectorAll('[role="main"]')];
358+
if (!mainCandidates.length) mainCandidates.push(shellMain);
359+
for (const candidate of mainCandidates) {
352360
candidate.classList.toggle("dream-home", candidate === home);
353361
candidate.classList.toggle("dream-task", candidate !== home);
354362
}
788 KB
Loading
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"schemaVersion": 1,
3+
"id": "preset-gothic-void-crusade",
4+
"name": "Gothic Void Crusade",
5+
"brandSubtitle": "CODEX DREAM SKIN",
6+
"tagline": "A solemn cathedral-world horizon for focused work.",
7+
"projectPrefix": "Select project · ",
8+
"projectLabel": "◉ Select project",
9+
"statusText": "VOID CRUSADE ONLINE",
10+
"quote": "MAKE SOMETHING WONDERFUL",
11+
"image": "background.jpg",
12+
"appearance": "auto",
13+
"art": {
14+
"focusX": 0.76,
15+
"focusY": 0.45,
16+
"safeArea": "left",
17+
"taskMode": "ambient"
18+
},
19+
"colors": {
20+
"background": "#0d0d0e",
21+
"panel": "#171513",
22+
"panelAlt": "#211d18",
23+
"accent": "#c8a55a",
24+
"accentAlt": "#e3c27a",
25+
"secondary": "#74352e",
26+
"highlight": "#8a2f27",
27+
"text": "#f3ead7",
28+
"muted": "#b5a386",
29+
"line": "rgba(200, 165, 90, .28)"
30+
},
31+
"promoTitle": "Codex Dream Skin",
32+
"promoSub": "Gothic Void Crusade",
33+
"promoUrl": "https://github.com/Fei-Away/Codex-Dream-Skin"
34+
}

windows/scripts/common-windows.ps1

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ function Install-DreamSkinRuntimeEngine {
130130
'assets\dream-skin.css',
131131
'assets\renderer-inject.js',
132132
'assets\theme.json',
133+
'presets\preset-gothic-void-crusade\background.jpg',
134+
'presets\preset-gothic-void-crusade\theme.json',
133135
'scripts\common-windows.ps1',
134136
'scripts\config-utf8.ps1',
135137
'scripts\image-metadata.mjs',
@@ -146,7 +148,8 @@ function Install-DreamSkinRuntimeEngine {
146148
throw "Dream Skin runtime source is incomplete: $relative"
147149
}
148150
}
149-
foreach ($directoryName in @('assets', 'scripts')) {
151+
$runtimeDirectories = @('assets', 'scripts', 'presets')
152+
foreach ($directoryName in $runtimeDirectories) {
150153
$sourceDirectory = Join-Path $sourceRoot $directoryName
151154
if ((Test-DreamSkinPathEqual -Left $fullStateRoot -Right $sourceDirectory) -or
152155
(Test-DreamSkinPathWithin -Path $fullStateRoot -Root $sourceDirectory)) {
@@ -162,7 +165,7 @@ function Install-DreamSkinRuntimeEngine {
162165
Ensure-DreamSkinManagedDirectory -Path $stagingRoot -Root $fullStateRoot
163166

164167
try {
165-
foreach ($directoryName in @('assets', 'scripts')) {
168+
foreach ($directoryName in $runtimeDirectories) {
166169
Copy-Item -LiteralPath (Join-Path $sourceRoot $directoryName) -Destination $stagingRoot `
167170
-Recurse -Force -ErrorAction Stop
168171
}
@@ -174,13 +177,17 @@ function Install-DreamSkinRuntimeEngine {
174177
}
175178

176179
$sourcePrefix = $sourceRoot.TrimEnd('\') + '\'
180+
$sourceTrees = @(
181+
foreach ($directoryName in $runtimeDirectories) { Join-Path $sourceRoot $directoryName }
182+
)
183+
$stagedTrees = @(
184+
foreach ($directoryName in $runtimeDirectories) { Join-Path $stagingRoot $directoryName }
185+
)
177186
$sourceFiles = @(
178-
Get-ChildItem -LiteralPath (Join-Path $sourceRoot 'assets'), (Join-Path $sourceRoot 'scripts') `
179-
-Recurse -File -Force -ErrorAction Stop
187+
Get-ChildItem -LiteralPath $sourceTrees -Recurse -File -Force -ErrorAction Stop
180188
)
181189
$stagedFiles = @(
182-
Get-ChildItem -LiteralPath (Join-Path $stagingRoot 'assets'), (Join-Path $stagingRoot 'scripts') `
183-
-Recurse -File -Force -ErrorAction Stop
190+
Get-ChildItem -LiteralPath $stagedTrees -Recurse -File -Force -ErrorAction Stop
184191
)
185192
if ($sourceFiles.Count -ne $stagedFiles.Count) {
186193
throw 'Staged Dream Skin runtime file count does not match its source.'

0 commit comments

Comments
 (0)