Skip to content

fix(cli): flush stdout before exiting - #93

Merged
aryanjasala merged 3 commits into
mainfrom
fix/cli-flush-stdout
Nov 9, 2026
Merged

aryanjasala merged 3 commits into
mainfrom
fix/cli-flush-stdout

Conversation

@aryanjasala

Copy link
Copy Markdown
Member

What this PR does

Stops wp-tooling from cutting its output short when it is piped. bin/wp-tooling.js called process.exit() as soon as a command resolved, which drops whatever stdout has not written yet. Writes to a pipe are asynchronous on macOS, so wp-tooling list --json | jq, or iapi-check --output json | jq (#91), received exactly 65,536 bytes of invalid JSON whenever the reader was not ready in time.

Closes

N/A

Changes

  • bin/wp-tooling.js sets process.exitCode, writes an empty chunk and exits from its callback, once everything queued before it has gone out. A closed pipe (EPIPE, for example | head) still exits straight away. Exit codes are unchanged.
  • tests/cli/bin.test.js pipes list --json (about 70 KiB) into a reader that starts a second late and checks it receives every byte, and checks a usage error still exits 2.
  • CHANGELOG entry under ### Fixed.

How I verified

$ node bin/wp-tooling.js list --json | (sleep 1; wc -c)    # main, three runs
65536
65536
65536
$ node bin/wp-tooling.js list --json | (sleep 1; wc -c)    # this branch, three runs
70949
70949
70949
$ npx jest --ci --coverage                                  # node-packages/wp-tooling
Test Suites: 83 passed, 83 total
Tests:       1380 passed, 1380 total
$ npm run lint -w @rtcamp/wp-tooling

The new test fails on main (Expected: 70949, Received: 65536) and passes here.

Reviewer notes

process.exit() drops whatever stdout has not written yet. Writes to a
pipe are asynchronous on macOS, so a report longer than the pipe buffer
piped into a reader that was not ready yet (wp-tooling list --json | jq,
iapi-check --output json | jq) arrived cut off at exactly 65,536 bytes,
as invalid JSON. The bin now sets the exit code, writes an empty chunk
and exits from its callback, after everything queued before it has gone
out. A closed pipe (EPIPE) still exits straight away.

A test pipes list --json (about 70 KiB) into a reader that starts a
second late and checks it receives every byte; it fails without the fix
on macOS. Linux writes to pipes synchronously, so there it passes either
way.
Copilot AI balanced review requested due to automatic review settings November 6, 2026 00:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The regression-test comment needs correction because asynchronous stdout writes can also truncate piped output on Linux, not just macOS.

1 open issue
What changed in this PR

This PR prevents truncated piped output from the wp-tooling CLI, supporting commands that produce large JSON reports.

Changes:

  • Waits for queued stdout writes before exiting, preserving command exit codes and handling closed pipes.
  • Adds regression tests for delayed pipe readers and usage-error exit codes.
  • Documents the fix in the changelog.
File Description
node-packages/​wp-tooling/​tests/​cli/​bin.test.js Tests complete piped output and usage-error exit status.
node-packages/​wp-tooling/​CHANGELOG.md Records the stdout truncation fix.
node-packages/​wp-tooling/​bin/​wp-tooling.js Defers exit until stdout finishes writing or reports an error.

Review effort: Balanced

Move the exit into src/cli/exit.js and wait for both streams. stderr
was cut at 64 KiB like stdout, and an EPIPE on it (2>&1 | head) turned
a successful run into exit code 1. Pipes are asynchronous on Linux too,
so correct the test and changelog notes that said macOS only.
@aryanjasala
aryanjasala requested a review from Adi-ty November 9, 2026 19:12
# Conflicts:
#	node-packages/wp-tooling/CHANGELOG.md
@aryanjasala
aryanjasala merged commit a52957d into main Nov 9, 2026
12 checks passed
github-actions Bot pushed a commit that referenced this pull request Nov 9, 2026
* fix(cli): flush stdout before exiting

process.exit() drops whatever stdout has not written yet. Writes to a
pipe are asynchronous on macOS, so a report longer than the pipe buffer
piped into a reader that was not ready yet (wp-tooling list --json | jq,
iapi-check --output json | jq) arrived cut off at exactly 65,536 bytes,
as invalid JSON. The bin now sets the exit code, writes an empty chunk
and exits from its callback, after everything queued before it has gone
out. A closed pipe (EPIPE) still exits straight away.

A test pipes list --json (about 70 KiB) into a reader that starts a
second late and checks it receives every byte; it fails without the fix
on macOS. Linux writes to pipes synchronously, so there it passes either
way.

* fix(cli): flush stderr as well as stdout before exiting

Move the exit into src/cli/exit.js and wait for both streams. stderr
was cut at 64 KiB like stdout, and an EPIPE on it (2>&1 | head) turned
a successful run into exit code 1. Pipes are asynchronous on Linux too,
so correct the test and changelog notes that said macOS only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants