@shipfox/api-logs 10.0.0 → 10.2.0

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.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +23 -0
  3. package/dist/core/append-logs.d.ts.map +1 -1
  4. package/dist/core/append-logs.js +13 -5
  5. package/dist/core/append-logs.js.map +1 -1
  6. package/dist/core/close-stream.d.ts.map +1 -1
  7. package/dist/core/close-stream.js +16 -1
  8. package/dist/core/close-stream.js.map +1 -1
  9. package/dist/core/entities/attempt-stream.d.ts +2 -1
  10. package/dist/core/entities/attempt-stream.d.ts.map +1 -1
  11. package/dist/core/entities/attempt-stream.js.map +1 -1
  12. package/dist/core/session/claude/rows.d.ts +15 -3
  13. package/dist/core/session/claude/rows.d.ts.map +1 -1
  14. package/dist/core/session/claude/rows.js +221 -15
  15. package/dist/core/session/claude/rows.js.map +1 -1
  16. package/dist/core/session/claude-parser.d.ts +4 -2
  17. package/dist/core/session/claude-parser.d.ts.map +1 -1
  18. package/dist/core/session/claude-parser.js +56 -10
  19. package/dist/core/session/claude-parser.js.map +1 -1
  20. package/dist/db/db.d.ts +113 -0
  21. package/dist/db/db.d.ts.map +1 -1
  22. package/dist/db/schema/attempt-streams.d.ts +113 -0
  23. package/dist/db/schema/attempt-streams.d.ts.map +1 -1
  24. package/dist/db/schema/attempt-streams.js +2 -0
  25. package/dist/db/schema/attempt-streams.js.map +1 -1
  26. package/dist/db/streams.d.ts +3 -1
  27. package/dist/db/streams.d.ts.map +1 -1
  28. package/dist/db/streams.js +6 -1
  29. package/dist/db/streams.js.map +1 -1
  30. package/dist/tsconfig.test.tsbuildinfo +1 -1
  31. package/drizzle/0002_wise_dorian_gray.sql +1 -0
  32. package/drizzle/meta/0002_snapshot.json +561 -0
  33. package/drizzle/meta/_journal.json +7 -0
  34. package/package.json +4 -4
  35. package/src/core/append-logs.test.ts +57 -0
  36. package/src/core/append-logs.ts +15 -3
  37. package/src/core/close-stream.ts +17 -1
  38. package/src/core/entities/attempt-stream.ts +2 -1
  39. package/src/core/session/claude/rows.ts +295 -13
  40. package/src/core/session/claude-parser.test.ts +620 -11
  41. package/src/core/session/claude-parser.ts +59 -10
  42. package/src/db/schema/attempt-streams.ts +3 -1
  43. package/src/db/streams.ts +10 -2
  44. package/test/fixtures/claude-session/agent-step.jsonl +12 -0
  45. package/test/fixtures/claude-session/sdk-system-subtypes.json +32 -0
  46. package/test/fixtures/claude-session.ts +45 -0
  47. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1 @@
