Support the Program Status Protocol (OSC 7501)#18

opened8h agobyVversecafe

Support the Program Status Protocol (OSC 7501), a generic terminal escape sequence that lets a program tell the terminal whether it is idle, working (with optional progress), blocked (on permission, question or auth), done, or in error, with a short message. Rex (Superlogical) shows it as tab spinners, blocked marks and session-picker indicators. Terminals that don't know it ignore it.

Ashlar owns the terminal session and already speaks the neighbouring sequences (OSC 8, OSC 52, OSC 11/4 palette queries), so it's the right layer to get the spec's rules right once instead of in every app.

Proposal

  • Reactive status primitive, such as useProgramStatus({ state, progress, msg, title, app }) or screen.status(...). It emits a report when values change, written to stdout outside the frame diff, like the OSC 52 write in src/core/selection.ts.
  • Enforce the spec in one place:
    • Each report replaces its record completely, so app and title are resent every time.
    • msg and title are base64 UTF-8 and must not contain control characters.
    • A report over the limits is dropped whole: 4096 bytes per sequence, 2048 decoded for msg, 192 for title, 32 for app.
  • Lifecycle: clear or finalize the status (done, error or idle) in mount/unmount and the existing SIGINT, SIGTERM and exit restore path, so every app follows the spec's advice to report before exiting.
  • Opt-in component links: <ProgressBar value> feeds progress (0–100), and Spinner/useStalled map to working with no percentage.

Optional

  • Feature detection: send OSC 7501 ; ?, then CSI c; if the CSI c reply arrives first, the terminal doesn't support it. This fits the palette query's OSC-response path through stdin-parser, but it's async while terminalCaps is computed synchronously from the environment. The spec allows sending without detection.
  • Also send OSC 9;4 progress for terminals that support only that. The spec allows sending both.

Related

src/core/terminal-caps.ts detects terminals only by TERM_PROGRAM/TERM. Rex renders with Ghostty's engine, so it likely supports sync output, hyperlinks and the Kitty keyboard protocol. That only helps if Rex reports itself as ghostty/xterm-ghostty, which is unverified.

Out of scope

Rex's server API, Lua events and per-program icons are Rex automation or built-in Rex artwork, not rendering. Apps choose their own app id, and ashlar passes it through.

Implemented in #20 (OSC 7501 program status: records, clear, feature detection, component links). Rex detection landed separately in #19.