Files
context-mode/hooks/codex
Ken JoandMert Köseoğlu ff5b0cff21 fix(codex): MCP sentinel namespace + PreToolUse rewrites + tool annotations (#844 #845 #846) (#851)
* fix(hooks): keep MCP sentinel alive across isolated PID namespaces (#844)

isMCPReady() unlinked any sentinel whose PID failed process.kill(pid, 0).
In a sandbox that shares /tmp but runs in a separate PID namespace, a live
host MCP PID is invisible, so the probe threw ESRCH and the readiness
sentinel was deleted — flipping readiness to false and making hooks fail
open while the MCP server was still running.

The reader now treats EPERM as alive, and on ESRCH trusts a recently
refreshed sentinel (90s window) instead of deleting it; only sentinels
older than the window are cleaned up. The server refreshes its sentinel
mtime every 30s (3x margin) while alive and clears the timer on shutdown.

Tests live in tests/hooks/core-routing.test.ts, which already owns the
mcp-ready directory-scan contract.

Fixes #844.

* fix(codex): emit allow+updatedInput / additionalContext, fail closed on older builds (#845)

The Codex PreToolUse formatter returned null for modify and context, so
curl/wget/HTTP/build redirects (routing `modify`) and guidance nudges
(routing `context`) were silently dropped — the original command ran and
its output flooded the model context. The drop dated to #225 when Codex
rejected updatedInput; current Codex (codex-cli >= 0.141.0) honors
permissionDecision:"allow" + updatedInput and additionalContext.

Capability is detected at runtime (codex-caps.mjs parses `codex --version`,
caches with a TTL, fails closed on any error) — no opt-in env flag, which
would rot into dead code. When supported, modify emits allow+updatedInput
(command rewrite) and context emits additionalContext. When not supported,
a command redirect FAILS CLOSED as a deny carrying the same guidance
(mirrors the claude-code / antigravity-cli echo extraction); non-command
rewrites and advisory context nudges are dropped rather than blocking the
tool. `ask` stays dropped (Codex still rejects permissionDecision:"ask").

The TS adapter (src/adapters/codex/index.ts) is a separate in-process layer
not on the external hook path; its conservative behavior is unchanged.

Tests (formatter + capability detection) live in tests/hooks/formatters.test.ts,
which owns Hook formatting. codex-caps.mjs is a new source module because no
existing module owns Codex runtime capability detection.

Fixes #845.

* fix(mcp): add accurate tool annotations to ctx_* descriptors (#846)

context-mode registered its ctx_* MCP tools without annotations. Codex
cancels unannotated tool calls before execution ("user cancelled MCP tool
call"), so read-only tools like ctx_stats and ctx_doctor never ran even
though the server was reachable.

Each tool now carries explicit annotations classified by real behavior
(no blanket readOnlyHint): read-only query/diagnostic tools (ctx_search,
ctx_stats, ctx_doctor) are readOnlyHint:true; executing/mutating/destructive
tools (ctx_execute, ctx_execute_file, ctx_batch_execute, ctx_index,
ctx_fetch_and_index, ctx_purge, ctx_upgrade, ctx_insight) are not, with
destructiveHint / openWorldHint set per behavior.

Tests live in tests/core/server.test.ts (Server & tools) and inspect the
actual registered descriptors via REGISTERED_CTX_TOOLS, not descriptions.

Fixes #846.

* refactor(codex): replace regex with algorithmic equivalents per no-regex rule (#844 #845 #846)

---------

Co-authored-by: Mert Köseoğlu <bm.ksglu@gmail.com>
2026-06-21 19:19:59 +03:00
..