1
+ ALTER TABLE "logs_attempt_streams" ADD COLUMN "claude_pending_tool_rows" jsonb;
@@ -0,0 +1,561 @@
1
+ {
2
+ "id": "c7c62bb2-21a0-48c3-95bd-38dda56a083b",
3
+ "prevId": "2d8b03a3-df94-4be5-a2cc-cd5b431bcd59",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "public.logs_attempt_streams": {
8
+ "name": "logs_attempt_streams",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "uuidv7()"
17
+ },
18
+ "job_id": {
19
+ "name": "job_id",
20
+ "type": "uuid",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "step_id": {
25
+ "name": "step_id",
26
+ "type": "uuid",
27
+ "primaryKey": false,
28
+ "notNull": true
29
+ },
30
+ "attempt": {
31
+ "name": "attempt",
32
+ "type": "integer",
33
+ "primaryKey": false,
34
+ "notNull": true
35
+ },
36
+ "workspace_id": {
37
+ "name": "workspace_id",
38
+ "type": "uuid",
39
+ "primaryKey": false,
40
+ "notNull": true
41
+ },
42
+ "project_id": {
43
+ "name": "project_id",
44
+ "type": "uuid",
45
+ "primaryKey": false,
46
+ "notNull": true
47
+ },
48
+ "workflow_run_attempt_id": {
49
+ "name": "workflow_run_attempt_id",
50
+ "type": "uuid",
51
+ "primaryKey": false,
52
+ "notNull": true
53
+ },
54
+ "committed_length": {
55
+ "name": "committed_length",
56
+ "type": "bigint",
57
+ "primaryKey": false,
58
+ "notNull": true,
59
+ "default": 0
60
+ },
61
+ "state": {
62
+ "name": "state",
63
+ "type": "text",
64
+ "primaryKey": false,
65
+ "notNull": true,
66
+ "default": "'open'"
67
+ },
68
+ "close_reason": {
69
+ "name": "close_reason",
70
+ "type": "text",
71
+ "primaryKey": false,
72
+ "notNull": false
73
+ },
74
+ "declared_total_bytes": {
75
+ "name": "declared_total_bytes",
76
+ "type": "bigint",
77
+ "primaryKey": false,
78
+ "notNull": false
79
+ },
80
+ "claude_has_init": {
81
+ "name": "claude_has_init",
82
+ "type": "boolean",
83
+ "primaryKey": false,
84
+ "notNull": true,
85
+ "default": false
86
+ },
87
+ "claude_session_id": {
88
+ "name": "claude_session_id",
89
+ "type": "text",
90
+ "primaryKey": false,
91
+ "notNull": false
92
+ },
93
+ "claude_turn": {
94
+ "name": "claude_turn",
95
+ "type": "integer",
96
+ "primaryKey": false,
97
+ "notNull": true,
98
+ "default": 0
99
+ },
100
+ "claude_pending_result": {
101
+ "name": "claude_pending_result",
102
+ "type": "jsonb",
103
+ "primaryKey": false,
104
+ "notNull": false
105
+ },
106
+ "claude_pending_tool_rows": {
107
+ "name": "claude_pending_tool_rows",
108
+ "type": "jsonb",
109
+ "primaryKey": false,
110
+ "notNull": false
111
+ },
112
+ "truncated": {
113
+ "name": "truncated",
114
+ "type": "boolean",
115
+ "primaryKey": false,
116
+ "notNull": true,
117
+ "default": false
118
+ },
119
+ "object_key": {
120
+ "name": "object_key",
121
+ "type": "text",
122
+ "primaryKey": false,
123
+ "notNull": false
124
+ },
125
+ "created_at": {
126
+ "name": "created_at",
127
+ "type": "timestamp with time zone",
128
+ "primaryKey": false,
129
+ "notNull": true,
130
+ "default": "now()"
131
+ },
132
+ "updated_at": {
133
+ "name": "updated_at",
134
+ "type": "timestamp with time zone",
135
+ "primaryKey": false,
136
+ "notNull": true,
137
+ "default": "now()"
138
+ },
139
+ "closed_at": {
140
+ "name": "closed_at",
141
+ "type": "timestamp with time zone",
142
+ "primaryKey": false,
143
+ "notNull": false
144
+ }
145
+ },
146
+ "indexes": {
147
+ "logs_attempt_streams_identity_unique": {
148
+ "name": "logs_attempt_streams_identity_unique",
149
+ "columns": [
150
+ {
151
+ "expression": "job_id",
152
+ "isExpression": false,
153
+ "asc": true,
154
+ "nulls": "last"
155
+ },
156
+ {
157
+ "expression": "step_id",
158
+ "isExpression": false,
159
+ "asc": true,
160
+ "nulls": "last"
161
+ },
162
+ {
163
+ "expression": "attempt",
164
+ "isExpression": false,
165
+ "asc": true,
166
+ "nulls": "last"
167
+ }
168
+ ],
169
+ "isUnique": true,
170
+ "concurrently": false,
171
+ "method": "btree",
172
+ "with": {}
173
+ },
174
+ "logs_attempt_streams_step_attempt_idx": {
175
+ "name": "logs_attempt_streams_step_attempt_idx",
176
+ "columns": [
177
+ {
178
+ "expression": "step_id",
179
+ "isExpression": false,
180
+ "asc": true,
181
+ "nulls": "last"
182
+ },
183
+ {
184
+ "expression": "attempt",
185
+ "isExpression": false,
186
+ "asc": true,
187
+ "nulls": "last"
188
+ }
189
+ ],
190
+ "isUnique": false,
191
+ "concurrently": false,
192
+ "method": "btree",
193
+ "with": {}
194
+ },
195
+ "logs_attempt_streams_open_by_job_idx": {
196
+ "name": "logs_attempt_streams_open_by_job_idx",
197
+ "columns": [
198
+ {
199
+ "expression": "job_id",
200
+ "isExpression": false,
201
+ "asc": true,
202
+ "nulls": "last"
203
+ }
204
+ ],
205
+ "isUnique": false,
206
+ "where": "\"state\" = 'open'",
207
+ "concurrently": false,
208
+ "method": "btree",
209
+ "with": {}
210
+ },
211
+ "logs_attempt_streams_open_age_idx": {
212
+ "name": "logs_attempt_streams_open_age_idx",
213
+ "columns": [
214
+ {
215
+ "expression": "created_at",
216
+ "isExpression": false,
217
+ "asc": true,
218
+ "nulls": "last"
219
+ }
220
+ ],
221
+ "isUnique": false,
222
+ "where": "\"state\" = 'open'",
223
+ "concurrently": false,
224
+ "method": "btree",
225
+ "with": {}
226
+ },
227
+ "logs_attempt_streams_retention_idx": {
228
+ "name": "logs_attempt_streams_retention_idx",
229
+ "columns": [
230
+ {
231
+ "expression": "closed_at",
232
+ "isExpression": false,
233
+ "asc": true,
234
+ "nulls": "last"
235
+ }
236
+ ],
237
+ "isUnique": false,
238
+ "where": "\"state\" = 'closed'",
239
+ "concurrently": false,
240
+ "method": "btree",
241
+ "with": {}
242
+ },
243
+ "logs_attempt_streams_uncompacted_idx": {
244
+ "name": "logs_attempt_streams_uncompacted_idx",
245
+ "columns": [
246
+ {
247
+ "expression": "closed_at",
248
+ "isExpression": false,
249
+ "asc": true,
250
+ "nulls": "last"
251
+ }
252
+ ],
253
+ "isUnique": false,
254
+ "where": "\"state\" = 'closed' and \"object_key\" is null",
255
+ "concurrently": false,
256
+ "method": "btree",
257
+ "with": {}
258
+ }
259
+ },
260
+ "foreignKeys": {},
261
+ "compositePrimaryKeys": {},
262
+ "uniqueConstraints": {},
263
+ "policies": {},
264
+ "checkConstraints": {},
265
+ "isRLSEnabled": false
266
+ },
267
+ "public.logs_chunks": {
268
+ "name": "logs_chunks",
269
+ "schema": "",
270
+ "columns": {
271
+ "id": {
272
+ "name": "id",
273
+ "type": "uuid",
274
+ "primaryKey": true,
275
+ "notNull": true,
276
+ "default": "uuidv7()"
277
+ },
278
+ "stream_id": {
279
+ "name": "stream_id",
280
+ "type": "uuid",
281
+ "primaryKey": false,
282
+ "notNull": true
283
+ },
284
+ "seq": {
285
+ "name": "seq",
286
+ "type": "bigserial",
287
+ "primaryKey": false,
288
+ "notNull": true
289
+ },
290
+ "stream_offset": {
291
+ "name": "stream_offset",
292
+ "type": "bigint",
293
+ "primaryKey": false,
294
+ "notNull": true
295
+ },
296
+ "byte_len": {
297
+ "name": "byte_len",
298
+ "type": "integer",
299
+ "primaryKey": false,
300
+ "notNull": true
301
+ },
302
+ "data": {
303
+ "name": "data",
304
+ "type": "bytea",
305
+ "primaryKey": false,
306
+ "notNull": true
307
+ },
308
+ "origin": {
309
+ "name": "origin",
310
+ "type": "text",
311
+ "primaryKey": false,
312
+ "notNull": true
313
+ },
314
+ "created_at": {
315
+ "name": "created_at",
316
+ "type": "timestamp with time zone",
317
+ "primaryKey": false,
318
+ "notNull": true,
319
+ "default": "now()"
320
+ }
321
+ },
322
+ "indexes": {
323
+ "logs_chunks_stream_seq_idx": {
324
+ "name": "logs_chunks_stream_seq_idx",
325
+ "columns": [
326
+ {
327
+ "expression": "stream_id",
328
+ "isExpression": false,
329
+ "asc": true,
330
+ "nulls": "last"
331
+ },
332
+ {
333
+ "expression": "seq",
334
+ "isExpression": false,
335
+ "asc": true,
336
+ "nulls": "last"
337
+ }
338
+ ],
339
+ "isUnique": false,
340
+ "concurrently": false,
341
+ "method": "btree",
342
+ "with": {}
343
+ }
344
+ },
345
+ "foreignKeys": {
346
+ "logs_chunks_stream_id_logs_attempt_streams_id_fk": {
347
+ "name": "logs_chunks_stream_id_logs_attempt_streams_id_fk",
348
+ "tableFrom": "logs_chunks",
349
+ "tableTo": "logs_attempt_streams",
350
+ "columnsFrom": ["stream_id"],
351
+ "columnsTo": ["id"],
352
+ "onDelete": "cascade",
353
+ "onUpdate": "no action"
354
+ }
355
+ },
356
+ "compositePrimaryKeys": {},
357
+ "uniqueConstraints": {},
358
+ "policies": {},
359
+ "checkConstraints": {},
360
+ "isRLSEnabled": false
361
+ },
362
+ "public.logs_job_accounting": {
363
+ "name": "logs_job_accounting",
364
+ "schema": "",
365
+ "columns": {
366
+ "job_id": {
367
+ "name": "job_id",
368
+ "type": "uuid",
369
+ "primaryKey": true,
370
+ "notNull": true
371
+ },
372
+ "workspace_id": {
373
+ "name": "workspace_id",
374
+ "type": "uuid",
375
+ "primaryKey": false,
376
+ "notNull": true
377
+ },
378
+ "stored_bytes_used": {
379
+ "name": "stored_bytes_used",
380
+ "type": "bigint",
381
+ "primaryKey": false,
382
+ "notNull": true,
383
+ "default": 0
384
+ },
385
+ "started_at": {
386
+ "name": "started_at",
387
+ "type": "timestamp with time zone",
388
+ "primaryKey": false,
389
+ "notNull": true,
390
+ "default": "now()"
391
+ },
392
+ "capped_at": {
393
+ "name": "capped_at",
394
+ "type": "timestamp with time zone",
395
+ "primaryKey": false,
396
+ "notNull": false
397
+ },
398
+ "created_at": {
399
+ "name": "created_at",
400
+ "type": "timestamp with time zone",
401
+ "primaryKey": false,
402
+ "notNull": true,
403
+ "default": "now()"
404
+ },
405
+ "updated_at": {
406
+ "name": "updated_at",
407
+ "type": "timestamp with time zone",
408
+ "primaryKey": false,
409
+ "notNull": true,
410
+ "default": "now()"
411
+ }
412
+ },
413
+ "indexes": {},
414
+ "foreignKeys": {},
415
+ "compositePrimaryKeys": {},
416
+ "uniqueConstraints": {},
417
+ "policies": {},
418
+ "checkConstraints": {},
419
+ "isRLSEnabled": false
420
+ },
421
+ "public.logs_outbox": {
422
+ "name": "logs_outbox",
423
+ "schema": "",
424
+ "columns": {
425
+ "id": {
426
+ "name": "id",
427
+ "type": "uuid",
428
+ "primaryKey": true,
429
+ "notNull": true,
430
+ "default": "uuidv7()"
431
+ },
432
+ "event_type": {
433
+ "name": "event_type",
434
+ "type": "text",
435
+ "primaryKey": false,
436
+ "notNull": true
437
+ },
438
+ "ordering_key": {
439
+ "name": "ordering_key",
440
+ "type": "text",
441
+ "primaryKey": false,
442
+ "notNull": false
443
+ },
444
+ "payload": {
445
+ "name": "payload",
446
+ "type": "jsonb",
447
+ "primaryKey": false,
448
+ "notNull": true
449
+ },
450
+ "created_at": {
451
+ "name": "created_at",
452
+ "type": "timestamp with time zone",
453
+ "primaryKey": false,
454
+ "notNull": true,
455
+ "default": "now()"
456
+ },
457
+ "dispatched_at": {
458
+ "name": "dispatched_at",
459
+ "type": "timestamp with time zone",
460
+ "primaryKey": false,
461
+ "notNull": false
462
+ },
463
+ "dispatch_attempts": {
464
+ "name": "dispatch_attempts",
465
+ "type": "integer",
466
+ "primaryKey": false,
467
+ "notNull": true,
468
+ "default": 0
469
+ },
470
+ "next_dispatch_at": {
471
+ "name": "next_dispatch_at",
472
+ "type": "timestamp with time zone",
473
+ "primaryKey": false,
474
+ "notNull": true,
475
+ "default": "now()"
476
+ },
477
+ "last_dispatch_error": {
478
+ "name": "last_dispatch_error",
479
+ "type": "jsonb",
480
+ "primaryKey": false,
481
+ "notNull": false
482
+ },
483
+ "last_dispatch_failed_at": {
484
+ "name": "last_dispatch_failed_at",
485
+ "type": "timestamp with time zone",
486
+ "primaryKey": false,
487
+ "notNull": false
488
+ },
489
+ "dead_lettered_at": {
490
+ "name": "dead_lettered_at",
491
+ "type": "timestamp with time zone",
492
+ "primaryKey": false,
493
+ "notNull": false
494
+ }
495
+ },
496
+ "indexes": {
497
+ "logs_outbox_pending_idx": {
498
+ "name": "logs_outbox_pending_idx",
499
+ "columns": [
500
+ {
501
+ "expression": "next_dispatch_at",
502
+ "isExpression": false,
503
+ "asc": true,
504
+ "nulls": "last"
505
+ },
506
+ {
507
+ "expression": "created_at",
508
+ "isExpression": false,
509
+ "asc": true,
510
+ "nulls": "last"
511
+ }
512
+ ],
513
+ "isUnique": false,
514
+ "where": "\"dispatched_at\" IS NULL AND \"dead_lettered_at\" IS NULL",
515
+ "concurrently": false,
516
+ "method": "btree",
517
+ "with": {}
518
+ },
519
+ "logs_outbox_dispatched_retention_idx": {
520
+ "name": "logs_outbox_dispatched_retention_idx",
521
+ "columns": [
522
+ {
523
+ "expression": "dispatched_at",
524
+ "isExpression": false,
525
+ "asc": true,
526
+ "nulls": "last"
527
+ },
528
+ {
529
+ "expression": "id",
530
+ "isExpression": false,
531
+ "asc": true,
532
+ "nulls": "last"
533
+ }
534
+ ],
535
+ "isUnique": false,
536
+ "where": "\"dispatched_at\" IS NOT NULL",
537
+ "concurrently": false,
538
+ "method": "btree",
539
+ "with": {}
540
+ }
541
+ },
542
+ "foreignKeys": {},
543
+ "compositePrimaryKeys": {},
544
+ "uniqueConstraints": {},
545
+ "policies": {},
546
+ "checkConstraints": {},
547
+ "isRLSEnabled": false
548
+ }
549
+ },
550
+ "enums": {},
551
+ "schemas": {},
552
+ "sequences": {},
553
+ "roles": {},
554
+ "policies": {},
555
+ "views": {},
556
+ "_meta": {
557
+ "columns": {},
558
+ "schemas": {},
559
+ "tables": {}
560
+ }
561
+ }
@@ -15,6 +15,13 @@
15
15
  "when": 1785166831100,
