Files
Codeman/packages/xterm-zerolag-input/CHANGELOG.md
T
Codeman maintainer a30524060a feat(predictive-echo): PredictiveEchoAddon + Layers 1-3 test suites (0.2.0)
Mosh-style write-through prediction: the consumer sends every keystroke
unchanged; the addon paints predicted glyphs and reconciles against the
parsed buffer. Confirm = cell match + cursor advance (placeholder-safe,
repaint-safe); two-pass mismatch cascade with neutral blanks (measured:
codex clears its placeholder on first echo); TTL bound; baseY-based line
reads; scroll/resize/off-row clears. Zero edits to zerolag-input-addon.ts.

Tests: 30 addon-law specs + renderer geometry (fake performance clock for
TTL/grace), 6 replay suites running the real algorithm through a real
@xterm/headless parser fed by the recorded codex fixtures, and a
500-iteration seeded fuzz with per-op span/record + grid invariants.
227 total, the pre-existing 175 untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 04:25:24 +02:00

11 KiB

xterm-zerolag-input

0.2.0

Minor Changes

  • New addon: PredictiveEchoAddon, mosh-style write-through prediction. The second echo mode for per-keystroke TUIs (OpenAI Codex's composer, live pickers) that buffer-until-Enter starves. Every keystroke is sent by the consumer immediately and unchanged; the addon paints the predicted glyph at the predicted cell and reconciles against the PARSED terminal buffer: confirmation requires the cell match plus a cursor advance past the record, foreign non-blank content on two consecutive passes cascades a drop, blank cells are neutral, a TTL bounds everything, and scroll/resize/sustained cursor moves clear the run. Visual-only by construction; it cannot gate, delay or rewrite input.
    • New exports: PredictiveEchoAddon, PredictiveEchoOptions, PredictionState, plus the long-intended charCellWidth / stringCellWidth helpers.
    • XtermTerminal type gains OPTIONAL members (buffer.active.cursorX/cursorY, getLine().getCell?, onWriteParsed?, onResize?). Additive only: existing consumers and mocks are unaffected.
    • IIFE build exposes window.PredictiveEchoAddon and a self-activating window.PredictiveEchoOverlay, alongside the unchanged ZerolagInputAddon / LocalEchoOverlay globals.
    • Tests: 52 new (30 addon-law specs, renderer geometry, 6 replay suites driven by fixtures recorded from real codex 0.147 through tmux + the production strip, and a 500-iteration seeded fuzz with per-op invariants). @xterm/headless as a devDependency; runtime dependencies remain zero.

0.1.8

Patch Changes

  • Fixed: sessions failed to start on macOS with Error: posix_spawnp failed. (issues #6 and #204)

    node-pty@1.1.0 publishes its macOS prebuilt helper as prebuilds/darwin-<arch>/spawn-helper with mode 0644, i.e. no execute bit. macOS launches every PTY through that helper, so a stock install failed on every session start. The bug is macOS-only: spawn-helper is a mac-only gyp target and node-pty ships no Linux prebuild, so Linux always compiles a correctly-permissioned helper from source.

    The previous fix chmodded only build/Release/spawn-helper, which on macOS does not exist (the prebuild is used, so node-gyp never runs), and it derived that path from require.resolve('node-pty'), landing on <pkg>/lib/build/Release/.... It was a no-op on every platform.

    • New scripts/fix-node-pty.mjs (also npm run fix:node-pty) chmods every spawn-helper it finds, in build/Release, build/Debug and each prebuilds/*/, then verifies the result by actually opening a PTY. A require() alone passes on a broken install, because the helper is only touched at spawn time.
    • postinstall no longer force-rebuilds node-pty from source on Node 22+. That step needed Xcode command line tools, cost 30-120s on every install, and deleted the prebuilds/ tree before compiling, so a Mac without a compiler was left with no working binary at all. A rebuild now happens only when the chmod plus spawn probe still fails, and the prebuilds tree is backed up and restored around it.
    • New spawnPtyWithHelperRepair() (src/utils/node-pty-repair.ts) wraps every pty.spawn() in session.ts, so an install that is already broken repairs itself on the first failed spawn and retries in-process instead of showing a dead session. Unrelated spawn errors are rethrown untouched; a second failure carries the npm run fix:node-pty hint.
    • scripts/fix-node-pty.mjs is now in the published files list, so global npm installs get the repair too.
    • Direct-PTY Claude spawns use the resolved absolute binary path (new getClaudeBinaryPath()) instead of the bare name claude, so a CLI installed outside the server's PATH still launches.

    Verified end to end on macOS 26.4 arm64: a stock npm i reproduces posix_spawnp failed., and after the fix the same install spawns a PTY successfully with the prebuilds preserved.

    Added: phone home screen (session overview)

    Under 430px the "C" logo now opens a session overview (current sessions, past sessions, spaces) instead of the welcome overlay: on a small screen "which session needs me" beats "how do I start one". Rows resume a session in place, and "New session here" goes through the normal quick-start path so remote and Docker cases keep their routing. Per-device setting mobileOverviewEnabled (phones only, default ON) in App Settings. Tablet and desktop are unchanged.

    Added: guided Tailscale setup in install.sh

    The network-access prompt is now 3-way: Tailscale, LAN, or local-only. The Tailscale path binds loopback and walks through installing Tailscale, logging in, the operator grant, the tailnet HTTPS-certificates toggle, and tailscale serve --bg <port>, then verifies the result end to end with curl. That gives HTTPS on a real certificate with no app password and no 0.0.0.0 bind, which is also what PWA install and web push need. install.sh tailscale retrofits it onto an existing install, and CODEMAN_TAILSCALE=1 presets the choice. Serve state is detected from tailscale serve status --json; the installer never runs tailscale serve reset and never touches serve mappings other than 443 to Codeman's port. README and docs/security-architecture.md updated to match.

    Docs: replaced a real tailnet hostname with placeholders in docs/web-tabs-fixes-plan.md.

    xterm-zerolag-input: npm description and keywords only, no code change.

0.1.7

Patch Changes

  • Fix a latent bug where a partial settings PUT silently reset live service state, and trim the xterm-zerolag-input README callout.
    • PUT /api/settings no longer resets watchers on a partial body. The three toggleService calls (subagent watcher, workflow-run watcher, image watcher) read the raw request body with ?? defaults, so every key a caller omitted was treated as "apply the default". A body of just {statusLineTelemetry:true} would START the subagent watcher and STOP the workflow and image watchers, undoing the persisted config. They now resolve from merged (persisted settings + incoming), the same convention the tmuxHistoryLimit branch in that handler already used, so any PUT reconciles services to the effective stored state. Nothing triggered this in practice because every shipped client sends a full settings payload rebuilt from the DOM, but it was a trap for the next partial-update caller.
    • Regression test: test/routes/system-routes-settings-partial-put.test.ts (4 cases) pins both directions, omitted keys preserve state and explicit keys still take effect. Verified to fail against the pre-fix handler.
    • CLAUDE.md records the rule under "Adding Features → App setting": anything acting on a setting in that handler must resolve from merged, never the request body.
    • xterm-zerolag-input README: removed the links line (getcodeman.com / install one-liner / star link) from the Codeman callout above the demo GIF. The callout keeps its links in the heading and body.

0.1.6

Patch Changes

  • Plan-usage chip now defaults ON on desktop, plus the reworked xterm-zerolag-input README.
    • Plan-usage chip defaults ON (desktop). The showPlanUsageLimits chip (live 5-hour and weekly plan usage from the Claude statusline) used to be opt-in and default OFF, so most users never saw it. Desktop now defaults ON; handhelds still default OFF so the phone header stays minimal and the mobile-header-buttons-policy guard keeps passing. Devices with an explicitly stored preference keep whatever they chose, so nobody's OFF gets overridden.
    • One resolver behind the chip. Added planUsageChipEnabled() in settings-ui.js and routed all three call sites through it: the App Settings checkbox, the chip's visibility, and the create-time statusLineTelemetry flag in session-ui.js. Those three had independent ?? false / === true defaults, and a chip revealed without the telemetry flag renders — forever, so a default flip on one site alone would have shipped a permanently empty chip.
    • Cron button comment corrected. The App Settings comment claimed "Cron button defaults ON" while the code, the template (btn-cron--hidden) and the CSS all default it OFF. Verified against a fresh browser profile: the button is hidden and its checkbox unchecked out of the box. Comment now matches, and states why the two halves stay consistent.
    • Docs. CLAUDE.md, docs/architecture-invariants.md and docs/usage-limits-display-plan.md updated for the new default and the single-resolver rule; the stale styles.css comment claiming the server strips the chip's hidden class at render was corrected (display is per-device, so the client reveals it).
    • xterm-zerolag-input README rework (0.1.5 shipped the content; this republishes with the graphic and promo changes): replaced the misaligned 8-line keystroke-flow diagram with a two-line stock-vs-zerolag contrast, added a Codeman callout above the demo GIF with links to getcodeman.com and the repo, and rewrote the Origin section so it argues the extraction story instead of repeating the promo.

0.1.5

Patch Changes

  • Rewrite the xterm-zerolag-input package README as a value-first document and correct the drift that had accumulated against the source.

    • Added the side-by-side phone demo GIF (docs/images/zerolag-demo-20260728.gif) as the hero image, referenced by absolute raw URL so it renders on npmjs.com as well as GitHub. The two-phone comparison shows 0ms local echo next to a 600ms-2.7s server echo on the same session.
    • New "Why this one" comparison table, an explicit list of target use cases (SSH web clients, cloud IDEs, mobile terminals, container consoles), and a bundle-size badge (6.1 kB gzipped, measured from the ESM build).
    • Corrected the test-count badge from 78 to the actual 175 tests across 5 files, in both the package README and the Published Packages section of the root README.
    • Removed the stale "Unicode/emoji rendered at single-cell width" limitation. CJK, fullwidth forms and emoji have had double-width rendering and visual-column positioning since the wide-character fix; the honest remaining caveat (per-code-point width summing over-counts ZWJ grapheme clusters) replaces it.
    • Documented the previously undocumented public setPrompt() method for switching prompt strategies at runtime, and the new "Wide characters (CJK, emoji)" integration section covering the optional Unicode11Addon path and the built-in range-table fallback.
    • Documented backgroundColor: 'transparent', corrected the foregroundColor default, and updated the grid-alignment math to reflect visual-column positioning rather than character index.

    No source changes, docs only.

0.1.4

Patch Changes

  • Initial changelog entry for changesets-based versioning