1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! Transcript tailer.
//!
//! tapes' wire capture yields a complete call inventory but no causal/fork
//! skeleton — that lives only in the harness's on-disk transcripts
//! (`~/.claude/projects/<cwd-encoded>/<sid>.jsonl` plus each session's
//! `subagents/` directory). The transcript lane (`POST /v1/ingest/transcript`)
//! carries them. This module is the client-side half every capture client needs:
//!
//! * [`files`] — discovery of a session's upload set and JSONL→records
//! conversion. Extracted verbatim from a daemon client, which mirrors the Go
//! reference client, so every client produces byte-identical upload sets for
//! the same on-disk state.
//! * [`trigger`] — the push state machine: 30 s quiescence, 5 min periodic safety
//! net, and a final push on harness exit.
//! * [`payload`] — the ingest payload shape, a cross-language contract with the
//! Go server.
//! * [`sweep`](mod@sweep) — a startup scan of the transcript tree, which finds sessions that
//! ended while the client was not running. New here rather than moved: it closes
//! a gap in any purely registry-driven discovery.
//! * [`codex_anchors`] — Codex's counterpart for the fork skeleton alone. Codex
//! writes no per-session transcript tree; the spawn edge lives in its rollout
//! files as `sub_agent_activity` records, and this module derives the anchor
//! rows that carry it down the same lane.
//!
//! The seed's `Transcript { path, harness }` placeholder is gone;
//! [`files::TranscriptFile`] is the real shape, and it carries the subagent id and
//! fork metadata that a transcript upload actually needs.
//!
//! # What stays with each client
//!
//! **Delivery, auth, and retry.** The HTTP call, the request timeout, the response
//! parsing, the credential — and the failure backoff schedule — differ per client,
//! and auth differs most of all: a client fronted by its own cloud edge rides a
//! bespoke auth header of its own so that edge admits the request, and no such
//! header is part of the tapes contract. So does each client's notion of *which*
//! sessions to track: a daemon client's registry is fed by its proxy's
//! per-request attribution, and a standalone client will have a different
//! hook.
//!
//! # Why the eager design is safe
//!
//! Every push decision here errs toward pushing again, because the ingest endpoint
//! is idempotent by construction: the server keys rows on a content hash of the
//! records array, so unchanged content answers `deduped` and a grown transcript
//! appends a new version. The fingerprint driving
//! [`trigger::TriggerInput::dirty`] is deliberately coarse (size + mtime), retries
//! re-read the files rather than buffering anything, and [`sweep`](mod@sweep) re-offers
//! transcripts a previous process may already have sent. The transcript files on
//! disk are the spool; there is no client-side queue to lose.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;