16
16
  "tag": "0001_strong_major_mapleleaf",
17
17
  "breakpoints": true
18
+ },
19
+ {
20
+ "idx": 2,
21
+ "version": "7",
22
+ "when": 1785232769856,
23
+ "tag": "0002_wise_dorian_gray",
24
+ "breakpoints": true
18
25
  }
19
26
  ]
20
27
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/api-logs",
3
3
  "license": "MIT",
4
- "version": "10.0.0",
4
+ "version": "10.2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -25,8 +25,8 @@
25
25
  "@temporalio/workflow": "1.18.1",
26
26
  "drizzle-orm": "^0.45.2",
27
27
  "zod": "^4.4.3",
28
- "@shipfox/api-auth-context": "10.0.0",
29
- "@shipfox/api-logs-dto": "9.0.2",
28
+ "@shipfox/api-auth-context": "10.2.0",
29
+ "@shipfox/api-logs-dto": "10.2.0",
30
30
  "@shipfox/api-workflows-dto": "10.0.0",
31
31
  "@shipfox/workflow-document": "2.1.3",
32
32
  "@shipfox/config": "1.2.4",
@@ -34,9 +34,9 @@
34
34
  "@shipfox/node-error-monitoring": "0.3.0",
35
35
  "@shipfox/node-fastify": "0.4.0",
