All checks were successful
publish / publish (push) Successful in 15s
A screenshot is normally sent to pi as a path, so the model gets its text and the reader gets nothing: pi renders image blocks in tool results but never on user messages. This extension closes both halves — the path collapses to "[Image #N]" as you type or on send, and the picture is drawn below the sent message. The rewrite is a terminal-input listener that re-reads a settled editor, joins word by word for paths with unescaped spaces, and reports a path that does not exist instead of eating the prompt. The drawing appends a custom session entry carrying the message's image blocks, one macrotask after message_end so it lands below the message pi persists afterwards, and renders it with pi-tui's inline image component under terminal.showImages and terminal.imageWidthCells. Entries stay out of the model context, so each image is still sent to the model once. Tests: npm test (21, node:test over a stand-in for pi: rewrite, send-time attachment, missing paths, append gate, renderer gating) and npm run typecheck. Co-Authored-By: nw-flash-flex <noreply@freno.me>
62 lines
3.2 KiB
Markdown
62 lines
3.2 KiB
Markdown
# pi-image-paths
|
||
|
||
Drop a screenshot into [pi](https://pi.dev)'s chat input — by path, by drag and drop, or pasted
|
||
whole from anywhere — and the picture becomes a real attachment instead of a long line of text.
|
||
|
||
```text
|
||
pi install npm:@mikefreno/pi-image-paths
|
||
```
|
||
|
||
```text
|
||
you › look at ~/Desktop/Screenshot\ 2026-10-21\ at\ 10.42.11.png — why is the header clipped?
|
||
↓
|
||
you › look at [Image #1] — why is the header clipped?
|
||
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
|
||
█ (the screenshot, drawn in the chat) █
|
||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||
```
|
||
|
||
## What it does
|
||
|
||
| Piece | Mechanism |
|
||
|---|---|
|
||
| Collapses the path as you type | A terminal-input listener re-reads the editor when it is idle: every token run that resolves to an image file is rewritten in place to `[Image #N]`, the way pi collapses big pastes into `[paste #N]`. Dropping three files at once flips all three. |
|
||
| Attaches on send | The `input` event resolves the markers it wrote, then looks for any image path still in the prompt (pasted whole, RPC mode, rewritten too late), attaches every file it finds, and leaves `[Image #N]` in the text. |
|
||
| Draws what was sent | Pi renders image blocks on tool results but never on user messages, so the sent images ride in a custom session entry that a registered entry renderer draws with pi-tui's inline-image component. The entry is appended one macrotask after `message_end` — pi persists the user message after extension handlers return — which puts the picture directly below the message in the live chat and in the session log. |
|
||
|
||
Supported: `png`, `jpg`/`jpeg`, `gif`, `webp`, `bmp`; `~` expansion; backslash-escaped spaces,
|
||
surrounding quotes, `file://` drops; bare filenames relative to the working directory; and paths
|
||
with unescaped spaces, which are joined word by word and disambiguated against the filesystem.
|
||
URLs are left alone, and a path that does not exist is reported as a warning instead of eating the
|
||
prompt.
|
||
|
||
## Settings
|
||
|
||
The drawing honours pi's own settings, live:
|
||
|
||
| Setting | Effect |
|
||
|---|---|
|
||
| `terminal.showImages` (default `true`) | Off: no entry is appended and nothing is drawn — the images still reach the model. |
|
||
| `terminal.imageWidthCells` (default `60`) | Width the picture is drawn at. |
|
||
| `terminal.images` (default `auto`) | No inline-image protocol: the renderer stays out of the way and the transcript keeps only the marker. |
|
||
|
||
Custom entries stay out of the model context, so the model still sees each image exactly once.
|
||
The image data is stored in the entry as well as in the message, which roughly doubles a session's
|
||
image bytes on disk.
|
||
|
||
Modes other than the interactive TUI attach images but draw nothing, and append no entries.
|
||
|
||
## Off the terminal: The Nook
|
||
|
||
[The Nook](https://nook.freno.me) puts every coding agent you run in your Mac's notch, on your
|
||
iPhone and on your Apple Watch. It renders the same image blocks, so a screenshot dropped into pi
|
||
shows up there as a picture too.
|
||
|
||
## Develop
|
||
|
||
```bash
|
||
npm test # node:test, driving the extension through a stand-in for pi
|
||
npm run typecheck
|
||
scripts/release-tag.sh # bump, tag and push; the v* tag publishes to npm
|
||
```
|