@songsid/agend 2.1.12-beta.8 → 2.1.12-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ import type { TranscriptEvents } from "./transcript-sources.js";
2
+ export interface KiroDbCursor {
3
+ conversationId: string | null;
4
+ historyCursor: number;
5
+ signature: string;
6
+ toolNames: Array<[string, string]>;
7
+ }
8
+ export declare class KiroDbReader {
9
+ private workingDirectory;
10
+ private dbPath;
11
+ private readonly createdAt;
12
+ private dbConversationId;
13
+ private dbHistoryCursor;
14
+ private dbSignature;
15
+ private dbToolNames;
16
+ /**
17
+ * One read-only handle for the life of the poll loop (#1048). Kiro's store
18
+ * is one database for every conversation — ~1 GB on a lived-in machine —
19
+ * and opening it per poll, for every kiro instance every 2 s, ran on the
20
+ * fleet's event loop.
21
+ */
22
+ private db;
23
+ /** The store file the handle was opened on; a replaced file is reopened. */
24
+ private dbIno;
25
+ private newestRowStmt;
26
+ private historyStmt;
27
+ private createdAtStmt;
28
+ constructor(workingDirectory: string, dbPath: string, now?: number, baseline?: boolean);
29
+ reset(): void;
30
+ /** Resolved once per baseline: realpath is a syscall, and this runs every poll. */
31
+ private dbKeys;
32
+ private workingDirectoryKeys;
33
+ close(): void;
34
+ /** The shared handle, opened on first use; null while the store is absent. */
35
+ private openDb;
36
+ /**
37
+ * The newest conversation for this workspace and its change signal. The
38
+ * size is `octet_length`, which SQLite answers from the record header:
39
+ * `length()` on TEXT counts characters, so it read every conversation in
40
+ * full on every poll (#1048) — 56 ms a round across 13 real kiro
41
+ * workspaces, against 0.05 ms for this. The size stays in the signature
42
+ * because two saves inside one millisecond share an `updated_at`.
43
+ * No `created_at` either: it is stored after `value`, so reading it walks
44
+ * the whole conversation too (9 ms for one 18 MB row); `updated_at` comes
45
+ * from the key index. `conversationCreatedAt()` reads it on a switch.
46
+ */
47
+ private newestDbRow;
48
+ /** When a conversation began; read only when the poll switches to it. */
49
+ private conversationCreatedAt;
50
+ /** The whole history, read only when the signature says it changed. */
51
+ private readDbHistory;
52
+ /**
53
+ * Kiro 2.19 moved primary conversations into data.sqlite3. Snapshot the
54
+ * active row in the isolate before admission so its existing history is
55
+ * never replayed as live tool progress.
56
+ */
57
+ baseline(): void;
58
+ private snapshotDbBaseline;
59
+ read(): TranscriptEvents | null;
60
+ cursor(): KiroDbCursor;
61
+ restore(cursor: KiroDbCursor): void;
62
+ poll(): Promise<TranscriptEvents>;
63
+ }
64
+ /** Strings a kiro assistant turn can carry: plain response + tool-call text. */
65
+ export declare function extractKiroAssistantStrings(entry: unknown): string[];
@@ -0,0 +1,258 @@
1
+ /** SQLite and large JSON work runs only in the transcript isolate. */
2
+ import Database from "better-sqlite3";
3
+ import { statSync, realpathSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ const EMPTY = { toolUses: [], toolResults: [], assistantTexts: [] };
6
+ const emptyEvents = () => ({ toolUses: [], toolResults: [], assistantTexts: [] });
7
+ export class KiroDbReader {
8
+ workingDirectory;
9
+ dbPath;
10
+ createdAt;
11
+ dbConversationId = null;
12
+ dbHistoryCursor = 0;
13
+ dbSignature = "";
14
+ dbToolNames = new Map();
15
+ /**
16
+ * One read-only handle for the life of the poll loop (#1048). Kiro's store
17
+ * is one database for every conversation — ~1 GB on a lived-in machine —
18
+ * and opening it per poll, for every kiro instance every 2 s, ran on the
19
+ * fleet's event loop.
20
+ */
21
+ db = null;
22
+ /** The store file the handle was opened on; a replaced file is reopened. */
23
+ dbIno = 0;
24
+ newestRowStmt = null;
25
+ historyStmt = null;
26
+ createdAtStmt = null;
27
+ constructor(workingDirectory, dbPath, now = Date.now(), baseline = true) {
28
+ this.workingDirectory = workingDirectory;
29
+ this.dbPath = dbPath;
30
+ this.createdAt = now;
31
+ if (baseline)
32
+ this.snapshotDbBaseline();
33
+ }
34
+ reset() {
35
+ this.close();
36
+ this.dbKeys = null;
37
+ this.dbConversationId = null;
38
+ this.dbHistoryCursor = 0;
39
+ this.dbSignature = "";
40
+ this.dbToolNames.clear();
41
+ this.snapshotDbBaseline();
42
+ }
43
+ /** Resolved once per baseline: realpath is a syscall, and this runs every poll. */
44
+ dbKeys = null;
45
+ workingDirectoryKeys() {
46
+ if (this.dbKeys)
47
+ return this.dbKeys;
48
+ const keys = new Set([this.workingDirectory, resolve(this.workingDirectory)]);
49
+ try {
50
+ keys.add(realpathSync(this.workingDirectory));
51
+ }
52
+ catch { /* keep literal/absolute cwd */ }
53
+ this.dbKeys = [...keys];
54
+ return this.dbKeys;
55
+ }
56
+ close() {
57
+ try {
58
+ this.db?.close();
59
+ }
60
+ catch { /* already closed */ }
61
+ this.db = null;
62
+ this.newestRowStmt = null;
63
+ this.historyStmt = null;
64
+ this.createdAtStmt = null;
65
+ }
66
+ /** The shared handle, opened on first use; null while the store is absent. */
67
+ openDb() {
68
+ let ino;
69
+ try {
70
+ ino = statSync(this.dbPath).ino;
71
+ }
72
+ catch {
73
+ this.close();
74
+ return null;
75
+ }
76
+ // A handle keeps reading the file it opened: if kiro replaced the store,
77
+ // that is a stale copy that never errors, so follow the path instead.
78
+ if (this.db && ino === this.dbIno)
79
+ return this.db;
80
+ this.close();
81
+ this.db = new Database(this.dbPath, { readonly: true, fileMustExist: true });
82
+ this.dbIno = ino;
83
+ return this.db;
84
+ }
85
+ /**
86
+ * The newest conversation for this workspace and its change signal. The
87
+ * size is `octet_length`, which SQLite answers from the record header:
88
+ * `length()` on TEXT counts characters, so it read every conversation in
89
+ * full on every poll (#1048) — 56 ms a round across 13 real kiro
90
+ * workspaces, against 0.05 ms for this. The size stays in the signature
91
+ * because two saves inside one millisecond share an `updated_at`.
92
+ * No `created_at` either: it is stored after `value`, so reading it walks
93
+ * the whole conversation too (9 ms for one 18 MB row); `updated_at` comes
94
+ * from the key index. `conversationCreatedAt()` reads it on a switch.
95
+ */
96
+ newestDbRow(db) {
97
+ const keys = this.workingDirectoryKeys();
98
+ if (!this.newestRowStmt || this.newestRowStmt.database !== db) {
99
+ this.newestRowStmt = db.prepare(`SELECT key, conversation_id, updated_at, octet_length(value) AS size
100
+ FROM conversations_v2 WHERE key IN (?, ?, ?)
101
+ ORDER BY updated_at DESC LIMIT 1`);
102
+ }
103
+ // Always three parameters, so one prepared statement serves every call.
104
+ const [a, b = a, c = b] = keys;
105
+ return this.newestRowStmt.get(a, b, c);
106
+ }
107
+ /** When a conversation began; read only when the poll switches to it. */
108
+ conversationCreatedAt(db, key, conversationId) {
109
+ if (!this.createdAtStmt || this.createdAtStmt.database !== db) {
110
+ this.createdAtStmt = db.prepare("SELECT created_at FROM conversations_v2 WHERE key = ? AND conversation_id = ? LIMIT 1");
111
+ }
112
+ const row = this.createdAtStmt.get(key, conversationId);
113
+ return row?.created_at ?? 0;
114
+ }
115
+ /** The whole history, read only when the signature says it changed. */
116
+ readDbHistory(db, key, conversationId) {
117
+ if (!this.historyStmt || this.historyStmt.database !== db) {
118
+ this.historyStmt = db.prepare("SELECT value FROM conversations_v2 WHERE key = ? AND conversation_id = ? LIMIT 1");
119
+ }
120
+ const row = this.historyStmt.get(key, conversationId);
121
+ if (!row)
122
+ return null;
123
+ try {
124
+ const parsed = JSON.parse(row.value);
125
+ return Array.isArray(parsed.history) ? parsed.history : [];
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
131
+ /**
132
+ * Kiro 2.19 moved primary conversations into data.sqlite3. Snapshot the
133
+ * active row in the isolate before admission so its existing history is
134
+ * never replayed as live tool progress.
135
+ */
136
+ baseline() { this.snapshotDbBaseline(); }
137
+ snapshotDbBaseline() {
138
+ try {
139
+ const db = this.openDb();
140
+ if (!db)
141
+ return;
142
+ const row = this.newestDbRow(db);
143
+ if (!row)
144
+ return;
145
+ const history = this.readDbHistory(db, row.key, row.conversation_id);
146
+ if (!history)
147
+ return;
148
+ this.dbConversationId = row.conversation_id;
149
+ this.dbHistoryCursor = history.length;
150
+ this.dbSignature = `${row.updated_at}:${row.size}`;
151
+ }
152
+ catch {
153
+ // Old Kiro schema or busy DB — legacy JSONL remains available.
154
+ this.close();
155
+ }
156
+ }
157
+ read() {
158
+ try {
159
+ const db = this.openDb();
160
+ if (!db)
161
+ return null;
162
+ const row = this.newestDbRow(db);
163
+ if (!row)
164
+ return null;
165
+ const signature = `${row.updated_at}:${row.size}`;
166
+ if (row.conversation_id === this.dbConversationId && signature === this.dbSignature)
167
+ return EMPTY;
168
+ const history = this.readDbHistory(db, row.key, row.conversation_id);
169
+ if (!history)
170
+ return EMPTY;
171
+ if (row.conversation_id !== this.dbConversationId) {
172
+ this.dbConversationId = row.conversation_id;
173
+ this.dbToolNames.clear();
174
+ // A conversation created after this monitor belongs to this daemon;
175
+ // an older conversation selected by --resume is history to baseline.
176
+ this.dbHistoryCursor = this.conversationCreatedAt(db, row.key, row.conversation_id) >= this.createdAt ? 0 : history.length;
177
+ }
178
+ if (history.length < this.dbHistoryCursor) {
179
+ // Compaction can replace history with a shorter summary. Treat the new
180
+ // compacted body as a baseline instead of waiting for it to grow past
181
+ // the old cursor (or replaying retained history).
182
+ this.dbHistoryCursor = history.length;
183
+ this.dbSignature = signature;
184
+ return EMPTY;
185
+ }
186
+ const events = emptyEvents();
187
+ for (const entry of history.slice(this.dbHistoryCursor)) {
188
+ collectKiroDbEvents(entry, events, this.dbToolNames);
189
+ }
190
+ this.dbHistoryCursor = history.length;
191
+ this.dbSignature = signature;
192
+ return events;
193
+ }
194
+ catch {
195
+ // A replaced or corrupted store: drop the handle so the next poll reopens.
196
+ this.close();
197
+ return null;
198
+ }
199
+ }
200
+ cursor() { return { conversationId: this.dbConversationId, historyCursor: this.dbHistoryCursor, signature: this.dbSignature, toolNames: [...this.dbToolNames] }; }
201
+ restore(cursor) { this.dbConversationId = cursor.conversationId; this.dbHistoryCursor = cursor.historyCursor; this.dbSignature = cursor.signature; this.dbToolNames = new Map(cursor.toolNames); }
202
+ async poll() { return this.read() ?? emptyEvents(); }
203
+ }
204
+ /** Strings a kiro assistant turn can carry: plain response + tool-call text. */
205
+ export function extractKiroAssistantStrings(entry) {
206
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
207
+ return [];
208
+ const assistant = entry.assistant;
209
+ if (!assistant || typeof assistant !== "object" || Array.isArray(assistant))
210
+ return [];
211
+ const out = [];
212
+ const record = assistant;
213
+ const response = record.Response;
214
+ if (response && typeof response.content === "string" && response.content.trim())
215
+ out.push(response.content);
216
+ const toolUse = record.ToolUse;
217
+ if (toolUse && typeof toolUse.content === "string" && toolUse.content.trim())
218
+ out.push(toolUse.content);
219
+ return out;
220
+ }
221
+ function collectKiroDbEvents(entry, out, toolNames) {
222
+ if (!entry || typeof entry !== "object")
223
+ return;
224
+ const record = entry;
225
+ // Assistant text is observable too (#995 scans it for fabricated peer
226
+ // envelopes — the #856 forgery lived in a ToolUse content string).
227
+ for (const text of extractKiroAssistantStrings(entry))
228
+ out.assistantTexts.push(text);
229
+ const assistant = record.assistant;
230
+ const toolUse = assistant?.ToolUse;
231
+ const uses = toolUse?.tool_uses;
232
+ if (Array.isArray(uses)) {
233
+ for (const raw of uses) {
234
+ if (!raw || typeof raw !== "object")
235
+ continue;
236
+ const use = raw;
237
+ const name = String(use.name ?? use.orig_name ?? "unknown");
238
+ const id = typeof use.id === "string" ? use.id : undefined;
239
+ if (id)
240
+ toolNames.set(id, name);
241
+ out.toolUses.push({ name, input: use.args ?? use.orig_args });
242
+ }
243
+ }
244
+ const user = record.user;
245
+ const content = user?.content;
246
+ const resultsContainer = content?.ToolUseResults;
247
+ const results = resultsContainer?.tool_use_results;
248
+ if (Array.isArray(results)) {
249
+ for (const raw of results) {
250
+ if (!raw || typeof raw !== "object")
251
+ continue;
252
+ const result = raw;
253
+ const id = typeof result.tool_use_id === "string" ? result.tool_use_id : "";
254
+ out.toolResults.push({ name: toolNames.get(id) ?? "toolResult" });
255
+ }
256
+ }
257
+ }
258
+ //# sourceMappingURL=kiro-db-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kiro-db-reader.js","sourceRoot":"","sources":["../src/kiro-db-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { KiroDbCursor } from "./kiro-db-reader.js";
2
+ import type { TranscriptEvents } from "./transcript-sources.js";
3
+ export declare const KIRO_TRANSCRIPT_BUDGET_MS = 15000;
4
+ export interface KiroDbInput {
5
+ dbPath: string;
6
+ workingDirectory: string;
7
+ createdAt: number;
8
+ baseline: boolean;
9
+ cursor?: KiroDbCursor;
10
+ }
11
+ export interface KiroDbReply {
12
+ events: TranscriptEvents | null;
13
+ cursor: KiroDbCursor;
14
+ }
15
+ export interface KiroDbLease {
16
+ read(input: KiroDbInput): Promise<KiroDbReply | null>;
17
+ close(): void;
18
+ }
19
+ export interface KiroDbLane {
20
+ acquire(): KiroDbLease;
21
+ }
22
+ export interface KiroWorkerRequest {
23
+ id: number;
24
+ owner: number;
25
+ deadlineAt: number;
26
+ input: KiroDbInput;
27
+ }
28
+ interface Isolate {
29
+ on(event: "message" | "error" | "exit", listener: (...args: any[]) => void): unknown;
30
+ postMessage(value: unknown): void;
31
+ terminate(): Promise<number>;
32
+ ref(): unknown;
33
+ unref(): unknown;
34
+ }
35
+ /** One physical isolate, one queued/in-flight request per source, warm RO handles.
36
+ * Queue time counts toward the total budget. Termination does not release the
37
+ * physical slot until exit: a stalled native read never creates a worker herd.
38
+ */
39
+ export declare class KiroTranscriptLane implements KiroDbLane {
40
+ private factory;
41
+ private now;
42
+ private worker;
43
+ private exiting;
44
+ private owners;
45
+ private pending;
46
+ private nextId;
47
+ private nextOwner;
48
+ constructor(factory?: () => Isolate, now?: () => number);
49
+ acquire(): KiroDbLease;
50
+ private settle;
51
+ private recycle;
52
+ private ensureWorker;
53
+ private read;
54
+ }
55
+ export declare const sharedKiroTranscriptLane: KiroTranscriptLane;
56
+ export {};
@@ -0,0 +1,141 @@
1
+ import { Worker } from "node:worker_threads";
2
+ import { performance } from "node:perf_hooks";
3
+ export const KIRO_TRANSCRIPT_BUDGET_MS = 15_000;
4
+ function createIsolate() {
5
+ return import.meta.url.endsWith(".ts")
6
+ ? new Worker(`const { workerData } = require("node:worker_threads"); import("tsx/esm/api").then(({ tsImport }) => tsImport(workerData.entry, workerData.entry));`, { eval: true, execArgv: [], workerData: { entry: new URL("./kiro-transcript-worker.ts", import.meta.url).href } })
7
+ : new Worker(new URL("./kiro-transcript-worker.js", import.meta.url), { execArgv: [] });
8
+ }
9
+ /** One physical isolate, one queued/in-flight request per source, warm RO handles.
10
+ * Queue time counts toward the total budget. Termination does not release the
11
+ * physical slot until exit: a stalled native read never creates a worker herd.
12
+ */
13
+ export class KiroTranscriptLane {
14
+ factory;
15
+ now;
16
+ worker = null;
17
+ exiting = null;
18
+ owners = new Set();
19
+ pending = new Map();
20
+ nextId = 0;
21
+ nextOwner = 0;
22
+ constructor(factory = createIsolate, now = () => performance.now()) {
23
+ this.factory = factory;
24
+ this.now = now;
25
+ }
26
+ acquire() {
27
+ const owner = ++this.nextOwner;
28
+ this.owners.add(owner);
29
+ return {
30
+ read: input => this.read(owner, input),
31
+ close: () => {
32
+ if (!this.owners.delete(owner))
33
+ return;
34
+ for (const [id, request] of this.pending)
35
+ if (request.owner === owner)
36
+ this.settle(id, null);
37
+ try {
38
+ this.worker?.postMessage({ close: owner });
39
+ }
40
+ catch {
41
+ this.recycle();
42
+ }
43
+ if (!this.owners.size)
44
+ this.recycle();
45
+ },
46
+ };
47
+ }
48
+ settle(id, reply) {
49
+ const request = this.pending.get(id);
50
+ if (!request)
51
+ return;
52
+ this.pending.delete(id);
53
+ clearTimeout(request.timer);
54
+ request.resolve(reply);
55
+ if (!this.pending.size)
56
+ this.worker?.unref();
57
+ }
58
+ recycle() {
59
+ const worker = this.worker;
60
+ if (!worker || this.exiting)
61
+ return;
62
+ for (const id of this.pending.keys())
63
+ this.settle(id, null);
64
+ // The exit listener owns release; a rejected termination keeps the slot.
65
+ this.exiting = new Promise(resolve => worker.on("exit", resolve));
66
+ try {
67
+ void worker.terminate().catch(() => { });
68
+ }
69
+ catch { /* retain physical reservation */ }
70
+ }
71
+ ensureWorker() {
72
+ if (this.worker)
73
+ return this.worker;
74
+ const worker = this.factory();
75
+ this.worker = worker;
76
+ worker.on("message", (message) => {
77
+ if (this.worker !== worker || this.exiting)
78
+ return;
79
+ const request = this.pending.get(message.id);
80
+ if (!request)
81
+ return;
82
+ if (this.now() >= request.deadlineAt) {
83
+ this.settle(message.id, null);
84
+ this.recycle();
85
+ }
86
+ else
87
+ this.settle(message.id, message.reply);
88
+ });
89
+ worker.on("error", () => { if (this.worker === worker)
90
+ this.recycle(); });
91
+ worker.on("exit", () => {
92
+ if (this.worker !== worker)
93
+ return;
94
+ this.worker = null;
95
+ this.exiting = null;
96
+ for (const [id, request] of this.pending)
97
+ if (request.worker === worker)
98
+ this.settle(id, null);
99
+ });
100
+ worker.unref();
101
+ return worker;
102
+ }
103
+ read(owner, input) {
104
+ if (!this.owners.has(owner))
105
+ return Promise.resolve(null);
106
+ const existing = [...this.pending.values()].find(request => request.owner === owner);
107
+ if (existing)
108
+ return existing.promise;
109
+ const id = ++this.nextId, deadlineAt = this.now() + KIRO_TRANSCRIPT_BUDGET_MS;
110
+ let resolve;
111
+ const promise = new Promise(done => { resolve = done; });
112
+ const request = { owner, deadlineAt, promise, resolve, timer: setTimeout(() => {
113
+ this.settle(id, null);
114
+ this.recycle();
115
+ }, KIRO_TRANSCRIPT_BUDGET_MS) };
116
+ this.pending.set(id, request);
117
+ void (async () => {
118
+ if (this.exiting)
119
+ await this.exiting;
120
+ if (!this.pending.has(id) || !this.owners.has(owner))
121
+ return;
122
+ if (this.now() >= deadlineAt) {
123
+ this.settle(id, null);
124
+ return;
125
+ }
126
+ try {
127
+ const worker = this.ensureWorker();
128
+ request.worker = worker;
129
+ worker.ref();
130
+ worker.postMessage({ id, owner, deadlineAt, input });
131
+ }
132
+ catch {
133
+ this.settle(id, null);
134
+ this.recycle();
135
+ }
136
+ })();
137
+ return promise;
138
+ }
139
+ }
140
+ export const sharedKiroTranscriptLane = new KiroTranscriptLane();
141
+ //# sourceMappingURL=kiro-transcript-lane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kiro-transcript-lane.js","sourceRoot":"","sources":["../src/kiro-transcript-lane.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import { parentPort } from "node:worker_threads";
2
+ import { performance } from "node:perf_hooks";
3
+ import { KiroDbReader } from "./kiro-db-reader.js";
4
+ const readers = new Map();
5
+ parentPort?.on("message", (message) => {
6
+ if ("close" in message) {
7
+ readers.get(message.close)?.close();
8
+ readers.delete(message.close);
9
+ return;
10
+ }
11
+ const { id, owner, input, deadlineAt } = message;
12
+ if (performance.now() >= deadlineAt) {
13
+ parentPort?.postMessage({ id, reply: null });
14
+ return;
15
+ }
16
+ let reader = readers.get(owner);
17
+ if (!reader) {
18
+ reader = new KiroDbReader(input.workingDirectory, input.dbPath, input.createdAt, false);
19
+ readers.set(owner, reader);
20
+ }
21
+ if (input.cursor)
22
+ reader.restore(input.cursor);
23
+ if (input.baseline)
24
+ reader.baseline();
25
+ const events = input.baseline ? { toolUses: [], toolResults: [], assistantTexts: [] } : reader.read();
26
+ parentPort?.postMessage({ id, reply: { events, cursor: reader.cursor() } });
27
+ });
28
+ //# sourceMappingURL=kiro-transcript-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kiro-transcript-worker.js","sourceRoot":"","sources":["../src/kiro-transcript-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;AAChD,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,OAA8C,EAAE,EAAE;IAC3E,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACvG,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IACjD,IAAI,WAAW,CAAC,GAAG,EAAE,IAAI,UAAU,EAAE,CAAC;QAAC,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC9F,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACxF,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,CAAC,MAAM;QAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,KAAK,CAAC,QAAQ;QAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACtG,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9E,CAAC,CAAC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type TranscriptMarkerKind } from "./delivery-reconciliation.js";
2
+ export declare const TRANSCRIPT_PROOF_READ: {
3
+ /** Bytes one look reads past the reader's position. */
4
+ chunkBytes: number;
5
+ /** A line longer than this (without its newline) is never decoded: skipped. */
6
+ maxLineBytes: number;
7
+ /** A look settles within this; a slower read is abandoned and its late result dropped. */
8
+ lookBudgetMs: number;
9
+ };
10
+ export type TranscriptLook = TranscriptMarkerKind | "no-match" | "unavailable" | "pending";
11
+ export declare class TranscriptDeltaReader {
12
+ private readonly path;
13
+ private readonly backend;
14
+ private readonly deliveryId;
15
+ private position;
16
+ private carry;
17
+ private skippingLine;
18
+ private inFlight;
19
+ constructor(path: string, offset: number, backend: string, deliveryId: string);
20
+ /** Where the next look reads from (tests). */
21
+ get readPosition(): number;
22
+ /** One bounded look. Never throws. */
23
+ look(): Promise<TranscriptLook>;
24
+ /** The next chunk past the position (null: nothing new), without touching the reader's state. */
25
+ private readChunk;
26
+ /** The complete lines of this chunk (and the carried start of one), each within the cap, judged once. */
27
+ private scan;
28
+ }