Skip to content
Draft
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 @@ -8,6 +8,7 @@

### 修复

- 修复 macOS 截断进程名时,菜单栏把已打开的 ChatGPT 误报为未运行的问题。高频状态检查现在只扫描一次进程表并匹配已保存或标准安装位置的完整主可执行路径,应用确认框复用同一状态结果。
- 注入器日志与 `--check` 结果不再记录页面标题和 URL。这些字段经 `launchctl submit -o` 落进 `~/Library/Application Support/` 下的长期日志文件,而 Codex 的窗口标题包含会话名与项目名。Windows 侧早已修正(见其 1.3.0 条目),macOS 未同步。渲染器探针也不再把 `document.title` 和 `location.href` 回传给宿主,仅保留结构标记。新增仓库级静态检查防止回归。

### 内部
Expand Down
2 changes: 1 addition & 1 deletion macos/scripts/apply-from-menubar-macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
23 changes: 17 additions & 6 deletions macos/scripts/status-dream-skin-macos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)"
Expand All @@ -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
Expand All @@ -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)"
Expand Down
24 changes: 24 additions & 0 deletions macos/tests/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down