diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 46397f92..f6ff0f0e 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Kept OSC 9;4 terminal progress alive with periodic updates so Ghostty does not clear the indicator during long-running agent work ([#3610](https://github.com/badlogic/pi-mono/issues/3610)) + ## [0.69.0] - 2026-04-22 ### Added diff --git a/packages/tui/src/terminal.ts b/packages/tui/src/terminal.ts index 8cedb73a..0f657307 100644 --- a/packages/tui/src/terminal.ts +++ b/packages/tui/src/terminal.ts @@ -6,6 +6,10 @@ import { StdinBuffer } from "./stdin-buffer.js"; const cjsRequire = createRequire(import.meta.url); +const TERMINAL_PROGRESS_KEEPALIVE_MS = 1000; +const TERMINAL_PROGRESS_ACTIVE_SEQUENCE = "\x1b]9;4;3\x07"; +const TERMINAL_PROGRESS_CLEAR_SEQUENCE = "\x1b]9;4;0;\x07"; + /** * Minimal terminal interface for TUI */ @@ -64,6 +68,7 @@ export class ProcessTerminal implements Terminal { private _modifyOtherKeysActive = false; private stdinBuffer?: StdinBuffer; private stdinDataHandler?: (data: string) => void; + private progressInterval?: ReturnType; private writeLogPath = (() => { const env = process.env.PI_TUI_WRITE_LOG || ""; if (!env) return ""; @@ -264,6 +269,10 @@ export class ProcessTerminal implements Terminal { } stop(): void { + if (this.clearProgressInterval()) { + process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE); + } + // Disable bracketed paste mode process.stdout.write("\x1b[?2004l"); @@ -364,10 +373,23 @@ export class ProcessTerminal implements Terminal { setProgress(active: boolean): void { if (active) { // OSC 9;4;3 - indeterminate progress - process.stdout.write("\x1b]9;4;3\x07"); + process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE); + if (!this.progressInterval) { + this.progressInterval = setInterval(() => { + process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE); + }, TERMINAL_PROGRESS_KEEPALIVE_MS); + } } else { + this.clearProgressInterval(); // OSC 9;4;0 - clear progress - process.stdout.write("\x1b]9;4;0;\x07"); + process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE); } } + + private clearProgressInterval(): boolean { + if (!this.progressInterval) return false; + clearInterval(this.progressInterval); + this.progressInterval = undefined; + return true; + } }