Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ Session state is stored under `~/.agent-tty` by default. In tests and automation
- `src/cli/main.ts` — public CLI contract and command registration.
- `src/cli/commands/*.ts` — command implementations; most behavior changes start here.
- `src/host/hostMain.ts` — per-session host orchestration for PTY, renderer, RPC, waits, and artifacts.
- `src/host/eventLog.ts` — append-only `events.jsonl` writer/reader; sequence numbers must stay contiguous.
- `src/host/replay.ts` — validated replay loader; keep its event-log assumptions aligned with `src/host/eventLog.ts`.
- `src/host/eventLog.ts` — append-only `events.jsonl` writer; append-time sequence numbers must stay contiguous.
- `src/host/replay.ts` — validated replay-input builder for manifest, dimensions, and target sequence semantics.
- `src/protocol/schemas.ts` and `src/protocol/messages.ts` — machine-facing schemas and result shapes.
- `src/storage/` — path guards, home/session resolution, manifest I/O, and artifact manifests.
- `src/storage/` — path guards, home/session resolution, manifest I/O, artifact manifests, and the persisted event-log codec.
- `src/renderer/ghosttyWeb/backend.ts` — reference renderer and Playwright browser harness.
- `src/export/asciicast.ts` and `src/export/webm.ts` — recording export logic.
- `src/util/assert.ts` — shared fail-fast assertion helpers.
Expand Down Expand Up @@ -156,8 +156,8 @@ If validation cannot run, state why and name the next best check.
- Treat the event log as canonical execution truth.
- New snapshot, screenshot, wait, or export features should flow through replayable event/state data.
- Do not add one-off state that only live PTY code can see.
- Keep `src/host/eventLog.ts` and `src/host/replay.ts` assumptions aligned.
- If you change the 50 MB event-log limit, update both `src/host/eventLog.ts` and `src/host/replay.ts`.
- Keep persisted event-log size limits, JSONL parsing, schema validation, and sequence validation centralized in `src/storage/eventLogCodec.ts`.
- If you change the 50 MB event-log limit, update `src/storage/eventLogCodec.ts` as the single source of truth.

## CI And Generated Files

Expand Down
6 changes: 6 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
**Session**:
A long-lived PTY-backed terminal instance owned by `agent-tty`.

**Event Log**:
The append-only history of a **Session**'s terminal output, user inputs, control actions, and lifecycle events. It is the canonical source used to reconstruct **Session** state for replay and artifact generation.

**Session Status**:
The lifecycle state of a **Session**: `running`, `exiting`, `exited`, `failed`, `destroying`, or `destroyed`.

Expand Down Expand Up @@ -41,6 +44,9 @@ A convenience policy predicate for the single `destroyed` **Session Status** val
- A `destroying` **Session** is **Active** and **Offline Replay Eligible**, but not **Terminal** or **Collectable**.
- `exited`, `failed`, and `destroyed` **Sessions** are **Terminal**, **Offline Replay Eligible**, and **Collectable**.

- A **Session** has one **Event Log**.
- An **Offline Replay Eligible Session** is reconstructed from its persisted **Event Log** and manifest.

## Example dialogue

> **Dev:** "Can garbage collection remove a **destroying** **Session**?"
Expand Down
19 changes: 19 additions & 0 deletions dogfood/issue-59-event-log-codec/commands.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail

HOME_DIR=/tmp/tmp.z9jvcxqfO5
SESSION_ID=01KQCM5YXV7201SPAN58AGD96S
BUNDLE_DIR=dogfood/issue-59-event-log-codec

