feat(default-reporter): add pnpm-render bin to render NDJSON from stdin#11530
Conversation
Adds a `default-reporter` bin to `@pnpm/cli.default-reporter` that reads pnpm-shaped NDJSON from stdin and pipes it through the default reporter. This lets external tools that emit `pnpm:*` log records (e.g. pacquet's `--reporter=ndjson`) reuse pnpm's renderer. Usage: `pacquet install --reporter=ndjson 2>&1 >/dev/null | default-reporter` Optional first positional argument sets the command name (defaults to `install`).
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a pnpm-render CLI binary and entrypoint, implements runCli to parse pnpm-shaped NDJSON from stdin and emit logs to the default reporter, and includes Jest tests, README docs, a changeset, and a cspell update. Changespnpm-render CLI Binary
Sequence DiagramsequenceDiagram
participant User
participant Shell
participant pnpmRender as pnpm-render
participant Parser
participant Reporter
participant Stdout
User->>Shell: run pnpm-render [cmd]
Shell->>pnpmRender: spawn process
pnpmRender->>Parser: read stdin NDJSON lines
Parser->>Reporter: emit Log objects
Reporter->>Stdout: render output lines
pnpmRender->>Reporter: close()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
`default-reporter` was too generic for a globally-installed binary; `pnpm-render` is namespaced and reflects what the bin does — render pnpm-shaped NDJSON from stdin.
Spawns the bin, pipes NDJSON, and asserts the rendered "Progress: resolved" line appears on stdout. Also exercises the malformed-line path. Catches regressions in the bin wiring (path, package.json bin entry, stdin parsing, clean shutdown on EOF) that the existing toOutput$ unit tests can't cover. Also fixes a race in src/cli.ts: initDefaultReporter registers its 'data' listener via setTimeout(0), so emitting events before the next tick dropped them. runCli now waits one tick before reading stdin. Documents the bin and the pacquet pipe usage in the README.
There was a problem hiding this comment.
Pull request overview
Adds a new pnpm-render executable to @pnpm/cli.default-reporter that reads pnpm-shaped NDJSON from stdin and renders it using pnpm’s default reporter, enabling external tools (e.g. pacquet) to reuse pnpm’s renderer.
Changes:
- Introduces a small CLI (
runCli) that parses NDJSON lines from stdin and forwards them intoinitDefaultReporter. - Adds the published
pnpm-renderbin entry + packagedbin/script, plus documentation and a changeset. - Adds Jest coverage for basic stdin rendering and non-JSON line handling.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cspell.json | Adds pacquet to spellcheck allowlist. |
| cli/default-reporter/test/cli.ts | Adds Jest tests that spawn the new pnpm-render bin and pipe NDJSON to stdin. |
| cli/default-reporter/src/cli.ts | Implements the new stdin-driven renderer CLI (runCli). |
| cli/default-reporter/README.md | Documents pnpm-render usage and piping example with pacquet. |
| cli/default-reporter/package.json | Publishes the new bin and ensures bin/ is included in package files. |
| cli/default-reporter/bin/pnpm-render.mjs | Adds the executable entrypoint invoking runCli. |
| .changeset/default-reporter-bin.md | Declares a minor release and documents the new bin. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cli/default-reporter/test/cli.ts`:
- Around line 44-49: The Promise awaiting the child process uses
child.on('exit', ...) which can fire before stdout/stderr are fully drained;
change the listener to child.on('close', (code) => { resolve(code) }) so the
Promise resolves only after all stdio streams are closed (keep child.on('error',
reject') intact); update the variable handling around exitCode/new Promise to
use the 'close' event on the child process instead of 'exit'.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: b6fdfc1a-e99a-4732-ba3d-da0a3c4b1885
📒 Files selected for processing (7)
.changeset/default-reporter-bin.mdcli/default-reporter/README.mdcli/default-reporter/bin/pnpm-render.mjscli/default-reporter/package.jsoncli/default-reporter/src/cli.tscli/default-reporter/test/cli.tscspell.json
- Drop throttleProgress: with no live producer, closing on stdin EOF can drop the trailing throttle emission and lose the final progress state. - Guard against valid-but-non-object JSON (e.g. `null`, numbers, strings): these would propagate to the reporter and crash on `log.name` access. - In the test, wait for child 'close' instead of 'exit' so stdout/stderr are fully drained before assertions run.
Restoring throttleProgress: 200 — rxjs throttleTime emits its pending trailing value when the source completes, and the standard pnpm:stage importing_done event completes the per-requirer progress stream (see reportProgress.ts). So for producers that emit importing_done at end of install (e.g. pacquet), the final progress value renders correctly. The remaining lossy case — a truncated stream without importing_done — is narrow and not worth losing redraw throttling for live producers.
…in (#11530) - Adds a `pnpm-render` bin to `@pnpm/cli.default-reporter` that reads pnpm-shaped NDJSON from stdin and pipes it through the default reporter, so external tools that emit `pnpm:*` log records can reuse pnpm's renderer. - Optional first positional arg sets the command name (defaults to `install`), e.g. `pnpm-render add` for piping output from `pacquet add`. ## Motivation [Pacquet](https://github.com/pnpm/pacquet) emits pnpm-shaped `--reporter=ndjson` output for forward-compatibility with pnpm's renderer, but there was no way to actually render it. With this bin: ```sh pacquet install --reporter=ndjson 2>&1 >/dev/null | pnpm-render ``` (pacquet writes NDJSON to stderr, so the redirect is needed.)
Summary
pnpm-renderbin to@pnpm/cli.default-reporterthat reads pnpm-shaped NDJSON from stdin and pipes it through the default reporter, so external tools that emitpnpm:*log records can reuse pnpm's renderer.install), e.g.pnpm-render addfor piping output frompacquet add.Motivation
Pacquet emits pnpm-shaped
--reporter=ndjsonoutput for forward-compatibility with pnpm's renderer, but there was no way to actually render it. With this bin:(pacquet writes NDJSON to stderr, so the redirect is needed.)
Test plan
pacquet install --reporter=ndjson: progress + context block render correctlyWritten by an agent (Claude Code, claude-opus-4-7).
Summary by CodeRabbit
New Features
Documentation
Tests
Chores