Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions macos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
### 修复

- 首页建议卡片的文字节点显式跟随主题正文色,避免 Codex 浅色模式的原生文字 token 覆盖深色主题并显示成近黑色;实时验证器会在卡片可见时核对实际文字颜色。
- 当前版本没有计划写入外观键时,macOS 安装不再解析或备份 `config.toml` 的 TOML 结构。包含多行 MCP `args` 或多行字符串的配置可以原样安装,旧备份的恢复流程仍保留严格检查。
- 保留 Codex 原生固定顶栏的定位与层级,避免打开任务侧边面板后开关被推出主区、导致面板无法关闭。
- 修复亮色背景图在 ChatGPT/Codex 暗色模式下错误生成浅色皮肤壳的问题。`appearance=auto` 现在跟随原生/系统外观,避免白字叠在浅色面板上导致界面不可读。
- 修复从“设置 > 外观”返回“已安排的任务”等无输入框路由后,验证器因找不到 composer 而拒绝合法 Codex 主界面的问题。
Expand Down
18 changes: 16 additions & 2 deletions macos/scripts/theme-config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import path from "node:path";
import { randomUUID } from "node:crypto";

const [mode, configPath, backupPath] = process.argv.slice(2);
// Backup these keys so Restore can put them back. Do NOT force dark —
// Dream Skin CSS auto-adapts to light/dark via data-dream-shell.
// Non-null entries are managed settings that install must back up for Restore.
// Keep these null because Dream Skin auto-adapts via data-dream-shell.
const settings = new Map([
["appearanceTheme", null],
["appearanceDarkCodeThemeId", null],
Expand Down Expand Up @@ -229,6 +229,20 @@ async function main() {
if (originalStat.isSymbolicLink() || !originalStat.isFile()) {
throw new Error("Codex config must be a regular file, not a symbolic link.");
}
const hasPlannedSettingWrites = [...settings.values()].some((line) => line !== null);
if (!hasPlannedSettingWrites) {
if (mode === "install") {
console.log("Left Codex appearance settings unchanged; no config backup was needed.");
return;
}
try {
await fs.access(backupPath);
} catch (error) {
if (error.code !== "ENOENT") throw error;
console.log("No selective theme backup is available; config.toml was left unchanged.");
return;
}
}
if (content.includes('"""') || content.includes("'''")) {
throw new Error("Refusing to rewrite TOML containing multiline strings.");
}
Expand Down
99 changes: 89 additions & 10 deletions macos/tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -700,21 +700,59 @@ BACKUP="$TMP/theme-backup.json"
/bin/cp "$CONFIG" "$TMP/original.toml"
"$NODE" "$ROOT/scripts/theme-config.mjs" install "$CONFIG" "$BACKUP" >/dev/null
/usr/bin/cmp -s "$CONFIG" "$TMP/original.toml"
[ ! -e "$BACKUP" ]
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$CONFIG" "$BACKUP" >/dev/null
/usr/bin/cmp -s "$CONFIG" "$TMP/original.toml"

# Backups from releases that managed appearance keys must still restore through
# the strict parser and disappear only after a successful round trip.
"$NODE" -e '
const backup = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
if (backup.values.appearanceTheme !== `appearanceTheme = "system"`) process.exit(1);
if (backup.values.appearanceDarkCodeThemeId !== `appearanceDarkCodeThemeId = "vscode-dark"`) process.exit(1);
' "$BACKUP"
const fs = require("node:fs");
const [file, configPath] = process.argv.slice(1);
fs.writeFileSync(file, `${JSON.stringify({
schemaVersion: 1,
platform: "darwin",
configPath,
values: {
appearanceTheme: `appearanceTheme = "system"`,
appearanceDarkCodeThemeId: `appearanceDarkCodeThemeId = "vscode-dark"`,
},
}, null, 2)}\n`);
' "$BACKUP" "$CONFIG"
/usr/bin/printf '%s\n' \
'model = "gpt-5"' \
'project = "中文项目"' \
'' \
'[desktop]' \
'appearanceTheme = "dark"' \
'appearanceDarkCodeThemeId = "monokai"' \
'keepMe = true' > "$CONFIG"
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$CONFIG" "$BACKUP" >/dev/null
/usr/bin/cmp -s "$CONFIG" "$TMP/original.toml"
[ ! -e "$BACKUP" ]

write_null_theme_backup() {
local backup="$1"
local config="$2"
"$NODE" -e '
const fs = require("node:fs");
const [file, configPath] = process.argv.slice(1);
fs.writeFileSync(file, `${JSON.stringify({
schemaVersion: 1,
platform: "darwin",
configPath,
values: { appearanceTheme: null, appearanceDarkCodeThemeId: null },
}, null, 2)}\n`);
' "$backup" "$config"
}

assert_theme_config_restore_rejected() {
local label="$1"
local config="$2"
local backup="$3"
/bin/cp "$config" "$config.original"
if "$NODE" "$ROOT/scripts/theme-config.mjs" restore "$config" "$backup" >/dev/null 2>&1; then
printf 'theme-config unexpectedly accepted invalid %s backup.\n' "$label" >&2
printf 'theme-config unexpectedly accepted unsafe %s restore.\n' "$label" >&2
exit 1
fi
/usr/bin/cmp -s "$config" "$config.original"
Expand Down Expand Up @@ -752,6 +790,7 @@ NO_DESKTOP_BACKUP="$TMP/theme-backup-without-desktop.json"
"$NODE" "$ROOT/scripts/theme-config.mjs" install "$NO_DESKTOP_CONFIG" "$NO_DESKTOP_BACKUP" >/dev/null
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$NO_DESKTOP_CONFIG" "$NO_DESKTOP_BACKUP" >/dev/null
/usr/bin/cmp -s "$NO_DESKTOP_CONFIG" "$TMP/original-without-desktop.toml"
[ ! -e "$NO_DESKTOP_BACKUP" ]

INVALID_UTF_CONFIG="$TMP/config-invalid-utf8.toml"
INVALID_UTF_BACKUP="$TMP/config-invalid-utf8-backup.json"
Expand All @@ -763,6 +802,11 @@ if "$NODE" "$ROOT/scripts/theme-config.mjs" install \
printf 'theme-config unexpectedly accepted invalid UTF-8.\n' >&2
exit 1
fi
if "$NODE" "$ROOT/scripts/theme-config.mjs" restore \
"$INVALID_UTF_CONFIG" "$INVALID_UTF_BACKUP" >/dev/null 2>&1; then
printf 'theme-config restore unexpectedly accepted invalid UTF-8.\n' >&2
exit 1
fi
/usr/bin/cmp -s "$INVALID_UTF_CONFIG" "$TMP/original-invalid-utf8.toml"
[ ! -e "$INVALID_UTF_BACKUP" ]
[ ! -e "$INVALID_UTF_CONFIG.dream-skin.lock" ]
Expand All @@ -776,11 +820,28 @@ assert_theme_config_install_rejected() {
printf 'theme-config unexpectedly accepted invalid %s config.\n' "$label" >&2
exit 1
fi
if "$NODE" "$ROOT/scripts/theme-config.mjs" restore "$config" "$backup" >/dev/null 2>&1; then
printf 'theme-config restore unexpectedly accepted invalid %s config.\n' "$label" >&2
exit 1
fi
/usr/bin/cmp -s "$config" "$config.original"
[ ! -e "$backup" ]
[ ! -e "$config.dream-skin.lock" ]
}

assert_theme_config_install_noop() {
local label="$1"
local config="$2"
local backup="$3"
/bin/cp "$config" "$config.original"
"$NODE" "$ROOT/scripts/theme-config.mjs" install "$config" "$backup" >/dev/null
/usr/bin/cmp -s "$config" "$config.original"
[ ! -e "$backup" ]
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$config" "$backup" >/dev/null
/usr/bin/cmp -s "$config" "$config.original"
[ ! -e "$config.dream-skin.lock" ]
}

SYMLINK_CONFIG_TARGET="$TMP/config-symlink-target.toml"
SYMLINK_CONFIG_PATH="$TMP/config-symlink.toml"
/usr/bin/printf '%s\n' '[desktop]' 'appearanceTheme = "system"' > "$SYMLINK_CONFIG_TARGET"
Expand All @@ -798,20 +859,37 @@ assert_theme_config_install_rejected nul "$NUL_CONFIG" "$TMP/config-nul-backup.j
DUPLICATE_DESKTOP_CONFIG="$TMP/config-duplicate-desktop.toml"
/usr/bin/printf '%s\n' '[desktop]' 'keep = 1' '[desktop]' 'keep = 2' \
> "$DUPLICATE_DESKTOP_CONFIG"
assert_theme_config_install_rejected duplicate-desktop "$DUPLICATE_DESKTOP_CONFIG" \
assert_theme_config_install_noop duplicate-desktop "$DUPLICATE_DESKTOP_CONFIG" \
"$TMP/config-duplicate-desktop-backup.json"

MULTILINE_CONFIG="$TMP/config-multiline.toml"
/usr/bin/printf '%s\n' 'note = """value' 'continued"""' '[desktop]' 'keep = true' \
> "$MULTILINE_CONFIG"
assert_theme_config_install_rejected multiline "$MULTILINE_CONFIG" \
"$TMP/config-multiline-backup.json"
MULTILINE_BACKUP="$TMP/config-multiline-backup.json"
assert_theme_config_install_noop multiline "$MULTILINE_CONFIG" "$MULTILINE_BACKUP"

PRESERVED_BACKUP="$TMP/config-preserved-backup.json"
write_null_theme_backup "$PRESERVED_BACKUP" "$MULTILINE_CONFIG"
/bin/cp "$PRESERVED_BACKUP" "$PRESERVED_BACKUP.original"
"$NODE" "$ROOT/scripts/theme-config.mjs" install \
"$MULTILINE_CONFIG" "$PRESERVED_BACKUP" >/dev/null
/usr/bin/cmp -s "$PRESERVED_BACKUP" "$PRESERVED_BACKUP.original"

MULTILINE_ARRAY_CONFIG="$TMP/config-multiline-array.toml"
/usr/bin/printf '%s\n' '[desktop]' 'rows = [' ' ["one", "two"],' ']' \
'appearanceTheme = "system"' > "$MULTILINE_ARRAY_CONFIG"
assert_theme_config_install_rejected multiline-array "$MULTILINE_ARRAY_CONFIG" \
"$TMP/config-multiline-array-backup.json"
MULTILINE_ARRAY_BACKUP="$TMP/config-multiline-array-backup.json"
assert_theme_config_install_noop multiline-array \
"$MULTILINE_ARRAY_CONFIG" "$MULTILINE_ARRAY_BACKUP"

write_null_theme_backup "$MULTILINE_BACKUP" "$MULTILINE_CONFIG"
assert_theme_config_restore_rejected multiline-layout "$MULTILINE_CONFIG" \
"$MULTILINE_BACKUP"
/bin/rm -f "$MULTILINE_BACKUP"
write_null_theme_backup "$MULTILINE_ARRAY_BACKUP" "$MULTILINE_ARRAY_CONFIG"
assert_theme_config_restore_rejected multiline-array-layout \
"$MULTILINE_ARRAY_CONFIG" "$MULTILINE_ARRAY_BACKUP"
/bin/rm -f "$MULTILINE_ARRAY_BACKUP"

CRLF_CONFIG="$TMP/config-crlf.toml"
CRLF_BACKUP="$TMP/config-crlf-backup.json"
Expand All @@ -821,6 +899,7 @@ CRLF_BACKUP="$TMP/config-crlf-backup.json"
"$NODE" "$ROOT/scripts/theme-config.mjs" install "$CRLF_CONFIG" "$CRLF_BACKUP" >/dev/null
"$NODE" "$ROOT/scripts/theme-config.mjs" restore "$CRLF_CONFIG" "$CRLF_BACKUP" >/dev/null
/usr/bin/cmp -s "$CRLF_CONFIG" "$TMP/original-crlf.toml"
[ ! -e "$CRLF_BACKUP" ]

/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "1.2.0" ]' _ "$ROOT"
"$ROOT/scripts/doctor-macos.sh" >/dev/null
Expand Down
Loading