From 6cf20494b2d023be32a98939a3fb3bbc73035a56 Mon Sep 17 00:00:00 2001 From: Brayden Siew Date: Fri, 3 Apr 2026 13:54:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20bridge=20review=E2=86=92rescue=20con?= =?UTF-8?q?text=20gap=20with=20per-repo=20saved=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When /codex:review or /codex:adversarial-review completes in the foreground, pipe output through `tee` to a repo-scoped file at ~/.codex/last-review-.md so findings survive across Codex cold-starts. When /codex:rescue is invoked with no task, check for that saved review and offer to fix those issues directly — no copy-pasting required. Using a per-repo hash instead of a global path prevents stale findings from one project bleeding into a rescue session in a different repo. All shell operations stay within each file's allowed-tools constraints: review.md and adversarial-review.md use Bash(git:*) for repo root and Bash(node:*) for dir creation and hashing; rescue.md (node-only) calls git via child_process.execSync inside a node one-liner. --- plugins/codex/commands/rescue.md | 13 ++++++++++++- plugins/codex/commands/review.md | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/plugins/codex/commands/rescue.md b/plugins/codex/commands/rescue.md index c92a289..c42b0b8 100644 --- a/plugins/codex/commands/rescue.md +++ b/plugins/codex/commands/rescue.md @@ -46,4 +46,15 @@ Operating rules: - Leave the model unset unless the user explicitly asks for one. If they ask for `spark`, map it to `gpt-5.3-codex-spark`. - Leave `--resume` and `--fresh` in the forwarded request. The subagent handles that routing when it builds the `task` command. - If the helper reports that Codex is missing or unauthenticated, stop and tell the user to run `/codex:setup`. -- If the user did not supply a request, ask what Codex should investigate or fix. +- If the user did not supply a request, check for a saved review from `/codex:review` or `/codex:adversarial-review`: +```bash +node -e "const {execSync:x}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto');let t;try{t=x('git rev-parse --show-toplevel',{encoding:'utf8'}).trim()}catch(e){t=null};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const p=os.homedir()+'/.codex/last-review-'+h+'.md';console.log(fs.existsSync(p)?'LAST_REVIEW_AVAILABLE':'NO_LAST_REVIEW');" +``` + - If `LAST_REVIEW_AVAILABLE`: use `AskUserQuestion` once with two options: + - `Fix issues from last review (Recommended)` — prepend the saved review content as context for the rescue task + - `Describe a new task` — ask what Codex should investigate or fix + - If the user chooses to fix from last review, read the review file with node and include it verbatim prefixed with: "The following issues were found in a prior Codex review. Please fix them:\n\n" +```bash +node -e "const {execSync:x}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto');let t;try{t=x('git rev-parse --show-toplevel',{encoding:'utf8'}).trim()}catch(e){t=null};const h=t?c.createHash('md5').update(t).digest('hex'):'global';process.stdout.write(fs.readFileSync(os.homedir()+'/.codex/last-review-'+h+'.md','utf8'));" +``` + - If `NO_LAST_REVIEW`: ask what Codex should investigate or fix. diff --git a/plugins/codex/commands/review.md b/plugins/codex/commands/review.md index fb70a48..68c23aa 100644 --- a/plugins/codex/commands/review.md +++ b/plugins/codex/commands/review.md @@ -40,19 +40,31 @@ Argument handling: - If the user needs custom review instructions or more adversarial framing, they should use `/codex:adversarial-review`. Foreground flow: -- Run: +- Get the repo root (falls back to "global" outside a git repo): ```bash -node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" +git rev-parse --show-toplevel 2>/dev/null || echo "global" +``` +- Create `~/.codex` and compute the save path. Substitute `` with the output of the previous step: +```bash +node -e "const c=require('crypto'),os=require('os'),fs=require('fs'),root=process.argv[1];const h=root&&root!=='global'?c.createHash('md5').update(root).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});console.log(d+'/last-review-'+h+'.md');" "" +``` +- Run, piping output to both the terminal and the save path. Substitute `` with the node output above: +```bash +node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" | tee "" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. - Do not fix any issues mentioned in the review output. Background flow: +- Determine the repo-scoped save path: +```bash +_REPO_HASH=$(git rev-parse --show-toplevel 2>/dev/null | md5 | awk '{print $1}' || echo "global") +``` - Launch the review with `Bash` in the background: ```typescript Bash({ - command: `node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS"`, + command: `node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" | tee ~/.codex/last-review-${_REPO_HASH}.md`, description: "Codex review", run_in_background: true }) From 7dee7f0d2176f0272f40fb274d32a4097e847af7 Mon Sep 17 00:00:00 2001 From: Brayden Siew Date: Fri, 3 Apr 2026 13:54:12 +0800 Subject: [PATCH 2/5] fix: apply same review-save logic to adversarial-review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missed in the previous commit — adversarial-review.md needs the same per-repo tee flow so its output is also available for /codex:rescue. --- plugins/codex/commands/adversarial-review.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/codex/commands/adversarial-review.md b/plugins/codex/commands/adversarial-review.md index da440ab..a985473 100644 --- a/plugins/codex/commands/adversarial-review.md +++ b/plugins/codex/commands/adversarial-review.md @@ -45,9 +45,17 @@ Argument handling: - Unlike `/codex:review`, it can still take extra focus text after the flags. Foreground flow: -- Run: +- Get the repo root (falls back to "global" outside a git repo): ```bash -node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" adversarial-review "$ARGUMENTS" +git rev-parse --show-toplevel 2>/dev/null || echo "global" +``` +- Create `~/.codex` and compute the save path. Substitute `` with the output of the previous step: +```bash +node -e "const c=require('crypto'),os=require('os'),fs=require('fs'),root=process.argv[1];const h=root&&root!=='global'?c.createHash('md5').update(root).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});console.log(d+'/last-review-'+h+'.md');" "" +``` +- Run, piping output to both the terminal and the save path. Substitute `` with the node output above: +```bash +node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" adversarial-review "$ARGUMENTS" | tee "" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. From 647cd1bc801f14b86f6d37fe4abf57accbecd1a2 Mon Sep 17 00:00:00 2001 From: Brayden Siew Date: Sun, 5 Apr 2026 13:31:59 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20harden=20background=20save=20flow=20?= =?UTF-8?q?=E2=80=94=20consistent=20hash,=20mkdir,=20exit=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The background flow had four bugs vs the foreground implementation: 1. Hash mismatch: `git ... | md5 | awk '{print $1}'` produces a different format than crypto.createHash('md5').digest('hex') used in foreground and rescue — background-saved files were never found. 2. No mkdir: ~/.codex was not created before tee, causing tee to fail on first run and silently drop the review output. 3. Exit code swallowed: piping through tee masks a non-zero companion exit, so failed reviews could be recorded as successful background jobs. 4. Adversarial background never saved: the adversarial-review background flow launched without any tee, so /codex:rescue could never find it. Fix: replace the background command in both review.md and adversarial-review.md with a single node wrapper that computes the hash via crypto (same as foreground/rescue), calls mkdirSync, runs the companion via spawnSync, writes the file only on exit 0, and exits with the companion's status code. --- plugins/codex/commands/adversarial-review.md | 4 ++-- plugins/codex/commands/review.md | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/plugins/codex/commands/adversarial-review.md b/plugins/codex/commands/adversarial-review.md index a985473..ea26ce6 100644 --- a/plugins/codex/commands/adversarial-review.md +++ b/plugins/codex/commands/adversarial-review.md @@ -62,10 +62,10 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" adversarial-review "$AR - Do not fix any issues mentioned in the review output. Background flow: -- Launch the review with `Bash` in the background: +- Launch the review with `Bash` in the background. The node wrapper uses the same hash logic as the foreground flow, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```typescript Bash({ - command: `node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" adversarial-review "$ARGUMENTS"`, + command: `node -e "const {spawnSync:sp}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=sp('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const r=sp(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const out=r.stdout?r.stdout.toString():'';process.stdout.write(out);if(r.status===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),out);process.exit(r.status??1);" -- "$ARGUMENTS"`, description: "Codex adversarial review", run_in_background: true }) diff --git a/plugins/codex/commands/review.md b/plugins/codex/commands/review.md index 68c23aa..4110140 100644 --- a/plugins/codex/commands/review.md +++ b/plugins/codex/commands/review.md @@ -57,14 +57,10 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" | t - Do not fix any issues mentioned in the review output. Background flow: -- Determine the repo-scoped save path: -```bash -_REPO_HASH=$(git rev-parse --show-toplevel 2>/dev/null | md5 | awk '{print $1}' || echo "global") -``` -- Launch the review with `Bash` in the background: +- Launch the review with `Bash` in the background. The node wrapper uses the same hash logic as the foreground flow, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```typescript Bash({ - command: `node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" | tee ~/.codex/last-review-${_REPO_HASH}.md`, + command: `node -e "const {spawnSync:sp}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=sp('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const r=sp(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const out=r.stdout?r.stdout.toString():'';process.stdout.write(out);if(r.status===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),out);process.exit(r.status??1);" -- "$ARGUMENTS"`, description: "Codex review", run_in_background: true }) From 74da0b248f4ccead13223e24ae88508e89148c35 Mon Sep 17 00:00:00 2001 From: Brayden Siew Date: Sun, 5 Apr 2026 14:43:43 +0800 Subject: [PATCH 4/5] fix: use streaming spawn for both foreground and background flows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Foreground: replace 3-step git+node+tee pipeline with a single streaming node wrapper — fixes pipefail gap where companion failure was masked by tee's exit 0 - Background: replace spawnSync (buffers entire output) with spawn (streams chunks in real-time) — fixes memory pressure on large reviews and ensures output appears progressively in /codex:result - Both flows now share the same wrapper pattern: streams stdout live, saves to ~/.codex/last-review-.md only on exit 0, propagates the companion exit code --- plugins/codex/commands/adversarial-review.md | 16 ++++------------ plugins/codex/commands/review.md | 16 ++++------------ 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/plugins/codex/commands/adversarial-review.md b/plugins/codex/commands/adversarial-review.md index ea26ce6..4f2ee8e 100644 --- a/plugins/codex/commands/adversarial-review.md +++ b/plugins/codex/commands/adversarial-review.md @@ -45,27 +45,19 @@ Argument handling: - Unlike `/codex:review`, it can still take extra focus text after the flags. Foreground flow: -- Get the repo root (falls back to "global" outside a git repo): +- Run the review. The node wrapper streams output in real-time, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```bash -git rev-parse --show-toplevel 2>/dev/null || echo "global" -``` -- Create `~/.codex` and compute the save path. Substitute `` with the output of the previous step: -```bash -node -e "const c=require('crypto'),os=require('os'),fs=require('fs'),root=process.argv[1];const h=root&&root!=='global'?c.createHash('md5').update(root).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});console.log(d+'/last-review-'+h+'.md');" "" -``` -- Run, piping output to both the terminal and the save path. Substitute `` with the node output above: -```bash -node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" adversarial-review "$ARGUMENTS" | tee "" +node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. - Do not fix any issues mentioned in the review output. Background flow: -- Launch the review with `Bash` in the background. The node wrapper uses the same hash logic as the foreground flow, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: +- Launch the review with `Bash` in the background. Same streaming node wrapper as the foreground flow: ```typescript Bash({ - command: `node -e "const {spawnSync:sp}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=sp('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const r=sp(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const out=r.stdout?r.stdout.toString():'';process.stdout.write(out);if(r.status===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),out);process.exit(r.status??1);" -- "$ARGUMENTS"`, + command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS"`, description: "Codex adversarial review", run_in_background: true }) diff --git a/plugins/codex/commands/review.md b/plugins/codex/commands/review.md index 4110140..161b301 100644 --- a/plugins/codex/commands/review.md +++ b/plugins/codex/commands/review.md @@ -40,27 +40,19 @@ Argument handling: - If the user needs custom review instructions or more adversarial framing, they should use `/codex:adversarial-review`. Foreground flow: -- Get the repo root (falls back to "global" outside a git repo): +- Run the review. The node wrapper streams output in real-time, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```bash -git rev-parse --show-toplevel 2>/dev/null || echo "global" -``` -- Create `~/.codex` and compute the save path. Substitute `` with the output of the previous step: -```bash -node -e "const c=require('crypto'),os=require('os'),fs=require('fs'),root=process.argv[1];const h=root&&root!=='global'?c.createHash('md5').update(root).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});console.log(d+'/last-review-'+h+'.md');" "" -``` -- Run, piping output to both the terminal and the save path. Substitute `` with the node output above: -```bash -node "${CLAUDE_PLUGIN_ROOT}/scripts/codex-companion.mjs" review "$ARGUMENTS" | tee "" +node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. - Do not fix any issues mentioned in the review output. Background flow: -- Launch the review with `Bash` in the background. The node wrapper uses the same hash logic as the foreground flow, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: +- Launch the review with `Bash` in the background. Same streaming node wrapper as the foreground flow: ```typescript Bash({ - command: `node -e "const {spawnSync:sp}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=sp('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const r=sp(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const out=r.stdout?r.stdout.toString():'';process.stdout.write(out);if(r.status===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),out);process.exit(r.status??1);" -- "$ARGUMENTS"`, + command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS"`, description: "Codex review", run_in_background: true }) From 8d5aa4ae92371058c19463e3747da4ba3193f1b6 Mon Sep 17 00:00:00 2001 From: Brayden Siew Date: Sun, 5 Apr 2026 22:56:44 +0800 Subject: [PATCH 5/5] fix: make cache writes best-effort with try/catch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mkdirSync and writeFileSync are now wrapped in try/catch so that unwritable ~/.codex (containers, locked-down envs) does not abort the review — saving last-review-*.md is optional metadata, not a hard prerequisite. --- plugins/codex/commands/adversarial-review.md | 4 ++-- plugins/codex/commands/review.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/codex/commands/adversarial-review.md b/plugins/codex/commands/adversarial-review.md index 4f2ee8e..b11ac6f 100644 --- a/plugins/codex/commands/adversarial-review.md +++ b/plugins/codex/commands/adversarial-review.md @@ -47,7 +47,7 @@ Argument handling: Foreground flow: - Run the review. The node wrapper streams output in real-time, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```bash -node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS" +node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';try{fs.mkdirSync(d,{recursive:true})}catch(e){};const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)try{fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks))}catch(e){};process.exit(code??1)});" -- "$ARGUMENTS" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. @@ -57,7 +57,7 @@ Background flow: - Launch the review with `Bash` in the background. Same streaming node wrapper as the foreground flow: ```typescript Bash({ - command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS"`, + command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';try{fs.mkdirSync(d,{recursive:true})}catch(e){};const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'adversarial-review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)try{fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks))}catch(e){};process.exit(code??1)});" -- "$ARGUMENTS"`, description: "Codex adversarial review", run_in_background: true }) diff --git a/plugins/codex/commands/review.md b/plugins/codex/commands/review.md index 161b301..2789777 100644 --- a/plugins/codex/commands/review.md +++ b/plugins/codex/commands/review.md @@ -42,7 +42,7 @@ Argument handling: Foreground flow: - Run the review. The node wrapper streams output in real-time, creates `~/.codex` if needed, saves output only on success, and propagates the exit code: ```bash -node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS" +node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';try{fs.mkdirSync(d,{recursive:true})}catch(e){};const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)try{fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks))}catch(e){};process.exit(code??1)});" -- "$ARGUMENTS" ``` - Return the command stdout verbatim, exactly as-is. - Do not paraphrase, summarize, or add commentary before or after it. @@ -52,7 +52,7 @@ Background flow: - Launch the review with `Bash` in the background. Same streaming node wrapper as the foreground flow: ```typescript Bash({ - command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';fs.mkdirSync(d,{recursive:true});const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks));process.exit(code??1)});" -- "$ARGUMENTS"`, + command: `node -e "const {spawn,spawnSync:ss}=require('child_process'),os=require('os'),fs=require('fs'),c=require('crypto'),path=require('path');let t;try{t=ss('git',['rev-parse','--show-toplevel'],{encoding:'utf8'}).stdout.trim()}catch(e){t=''};const h=t?c.createHash('md5').update(t).digest('hex'):'global';const d=os.homedir()+'/.codex';try{fs.mkdirSync(d,{recursive:true})}catch(e){};const args=process.argv.slice(2).filter(Boolean);const child=spawn(process.execPath,[path.resolve(process.env.CLAUDE_PLUGIN_ROOT,'scripts/codex-companion.mjs'),'review',...args],{stdio:['inherit','pipe','inherit'],env:process.env});const chunks=[];child.stdout.on('data',chunk=>{process.stdout.write(chunk);chunks.push(chunk)});child.on('close',code=>{if(code===0)try{fs.writeFileSync(path.join(d,'last-review-'+h+'.md'),Buffer.concat(chunks))}catch(e){};process.exit(code??1)});" -- "$ARGUMENTS"`, description: "Codex review", run_in_background: true })