OpenTUI 0.6.3

npmGitHub release

A coding agent such as opencode can wait for minutes at a permission prompt in a background tab. Before this release, the terminal could not tell the user about it. In 0.6.3, the agent can report its state to the terminal:

renderer.setProgramStatus({ state: "blocked", kind: "permission", app: "opencode", message: "Allow bash?" })

This call writes one report in the Program Status Protocol, OSC 7501. The terminal decides how to show the report. It can use a tab indicator, an inbox entry, or a desktop notification. A terminal that does not implement the protocol ignores the sequence, so setProgramStatus() does not wait for capability detection. capabilities.program_status only tells you that a reply arrived. A false value can also mean that the reply has not arrived yet.

Each report replaces one record, and a field that a report omits is gone from the record. Send app and title with every report that needs them. A program that runs several tasks can give each task its own record with an id. It can then remove that record with clear:

renderer.setProgramStatus({ state: "working", id: "subagent-1", title: "Explore", progress: 40 })
renderer.setProgramStatus({ state: "clear", id: "subagent-1" })

Records belong to the terminal, not to the renderer. OpenTUI does not clear them when the renderer is destroyed or suspended. When the process exits, the terminal drops working and blocked records. It keeps done and error records for the user to find. If the user should see the result, report done or error before the program exits. OpenTUI also does not wrap reports in tmux or GNU Screen passthrough. The outer terminal cannot tell panes apart or see the program exit, so a working record from a pane would never clear.

C hosts send the same report with ot_session_control() and OT_CONTROL_PROGRAM_STATUS. The payload is an ot_session_program_status struct, followed by the id, app, title, and message bytes. Native code checks every report on both paths before it writes anything. A report that a terminal would discard or only partly read fails at the call.

Added

  • core: renderer.setProgramStatus(status) and NativeSession.setProgramStatus(status) send one OSC 7501 program status report. They return false when OpenTUI does not queue the report, and they throw for an invalid report. See Program status. (#1657)
  • core: TerminalCapabilities.program_status is true when the terminal replies to the OSC 7501 ; ? query. The renderer sends this query at startup with the other capability queries, but not to foot. See Terminal capabilities. (#1657)
  • native: ot_session_control() with OT_CONTROL_PROGRAM_STATUS and an ot_session_program_status payload sends a program status report. OT_CAP_PROGRAM_STATUS is set when the terminal replies to the query. See Program status. (#1657)

Changed

  • native: ot_session_control() now checks the payload before the terminal phase. While the terminal is not active, an invalid payload returns OT_INVALID_ARGUMENT instead of OT_INVALID_PHASE. A title with control characters is one example. See Frames and output. (#1657)

API changes#

@opentui/core#

Added

  • method CliRenderer.setProgramStatus(status: ProgramStatus): boolean
  • method NativeSession.setProgramStatus(status: ProgramStatus): boolean
  • property TerminalCapabilities.program_status: boolean
  • type ProgramStatus = (ProgramStatusRecord & { state: "idle" | "done" | "error"; }) | (ProgramStatusRecord & { state: "working"; progress?: number; }) | (ProgramStatusRecord & { state: "blocked"; kind?: ProgramStatusKind; progress?: number; }) | { state: "clear"; id?: string; }
  • type ProgramStatusKind = "permission" | "question" | "auth"

Changed

  • type NativeSessionControl = { kind: "capability-response"; bytes: Uint8Array; } | { kind: "palette-query"; bytes: Uint8Array; } | { kind: "title"; title: string; } | { kind: "mouse"; mode: "disabled" | "drag" | "motion"; } | { kind: "kitty-keyboard-flags"; flags: number; } | { kind: "restore-modes" | "query-pixel-resolution" | "query-theme-colors" | "reset-background"; }type NativeSessionControl = { kind: "capability-response"; bytes: Uint8Array; } | { kind: "palette-query"; bytes: Uint8Array; } | { kind: "title"; title: string; } | { kind: "mouse"; mode: "disabled" | "drag" | "motion"; } | { kind: "kitty-keyboard-flags"; flags: number; } | { kind: "program-status"; status: ProgramStatus; } | { kind: "restore-modes" | "query-pixel-resolution" | "query-theme-colors" | "reset-background"; }

opentui.h#

Added

  • const OT_CAP_PROGRAM_STATUS = 131072
  • const OT_CONTROL_PROGRAM_STATUS = 11
  • const OT_PROGRAM_KIND_AUTH = 3
  • const OT_PROGRAM_KIND_PERMISSION = 1
  • const OT_PROGRAM_KIND_QUESTION = 2
  • const OT_PROGRAM_STATE_BLOCKED = 4
  • const OT_PROGRAM_STATE_CLEAR = 6
  • const OT_PROGRAM_STATE_DONE = 3
  • const OT_PROGRAM_STATE_ERROR = 5
  • const OT_PROGRAM_STATE_IDLE = 1
  • const OT_PROGRAM_STATE_WORKING = 2
  • const OT_PROGRAM_STATUS_PROGRESS = 1
  • struct ot_session_program_status