Skip to content

Rex support (experimental): host semantics and OSC 7501 program status - #543

Draft
raiseCatError wants to merge 3 commits into
devfrom
feature/rex-program-status-20261111
Draft

raiseCatError wants to merge 3 commits into
devfrom
feature/rex-program-status-20261111

Conversation

@raiseCatError

@raiseCatError raiseCatError commented Nov 11, 2026 •

Copy link
Copy Markdown
Owner

Rex support (experimental): host semantics and OSC 7501 program status.

What changed and why

Rex (Superlogical, built on Ghostty's terminal core) sets TERM_PROGRAM=rex, REX_SESSION, REX_BLOCK and REX_SERVER. NMSh treated it as an unknown host and sent it nothing. This change is confined to src/host/, plus one per-frame call in TerminalApp. The core has no Rex dependency, and the existing "frontend does not branch on host products" architecture test still passes.

  • OSC 7 and OSC 133 in Rex, as on Ghostty. Rex documents OSC 133 A as its prompt boundary and reports OSC 7 as the block's directory.

  • The host is named "Rex". NMSh opens no Rex blocks or windows, uses no Rex CLI, and never reads or writes Rex's configuration or key bindings.

  • OSC 7501 program status (src/host/programStatus.ts) uses one record of NMSh's own (id=nmsh, app=nmsh). It never touches the root record or clears every record. States are reported only from NMSh's own evidence:

    NMSh knows Reported
    a command runs working
    the shell confirms a hidden read blocked, kind=auth
    the shell confirms a line read blocked, kind=question
    a held queued line waits for approval blocked, kind=permission
    the queue paused because an entry failed error
    anything else (free prompt, a likely-but-unconfirmed read, a pause you asked for) record cleared
    • Messages are fixed NMSh text. No command line, path or typing reaches the host; a test checks this.
    • Reports are written only on change, and only while NMSh owns the screen. A command start is written at once, like OSC 133 C.
    • The record is resent after a new prompt zone, and cleared when NMSh stops or is suspended.
    • It's sent only for TERM_PROGRAM=rex outside tmux, screen and Zellij. There is no ? query, so other hosts never see it. NMSH_PROGRAM_STATUS=0 turns it off; =1 forces it on.
    • The record is also cleared when the frontend ends on an uncaught error. SIGKILL can't be handled: in that case the record stays until Rex drops it.

Review fixes (2026-11-11)

  • cece7ed9 / dc3fe8bc: no OSC 7501, and no Rex OSC 133/OSC 7 claim, inside Zellij. TERM_PROGRAM is inherited from the outer host, and the rest of NMSh already treats ZELLIJ as nested. The status record is now also cleared on an abnormal exit (process exit without stop()). Tests were added to programStatus.test.ts.

Automated verification

  • tests/programStatus.test.ts covers:
    • support rules
    • protocol encoding against the spec's key and value grammar and limits
    • write-on-change and owned-screen behaviour
    • states derived by a real TerminalApp, including the no-leak check
  • At dc3fe8bc: programStatus, hostSemantics, hostProfiles, hostIntegration, muxInterop, startupLaunch and startupRestore give 54 of 55 passing. The failure is the GNU screen interop test, which also fails on pristine dev (being investigated separately).
  • npm run verify at the original head 0530aa08: 4,571 of 4,589 tests pass. The full gate will be rerun once on the pinned integration candidate. The 4 failures also fail on pristine origin/dev on this Mac: GNU screen interop, live alias refresh, text editor panel, suite-runner tmpdir hygiene.

Checked in Rex (scripted, isolated)

Rex Beta 0.1.0-preview.14 on macOS. The test used an isolated Rex session (killed afterwards) and an isolated NMSh HOME, config and runtime directory. Rex's own block API (rex block call … pwd|program_status) showed:

  • pwd = the shell's directory via OSC 7.
  • Idle: no records. During sleep: nmsh working.
  • Held line after sleep: nmsh blocked permission. After /queue clear: none.
  • read -s: nmsh blocked auth. Answered: none. The secret was never in Rex's scrollback.
  • Failed queued false: nmsh error.
  • After NMSh exited, with the block kept alive by a wrapper: no records. (Rex may also drop records on process change, so this run doesn't isolate NMSh's own clear; the unit test does.)

Not verified:

  • Physical keyboard behaviour in the Rex app, including whether any Rex client default takes Ctrl+Q or Ctrl+S. The server's rex keymap lists no bindings and ~/.config/rex/init.lua doesn't exist; client defaults aren't listed.
  • How Rex presents the status in its UI.
  • The xterm-rex terminfo (not installed here; Rex fell back to xterm-256color).

Needs human testing (Rex app)

  1. Run NMSh in a Rex tab. Check the tab or sidebar status during sleep 10, a sudo -k true password prompt, a held line, and a failed queue.
  2. Check that Ctrl+Q, Ctrl+S, Shift+Enter, Tab and Esc reach NMSh.
  3. Quit NMSh and check that no status is left behind.

Known limits / risks

  • A frontend killed with SIGKILL can't clear its record.
  • While a full-screen program runs (vim, ssh), the status stays working, because the command is still running.
  • Physical Rex UI behaviour hasn't been checked.

Refs #473. Integration order and the pinned candidate are tracked on #541.

In Rex (TERM_PROGRAM=rex) NMSh now sends OSC 7 and OSC 133 as it does on
Ghostty, names the host, and reports its state with Rex's documented
OSC 7501 program status in a record of its own (id=nmsh): working while a
command runs; blocked (auth/question) only when the shell confirms a
program reads hidden input or a line; blocked (permission) while a held
queued line waits for approval; error while the queue is paused after a
failure; otherwise the record is cleared. Messages are fixed text; no
command line or typing reaches the host. Reports are written on change,
only while NMSh owns the screen (a command start at once, like OSC 133 C),
and the record is cleared when NMSh stops or is suspended.

Nothing is sent inside tmux or screen or to other hosts; NMSH_PROGRAM_STATUS
turns it off or forces it on. NMSh never reads the status back, opens no
Rex blocks or windows and does not change Rex's configuration.
…abnormal exit

Zellij owns the real terminal like tmux and screen, and TERM_PROGRAM is
inherited from the outer host, so neither OSC 7501 nor Rex's OSC 133/OSC 7
claim applies inside it (the rest of NMSh already treats ZELLIJ as nested). A
frontend that ends without stop() (an uncaught error) now clears its OSC 7501
record on process exit, as SIGTERM, SIGHUP, /zsh and normal exit already did.

Refs #473

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant