#36

feat: add @wterm/serialize for session persistence

Openmvanhornwants to merge intofrom

Closes #35.

Adds a new package @wterm/serialize that snapshots wterm state (grid cells, scrollback, cursor, modes, palette) into a portable string and restores it into a fresh terminal. Matches the capability xterm.js users get from @xterm/addon-serialize.

Usage

import { WTerm } from "@wterm/dom";
import { serialize, restore } from "@wterm/serialize";

const term = new WTerm();
term.open(document.getElementById("terminal")!);
term.write("some output\r\n");

const snapshot = serialize(term);
localStorage.setItem("wterm-session", snapshot);

const next = new WTerm();
next.open(document.getElementById("terminal")!);
restore(next, localStorage.getItem("wterm-session")!);

Approach

  • Snapshot is an ANSI stream: replaying it via term.write() reproduces the exact cell state, which reuses the renderer you already have rather than introducing a parallel restore path
  • Encodes visible grid + scrollback + cursor position + SGR attributes + DECSET modes + 256/truecolor palette
  • Zero runtime deps
  • New package only; no edits to @wterm/core or @wterm/dom

Testing

17 new tests in packages/@wterm/serialize/src/__tests__/:

  • encode: SGR attrs, 256-color, truecolor, scrollback, DECSET modes, cursor position
  • roundtrip: serialize then restore produces an identical grid snapshot

Full repo CI is green: pnpm test 151 passing, pnpm format:check, pnpm typecheck, pnpm build all clean.

Demo

Left terminal holds a live session. serialize() returns a snapshot string. A fresh WTerm mounts after reload and restore() rebuilds the exact state into the right terminal.

Notes

  • Docs page and API reference entry added per AGENTS.md
  • No new runtime dependencies
  • Ready for review

🤖 Generated with Claude Code

Activity

5
vercel[bot]6mo ago

@mvanhorn is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot]reviewed6mo ago
socket-security[bot]2mo ago
mvanhorn2mo ago

Rebased onto main. The only conflict was pnpm-lock.yaml, which I regenerated with pnpm 10.11.0 to match the pinned packageManager.

Worth flagging that regenerating re-resolved 22 transitive packages beyond this PR's own additions. pnpm install --frozen-lockfile validates, but if you would rather keep the lockfile churn out of this PR, say so and I will pin it back to main's and let your release tooling pick it up.