npx tsx src/cli/main.ts --home "$HOME_DIR" create --json -- /bin/sh > "$BUNDLE_DIR/create.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" type "$SESSION_ID" "printf 'hello from codec dogfood\\n'" --json > "$BUNDLE_DIR/type-print.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" send-keys "$SESSION_ID" ENTER --json > "$BUNDLE_DIR/enter-print.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" wait "$SESSION_ID" --text "hello from codec dogfood" --timeout 10000 --json > "$BUNDLE_DIR/wait-text.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" type "$SESSION_ID" exit --json > "$BUNDLE_DIR/type-exit.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" send-keys "$SESSION_ID" ENTER --json > "$BUNDLE_DIR/enter-exit.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" wait "$SESSION_ID" --exit --timeout 10000 --json > "$BUNDLE_DIR/wait-exit.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" snapshot "$SESSION_ID" --json > "$BUNDLE_DIR/snapshot.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" record export "$SESSION_ID" --format asciicast --out "$PWD/$BUNDLE_DIR/recording.cast" --json > "$BUNDLE_DIR/record-export-asciicast.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" screenshot "$SESSION_ID" --json > "$BUNDLE_DIR/screenshot.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" record export "$SESSION_ID" --format webm --timing max-speed --out "$PWD/$BUNDLE_DIR/recording.webm" --json > "$BUNDLE_DIR/record-export-webm.json"
npx tsx src/cli/main.ts --home "$HOME_DIR" destroy "$SESSION_ID" --json > "$BUNDLE_DIR/destroy.json"
12 changes: 12 additions & 0 deletions dogfood/issue-59-event-log-codec/create.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"ok": true,
"command": "create",
"timestamp": "2026-04-29T12:42:19.764Z",
"result": {
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"createdAt": "2026-04-29T12:42:18.942Z",
"cols": 80,
"rows": 24,
"shell": "/bin/bash"
}
}
9 changes: 9 additions & 0 deletions dogfood/issue-59-event-log-codec/destroy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ok": true,
"command": "destroy",
"timestamp": "2026-04-29T12:42:40.804Z",
"result": {
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"destroyed": true
}
}
10 changes: 10 additions & 0 deletions dogfood/issue-59-event-log-codec/enter-exit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"ok": true,
"command": "send-keys",
"timestamp": "2026-04-29T12:42:25.660Z",
"result": {
"accepted": ["ENTER"],
"bytesWritten": 1,
"seq": 7
}
}
10 changes: 10 additions & 0 deletions dogfood/issue-59-event-log-codec/enter-print.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"ok": true,
"command": "send-keys",
"timestamp": "2026-04-29T12:42:21.994Z",
"result": {
"accepted": ["ENTER"],
"bytesWritten": 1,
"seq": 3
}
}
5 changes: 5 additions & 0 deletions dogfood/issue-59-event-log-codec/event-log-check.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"eventCount": 10,
"firstSeq": 0,
"lastSeq": 9
}
10 changes: 10 additions & 0 deletions dogfood/issue-59-event-log-codec/events.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{"seq":0,"ts":"2026-04-29T12:42:19.675Z","type":"output","payload":{"data":"$ "}}
{"seq":1,"ts":"2026-04-29T12:42:20.888Z","type":"input_text","payload":{"data":"printf 'hello from codec dogfood\\n'"}}
{"seq":2,"ts":"2026-04-29T12:42:20.888Z","type":"output","payload":{"data":"printf 'hello from codec dogfood\\n'"}}
{"seq":3,"ts":"2026-04-29T12:42:21.992Z","type":"input_keys","payload":{"keys":["ENTER"]}}
{"seq":4,"ts":"2026-04-29T12:42:21.992Z","type":"output","payload":{"data":"\r\nhello from codec dogfood\r\n$ "}}
{"seq":5,"ts":"2026-04-29T12:42:24.663Z","type":"input_text","payload":{"data":"exit"}}
{"seq":6,"ts":"2026-04-29T12:42:24.663Z","type":"output","payload":{"data":"exit"}}
{"seq":7,"ts":"2026-04-29T12:42:25.657Z","type":"input_keys","payload":{"keys":["ENTER"]}}
{"seq":8,"ts":"2026-04-29T12:42:25.658Z","type":"output","payload":{"data":"\r\n"}}
{"seq":9,"ts":"2026-04-29T12:42:25.659Z","type":"exit","payload":{"exitCode":0,"exitSignal":null}}
1 change: 1 addition & 0 deletions dogfood/issue-59-event-log-codec/home.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/tmp/tmp.z9jvcxqfO5
11 changes: 11 additions & 0 deletions dogfood/issue-59-event-log-codec/notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Issue #59 event-log codec dogfood

