From 492cb8a48a14f1c32631e2b815b365a7305498a2 Mon Sep 17 00:00:00 2001 From: Esilama <159230931+Es1lama@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:56:33 +0800 Subject: [PATCH] fix(macos): detect ChatGPT by executable path --- macos/CHANGELOG.md | 1 + macos/scripts/apply-from-menubar-macos.sh | 2 +- macos/scripts/status-dream-skin-macos.sh | 23 ++++++++++++++++------ macos/tests/run-tests.sh | 24 +++++++++++++++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/macos/CHANGELOG.md b/macos/CHANGELOG.md index 6f9d123e..03621367 100644 --- a/macos/CHANGELOG.md +++ b/macos/CHANGELOG.md @@ -8,6 +8,7 @@ ### 修复 +- 修复 macOS 截断进程名时,菜单栏把已打开的 ChatGPT 误报为未运行的问题。高频状态检查现在只扫描一次进程表并匹配已保存或标准安装位置的完整主可执行路径,应用确认框复用同一状态结果。 - 注入器日志与 `--check` 结果不再记录页面标题和 URL。这些字段经 `launchctl submit -o` 落进 `~/Library/Application Support/` 下的长期日志文件,而 Codex 的窗口标题包含会话名与项目名。Windows 侧早已修正(见其 1.3.0 条目),macOS 未同步。渲染器探针也不再把 `document.title` 和 `location.href` 回传给宿主,仅保留结构标记。新增仓库级静态检查防止回归。 ### 内部 diff --git a/macos/scripts/apply-from-menubar-macos.sh b/macos/scripts/apply-from-menubar-macos.sh index 28e40599..abeb05eb 100755 --- a/macos/scripts/apply-from-menubar-macos.sh +++ b/macos/scripts/apply-from-menubar-macos.sh @@ -58,7 +58,6 @@ progress "已收到点击…" set +e CHEAP_RUNNING="false" -/usr/bin/pgrep -x ChatGPT >/dev/null 2>&1 && CHEAP_RUNNING="true" SESSION="off" THEME_NAME="" PORT="9341" @@ -68,6 +67,7 @@ if [ -x "$SCRIPT_DIR/status-dream-skin-macos.sh" ]; then session=*) SESSION="${line#session=}" ;; theme=*) THEME_NAME="${line#theme=}" ;; port=*) PORT="${line#port=}" ;; + codex=*) CHEAP_RUNNING="${line#codex=}" ;; esac done < <("$SCRIPT_DIR/status-dream-skin-macos.sh" 2>/dev/null) fi diff --git a/macos/scripts/status-dream-skin-macos.sh b/macos/scripts/status-dream-skin-macos.sh index 3db90174..98096b7f 100755 --- a/macos/scripts/status-dream-skin-macos.sh +++ b/macos/scripts/status-dream-skin-macos.sh @@ -33,6 +33,7 @@ APPLIED_THEME_ID="" CODEX_RUNNING="false" OPERATION_STATUS="" OPERATION_MESSAGE="" +SAVED_CODEX_EXE="" read_json_text_field() { # Parse machine-written JSON (one key per line) without python3, which macOS @@ -87,12 +88,6 @@ injector_identity_matches() { [ -n "$actual_start" ] && [ "$actual_start" = "$expected_start" ] } -# Codex process: cheap name match only. 26.707 renamed Codex.app to -# ChatGPT.app, while older installs still expose the former process name. -if /usr/bin/pgrep -x ChatGPT >/dev/null 2>&1 || /usr/bin/pgrep -x Codex >/dev/null 2>&1; then - CODEX_RUNNING="true" -fi - if [ -f "$STATE_PATH" ]; then STATE_SNAPSHOT="$(/bin/cat "$STATE_PATH" 2>/dev/null)" saved_port="$(read_json_text_field "$STATE_SNAPSHOT" port)" @@ -102,6 +97,7 @@ if [ -f "$STATE_PATH" ]; then saved_start="$(read_json_text_field "$STATE_SNAPSHOT" injectorStartedAt)" saved_node="$(read_json_text_field "$STATE_SNAPSHOT" nodePath)" saved_injector="$(read_json_text_field "$STATE_SNAPSHOT" injectorPath)" + SAVED_CODEX_EXE="$(read_json_text_field "$STATE_SNAPSHOT" codexExe)" APPLIED_THEME_ID="$(read_json_text_field "$STATE_SNAPSHOT" appliedThemeId)" APPLIED_THEME_NAME="$(read_json_text_field "$STATE_SNAPSHOT" appliedThemeName)" if injector_identity_matches "${pid:-}" "$saved_start" "$saved_node" "$saved_injector" "$PORT"; then @@ -126,6 +122,21 @@ if [ -f "$STATE_PATH" ]; then fi fi +# macOS may truncate the process name exposed to pgrep (for example, +# /Applications/Ch). Match the complete main command path and ignore helpers. +while IFS= read -r command_line; do + for candidate in "$SAVED_CODEX_EXE" \ + "/Applications/ChatGPT.app/Contents/MacOS/ChatGPT" \ + "$HOME/Applications/ChatGPT.app/Contents/MacOS/ChatGPT" \ + "/Applications/Codex.app/Contents/MacOS/Codex" \ + "$HOME/Applications/Codex.app/Contents/MacOS/Codex"; do + [ -n "$candidate" ] || continue + case "$command_line" in + "$candidate"|"$candidate "*) CODEX_RUNNING="true"; break 2 ;; + esac + done +done < <(/bin/ps -axo command= 2>/dev/null) + if [ -f "$THEME_DIR/theme.json" ]; then THEME_SNAPSHOT="$(/bin/cat "$THEME_DIR/theme.json" 2>/dev/null)" THEME_ID="$(read_json_text_field "$THEME_SNAPSHOT" id)" diff --git a/macos/tests/run-tests.sh b/macos/tests/run-tests.sh index e5c9ec3e..93edee30 100755 --- a/macos/tests/run-tests.sh +++ b/macos/tests/run-tests.sh @@ -667,6 +667,30 @@ STATUS_JSON="$(/usr/bin/env HOME="$STATUS_HOME" "$ROOT/scripts/status-dream-skin wait "$STATUS_PID" 2>/dev/null || true STATUS_PID="" +# The main executable can have a truncated process name on macOS even though +# its command starts with the complete path saved by the launcher. +STATUS_CODEX_EXE="$TMP/Fake ChatGPT" +/bin/bash -c 'exec -a "$1" /bin/sleep 600' _ "$STATUS_CODEX_EXE" & +STATUS_PID="$!" +/bin/sleep 0.08 +"$NODE" -e ' + const fs = require("node:fs"); + const [file, codexExe] = process.argv.slice(1); + fs.writeFileSync(file, `${JSON.stringify({ + schemaVersion: 4, + session: "off", + codexExe, + })}\n`); +' "$STATUS_STATE_ROOT/state.json" "$STATUS_CODEX_EXE" +STATUS_JSON="$(/usr/bin/env HOME="$STATUS_HOME" "$ROOT/scripts/status-dream-skin-macos.sh" --json)" +"$NODE" -e ' + const value = JSON.parse(process.argv[1]); + if (value.codexRunning !== true) process.exit(1); +' "$STATUS_JSON" +/bin/kill -TERM "$STATUS_PID" 2>/dev/null || true +wait "$STATUS_PID" 2>/dev/null || true +STATUS_PID="" + # The common stop path must reject a real watcher running on 19341 when the # saved state claims 1934, even though nodePath/injectorPath/start-time all # match. This exercises the signal gate directly (status has its own matcher).