openai / openai/codex-plugin-cc

`runCommand` sets `maxBuffer: options.maxBuffer` — the ENOBUFS fix from #179 works only because a spread `undefined` deletes Node's default

Open
#744 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
33.3k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Summary

runCommand in plugins/codex/scripts/lib/process.mjs:10 sets maxBuffer: options.maxBuffer. No caller except measureGitOutputBytes (lib/git.mjs:41) ever supplies a value, so for every other command that property is literally undefined.

That is not the same as omitting it. spawnSync builds its options as

options = {
  __proto__: null,
  maxBuffer: MAX_BUFFER,      // 1 MiB
  ...normalizeSpawnArguments(file, args, options),
};

The spread carries an own maxBuffer property whose value is undefined, which overwrites the 1 MiB default. The result is not "1 MiB" and not "the caller's value" — it is no limit at all.

So #11 and #151 are genuinely fixed on main, but not by the size gate that PR #179 added, and not by anything named in that PR. They are fixed because a property that looks like an inert pass-through happens to delete Node's default. Nothing documents this and no test covers it.

Consequence 1: one refactor away from reopening #11 and #151

Every shape a reader would consider equivalent restores the 1 MiB cap:

maxBuffer: options.maxBuffer ?? MAX,                            // different
...(options.maxBuffer !== undefined && { maxBuffer: options.maxBuffer }),  // different
// or just dropping the line as "it does nothing"

Same repo, same review, only that line changed:

upstream HEAD  (maxBuffer: options.maxBuffer) -> OK   inputMode=self-collect diffBytes=0
same logic, key omitted when unset            -> ENOBUFS  spawnSync git ENOBUFS

Consequence 2: the reads that are unbounded are the ones the gate never measures

PR #179's gate measures only the diff, and only to decide inline-diff vs self-collect. These run on every review, before and outside the gate, with no ceiling:

line command
git.mjs:123-125 diff --cached --name-only, diff --name-only, ls-files --others --exclude-standard
git.mjs:227 status --short --untracked-files=all
git.mjs:266-267 diff --name-only <range>, log --oneline --decorate <range>

--untracked-files=all expands every file under every untracked directory, so a repo with an unignored node_modules/, build/ or coverage output produces megabytes of path names while the diff itself is empty. Today that is read into a JS string with no limit; after any of the refactors above it is ENOBUFS. Neither is the intended behaviour, and per #151 an ENOBUFS from binaryAvailable surfaces as the misleading "Codex CLI is not installed".

Repro

git init repro && cd repro
git commit -qm init --allow-empty
mkdir -p build/assets
python3 -c "
import os
for i in range(14000):
    open('build/assets/generated_component_with_a_reasonably_long_file_name_%05d.chunk.js' % i, 'w').write('x')
"
git status --short --untracked-files=all | wc -c   # 1176000 -> over Node's 1 MiB default
git diff --binary | wc -c                          # 0       -> the measured gate sees nothing

Then collectReviewContext(cwd, { mode: "working-tree" }) buffers ~1.15 MB of path names on main, and throws ENOBUFS under any of the equivalent-looking rewrites.

Suggested fix

Give the pass-through an explicit, generous default so the ceiling is stated rather than inherited from a spread quirk:

// Node defaults maxBuffer to 1 MiB, which ENOBUFS on any git output larger than that.
maxBuffer: options.maxBuffer ?? 256 * 1024 * 1024,

measureGitOutputBytes still passes its own small bound, so the inline-diff / self-collect gate is unaffected. A regression test asserting that a >1 MiB git status survives runCommand would pin the behaviour that #11 and #151 currently depend on implicitly.

Environment

  • codex-plugin-cc: main @ db52e28 (1.0.6); originally hit on 1.0.2, which had no maxBuffer line at all
  • Node.js: v24.12.0 and v25.9.0 (identical results)
  • macOS arm64

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in plugins/codex/scripts/lib/process.mjs:10 and compare its runCommand options with the caller at lib/git.mjs:41; then inspect the git output calls around lines 123-125, 227, and 266-267. Add a regression test exercising a git status larger than 1 MiB through runCommand, while confirming measureGitOutputBytes keeps its separate bound; done means the large status succeeds without reopening the existing ENOBUFS failures.

Written by the indexing model from the issue text.

Assessment

Tech stack
git, javascript, node.js
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.