termstate-store 0.0.2

Terminal-side record store for OSC 7501 (Program Status Protocol): replacement, clearing, app inheritance, lifetime and eviction rules
Documentation
  • Coverage
  • 100%
    29 out of 29 items documented0 out of 19 items with examples
  • Size
  • Source code size: 15.4 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 186.7 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2s Average build duration of successful builds.
  • all releases: 2s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • linyiru/termstate
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • linyiru

termstate

A conformance-tested implementation of OSC 7501, the Program Status Protocol: a terminal escape sequence that lets a program tell the terminal whether it is idle, working, done, blocked on the user, or failed, and why.

ESC ] 7501 ; state=blocked:kind=permission:app=terraform:msg=QXBwbHkgMyB0byBhZGQsIDEgdG8gY2hhbmdlLCAwIHRvIGRlc3Ryb3k/ ESC \

Implements spec revision 0.4 (2026-10-10).

Crates

crate for
termstate-core both sides no_std, no allocation, no dependencies. Report builder and encoder, body parser, streaming scanner that extracts or strips sequences from terminal output, feature-detection query and reply.
termstate-store terminals, multiplexers no_std + alloc. The record set one terminal keeps: replacement, subtree clear, app inheritance, lifetime events, 64–256 record cap with LRU eviction.

Program side:

use termstate_core::{Report, State, Kind};

let report = Report::builder(State::Blocked)
    .kind(Kind::Permission)
    .app("terraform")
    .msg("Apply 3 to add, 1 to change, 0 to destroy?")
    .build()?;            // refuses anything a terminal would discard
print!("{report}");       // ESC ] 7501 ; ... ESC \

Terminal or multiplexer side:

use termstate_core::scan::{Event, Scanner};
use termstate_store::Store;

let mut scanner = Scanner::new();
let mut store = Store::new();
scanner.feed(&pty_output, |event| match event {
    Event::Passthrough(bytes) => forward(bytes),
    Event::Sequence { message: Ok(m), .. } => { store.apply(&m); }
    Event::Sequence { message: Err(_), .. } => {} // discarded, per spec
});

How conformance is verified

The goal is that every behaviour traces to a sentence in the spec, and that nothing drifts silently. Run everything with scripts/check.sh.

  1. Requirement trace. spec-tests/requirements.json quotes all 54 normative statements of the spec, verbatim, with ids. scripts/check-trace.py fails if a quote no longer appears in the live spec, or if a testable requirement has no covering test.
  2. Spec lock. scripts/fetch-spec.py hashes the live spec and compares it with spec-tests/SPEC.lock; CI runs it weekly.
  3. Language-neutral vectors. spec-tests/vectors: 145 parse, 21 scan and 19 store cases in plain JSON, each naming the requirements it covers. Any implementation in any language can load them (format).
  4. Written interpretations. Where the spec leaves room, the choice is documented in docs/interpretations.md (INT-1…17) and the vectors that depend on it say so.
  5. Differential testing against Ghostty. tools/ghostty-diff/run.sh feeds every vector to libghostty-vt's parser (by the spec's author) and compares. At ghostty 0b1729e9: 0 unexpected differences on terminal-side cases.
  6. Properties. Scanner output does not depend on how input is split into reads; the parser never panics; every accepted report re-encodes to itself.
  7. Coverage floor. cargo llvm-cov must report ≥ 95% of lines.

Status

Pre-release (0.0.x). Planned: a std facade with tty output and feature detection, a termstate CLI, a C ABI for other languages, and WASM.

License

MIT or Apache-2.0, at your option.