Skip to content

Commit 6e423d4

Browse files
committed
Fix macOS proxy autostart durability
1 parent 33d7f4f commit 6e423d4

4 files changed

Lines changed: 51 additions & 7 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ Default paths:
193193

194194
- `install --start` starts the local proxy first, health-checks it, then switches Codex config.
195195
- Enable also sets `features.codex_hooks = true` and adds one user-level `SessionStart` hook. The
196-
hook calls `codex-fast-proxy autostart --quiet`, starts or refreshes the proxy only when Codex
197-
config still points to the recorded local proxy, and otherwise exits quietly. Codex may run this
198-
hook for each new or resumed session; normal no-op checks do not write autostart log entries.
196+
hook uses the current Python executable to run `codex_fast_proxy autostart --quiet`, starts or
197+
refreshes the proxy only when Codex config still points to the recorded local proxy, and otherwise
198+
exits quietly. Codex may run this hook for each new or resumed session; normal no-op checks do not
199+
write autostart log entries.
199200
- Plain `install` refuses to switch config without a running proxy.
200201
- If startup or config switching fails, the manager restores the backed-up config.
201202
- Running Codex processes do not hot-switch provider config. Restart Codex App and return to the
@@ -366,8 +367,9 @@ Fetch and follow instructions from https://raw.githubusercontent.com/gaoguobin/c
366367
- dashboard 只读取最近一次 benchmark 的脱敏摘要,不提供会消耗 quota 的启动按钮。
367368
- 浏览器打开 `http://127.0.0.1:8787/v1` 时显示只读本地状态页;API 请求仍按原逻辑转发。
368369
- provider 通用:自动读取当前 active provider 的原始 `base_url` 作为 upstream。
369-
- 启用后写入 Codex `SessionStart` hook;后续 Codex App/CLI 新建或恢复会话时,如果配置仍指向本地
370-
proxy,会自动启动或刷新代理。用户手动改回直连时 hook 会静默跳过,正常 no-op 不写日志。
370+
- 启用后写入 Codex `SessionStart` hook;hook 使用当前 Python 可执行文件运行 autostart。后续 Codex
371+
App/CLI 新建或恢复会话时,如果配置仍指向本地 proxy,会自动启动或刷新代理。用户手动改回直连时
372+
hook 会静默跳过,正常 no-op 不写日志。
371373

372374
### 回滚保护
373375

skills/codex-fast-proxy/SKILL.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ Use `--upstream-base <url>` only when Codex config does not contain a usable pro
104104
- `install --start` backs up `~/.codex/config.toml`.
105105
- The selected provider's original `base_url` becomes `upstream_base`.
106106
- The selected provider's `base_url` becomes `http://127.0.0.1:8787/v1`.
107-
- A `SessionStart` hook calls `python -m codex_fast_proxy autostart --quiet` on future Codex sessions.
107+
- A `SessionStart` hook calls the current Python executable with
108+
`-m codex_fast_proxy autostart --quiet` on future Codex sessions.
108109
- The proxy only injects `service_tier="priority"` into `POST /v1/responses` when that field is absent.
109110
- `benchmark` compares synthetic Codex-style requests with no `service_tier` against
110111
`service_tier="priority"`. The default `codex-cli` mode is intended to measure real Codex

src/codex_fast_proxy/manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def restore_hook_feature_flag(config_path: Path, backup_path: str | None, hook_r
356356

357357
def command_for_hook(paths: ProxyPaths) -> str:
358358
args = [
359-
"python",
359+
sys.executable,
360360
"-m",
361361
"codex_fast_proxy",
362362
"autostart",
@@ -920,6 +920,7 @@ def launch_background(paths: ProxyPaths, settings: ProxySettings, verbose_proxy:
920920
stderr=stderr,
921921
stdin=subprocess.DEVNULL,
922922
creationflags=creation_flags,
923+
start_new_session=(os.name != "nt"),
923924
)
924925

925926
try:

tests/test_manager.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ def fake_start_background(paths, settings, verbose_proxy):
222222
self.assertTrue(config["features"]["codex_hooks"])
223223
self.assertTrue(has_startup_hook(paths))
224224
self.assertEqual(session_start[0]["matcher"], "startup|resume")
225+
self.assertIn(sys.executable, command)
225226
self.assertIn("codex_fast_proxy", command)
226227
self.assertIn("autostart", command)
227228
self.assertIn("--quiet", command)
@@ -890,6 +891,45 @@ def fake_launch_background(paths, settings, verbose_proxy):
890891
self.assertEqual(result["reason"], "runtime_changed")
891892
self.assertEqual(calls, ["stop", "start"])
892893

894+
def test_launch_background_detaches_process_on_posix(self) -> None:
895+
codex_home = self.temp_dir / ".codex"
896+
paths = paths_for(codex_home)
897+
settings = manager.ProxySettings(
898+
provider="acme",
899+
host="127.0.0.1",
900+
port=18787,
901+
proxy_base="/v1",
902+
upstream_base="https://api.acme.test/v1",
903+
service_tier="priority",
904+
)
905+
captured: dict[str, object] = {}
906+
907+
class FakeProcess:
908+
pid = 1234
909+
910+
original_is_port_available = manager.is_port_available
911+
original_wait_for_proxy_health = manager.wait_for_proxy_health
912+
original_popen = manager.subprocess.Popen
913+
914+
def fake_popen(command, **kwargs):
915+
captured["command"] = command
916+
captured["kwargs"] = kwargs
917+
return FakeProcess()
918+
919+
manager.is_port_available = lambda _host, _port: True
920+
manager.wait_for_proxy_health = lambda _settings, _process: {"ok": True, "pid": _process.pid}
921+
manager.subprocess.Popen = fake_popen
922+
try:
923+
result = manager.launch_background(paths, settings, verbose_proxy=False)
924+
finally:
925+
manager.is_port_available = original_is_port_available
926+
manager.wait_for_proxy_health = original_wait_for_proxy_health
927+
manager.subprocess.Popen = original_popen
928+
929+
self.assertEqual(result["status"], "started")
930+
self.assertEqual(captured["command"][0], sys.executable)
931+
self.assertEqual(captured["kwargs"]["start_new_session"], manager.os.name != "nt")
932+
893933
def test_quiet_autostart_does_not_log_noop_events(self) -> None:
894934
codex_home = self.temp_dir / ".codex"
895935
paths = paths_for(codex_home)

0 commit comments

Comments
 (0)