Skip to main content

termwright_protocol/
lib.rs

1//! Semantic side-channel client for the [termwright] terminal test driver.
2//!
3//! An instrumented TUI publishes its widget tree over a unix socket and
4//! commits each render with a signed OSC marker, so tests can assert on *roles
5//! and names* instead of screen-scraping cells. This crate is the protocol
6//! side of that contract: framing, the marker, message and snapshot
7//! validation, and a blocking socket client. It ships no framework adapter —
8//! wire it into whatever draws your screen.
9//!
10//! **Dormant rule.** Without `TERMWRIGHT_ENDPOINT` and `TERMWRIGHT_TOKEN` in
11//! the environment, [`Client::from_env`] returns `None` and nothing happens at
12//! all: no socket, no marker, no change to what the terminal receives.
13//!
14//! ```no_run
15//! use termwright_protocol::{Client, Node, Options, Role, Snapshot};
16//!
17//! let mut client = match Client::from_env(Options::new("my-tui", "1.0.0")) {
18//!     Some(client) => client,
19//!     None => return, // not instrumented: render normally and stop here
20//! };
21//! client.connect(termwright_protocol::DIAL_TIMEOUT).expect("handshake");
22//!
23//! let mut snapshot = Snapshot::new(80, 24);
24//! snapshot.push(Node::new("root", Role::Dialog, "Permission"));
25//! snapshot.push(Node::new("ok", Role::Button, "Approve").with_parent("root"));
26//!
27//! if let Some(marker) = client.publish(&mut snapshot).expect("publish") {
28//!     // Only after the render's last byte has been written.
29//!     print!("{marker}");
30//! }
31//! ```
32//!
33//! The normative implementation is the TypeScript package
34//! `@termwright/protocol`; this crate is verified against the shared vectors
35//! in `clients/test-vectors`.
36//!
37//! [termwright]: https://github.com/gorce-ai/termwright
38
39#![forbid(unsafe_code)]
40#![warn(missing_docs)]
41
42pub mod client;
43pub mod debug;
44pub mod error;
45pub mod evidence;
46pub mod framing;
47pub mod limits;
48pub mod logs;
49pub mod marker;
50pub mod messages;
51pub mod publication_queue;
52pub mod roles;
53/// Bridge from `tracing`, enabled by the `tracing` feature.
54#[cfg(feature = "tracing")]
55pub mod tracing_layer;
56
57pub mod tree;
58mod validate;
59
60pub use client::{Client, Options, DIAL_TIMEOUT, ENV_ENDPOINT, ENV_TOKEN};
61pub use debug::{debug_path, Category, DebugLog, ENV_DEBUG, ENV_DEBUG_FILE};
62pub use error::{Error, ParseError, ValidationError, Violation};
63pub use framing::{encode_frame, project_dto, Frame, FrameDecoder, FRAME_HEADER_BYTES};
64pub use limits::{Limits, ABSOLUTE_LIMITS, DEFAULT_LIMITS, DEFAULT_NEGOTIATION_MS};
65pub use logs::{validate_log_record, AttrValue, LogLevel, LogRecord, LOG_LEVELS, MAX_LOG_ATTRS};
66pub use marker::{
67    compute_mac, encode_marker, verify_marker_payload, RenderMarker, MARKER_MAC_BYTES,
68    MARKER_OSC_CODE, MARKER_OSC_PREFIX,
69};
70pub use messages::{
71    parse_adapter_message, parse_driver_message, DegradedSessionCapability,
72    EvidenceProviderRegistration, ProbeIdentityKind, ProbeInfo, ProbeInjectionTier,
73    ProbeInstrumentation, ProbeSemanticClass, PROTOCOL_ID, PROTOCOL_VERSION,
74};
75pub use publication_queue::PublicationQueue;
76pub use roles::{Action, Capability, Role};
77pub use tree::{
78    Cursor, CursorShape, EvidenceMethod, EvidenceProvenance, EvidenceSource, EvidenceStrength,
79    Node, NodeGeometryObservations, Observation, Orientation, PhysicalInputRecipe,
80    PhysicalInputRecipeAction, PhysicalInputRecipeStep, PointerHitGrid, PointerHitRegion,
81    Provenance, ProviderActionRecipes, ProviderFocusState, ProviderPaintedRegion,
82    ProviderPointerRegion, ProviderPointerSpan, ProviderRevisionEvidence, ProviderScrollState,
83    ProviderTerminalInputModes, Rect, ScrollState, SemanticPaintedRegion, SemanticValueObservation,
84    SemanticValueSensitivity, Snapshot, State, TextRange,
85};
86pub use validate::validate_snapshot;
87
88/// The fields a node and a state may carry, as this client knows them.
89///
90/// Exposed so a test can compare them against the protocol's own exported
91/// lists: a field added upstream must fail a test here rather than wait to be
92/// noticed as a rejected snapshot in production.
93pub mod schema_keys {
94    pub use crate::validate::{NODE_KEYS, STATE_KEYS};
95}