npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yuru7/pi-print-stream

v0.2.1

Published

A Pi extension that streams non-interactive runs: realtime text, tool JSONL, transient thinking, and usage summary

Downloads

498

Readme

pi-print-stream

A Pi extension that adds a --stream CLI flag for non-interactive runs.

pi -p "review this repository" --stream

While the turn runs:

  • Answer text streams to stdout in realtime and stays in the scrollback.
  • Tool calls stream as one JSON object per line and stay in the scrollback.
  • Thinking appears as a transient block of at most 8 screen rows (TTY only) and never pollutes the scrollback or redirected output.
  • When the run finishes, a usage summary shows tokens, elapsed time, TPS, and a command to continue the session.

How it works

--stream is a wrapper over pi --mode json -p. It intercepts the prompt, spawns a child pi --mode json -p "<prompt>" with the same model and flags, renders the child's JSONL event stream, and returns handled so Pi's own turn does not run twice. The child uses Pi's real print-mode path, so prompt handling, retries, and compaction behave exactly like a normal pi -p run.

pi -p "explain this repo" --stream      # recommended
pi --stream "explain this repo"         # also works (prompt recovered from argv)

Install

pi install npm:@yuru7/pi-print-stream

Local development:

pi -e ./extensions/index.ts -p "your prompt" --stream

Output

Answer text

text_delta events are written to stdout immediately, in arrival order. On a TTY the answer Markdown is rendered for the terminal with markdansi (headings, bold, lists, code blocks, tables, and more) as an append-only stream: completed lines are emitted as they arrive, while fenced code blocks and tables stay buffered until complete. Tool calls never reset the Markdown state. When stdout is not a TTY (redirect, pipe, tee, scripts), the raw Markdown is written unchanged with no ANSI sequences, keeping logs and pipes machine-readable.

Tool calls

Tool activity is emitted as compact JSONL, one event per line. On a TTY the lines are dimmed to stay unobtrusive; redirected output stays plain so grep/jq keep working:

{"type":"tool_start","id":"tool_1","name":"read","args":{"path":"src/index.ts"}}
{"type":"tool_end","id":"tool_1","name":"read","status":"success","elapsed_ms":42}

tool_end.status is "success" or "error". elapsed_ms is measured with a monotonic clock from tool_execution_start to tool_execution_end, so parallel tool calls are measured independently.

Tool result bodies are intentionally not printed: read, bash, grep, and web fetches can be very large. The stream shows the fact, name, args, status, and timing of each call.

Thinking (TTY only)

On a TTY, thinking deltas render as a transient block near the bottom of the screen:

────────────────────────────────────────
Thinking
  Need to inspect how message events are emitted.
  Tool execution should remain persistent.
  ...
────────────────────────────────────────
  • At most 8 screen rows are shown (wrapping-aware: CJK, emoji, and ANSI sequences are measured by display width, not string.length).
  • Older content scrolls off the top; only the latest rows are visible.
  • Tool calls alone never end the thinking session: the block is hidden, the tool line is written, and the thinking view is repainted below it.
  • The block is erased when answer text starts, and before errors or the final summary are written, so outputs never interleave.
  • The block is erased on resize and repainted with the new terminal width.
  • The thinking session ends when answer text takes over; tool-only message boundaries leave the view intact.

When stdout is not a TTY (redirect, pipe, tee, scripts), thinking is discarded completely and no ANSI control sequences are emitted. Only answer text, tool JSONL, and the final summary are written, keeping logs and pipes machine-readable.

Final summary

A compact 3-line block:

Done in 24.8s  TPS: 331.2 tok/s
Tokens: Input 12,481 / Cache read 48,220 / Output 3,842 / Cache write 0
To resume this session: pi --session 01a089b9-ae47-7772-8ce5-bd7cbb67bc29

The session ID comes from the leading {"type":"session",...} header of the child --mode json stream. The To resume this session line is omitted when no session ID is available (for example --no-session or a failure before the header arrives).

On failure the title is Failed and the statistics collected so far are shown. A missing trailing newline in the answer is added before the summary. On a TTY the block is dimmed; otherwise it is plain text.

TPS definition

TPS = Output tokens / Generation seconds

Generation time is the sum of message_startmessage_end intervals for assistant messages. Tool execution, network waits, and retries use wall-clock Elapsed time but are excluded from Generation and TPS, so the number reflects model generation speed rather than whole-agent latency. Usage is summed from each assistant message_end.message.usage (input, output, cacheRead, cacheWrite); missing fields count as zero. When generation time is zero, TPS is shown as -.

Behavior notes

  • Non-interactive only (print mode without UI). In interactive mode the TUI already renders the turn, so --stream is a no-op. Under --mode json or --mode rpc, Pi emits its own machine stream and --stream stays out of the way.
  • Malformed JSONL lines from the child never pollute stdout; a warning goes to stderr and streaming continues.
  • SIGINT / SIGTERM erase the transient thinking view, forward the same signal to the child, and exit with 130 / 143. The child exit code is otherwise propagated; a final assistant stopReason: "error" maps to exit 1 even when the JSON child itself exits 0.
  • All user-facing output is written to the real stdout (fd 1). Pi takes over process.stdout.write in print mode (forwarding extension output to stderr), so writing through process.stdout would lose redirected output. TTY detection and terminal width are likewise probed from fd 1, never from the replaced process.stdout object.
  • No TUI framework, syntax highlighting, tool-result dumps, or session restore is included. Output stays on stdout/ANSI by design.

License

MIT