Skip to content

Commit 918e8df

Browse files
EchoJamieEchoJamie
andauthored
fix(macos): align menu reapply and ChatGPT launch semantics (#342)
* fix(macos): avoid restart prompt before hot reapply * fix(macos): open ChatGPT through skin launcher * docs(macos): record menu launch semantics fix * fix(macos): restore consistent ChatGPT launch behavior * fix(macos): restore ChatGPT open fallback consistency --------- Co-authored-by: EchoJamie <yize.ma@definesys.com>
1 parent 5419b6e commit 918e8df

4 files changed

Lines changed: 108 additions & 5 deletions

File tree

TASK_PROGRESS.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,46 @@
11
# Task Progress
22

3+
## macOS menu reapply/open ChatGPT restart fix (2026-08-05)
4+
5+
- [scope] Branch `codex/fix-macos-reapply-open-chatgpt` was created from latest
6+
`upstream/main` (`0a727a5`). Fix the macOS menu behavior where the first
7+
"重新应用皮肤" click can restart ChatGPT even though the prompt says no restart,
8+
and review its interaction with the separate "打开 ChatGPT" action.
9+
- [diagnosed] The menu title is derived from lightweight `session=active`
10+
status, while `apply-from-menubar-macos.sh` always calls
11+
`start-dream-skin-macos.sh --restart-existing`. If ChatGPT is running without
12+
a verified CDP endpoint, `start-dream-skin-macos.sh` stops and relaunches it.
13+
- [implemented] `apply-from-menubar-macos.sh` keeps the original
14+
`CHEAP_RUNNING` / `SESSION` prompt flow and now attempts `hot_reapply_theme`
15+
after the existing confirmation but before falling back to
16+
`start-dream-skin-macos.sh --restart-existing`. A successful hot reapply
17+
exits without restarting ChatGPT.
18+
- [corrected] The native menu keeps the original "打开 ChatGPT" operation title
19+
and always shows that action. Its implementation preserves the original
20+
"未找到 ChatGPT" and "无法打开 ChatGPT" error surfaces, but replaces the
21+
successful native `NSWorkspace.openApplication` launch with the Dream Skin
22+
start path only when the installed engine is complete. If the engine is
23+
missing or incomplete, the action falls back to native `NSWorkspace` opening
24+
and does not install the engine implicitly.
25+
- [covered] Added static regressions to lock menu apply hot-reload ordering,
26+
the preserved session-driven prompt model, the unchanged "打开 ChatGPT" title,
27+
the Dream Skin-backed open action, and the native fallback when the engine is
28+
not installed. The macOS test Gatekeeper scan now ignores the same
29+
`.build-*` SwiftPM artifacts already listed in `macos/menubar-app/.gitignore`.
30+
- [verified 2026-08-06] `bash -n
31+
macos/scripts/apply-from-menubar-macos.sh macos/tests/run-tests.sh`,
32+
`git diff --check`, `swift build --package-path macos/menubar-app --product
33+
CodexDreamSkinMenuBar`, and `CODEX_DREAM_SKIN_SKIP_DOCTOR=1 bash
34+
macos/tests/run-tests.sh` all pass. The wrapper skipped Doctor as requested
35+
by the environment flag.
36+
- [gap] Live restore / re-apply / open ChatGPT smoke has not been rerun after
37+
narrowing the implementation back to the minimal AppDelegate + hot-reapply
38+
path.
39+
- [gap] Direct `swift test --package-path macos/menubar-app` fails on this host
40+
because the installed Swift toolchain cannot import `XCTest`; the repository
41+
macOS test wrapper detects the missing full matching Xcode platform and skips
42+
native XCTest accordingly.
43+
344
## Client release v1.5.11 — preparing (2026-08-01)
445

546
- [base/merged] Settings renderer PR #334 passed exact-head CI run

macos/menubar-app/Sources/CodexDreamSkinMenuBar/AppDelegate.swift

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -946,13 +946,32 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
946946
showError(title: "未找到 ChatGPT", message: "请先安装并至少启动一次官方 ChatGPT / Codex 桌面应用。")
947947
return
948948
}
949-
let configuration = NSWorkspace.OpenConfiguration()
950-
NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _, error in
951-
if let error {
952-
DispatchQueue.main.async {
953-
self.showError(title: "无法打开 ChatGPT", message: error.localizedDescription)
949+
guard !operationInFlight else { return }
950+
guard !engineNeedsInstall(),
951+
let script = installedScript(named: "start-dream-skin-macos.sh") else {
952+
let configuration = NSWorkspace.OpenConfiguration()
953+
NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { _, error in
954+
if let error {
955+
DispatchQueue.main.async {
956+
self.showError(title: "无法打开 ChatGPT", message: error.localizedDescription)
957+
}
954958
}
955959
}
960+
return
961+
}
962+
operationInFlight = true
963+
rebuildMenu()
964+
ScriptRunner.run(script: script) { [weak self] result in
965+
guard let self else { return }
966+
self.operationInFlight = false
967+
self.refreshStatus()
968+
self.rebuildMenu()
969+
if !result.succeeded {
970+
self.showError(
971+
title: "无法打开 ChatGPT",
972+
message: self.conciseOutput(result.output, fallback: "请检查 ChatGPT 是否已安装,并重试。")
973+
)
974+
}
956975
}
957976
}
958977

macos/scripts/apply-from-menubar-macos.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ fi
111111

112112
progress "检查 ChatGPT…"
113113
ensure_state_root
114+
progress "尝试热重载皮肤…"
115+
116+
if hot_reapply_theme "$PORT" 8000; then
117+
progress "完成:皮肤已应用"
118+
exit 0
119+
fi
120+
114121
progress "启动/连接调试口…"
115122

116123
"$SCRIPT_DIR/start-dream-skin-macos.sh" --restart-existing >>"$LOG_OUT" 2>&1

macos/tests/run-tests.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ UPDATE_JSON="$({
9191
if (value.releaseUrl !== "https://github.com/Fei-Away/Codex-Dream-Skin/releases/latest") process.exit(1);
9292
' "$UPDATE_JSON"
9393
if /usr/bin/grep -R -n -E --exclude-dir='.build' \
94+
--exclude-dir='.build-*' \
9495
'xattr|spctl[[:space:]]+--master-disable' \
9596
"$ROOT/menubar-app" "$ROOT/scripts/build-menubar-app.sh" "$ROOT/scripts/build-dmg.sh" >/dev/null; then
9697
printf 'Native distribution must not bypass Gatekeeper or remove quarantine attributes.\n' >&2
@@ -753,6 +754,41 @@ if /usr/bin/grep -F -q 'index($0, "--port " port)' "$ROOT/scripts/common-macos.s
753754
printf 'injector discovery still accepts a near-prefix port.\n' >&2
754755
exit 1
755756
fi
757+
APPLY_SCRIPT="$ROOT/scripts/apply-from-menubar-macos.sh"
758+
/usr/bin/grep -F -q 'if hot_reapply_theme "$PORT" 8000; then' "$APPLY_SCRIPT"
759+
/usr/bin/grep -F -q 'SESSION="off"' "$APPLY_SCRIPT"
760+
/usr/bin/grep -F -q 'if ! confirm "$PROMPT" "$OK_LABEL"; then' "$APPLY_SCRIPT"
761+
/usr/bin/grep -F -q '"$SCRIPT_DIR/start-dream-skin-macos.sh" --restart-existing' "$APPLY_SCRIPT"
762+
if /usr/bin/grep -F -q 'CODEX_RUNNING=' "$APPLY_SCRIPT" ||
763+
/usr/bin/grep -F -q 'MENU_ACTION=' "$APPLY_SCRIPT" ||
764+
/usr/bin/grep -F -q 'OPEN_PROMPT=' "$APPLY_SCRIPT"; then
765+
printf 'menu apply must preserve the original session-driven prompt model.\n' >&2
766+
exit 1
767+
fi
768+
HOT_LINE="$(/usr/bin/grep -n 'hot_reapply_theme "$PORT" 8000' "$APPLY_SCRIPT" | /usr/bin/head -1 | /usr/bin/cut -d: -f1)"
769+
CONFIRM_LINE="$(/usr/bin/grep -n 'if ! confirm "$PROMPT" "$OK_LABEL"; then' "$APPLY_SCRIPT" | /usr/bin/head -1 | /usr/bin/cut -d: -f1)"
770+
START_LINE="$(/usr/bin/grep -n 'start-dream-skin-macos.sh" --restart-existing' "$APPLY_SCRIPT" | /usr/bin/head -1 | /usr/bin/cut -d: -f1)"
771+
if [ -z "$HOT_LINE" ] || [ -z "$CONFIRM_LINE" ] || [ -z "$START_LINE" ] ||
772+
[ "$CONFIRM_LINE" -ge "$HOT_LINE" ] ||
773+
[ "$HOT_LINE" -ge "$START_LINE" ]; then
774+
printf 'menu apply must keep its confirmation and hot-reapply before falling back to start.\n' >&2
775+
exit 1
776+
fi
777+
MENU_SOURCE="$ROOT/menubar-app/Sources/CodexDreamSkinMenuBar/AppDelegate.swift"
778+
OPEN_CODEX_BODY="$(/usr/bin/sed -n '/@objc private func openCodex()/,/@objc private func openDreamSkinWebsite()/p' "$MENU_SOURCE")"
779+
/usr/bin/grep -F -q 'addActionItem("打开 ChatGPT", action: #selector(openCodex), enabled: !busy)' "$MENU_SOURCE"
780+
/usr/bin/grep -F -q 'showError(title: "未找到 ChatGPT", message: "请先安装并至少启动一次官方 ChatGPT / Codex 桌面应用。")' "$MENU_SOURCE"
781+
/usr/bin/grep -F -q 'guard !engineNeedsInstall(),' "$MENU_SOURCE"
782+
/usr/bin/grep -F -q 'let script = installedScript(named: "start-dream-skin-macos.sh") else {' "$MENU_SOURCE"
783+
/usr/bin/grep -F -q 'NSWorkspace.shared.openApplication(at: appURL, configuration: configuration)' "$MENU_SOURCE"
784+
/usr/bin/grep -F -q 'ScriptRunner.run(script: script)' "$MENU_SOURCE"
785+
/usr/bin/grep -F -q 'title: "无法打开 ChatGPT",' "$MENU_SOURCE"
786+
if /usr/bin/grep -F -q 'applyTitle = "打开并应用皮肤"' "$MENU_SOURCE" ||
787+
/usr/bin/grep -F -q 'runInstalledScript(named: "apply-from-menubar-macos.sh", operation: "打开 ChatGPT")' "$MENU_SOURCE" ||
788+
/usr/bin/printf '%s\n' "$OPEN_CODEX_BODY" | /usr/bin/grep -F -q 'installBundledEngineIfNeeded(force:'; then
789+
printf 'Open ChatGPT must keep its menu title and must not use menu apply or install the engine implicitly.\n' >&2
790+
exit 1
791+
fi
756792

757793
# Corrupt or structurally incomplete state must be preserved and fail closed;
758794
# otherwise pause/restore could overwrite evidence while a watcher survives.

0 commit comments

Comments
 (0)