From 19b98694df40543afd0797d52ec69aa965617e7b Mon Sep 17 00:00:00 2001 From: Cannon07 Date: Fri, 22 May 2026 02:18:31 +0530 Subject: [PATCH 1/2] feat: in-process Lua core handler for codex (#47, phase 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flips Codex's PreToolUse / PostToolUse hooks from per-shim bash translation to a single RPC into the in-process Lua orchestrator, matching the pattern already shipped for claudecode (#63), opencode (#65), and copilot (#66). - backends/codex/code-{preview,close}-diff.sh: trimmed to the copilot shape — set -uo pipefail (no -e), fast-path filter for read/view/glob/grep/ls/ list_files plus mcp__*, socket discovery, then a single nvim_call into pre_tool / post_tool. Abstains (exit 0, no stdout) when nvim is unreachable so codex falls back to its native ask-before-write loop. - lua/code-preview/pre_tool/normalisers.lua: new codex entry. Codex's payload is almost canonical (top-level tool_name, cwd, tool_input), so the only real translation is apply_patch → ApplyPatch with tool_input.command moved to tool_input.patch_text. Edit / Write / Bash / ApplyPatch are passthrough; file_path is run through resolve_path for cross-backend key parity. Blank file_path / command / patch text drop tool_name to nil so the dispatcher no-ops (matches the old shim's defensive `[[ -z $FP ]] && exit 0` guards). - lua/code-preview/pre_tool/emitters.lua: explicit codex = none entry (mirrors copilot). Codex has no review-gate analogue to emit a permissionDecision for. - tests/plugin/pre_tool_normaliser_spec.lua: new describe block covering apply_patch translation, ApplyPatch/Edit/Write/Bash passthrough, blank-field defenses dropping tool_name, mcp__* and noise tools yielding nil. Refs #47 (phase 3). No behaviour change for codex users. Co-Authored-By: Claude Opus 4.7 --- backends/codex/code-close-diff.sh | 91 ++++----------- backends/codex/code-preview-diff.sh | 131 ++++++---------------- lua/code-preview/pre_tool/emitters.lua | 3 +- lua/code-preview/pre_tool/normalisers.lua | 52 ++++++++- tests/plugin/pre_tool_normaliser_spec.lua | 126 +++++++++++++++++++++ 5 files changed, 233 insertions(+), 170 deletions(-) diff --git a/backends/codex/code-close-diff.sh b/backends/codex/code-close-diff.sh index 55c74fc..638bcf5 100755 --- a/backends/codex/code-close-diff.sh +++ b/backends/codex/code-close-diff.sh @@ -1,90 +1,37 @@ #!/usr/bin/env bash -# code-close-diff.sh — PostToolUse hook adapter for OpenAI Codex CLI. +# code-close-diff.sh — PostToolUse hook entry for OpenAI Codex CLI. # -# Mirrors the translation in code-preview-diff.sh and delegates to -# bin/core-post-tool.sh. Only the fields core-post-tool.sh reads are -# populated (tool_name, cwd, file_path or patch_text). +# Single RPC into the in-process orchestrator (lua/code-preview/post_tool.lua). +# The orchestrator clears the changes registry, closes any open preview for +# the affected file, and refreshes neo-tree. +# +# When Neovim is unreachable, the shim abstains silently (exit 0). +# No `set -e`: abstain on jq/nvim_call failure rather than surfacing a +# hook failure to the agent. See the matching note in code-preview-diff.sh. set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" BIN_DIR="$SCRIPT_DIR/../../bin" -export CODE_PREVIEW_BACKEND="codex" INPUT="$(cat)" -TOOL="$(printf '%s' "$INPUT" | jq -r '.tool_name // ""')" -CWD="$(printf '%s' "$INPUT" | jq -r '.cwd // ""')" - +# Fast-path filter — see the matching note in code-preview-diff.sh. +TOOL="$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || true)" case "$TOOL" in ""|read|view|glob|grep|ls|list_files) exit 0 ;; -esac -case "$TOOL" in mcp__*) exit 0 ;; esac -log() { :; } -# shellcheck source=/dev/null -source "$BIN_DIR/nvim-socket.sh" "$CWD" 2>/dev/null || true -# shellcheck source=/dev/null -source "$BIN_DIR/nvim-call.sh" 2>/dev/null || true -if [[ -n "${NVIM_SOCKET:-}" ]]; then - _CTX="$(nvim_call code-preview.log state '[]' || echo '{}')" - _DBG=$(echo "$_CTX" | jq -r '.debug // false' 2>/dev/null) - _LOG=$(echo "$_CTX" | jq -r '.log_file // ""' 2>/dev/null) - if [[ "$_DBG" == "true" && -n "$_LOG" ]]; then - log() { printf '[%s] [INFO] codex/post: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$_LOG"; } - fi -fi - -log "tool=$TOOL" +CWD="$(printf '%s' "$INPUT" | jq -r '.cwd // empty' 2>/dev/null || true)" -case "$TOOL" in - apply_patch) - PATCH="$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')" - if [[ -z "$PATCH" ]]; then - log "apply_patch with empty/missing patch text — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: "ApplyPatch", - cwd: .cwd, - tool_input: { patch_text: (.tool_input.command // "") } - }')" - ;; - - ApplyPatch|Edit|Write) - FP="$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // ""')" - if [[ -z "$FP" ]]; then - log "$TOOL with empty/missing file_path — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: .tool_name, - cwd: .cwd, - tool_input: .tool_input - }')" - ;; - - Bash) - CMD="$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')" - if [[ -z "$CMD" ]]; then - log "Bash with empty/missing command — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: .tool_name, - cwd: .cwd, - tool_input: .tool_input - }')" - ;; - - *) - log "unhandled tool=$TOOL — exiting" - exit 0 - ;; -esac +source "$BIN_DIR/nvim-socket.sh" "$CWD" 2>/dev/null || true +source "$BIN_DIR/nvim-call.sh" -log "translated tool=$TOOL → closing" +if [[ -z "${NVIM_SOCKET:-}" ]]; then + exit 0 +fi -printf '%s' "$NORMALIZED" | "$BIN_DIR/core-post-tool.sh" +ARGS="$(jq -nc --argjson r "$INPUT" --arg b codex '[$r, $b]' 2>/dev/null || true)" +[[ -z "$ARGS" ]] && exit 0 +nvim_call code-preview.post_tool handle "$ARGS" >/dev/null diff --git a/backends/codex/code-preview-diff.sh b/backends/codex/code-preview-diff.sh index 30b0be5..95da6c7 100755 --- a/backends/codex/code-preview-diff.sh +++ b/backends/codex/code-preview-diff.sh @@ -1,114 +1,53 @@ #!/usr/bin/env bash -# code-preview-diff.sh — PreToolUse hook adapter for OpenAI Codex CLI. +# code-preview-diff.sh — PreToolUse hook entry for OpenAI Codex CLI. # -# Translates Codex's hook payload (stdin JSON with tool_name/tool_input) into -# the normalized {tool_name, cwd, tool_input} format consumed by -# bin/core-pre-tool.sh, then delegates to it. +# After issue #47 phase 3, this shim does almost nothing: it discovers the +# running Neovim's socket and makes a single RPC call into the in-process +# orchestrator (lua/code-preview/pre_tool/init.lua), then prints whatever the +# orchestrator returns. The bash that used to translate Codex's +# {tool_name, cwd, tool_input} payload (and the apply_patch → ApplyPatch +# field move) now lives in lua/code-preview/pre_tool/normalisers.lua +# (codex entry). # -# Field mapping: -# apply_patch → ApplyPatch (tool_input.command holds the patch text; -# we move it under .patch_text) -# ApplyPatch → ApplyPatch (passthrough; canonical name) -# Edit → Edit (passthrough; assumes Claude-Code-style -# {file_path, old_string, new_string}) -# Write → Write (passthrough; assumes {file_path, content}) -# Bash → Bash (passthrough) -# read/glob/MCP/... → ignored -# -# Note: today's Codex models route all file edits through `apply_patch`. The -# Edit/Write branches exist defensively in case a future Codex version (or -# an MCP server) emits those names with Claude-Code-style field shapes. - +# When Neovim is unreachable, the shim abstains: exit 0 with no stdout. +# Codex then falls back to its native ask-before-write loop as if the plugin +# weren't installed. See docs/adr/0005-core-handler-runs-in-process.md. + +# No `set -e`: the shim is the boundary between the agent and the plugin. +# When jq fails on a malformed payload or nvim_call returns rc=2, we want +# to exit 0 (abstain) so the agent falls back to its native flow rather +# than seeing a hook failure. set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" BIN_DIR="$SCRIPT_DIR/../../bin" -export CODE_PREVIEW_BACKEND="codex" INPUT="$(cat)" -TOOL="$(printf '%s' "$INPUT" | jq -r '.tool_name // ""')" -CWD="$(printf '%s' "$INPUT" | jq -r '.cwd // ""')" - -# Skip noisy/no-op tools before the expensive socket/log-setup RPC. +# Fast-path filter for tools that never produce a preview. Codex hits hooks +# directly (no TS-side allowlist like opencode), so every tool firing — +# including the very chatty read/view/glob/grep/ls/list_files and MCP +# tools — would otherwise pay for socket discovery + an RPC round-trip just +# for the Lua normaliser to return tool_name=nil. The Lua map in +# pre_tool.normalisers remains the source of truth; this case is purely a +# perf filter. +TOOL="$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || true)" case "$TOOL" in ""|read|view|glob|grep|ls|list_files) exit 0 ;; -esac -# MCP tools follow `mcp__server__name`; we don't preview them. -case "$TOOL" in mcp__*) exit 0 ;; esac -# Logging — mirrors copilot/code-preview-diff.sh. Gated on `debug = true`. -log() { :; } -# shellcheck source=/dev/null -source "$BIN_DIR/nvim-socket.sh" "$CWD" 2>/dev/null || true -# shellcheck source=/dev/null -source "$BIN_DIR/nvim-call.sh" 2>/dev/null || true -if [[ -n "${NVIM_SOCKET:-}" ]]; then - _CTX="$(nvim_call code-preview.log state '[]' || echo '{}')" - _DBG=$(echo "$_CTX" | jq -r '.debug // false' 2>/dev/null) - _LOG=$(echo "$_CTX" | jq -r '.log_file // ""' 2>/dev/null) - if [[ "$_DBG" == "true" && -n "$_LOG" ]]; then - log() { printf '[%s] [INFO] codex/pre: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$_LOG"; } - fi -fi - -log "tool=$TOOL cwd=$CWD" +CWD="$(printf '%s' "$INPUT" | jq -r '.cwd // empty' 2>/dev/null || true)" -case "$TOOL" in - apply_patch) - # Codex stores the raw `*** Begin Patch ... *** End Patch` text in - # tool_input.command. Our ApplyPatch handler in core-pre-tool.sh reads - # tool_input.patch_text, so move the field. - PATCH="$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')" - if [[ -z "$PATCH" ]]; then - log "apply_patch with empty/missing patch text — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: "ApplyPatch", - cwd: .cwd, - tool_input: { patch_text: (.tool_input.command // "") } - }')" - ;; - - ApplyPatch|Edit|Write) - # Edit/Write-family tools require a non-empty file_path. Without it, - # core-pre-tool.sh would push a broken diff downstream. - FP="$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // ""')" - if [[ -z "$FP" ]]; then - log "$TOOL with empty/missing file_path — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: .tool_name, - cwd: .cwd, - tool_input: .tool_input - }')" - ;; - - Bash) - # Bash needs a non-empty command to be useful (rm detection, shell-write - # detection both run on the command string). - CMD="$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')" - if [[ -z "$CMD" ]]; then - log "Bash with empty/missing command — skipping" - exit 0 - fi - NORMALIZED="$(printf '%s' "$INPUT" | jq '{ - tool_name: .tool_name, - cwd: .cwd, - tool_input: .tool_input - }')" - ;; - - *) - log "unhandled tool=$TOOL — exiting" - exit 0 - ;; -esac +# Socket discovery — silent failure is fine, we abstain below. +source "$BIN_DIR/nvim-socket.sh" "$CWD" 2>/dev/null || true +source "$BIN_DIR/nvim-call.sh" -log "translated tool=$TOOL → $(printf '%s' "$NORMALIZED" | jq -c '{tool_name, file: .tool_input.file_path // "", has_patch: (.tool_input.patch_text != null)}' 2>/dev/null || echo 'parse-error')" +if [[ -z "${NVIM_SOCKET:-}" ]]; then + exit 0 +fi -printf '%s' "$NORMALIZED" | "$BIN_DIR/core-pre-tool.sh" +ARGS="$(jq -nc --argjson r "$INPUT" --arg b codex '[$r, $b]' 2>/dev/null || true)" +# Malformed payload (jq couldn't parse) — abstain silently. +[[ -z "$ARGS" ]] && exit 0 +nvim_call code-preview.pre_tool handle "$ARGS" diff --git a/lua/code-preview/pre_tool/emitters.lua b/lua/code-preview/pre_tool/emitters.lua index 5cd8e08..0f48a73 100644 --- a/lua/code-preview/pre_tool/emitters.lua +++ b/lua/code-preview/pre_tool/emitters.lua @@ -33,7 +33,8 @@ M.emitters = { claudecode = claudecode, opencode = none, copilot = none, - -- codex / gemini default to `none` via the fallback below. + codex = none, + -- gemini defaults to `none` via the fallback below. } --- @param backend string diff --git a/lua/code-preview/pre_tool/normalisers.lua b/lua/code-preview/pre_tool/normalisers.lua index 371f721..5c5721d 100644 --- a/lua/code-preview/pre_tool/normalisers.lua +++ b/lua/code-preview/pre_tool/normalisers.lua @@ -173,11 +173,61 @@ local function copilot(raw) } end +-- Codex's hook payload is almost canonical: top-level {tool_name, cwd, +-- tool_input}. The only real translation is apply_patch → ApplyPatch with +-- tool_input.command (the raw `*** Begin Patch ... *** End Patch` text) +-- moved to tool_input.patch_text. Edit/Write/Bash/ApplyPatch are otherwise +-- passthrough — codex models route all edits through apply_patch today, +-- but the Edit/Write/Bash branches exist defensively in case a future +-- codex version (or an MCP server) emits those names with Claude-Code- +-- style field shapes. resolve_path is applied for parity with the other +-- backends so internal keys compare equal across agents. +local function codex(raw) + local tool = (raw and raw.tool_name) or "" + local cwd = (raw and raw.cwd) or "" + local args = (raw and raw.tool_input) or {} + + local function blank(s) return s == nil or s == "" end + + if tool == "apply_patch" then + if blank(args.command) then + return { tool_name = nil, cwd = cwd, tool_input = {} } + end + return { + tool_name = "ApplyPatch", + cwd = cwd, + tool_input = { patch_text = args.command }, + } + elseif tool == "ApplyPatch" then + if blank(args.patch_text) then + return { tool_name = nil, cwd = cwd, tool_input = {} } + end + return { tool_name = "ApplyPatch", cwd = cwd, tool_input = args } + elseif tool == "Edit" or tool == "Write" then + local fp = resolve_path(args.file_path, cwd) + if blank(fp) then + return { tool_name = nil, cwd = cwd, tool_input = {} } + end + local out = {} + for k, v in pairs(args) do out[k] = v end + out.file_path = fp + return { tool_name = tool, cwd = cwd, tool_input = out } + elseif tool == "Bash" then + if blank(args.command) then + return { tool_name = nil, cwd = cwd, tool_input = {} } + end + return { tool_name = "Bash", cwd = cwd, tool_input = args } + end + + return { tool_name = nil, cwd = cwd, tool_input = {} } +end + M.normalisers = { claudecode = identity, opencode = opencode, copilot = copilot, - -- codex / gemini will land their own normalisers as they flip. + codex = codex, + -- gemini will land its own normaliser when it flips. } --- @param raw table decoded hook payload diff --git a/tests/plugin/pre_tool_normaliser_spec.lua b/tests/plugin/pre_tool_normaliser_spec.lua index 70ea38d..dd6d1b1 100644 --- a/tests/plugin/pre_tool_normaliser_spec.lua +++ b/tests/plugin/pre_tool_normaliser_spec.lua @@ -246,3 +246,129 @@ describe("normalisers.normalise (copilot)", function() assert.equals("/proj/p.lua", out.tool_input.file_path) end) end) + +describe("normalisers.normalise (codex)", function() + -- Codex's hook payload is almost canonical: top-level {tool_name, cwd, + -- tool_input}. The only real translation is apply_patch → ApplyPatch with + -- tool_input.command moved to tool_input.patch_text. + + it("apply_patch translates to ApplyPatch with patch_text", function() + local out = normalisers.normalise({ + tool_name = "apply_patch", + cwd = "/proj", + tool_input = { command = "*** Begin Patch\n*** End Patch\n" }, + }, "codex") + assert.equals("ApplyPatch", out.tool_name) + assert.equals("*** Begin Patch\n*** End Patch\n", out.tool_input.patch_text) + end) + + it("ApplyPatch passes through unchanged", function() + local out = normalisers.normalise({ + tool_name = "ApplyPatch", + cwd = "/proj", + tool_input = { patch_text = "PATCH" }, + }, "codex") + assert.equals("ApplyPatch", out.tool_name) + assert.equals("PATCH", out.tool_input.patch_text) + end) + + it("Edit passthrough resolves relative file_path", function() + local out = normalisers.normalise({ + tool_name = "Edit", + cwd = "/proj", + tool_input = { file_path = "src/foo.lua", old_string = "a", new_string = "b" }, + }, "codex") + assert.equals("Edit", out.tool_name) + assert.equals("/proj/src/foo.lua", out.tool_input.file_path) + assert.equals("a", out.tool_input.old_string) + assert.equals("b", out.tool_input.new_string) + end) + + it("Edit collapses .. segments via resolve_path", function() + local out = normalisers.normalise({ + tool_name = "Edit", + cwd = "/proj/sub", + tool_input = { file_path = "../foo.lua" }, + }, "codex") + assert.equals("/proj/foo.lua", out.tool_input.file_path) + end) + + it("Write passthrough preserves content and resolves file_path", function() + local out = normalisers.normalise({ + tool_name = "Write", + cwd = "/proj", + tool_input = { file_path = "new.lua", content = "hello" }, + }, "codex") + assert.equals("Write", out.tool_name) + assert.equals("/proj/new.lua", out.tool_input.file_path) + assert.equals("hello", out.tool_input.content) + end) + + it("Bash passthrough preserves command", function() + local out = normalisers.normalise({ + tool_name = "Bash", + cwd = "/proj", + tool_input = { command = "ls" }, + }, "codex") + assert.equals("Bash", out.tool_name) + assert.equals("ls", out.tool_input.command) + end) + + it("apply_patch with empty command drops tool_name", function() + local out = normalisers.normalise({ + tool_name = "apply_patch", + cwd = "/proj", + tool_input = { command = "" }, + }, "codex") + assert.is_nil(out.tool_name) + end) + + it("Edit with empty file_path drops tool_name", function() + local out = normalisers.normalise({ + tool_name = "Edit", + cwd = "/proj", + tool_input = { file_path = "", old_string = "a", new_string = "b" }, + }, "codex") + assert.is_nil(out.tool_name) + end) + + it("Write with empty file_path drops tool_name", function() + local out = normalisers.normalise({ + tool_name = "Write", + cwd = "/proj", + tool_input = { file_path = "", content = "x" }, + }, "codex") + assert.is_nil(out.tool_name) + end) + + it("Bash with empty command drops tool_name", function() + local out = normalisers.normalise({ + tool_name = "Bash", + cwd = "/proj", + tool_input = { command = "" }, + }, "codex") + assert.is_nil(out.tool_name) + end) + + it("mcp__* tools yield nil tool_name", function() + -- The shim fast-path filter drops these before RPC, but the Lua map + -- remains the source of truth for correctness. + local out = normalisers.normalise({ + tool_name = "mcp__server__do_thing", + cwd = "/proj", + tool_input = { whatever = true }, + }, "codex") + assert.is_nil(out.tool_name) + end) + + it("noise tools (read/view/glob/grep/ls/list_files) yield nil tool_name", function() + for _, tool in ipairs({ "read", "view", "glob", "grep", "ls", "list_files" }) do + local out = normalisers.normalise({ + tool_name = tool, + cwd = "/proj", + tool_input = {}, + }, "codex") + assert.is_nil(out.tool_name) + end + end) +end) From dba4bee58e0ca362cb56c1f9842e869544a2ca66 Mon Sep 17 00:00:00 2001 From: Cannon07 Date: Fri, 22 May 2026 12:40:46 +0530 Subject: [PATCH 2/2] docs: refresh codex test docstrings + path-normalisation note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors PR #66's followup for copilot: - tests/backends/codex/test_{apply_patch,edit}.sh: docstrings still referenced the old bash adapter / bin/core-pre-tool.sh flow. Point them at the new in-process Lua normaliser. - lua/code-preview/pre_tool/normalisers.lua (codex block): add the path-normalisation note so the resolve_path call doesn't look magical to the next reader (parity with copilot's block). Also note that the canonical-ApplyPatch branch fixes a dormant bug in the old shim — its ApplyPatch|Edit|Write case blank-checked file_path, which canonical ApplyPatch doesn't carry, so any such payload would have been silently dropped. Nothing emits canonical ApplyPatch today, but the new branch checks patch_text correctly. Co-Authored-By: Claude Opus 4.7 --- lua/code-preview/pre_tool/normalisers.lua | 15 +++++++++++++-- tests/backends/codex/test_apply_patch.sh | 5 +++-- tests/backends/codex/test_edit.sh | 3 ++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lua/code-preview/pre_tool/normalisers.lua b/lua/code-preview/pre_tool/normalisers.lua index 5c5721d..78d961b 100644 --- a/lua/code-preview/pre_tool/normalisers.lua +++ b/lua/code-preview/pre_tool/normalisers.lua @@ -180,8 +180,19 @@ end -- passthrough — codex models route all edits through apply_patch today, -- but the Edit/Write/Bash branches exist defensively in case a future -- codex version (or an MCP server) emits those names with Claude-Code- --- style field shapes. resolve_path is applied for parity with the other --- backends so internal keys compare equal across agents. +-- style field shapes. +-- +-- Note: file paths are run through the shared `resolve_path`, which collapses +-- ../ and ./ segments via vim.fs.normalize. The old bash codex shim did not — +-- paths were preserved verbatim. The change is deliberate and matches the +-- opencode/copilot contract: internal keys (active_diffs, changes registry) +-- must be canonical so logically-same files compare equal across backends. +-- +-- The canonical-ApplyPatch branch (uppercase) below also fixes a dormant +-- bug in the old shim: its `ApplyPatch|Edit|Write` case blank-checked +-- tool_input.file_path, which canonical ApplyPatch doesn't carry, so any +-- such payload would have been silently dropped. Nothing emits canonical +-- ApplyPatch today, but the new branch checks patch_text correctly. local function codex(raw) local tool = (raw and raw.tool_name) or "" local cwd = (raw and raw.cwd) or "" diff --git a/tests/backends/codex/test_apply_patch.sh b/tests/backends/codex/test_apply_patch.sh index 44a9d48..74da92f 100755 --- a/tests/backends/codex/test_apply_patch.sh +++ b/tests/backends/codex/test_apply_patch.sh @@ -2,8 +2,9 @@ # test_apply_patch.sh — E2E tests for Codex CLI apply_patch workflow # # Codex carries the `*** Begin Patch … *** End Patch` payload in -# tool_input.command (not tool_input.patch_text). The adapter rewrites the -# field name and forwards to bin/core-pre-tool.sh, which uses the same +# tool_input.command (not tool_input.patch_text). After #47 phase 3 the +# rename happens in lua/code-preview/pre_tool/normalisers.lua (codex entry); +# the shim now just RPCs into pre_tool.handle, which uses the same # apply-patch.lua parser the other backends share. CODEX_PRE="$REPO_ROOT/backends/codex/code-preview-diff.sh" diff --git a/tests/backends/codex/test_edit.sh b/tests/backends/codex/test_edit.sh index 55e232d..6f20305 100755 --- a/tests/backends/codex/test_edit.sh +++ b/tests/backends/codex/test_edit.sh @@ -7,7 +7,8 @@ # # Codex specifics: # - apply_patch carries the patch text in tool_input.command (not patch_text). -# The adapter rewrites that field; covered in test_apply_patch.sh. +# The codex normaliser in lua/code-preview/pre_tool/normalisers.lua +# rewrites that field; covered in test_apply_patch.sh. # - Today's models route ALL file edits through apply_patch. Edit/Write/ # MultiEdit are passed through defensively for forward compat. # - Bash detection: rm marks deleted; output redirection (Tier 1 shell