perf: cheaper ingest — no re-parse of live hooked transcripts, delta hook writes, lighter pollers
- Session sync leaves a transcript alone while hooks feed its session live (active, newest event a hook's, touched within DASHBOARD_SYNC_LIVE_HOOK_MS, default 5 min) and catches it up once quiet; a hook-created session (which importSession skips anyway) is only snapshotted, never parsed. - Hook writer keeps a per-transcript mark (applied after commit): an unchanged TranscriptCache result skips token/compaction/API-error/turn writes, a grown one walks only the entries after the last one handled. - Codex usage: one stamp query per pass instead of one row per journal; between full passes (first + every 5 min) only the newest day folders and journals written in the last hour are statted; fork parents resolved from the table or a full walk. - Cursor/Antigravity polls back off to 60 s after idle passes (server/lib/backoff-poll.js); lane sync runs only while another dashboard shares the data dir (checked every 30 s).
This commit is contained in:
+17
-5
@@ -1066,7 +1066,7 @@ flowchart TD
|
||||
- Uses Node.js `http` module directly — no dependencies.
|
||||
- Resolution order is **env override → discovery file → default**:
|
||||
- `CLAUDE_DASHBOARD_PORT` forces a single target (no fan-out, no discovery).
|
||||
- Otherwise `server/lib/server-info.js` reads `~/.claude/.agenthub.json`, prunes dead-PID entries, and returns one live `port` per unique `dataDir` (lowest port wins when two instances share `~/.claude/agenthub`). The handler POSTs to each returned port in parallel. The other instance learns of a lane the hooks moved through `broadcastForeignLaneChanges` (`server/routes/lanes.js`): every `DASHBOARD_LANE_SYNC_MS` (2 s) it reads `PRAGMA data_version`, which moves only on another connection's commit, and re-broadcasts each lane whose `updated_at` changed (and `removed` for a vanished one) to its own browsers. Sessions and events are not re-broadcast this way — a page on that instance shows them on its next fetch.
|
||||
- Otherwise `server/lib/server-info.js` reads `~/.claude/.agenthub.json`, prunes dead-PID entries, and returns one live `port` per unique `dataDir` (lowest port wins when two instances share `~/.claude/agenthub`). The handler POSTs to each returned port in parallel. The other instance learns of a lane the hooks moved through `broadcastForeignLaneChanges` (`server/routes/lanes.js`): every `DASHBOARD_LANE_SYNC_MS` (2 s) — while `peersSharingDataDir()` finds another live dashboard on its data dir, which it checks every 30 s — it reads `PRAGMA data_version`, which moves only on another connection's commit, and re-broadcasts each lane whose `updated_at` changed (and `removed` for a vanished one) to its own browsers. Sessions and events are not re-broadcast this way — a page on that instance shows them on its next fetch.
|
||||
- If neither yields anything, the handler falls back to `4820`.
|
||||
- Per-target promises never reject — a dead listener can't starve the others, and the handler can wait on `Promise.all` for clean exit timing.
|
||||
|
||||
@@ -1223,7 +1223,12 @@ common "nothing changed" tick is just a handful of `stat` calls), funnels them
|
||||
through the same `parseSessionFile` + `importSession` pipeline as every other
|
||||
path, and broadcasts `session_created` for newly imported sessions /
|
||||
`session_updated` for grown ones — the same events hooks emit, so the UI
|
||||
refreshes live. All timers and watchers are `unref`'d and best-effort; nothing
|
||||
refreshes live. Two kinds of transcript are not re-parsed: one whose session
|
||||
hooks are feeding **live** (status `active`, newest event a hook's, a hook
|
||||
within `DASHBOARD_SYNC_LIVE_HOOK_MS`, default 5 min) is left until it goes
|
||||
quiet or ends — then caught up once — and one whose session a hook created
|
||||
(no `imported` flag, which `importSession` skips anyway) only has its durable
|
||||
snapshot refreshed, never a parse. All timers and watchers are `unref`'d and best-effort; nothing
|
||||
here blocks shutdown or can take down the server.
|
||||
|
||||
### Upload request sequence
|
||||
@@ -1579,7 +1584,11 @@ re-point if that changes.
|
||||
`DASHBOARD_CODEX_POLL_MS` beat, a first pass over every journal in the
|
||||
background at startup). Each file's read offset and parse state live in the
|
||||
`codex_rollouts` table, so an unchanged file is never re-read and a grown one is
|
||||
read from where it stopped. `token_count` events are summed per `turn_context`
|
||||
read from where it stopped (a pass loads every row's size/mtime in one query).
|
||||
The first pass and one every five minutes walk every journal; the poll's other
|
||||
passes stat only the two newest day folders plus the journals the table saw
|
||||
written in the last hour (or not yet read to the end), so a thread resumed
|
||||
after an hour's quiet in an older folder is picked up by the next full pass. `token_count` events are summed per `turn_context`
|
||||
model — `input_tokens` includes `cached_input_tokens` (stored as input − cached
|
||||
plus cache_read) and `output_tokens` includes reasoning. A **fork** copies its
|
||||
parent's whole history into its own file, token events included, so every total
|
||||
@@ -1654,7 +1663,9 @@ the binary's own proto descriptors.
|
||||
|
||||
**Sessions and tokens** (`server/lib/antigravity-usage.js`,
|
||||
`startAntigravityUsagePoll`, every `DASHBOARD_ANTIGRAVITY_POLL_MS`, default
|
||||
15000, `0` disables). agy writes one SQLite file per conversation,
|
||||
15000, `0` disables; after a pass that read nothing, wrote nothing and left no
|
||||
fresh session to settle it slows to once a minute until one finds work —
|
||||
`server/lib/backoff-poll.js`). agy writes one SQLite file per conversation,
|
||||
`~/.gemini/antigravity-cli/conversations/<conversation id>.db`. Each is opened
|
||||
read-only whenever its mtime (or its non-empty `-wal`'s) changes;
|
||||
`antigravity_conversations` holds the mtime read, so a session the user deleted
|
||||
@@ -1743,7 +1754,8 @@ is ever inferred.
|
||||
## Cursor Sessions
|
||||
|
||||
`server/lib/cursor-usage.js` (`startCursorUsagePoll`, every
|
||||
`DASHBOARD_CURSOR_POLL_MS`, default 15000, `0` disables) reads the agent
|
||||
`DASHBOARD_CURSOR_POLL_MS`, default 15000, `0` disables; idle passes slow it to
|
||||
once a minute like the Antigravity poll) reads the agent
|
||||
transcripts Cursor writes — the CLI (`cursor-agent`) and the editor's agent both —
|
||||
at `~/.cursor/projects/<project slug>/agent-transcripts/<id>/<id>.jsonl`
|
||||
(`AGENTHUB_CURSOR_DIR` overrides `~/.cursor`). Each becomes a `sessions` row with
|
||||
|
||||
Reference in New Issue
Block a user