diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7133939a1..7d9fe089f 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -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)) diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 2f0b69e9a..af6656e4d 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -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 diff --git a/packages/tui/src/tui-main-screen.ts b/packages/tui/src/tui-main-screen.ts index c497acdbf..71229fcb5 100644 --- a/packages/tui/src/tui-main-screen.ts +++ b/packages/tui/src/tui-main-screen.ts @@ -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) { diff --git a/packages/tui/test/tui-render.test.ts b/packages/tui/test/tui-render.test.ts index 3749eac76..c01142a4a 100644 --- a/packages/tui/test/tui-render.test.ts +++ b/packages/tui/test/tui-render.test.ts @@ -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);