36
36
  "@shipfox/node-module": "1.0.4",
37
- "@shipfox/node-opentelemetry": "0.6.3",
38
37
  "@shipfox/node-outbox": "0.2.6",
39
38
  "@shipfox/node-postgres": "0.4.4",
39
+ "@shipfox/node-opentelemetry": "0.6.3",
40
40
  "@shipfox/node-temporal": "0.4.4"
41
41
  },
42
42
  "imports": {
@@ -208,6 +208,7 @@ describe('appendLogs', () => {
208
208
  },
209
209
  }),
210
210
  ),
211
+ endLine(0),
211
212
  );
212
213
 
213
214
  await appendLogs({...ctx, attempt: 1, offset: 0, body}, workflows);
@@ -368,6 +369,62 @@ describe('appendLogs', () => {
368
369
  });
369
370
  });
370
371
 
372
+ it('folds a tool-use summary across append requests before storing the row', async () => {
373
+ const ctx = newCtx();
374
+ await allowLargeLogBudget(ctx);
375
+ const workflows = createFakeInterModuleClients({
376
+ workflows: defineInterModulePresentation(workflowsInterModuleContract, {
377
+ startRunFromTrigger: vi.fn(),
378
+ deliverEventToJobListener: vi.fn(),
379
+ getStepLogContext: () => ({harness: 'claude' as const}),
380
+ getLeasedAgentToolContext: vi.fn(),
381
+ }),
382
+ }).workflows;
383
+ const first = ndjsonBody(
384
+ sessionLine(
385
+ JSON.stringify({
386
+ type: 'assistant',
387
+ message: {
388
+ role: 'assistant',
389
+ content: [
390
+ {type: 'tool_use', id: 'tool-1', name: 'Read', input: {file_path: 'src/a.ts'}},
391
+ ],
392
+ },
393
+ }),
394
+ ),
395
+ );
396
+ const second = ndjsonBody(
397
+ sessionLine(
398
+ JSON.stringify({
399
+ type: 'tool_use_summary',
400
+ summary: 'Read the source file.',
401
+ preceding_tool_use_ids: ['tool-1'],
402
+ }),
403
+ ),
404
+ endLine(0),
405
+ );
406
+
407
+ await appendLogs({...ctx, attempt: 1, offset: 0, body: first}, workflows);
408
+ await appendLogs({...ctx, attempt: 1, offset: first.length, body: second}, workflows);
409
+
410
+ const stream = await findStream({...ctx, attempt: 1});
411
+ const rows = recordsFromChunks(await listChunks(stream?.id as string)).flatMap((record) =>
412
+ record.type === 'agent_session' ? [record.row] : [],
413
+ );
414
+
415
+ expect(rows).toEqual([
416
+ {
417
+ kind: 'tool-call',
418
+ timestamp: expect.any(Number),
419
+ id: 'tool-1',
420
+ name: 'Read',
421
+ input: '{\n "file_path": "src/a.ts"\n}',
422
+ summary: 'Read the source file.',
423
+ },
424
+ ]);
425
+ expect(stream?.claudePendingToolRows).toEqual([]);
426
+ });
427
+
371
428
  it('does not duplicate parsed rows on a retried append', async () => {
372
429
  const ctx = newCtx();
373
430
  await allowLargeLogBudget(ctx);