- Date: 2026-04-29T12:42:18Z
- Isolated AGENT_TTY_HOME: /tmp/tmp.z9jvcxqfO5

snapshot: ok
screenshot: ok
screenshot artifact copied: screenshot-9-reference-dark.png
record-export-webm: ok
webm artifact copied: recording.webm
Dogfood home retained at: /tmp/tmp.z9jvcxqfO5
23 changes: 23 additions & 0 deletions dogfood/issue-59-event-log-codec/record-export-asciicast.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"ok": true,
"command": "record export",
"timestamp": "2026-04-29T12:42:29.443Z",
"result": {
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"format": "asciicast",
"artifactPath": "/home/coder/.mux/src/agent-terminal/grill-docs-cyte/dogfood/issue-59-event-log-codec/recording.cast",
"bytes": 350,
"sha256": "6743c1b391eb593bb538eec634cf1a33aa14a693759ad574edc69892e5a26272",
"capturedAtSeq": 9,
"durationMs": 5984,
"metadata": {
"width": 80,
"height": 24,
"title": "01KQCM5YXV7201SPAN58AGD96S",
"timestamp": 1777466539,
"outputEventCount": 5,
"resizeEventCount": 0,
"markerCount": 0
}
}
}
24 changes: 24 additions & 0 deletions dogfood/issue-59-event-log-codec/record-export-webm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"ok": true,
"command": "record export",
"timestamp": "2026-04-29T12:42:39.419Z",
"result": {
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"format": "webm",
"artifactPath": "/home/coder/.mux/src/agent-terminal/grill-docs-cyte/dogfood/issue-59-event-log-codec/recording.webm",
"bytes": 14356,
"sha256": "bb845c575030ded3c0aeacda922ec2ceb76454abcaf7f68c39867456bdf8c1ae",
"capturedAtSeq": 9,
"durationMs": 5984,
"metadata": {
"width": 80,
"height": 24,
"profileName": "reference-dark",
"renderProfileHash": "8ffed6af301ec7c0e6b69599c3be0d1d12096f9fcdfc59d0bbb4cc474d64c53d",
"timingMode": "max-speed",
"rendererBackend": "ghostty-web",
"outputEventCount": 5,
"resizeEventCount": 0
}
}
}
Empty file.
6 changes: 6 additions & 0 deletions dogfood/issue-59-event-log-codec/recording.cast
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{"version":2,"width":80,"height":24,"timestamp":1777466539,"title":"01KQCM5YXV7201SPAN58AGD96S","sessionId":"01KQCM5YXV7201SPAN58AGD96S","env":{"TERM":"xterm-256color"},"toolVersion":"0.1.1-beta.4"}
[0,"o","$ "]
[1.213,"o","printf 'hello from codec dogfood\\n'"]
[2.317,"o","\r\nhello from codec dogfood\r\n$ "]
[4.988,"o","exit"]
[5.983,"o","\r\n"]
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions dogfood/issue-59-event-log-codec/screenshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"ok": true,
"command": "screenshot",
"timestamp": "2026-04-29T12:42:32.263Z",
"result": {
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"capturedAtSeq": 9,
"profileName": "reference-dark",
"cols": 80,
"rows": 24,
"artifactPath": "/tmp/tmp.z9jvcxqfO5/sessions/01KQCM5YXV7201SPAN58AGD96S/artifacts/screenshot-9-reference-dark.png",
"pngSizeBytes": 5709,
"cursorVisible": false,
"rendererBackend": "ghostty-web",
"pixelWidth": 640,
"pixelHeight": 384,
"sha256": "17afb55252eb2ac6bdc2d2e6073691b1c6877733b37001e2eadb717c555c4dbb",
"renderProfileHash": "8ffed6af301ec7c0e6b69599c3be0d1d12096f9fcdfc59d0bbb4cc474d64c53d"
}
}
Empty file.
19 changes: 19 additions & 0 deletions dogfood/issue-59-event-log-codec/session.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": 1,
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"createdAt": "2026-04-29T12:42:18.942Z",
"updatedAt": "2026-04-29T12:42:25.659Z",
"status": "exited",
"command": ["/bin/sh"],
"cwd": "/home/coder/.mux/src/agent-terminal/grill-docs-cyte",
"shell": "/bin/bash",
"term": "xterm-256color",
"cols": 80,
"rows": 24,
"creationCols": 80,
"creationRows": 24,
"hostPid": 1834170,
"childPid": 1834218,
"exitCode": 0,
"exitSignal": null
}
113 changes: 113 additions & 0 deletions dogfood/issue-59-event-log-codec/snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"ok": true,
"command": "snapshot",
"timestamp": "2026-04-29T12:42:28.225Z",
"result": {
"format": "structured",
"sessionId": "01KQCM5YXV7201SPAN58AGD96S",
"capturedAtSeq": 9,
"cols": 80,
"rows": 24,
"cursorRow": 3,
"cursorCol": 0,
"isAltScreen": false,
"visibleLines": [
{
"row": 0,
"text": "$ printf 'hello from codec dogfood\\n'"
},
{
"row": 1,
"text": "hello from codec dogfood"
},
{
"row": 2,
"text": "$ exit"
},
{
"row": 3,
"text": ""
},
{
"row": 4,
"text": ""
},
{
"row": 5,
"text": ""
},
{
"row": 6,
"text": ""
},
{
"row": 7,
"text": ""
},
{
"row": 8,
"text": ""
},
{
"row": 9,
"text": ""
},
{
"row": 10,
"text": ""
},
{
"row": 11,
"text": ""
},
{
"row": 12,
"text": ""
},
{
"row": 13,
"text": ""
},
{
"row": 14,
"text": ""
},
{
"row": 15,
"text": ""
},
{
"row": 16,
"text": ""
},
{
"row": 17,
"text": ""
},
{
"row": 18,
"text": ""
},
{
"row": 19,
"text": ""
},
{
"row": 20,
"text": ""
},
{
"row": 21,
"text": ""
},
{
"row": 22,
"text": ""
},
{
"row": 23,
"text": ""
}
]
}
}
Empty file.
6 changes: 6 additions & 0 deletions dogfood/issue-59-event-log-codec/type-exit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"ok": true,
"command": "type",
"timestamp": "2026-04-29T12:42:24.665Z",
"result": {}
}
6 changes: 6 additions & 0 deletions dogfood/issue-59-event-log-codec/type-print.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"ok": true,
"command": "type",
"timestamp": "2026-04-29T12:42:20.889Z",
"result": {}
}
9 changes: 9 additions & 0 deletions dogfood/issue-59-event-log-codec/wait-exit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ok": true,
"command": "wait",
"timestamp": "2026-04-29T12:42:26.783Z",
"result": {
"timedOut": false,
"exitCode": 0
}
}
13 changes: 13 additions & 0 deletions dogfood/issue-59-event-log-codec/wait-text.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"ok": true,
"command": "wait",
"timestamp": "2026-04-29T12:42:23.643Z",
"result": {
"matched": true,
"timedOut": false,
"matchedText": "hello from codec dogfood",
"cursorRow": 2,
"cursorCol": 2,
"capturedAtSeq": 4
}
}
2 changes: 1 addition & 1 deletion src/cli/commands/record-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
generateWebmExport,
type WebmExportResult,
} from '../../export/webm.js';
import { readEventLogRecords } from '../../host/replay.js';
import { readEventLogRecords } from '../../storage/eventLogCodec.js';
import { hashProfile, resolveProfile } from '../../renderer/profiles.js';
import { CliError } from '../errors.js';
import { ERROR_CODES, makeCliError } from '../../protocol/errors.js';
Expand Down
Loading
Loading