mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(tui): stop writing OSC 133 prompt markers in regular mode (#11565)
In regular TUI mode, user and assistant messages wrote OSC 133 (`A`/`B`/`C`) shell-integration markers straight to the terminal. Terminals that display OSC 7501 program status (Rex, iTerm2 3.7.5+) read `133;A` as a new shell prompt and drop the current status. As a result, the `working` indicator disappeared right after a run started and only `done` showed up at the end. Fullscreen mode was not affected because it already strips these markers before writing. ## Change - `TuiMainScreen.doRender()` (`packages/tui/src/tui-main-screen.ts`) now strips OSC 133 markers from the start of each rendered line before compositing and writing. It uses the same pattern as fullscreen (`OSC133_ZONE_PREFIX`). - The message components still produce the markers. Fullscreen uses them internally for prompt navigation and already strips them before writing, so its behavior is unchanged. - In regular mode, the terminal's own jump-to-prompt shortcuts no longer stop at pi messages (added in #1805). ## Testing - New test in `packages/tui/test/tui-render.test.ts`: no `ESC]133;` reaches the terminal across a full render and a differential render, with both BEL and ST terminators. It fails without the change and passes with it. - These pass: - `packages/tui` `npm test` - `test/user-message.test.ts` and `test/assistant-message.test.ts` in coding-agent - `npm run check` - I ran `pi -ne --tui-mode regular` with `PI_PROGRAM_STATUS=1` and a streaming test provider, capturing all terminal output with `script`. - Before: `7501 working`, then repeated `133;A`/`133;B`/`133;C`, then `7501 done`. - After: only `7501 idle` → `working` → `done`, and no OSC 133. Fixes #11519 Requested by @davidbrai Co-authored-by: triagent <triagent@localhost>
This commit is contained in:
parent
ba7bdb9afc
commit
19ce8059c3
4 changed files with 25 additions and 1 deletions
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- Fixed the working status (OSC 7501) disappearing in Rex and iTerm2 during runs in regular TUI mode. Rendered messages wrote OSC 133 prompt markers to the terminal, which the terminal treats as a new shell prompt; regular mode no longer writes them ([#11519](https://github.com/earendil-works/pi/issues/11519))
|
||||
- Fixed compaction, branch summaries, and bug-report summaries in SDK sessions passing the stored OAuth token back to the model runtime as an explicit API key. Provider auth that treats explicit keys differently from stored OAuth now sees the OAuth login, as normal prompts do ([#11520](https://github.com/earendil-works/pi/issues/11520))
|
||||
- Fixed a redundant system prompt update (tools, rules) when an extension set the same active tools in a different order, for example a reversed `pi.setActiveTools()` list. Tools that stay active now keep their order and newly activated tools are appended ([#11495](https://github.com/earendil-works/pi/issues/11495))
|
||||
- Fixed `pi.exec()` crashing pi with `RangeError: Invalid string length` when a command printed more output than fits in a string. The default output cap is the smaller of 256 MiB and the runtime string limit; past the cap, the command is terminated and the result has `truncated: true` and a nonzero exit code ([#11360](https://github.com/earendil-works/pi/issues/11360))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
### Fixed
|
||||
|
||||
- Fixed regular-mode `TUI` writing OSC 133 prompt markers from rendered lines to the terminal. Terminals treat `133;A` as a new shell prompt and drop the OSC 7501 program status, so the working indicator disappeared during runs. Fullscreen still uses the markers for prompt navigation and already stripped them ([#11519](https://github.com/earendil-works/pi/issues/11519))
|
||||
- Fixed fullscreen double-click selection splitting paths and tokens at `~`, `.`, `\`, and `+`. Word characters now match iTerm2's defaults ([#10980](https://github.com/earendil-works/pi/issues/10980))
|
||||
- Fixed `fuzzyMatch()` ranking a query scattered over an earlier part of the text above a contiguous match later in it. It now also scores each contiguous occurrence of the query and keeps the best alignment ([#11220](https://github.com/earendil-works/pi/issues/11220), [#11296](https://github.com/earendil-works/pi/pull/11296))
|
||||
- Fixed `ProcessTerminal.setTitle()` writing control characters from the title, which could end the title sequence and send the rest to the terminal as escape sequences
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import { deleteKittyImage, isImageLine } from "./terminal-image.ts";
|
|||
import { type TUI, TuiBase, type TuiStopOptions } from "./tui.ts";
|
||||
import { visibleWidth } from "./utils.ts";
|
||||
|
||||
/** OSC 133 prompt markers at the start of a rendered line. Fullscreen uses them for prompt navigation. */
|
||||
const OSC133_ZONE_PREFIX = /^(?:\x1b\]133;[ABC](?:\x07|\x1b\\))+/;
|
||||
|
||||
const KITTY_SEQUENCE_PREFIX = "\x1b_G";
|
||||
const MAX_RENDER_WRITE_CHARS = 1024 * 1024;
|
||||
|
||||
|
|
@ -262,7 +265,8 @@ export class TuiMainScreen extends TuiBase implements TUI {
|
|||
|
||||
// Render all components to get new lines
|
||||
// Resolve fake cursors before compositing so overlays and line slicing see plain SGR codes
|
||||
let newLines = this.resolveFakeCursors(this.render(width));
|
||||
// Drop OSC 133 markers: the terminal reads 133;A as a new shell prompt, which ends program status (OSC 7501)
|
||||
let newLines = this.resolveFakeCursors(this.render(width).map((line) => line.replace(OSC133_ZONE_PREFIX, "")));
|
||||
|
||||
// Composite overlays into the rendered lines (before differential compare)
|
||||
if (this.hasOverlayEntries) {
|
||||
|
|
|
|||
|
|
@ -209,6 +209,24 @@ describe("TUI bounded render output", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("TUI OSC 133 markers", () => {
|
||||
it("does not write OSC 133 prompt markers to the terminal", () => {
|
||||
// Terminals read 133;A as a new shell prompt and drop the OSC 7501 program status.
|
||||
const terminal = new BoundedWriteTerminal();
|
||||
const tui = new TuiMainScreen(terminal);
|
||||
const component = new TestComponent();
|
||||
tui.addChild(component);
|
||||
component.lines = ["\x1b]133;A\x07prompt", "\x1b]133;B\x07\x1b]133;C\x07output"];
|
||||
tui.renderNow();
|
||||
component.lines = [...component.lines, "\x1b]133;A\x1b\\reply", "\x1b]133;B\x1b\\\x1b]133;C\x1b\\done"];
|
||||
tui.renderNow();
|
||||
|
||||
const output = terminal.writes.join("");
|
||||
assert.ok(!output.includes("\x1b]133;"), "regular mode must not emit OSC 133 markers");
|
||||
for (const text of ["prompt", "output", "reply", "done"]) assert.ok(output.includes(text));
|
||||
});
|
||||
});
|
||||
|
||||
/** Set each environment variable to `value`, returning a function that restores the previous state. */
|
||||
function overrideEnv(names: readonly string[], value: string): () => void {
|
||||
const previousValues = names.map((name) => [name, process.env[name]] as const);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue