The ACTUAL blocker for pi's interactive TUI under perry (supersedes the async-generator theory — see below). Pi renders and accepts typed text, but pressing Enter (CR 0x0d) does not submit the message under perry, where node (same bundle) submits and renders the response.
Evidence (fixed-binary A/B, decisive)
Using /tmp/pi-fixed = pi compiled WITH the async-generator await-suspension fix (#6727), interactive PTY repro, bogus API key (a valid request 401s — that's the expected visible result):
| Enter byte |
perry result |
node result |
CR 0x0d |
"hello" stuck in input, no submit, no "Working…", no 401 (19547 B) |
submit → "Working…" → "Error: 401 authentication_error" (33338 B) |
LF 0x0a |
input processed differently (25792 B) but still no 401 |
— |
CRLF 0x0d0a |
25792 B, no 401 |
— |
So no Enter variant submits+responds under perry; node does with CR. The async-generator fix (#6727) does NOT change this (perry CR result byte-identical with and without it) — confirming the keypress→submit path, not async-generator event forwarding, is what blocks pi. (#6727 fixes a real, separate async-generator await-on-pending-Promise deadlock and is worth landing on its own; it would be the NEXT blocker once submit works.)
Mechanism (where to look)
Pi reads raw stdin itself: process.stdin.setRawMode(true) (bundle ~232037) + process.stdin.on("data", stdinDataHandler) (~232095), and runs a custom keypress parser that also negotiates the Kitty keyboard protocol (queryAndEnableKittyProtocol, KITTY_KEYBOARD_PROTOCOL_QUERY). Enter/CR decoding flows through that raw-byte parse (charCodeAt, string/Buffer handling, CR/LF/CRLF logic at ~50346, Kitty sequence parsing). A perry divergence in one of: (a) how stdin.on("data") delivers the chunk under raw mode (Buffer vs string, encoding, chunk boundaries), (b) charCodeAt/string comparison in the parser, (c) the Kitty-protocol negotiation buffer handling, or (d) setRawMode/termios not matching node (CR vs LF delivery). The CR-vs-LF asymmetry points at the parser receiving/classifying the Enter byte differently than under node.
Diagnosis approach
Instrument node-vs-perry inside stdinDataHandler / the keypress parser in the UNMINIFIED bundle (pi-target/dist/pi-bundle.mjs): log the exact bytes/keyname the parser receives and classifies for a sent CR under each runtime; find the first divergence. Repro harness: scratchpad/pty_drive.py (PTY_SCRIPT scripted input); fd pre-placed HOME; cwd=pi-target/dist; binary /tmp/pi-fixed (or recompile). Node oracle: node pi-bundle.mjs. Reduce to a minimal fixture (raw-mode stdin + the same parse shape) and fix the perry divergence node-identically.
Blocks pi interactive chat entirely. Peer walls on the pi path: #6704 (render, merged), #6727 (async-gen, worth landing), OAuth/login (source-tweak workaround).
The ACTUAL blocker for pi's interactive TUI under perry (supersedes the async-generator theory — see below). Pi renders and accepts typed text, but pressing Enter (CR
0x0d) does not submit the message under perry, where node (same bundle) submits and renders the response.Evidence (fixed-binary A/B, decisive)
Using
/tmp/pi-fixed= pi compiled WITH the async-generator await-suspension fix (#6727), interactive PTY repro, bogus API key (a valid request 401s — that's the expected visible result):0x0d0x0a0x0d0aSo no Enter variant submits+responds under perry; node does with CR. The async-generator fix (#6727) does NOT change this (perry CR result byte-identical with and without it) — confirming the keypress→submit path, not async-generator event forwarding, is what blocks pi. (#6727 fixes a real, separate async-generator
await-on-pending-Promise deadlock and is worth landing on its own; it would be the NEXT blocker once submit works.)Mechanism (where to look)
Pi reads raw stdin itself:
process.stdin.setRawMode(true)(bundle ~232037) +process.stdin.on("data", stdinDataHandler)(~232095), and runs a custom keypress parser that also negotiates the Kitty keyboard protocol (queryAndEnableKittyProtocol,KITTY_KEYBOARD_PROTOCOL_QUERY). Enter/CR decoding flows through that raw-byte parse (charCodeAt, string/Bufferhandling, CR/LF/CRLF logic at ~50346, Kitty sequence parsing). A perry divergence in one of: (a) howstdin.on("data")delivers the chunk under raw mode (Buffer vs string, encoding, chunk boundaries), (b)charCodeAt/string comparison in the parser, (c) the Kitty-protocol negotiation buffer handling, or (d)setRawMode/termios not matching node (CR vs LF delivery). The CR-vs-LF asymmetry points at the parser receiving/classifying the Enter byte differently than under node.Diagnosis approach
Instrument node-vs-perry inside
stdinDataHandler/ the keypress parser in the UNMINIFIED bundle (pi-target/dist/pi-bundle.mjs): log the exact bytes/keyname the parser receives and classifies for a sent CR under each runtime; find the first divergence. Repro harness:scratchpad/pty_drive.py(PTY_SCRIPTscripted input); fd pre-placed HOME; cwd=pi-target/dist; binary/tmp/pi-fixed(or recompile). Node oracle:node pi-bundle.mjs. Reduce to a minimal fixture (raw-mode stdin + the same parse shape) and fix the perry divergence node-identically.Blocks pi interactive chat entirely. Peer walls on the pi path: #6704 (render, merged), #6727 (async-gen, worth landing), OAuth/login (source-tweak workaround).