This directory converts a session's event log into recording exports. generateAsciicast builds an asciicast v2 recording as a string and leaves the file write to the caller. generateWebmExport replays the events into a video-capable renderer backend (by default GhosttyWebBackend, which runs headless Chromium) and saves the recorded WebM video at the requested path.
AsciicastHeader:version: 2,width,height,timestamp,title, optionalsessionIdandtoolVersion, andenv.TERM[asciicast.ts:AsciicastHeader].AsciicastExport:contents,header,capturedAtSeq,durationMs,outputEventCount,resizeEventCountandmarkerCount[asciicast.ts:AsciicastExport].generateAsciicast(sessionId, manifest, events, toolVersion?)returns anAsciicastExport. It runs synchronously [asciicast.ts:generateAsciicast].WebmExportOptions:sessionId,sessionDir,manifest,events,outputPath, and optionaltargetSeq,profileName,timingModeandrendererName[webm.ts:WebmExportOptions].WebmExportDeps: optionalbackendFactoryandreplayTimeoutMs, for tests and callers that supply their own backend [webm.ts:WebmExportDeps].WebmExportResult:capturedAtSeq,durationMs,outputEventCount,resizeEventCount,cols,rows,profileName,timingModeandrendererBackend[webm.ts:WebmExportResult].generateWebmExport(options, deps?)returns aPromise<WebmExportResult>[webm.ts:generateWebmExport].
generateAsciicastasserts a non-emptysessionIdequal tomanifest.sessionId, positivemanifest.colsandmanifest.rows, and a non-emptytoolVersionwhen given [asciicast.ts:generateAsciicast].manifest.createdAtmust parse as a valid timestamp even when there are events. The header uses it wheneventsis empty [asciicast.ts:parseTimestamp].- Event timestamps must parse to finite numbers [asciicast.ts:parseTimestamp]. They must not decrease from one event to the next [asciicast.ts:generateAsciicast].
- Event mapping:
outputbecomeso,resizebecomesrwithCOLSxROWS, andmarkerbecomesm. Input, run, signal and exit events are skipped. An unknown type reachesunreachable()[asciicast.ts:generateAsciicast]. generateWebmExportasserts a non-emptysessionId, absolutesessionDirandoutputPath, a non-empty event list, and positive initial dimensions [webm.ts:generateWebmExport].- Defaults: timing mode
recordedand profilereference-dark[webm.ts:generateWebmExport]. - A requested
libghostty-vtrenderer is replaced withghostty-web. A code comment sayslibghostty-vtis semantic-only [webm.ts:generateWebmExport]. - The default backend factory accepts only
ghostty-web[webm.ts:createDefaultBackend]. - Timing presets:
acceleratedcaps gaps at 400 ms and holds frames at least 100 ms.max-speedholds frames at least 16 ms. Each mode holds the final frame (1000 ms, or 500 ms formax-speed) [webm.ts:buildReplayTimingOptions]. - The timed replay fails after
REPLAY_TIMEOUT_MS(5 minutes) [webm.ts:REPLAY_TIMEOUT_MS].
generateAsciicast: none found in code. It returns the NDJSON text incontents.generateWebmExportcreates a temporary video directory withmkdtempunderos.tmpdir()(prefixagent-tty-webm-) and sets its mode to0o700[webm.ts:generateWebmExport].- It builds the replay input with
buildReplayInputfromsrc/host/replay.tsand the profile withresolveProfilefromsrc/renderer/profiles.ts[webm.ts:generateWebmExport]. - The default backend is a
GhosttyWebBackendthat records video into the temporary directory [webm.ts:createDefaultBackend]. - The
.webmfile is written only bybackend.finalizeVideo(outputPath)[webm.ts:generateWebmExport]. - In
finallyit awaitsbackend.dispose()without a catch, so dispose errors propagate. Then it removes the temporary directory withrm({ recursive: true, force: true })and ignoresrmerrors. A throwingdispose()skips therm[webm.ts:generateWebmExport].
- Run:
npx vitest run test/unit/export test/unit/commands/record-export.test.ts - Run (integration):
npx vitest run --maxWorkers=1 test/integration/record-export.test.ts - Run (e2e, needs Playwright Chromium from
mise run bootstrap):npx vitest run --maxWorkers=1 test/e2e/export-fixtures.test.ts - Run:
npm run typecheck