Codex CLI publishes no workspace env var to its MCP child, so when the
host is launched from outside a project (e.g. $HOME), every project-aware
tool (ctx_stats, SessionDB, hash) ends up rooted at $HOME instead of the
user's project. Mirror Claude Code's transcript heuristic for Codex:
* resolveCodexSessionCwd() — read meta.cwd from the most-recently-
modified ${CODEX_HOME ?? ~/.codex}/sessions/<uuid>.jsonl; with
plugin-install-path poison guard and transcriptMaxAgeMs freshness
gate (multi-window safety).
* resolveProjectDir() — when strictPlatform === "codex" and the env
cascade yields nothing, fall through to the session-log heuristic
BEFORE PWD/cwd.
* src/server.ts getProjectDir() — when detectPlatform() returns
"codex", pass codexHome to the resolver so production code reaches
the new branch (without this wiring it was dead code). Export
getProjectDir for integration testing.
* PolyglotExecutor — accept an explicit cwd override on ExecuteOptions
so per-call sites can pin shell cwd to the resolved project root
without mutating process-wide state.
Tests:
* tests/util/codex-session-cwd-resolution.test.ts — 15 unit tests on
the helper + resolveProjectDir strict-codex branch (fresh log wins,
stale rejected, malformed survived, plugin path poison rejected,
missing sessions dir handled, foreign env ignored).
* tests/executor/cwd-override.test.ts — 2 tests proving the
PolyglotExecutor cwd override pins shell pwd and falls back to
projectRoot when undefined.
* tests/integration/project-dir-strict.test.ts — extended with an
end-to-end test that boots getProjectDir() in a Codex-shaped env
(CODEX_THREAD_ID + CODEX_HOME pointing at a fresh fixture session)
and asserts the returned path is the session-log meta.cwd. Verifies
the full #45 chain: detector -> server.getProjectDir() -> resolver
-> session log -> meta.cwd.
* .mcp.json.codex.example — Codex-specific manifest snippet
documenting CONTEXT_MODE_PROJECT_DIR as the explicit escape hatch.
All 209 tests in tests/util/, tests/integration/, tests/executor/ pass.
tsc --noEmit clean.