fix: cap pm item reads at 64 MiB instead of Node's 1 MiB spawnSync default

Merged
UN
3mo ago
+48-4

Problem

buildCsvExport() — the CSV export itself spawns the pm CLI to read items but passes no maxBuffer, so Node's 1 MiB spawnSync default applies.

Measured with this package's exact argv against a real 443-item pm workspace: 1,054,002 bytes — over the cap, failing today.

Past the cap the child is killed and the result comes back as:

status: null   signal: SIGTERM   error.code: ENOBUFS   stderr: ""

Because stderr is empty, the failure surfaced with nothing to diagnose. And at larger sizes stdout is genuinely truncated mid-document — verified by forcing a 100 KiB cap on the same workspace:

JSON.parse -> Unterminated string in JSON at position 130829

This is the package's primary function: exporting a mature tracker is exactly when it matters.

This was a straggler: pm-changelog, pm-context, pm-brief, pm-graph and pm-linear already cap their pm reads explicitly. A fleet-wide audit this session found 8 packages that did not.

Change

  • cap the pm read at 64 MiB, matching the sibling packages
  • report an ENOBUFS overrun explicitly — naming the limit and the remedy — instead of an unexplained failure

Verification

Same argv, same real 443-item workspace:

read bufferresult
Node default (1 MiB)status: null, ENOBUFS, empty stderr
64 MiB (this PR)status: 0, complete payload

Typecheck and the full test suite pass; changelog:check green.

pm items

itemstatus
pm-csv-m13h — pm item reads are capped at Node's 1 MiB spawnSync default, so a mature tracker fails with no diagnosisclosed

Companion-tracked fleet sweep; the same fix landed in pm-github (unbraind/pm-github#13), where it additionally unblocked --atomic --dry-run.

🤖 Generated with Claude Code


Summary by cubic

Cap pm item reads to 16 MiB by default (overridable via PM_LIST_MAX_BUFFER) to avoid Node’s 1 MiB spawnSync limit and stop silent truncation. The cap now resolves per call, and overruns and real pm exits report clear errors.

  • Bug Fixes
    • Apply maxBuffer via pmListMaxBuffer() to all pm list-all calls (CSV export, key index, applied-by-transaction); env override is read at runtime.
    • On ENOBUFS, throw a message that names the effective limit and suggests narrowing the export or raising PM_LIST_MAX_BUFFER; nonzero pm exits now surface stderr.
    • Reject malformed PM_LIST_MAX_BUFFER values (e.g., "64MiB"); use Number() with a positive safe-integer check and fall back to the default.