pty emit + pty state: user events and per-session JSON bag
pty emit publishes user.* events to a session's .events.jsonl; the
user.* namespace is reserved for arbitrary app events. Inside a
session the ref is omitted — $PTY_SESSION resolves it.
pty state adds a per-session JSON key/value bag with get/set/delete/
keys subcommands. Mutations auto-emit state.set / state.delete events
so downstream watchers see a full history. Writes go through the
atomic writeMetadata rename; in-process Promise.all over setState is
safe, cross-process writers can still race on the RMW window.
Both features are re-exported from @myobie/pty/client for programmatic
use (emitUserEvent, getState, setState, deleteState, listStateKeys,
plus the new event type unions).
Hardening surfaced while writing tests and during review:
- deleteState returns bool; CLI gates state.delete emission on it so a
delete of a missing key is a quiet no-op (no ghost event).
- getStateKey / deleteState use Object.prototype.hasOwnProperty so
prototype names (toString, constructor, __proto__) never match.
- appendEvent honors the same MAX_LINES retention as EventWriter with
a stat-based fast path — scripts in a loop don't grow events.jsonl
unbounded.
- pty state set rejects 3+ positionals instead of silently joining
them with spaces into JSON.parse.
- pty state keys rejects extra positionals, matching the other
subcommands.