@vitest-agent/sdk 2.4.13 → 2.5.1

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.
package/testing.d.ts CHANGED
@@ -9,7 +9,7 @@ declare const DataStoreError_base: new <A extends Record<string, any> = {}>(args
9
9
  * Error raised when a SQLite operation fails at read, write, or migration time.
10
10
  * @public
11
11
  */
12
- declare class DataStoreError extends DataStoreError_base<{
12
+ export declare class DataStoreError extends DataStoreError_base<{
13
13
  readonly operation: "read" | "write" | "migrate";
14
14
  readonly table: string;
15
15
  readonly reason: string;
@@ -26,7 +26,7 @@ declare class DataStoreError extends DataStoreError_base<{
26
26
  * Complete per-project test report written to disk as JSON.
27
27
  * @public
28
28
  */
29
- declare const AgentReport: Schema.Struct<{
29
+ export declare const AgentReport: Schema.Struct<{
30
30
  readonly timestamp: Schema.String;
31
31
  readonly project: Schema.optional<Schema.String>;
32
32
  readonly reason: Schema.Literals<readonly ["passed", "failed", "interrupted"]>;
@@ -132,6 +132,7 @@ declare const AgentReport: Schema.Struct<{
132
132
  }>>;
133
133
  readonly scoped: Schema.withDecodingDefaultKey<Schema.Boolean, never>;
134
134
  readonly scopedFiles: Schema.optional<Schema.$Array<Schema.String>>;
135
+ readonly totalFiles: Schema.optional<Schema.Number>;
135
136
  readonly lowCoverage: Schema.$Array<Schema.Struct<{
136
137
  readonly file: Schema.String;
137
138
  readonly summary: Schema.Struct<{
@@ -170,17 +171,21 @@ declare const AgentReport: Schema.Struct<{
170
171
  readonly sample: Schema.optional<Schema.String>;
171
172
  }>>;
172
173
  readonly truncated: Schema.optional<Schema.Boolean>;
174
+ readonly fromFailingTests: Schema.optional<Schema.Struct<{
175
+ readonly total: Schema.Number;
176
+ readonly files: Schema.Number;
177
+ }>>;
173
178
  }>>;
174
179
  }>;
175
180
  /** @public */
176
- type AgentReport = typeof AgentReport.Type;
181
+ export type AgentReport = typeof AgentReport.Type;
177
182
  //#endregion
178
183
  //#region src/schemas/Baselines.d.ts
179
184
  /**
180
185
  * Coverage baselines -- the auto-ratcheting high-water mark.
181
186
  * @public
182
187
  */
183
- declare const CoverageBaselines: Schema.Struct<{
188
+ export declare const CoverageBaselines: Schema.Struct<{
184
189
  readonly updatedAt: Schema.String;
185
190
  readonly global: Schema.Struct<{
186
191
  readonly lines: Schema.optional<Schema.Number>;
@@ -196,14 +201,14 @@ declare const CoverageBaselines: Schema.Struct<{
196
201
  }>]>>, never>;
197
202
  }>;
198
203
  /** @public */
199
- type CoverageBaselines = typeof CoverageBaselines.Type;
204
+ export type CoverageBaselines = typeof CoverageBaselines.Type;
200
205
  //#endregion
201
206
  //#region src/schemas/CacheManifest.d.ts
202
207
  /**
203
208
  * Root manifest file that indexes all project reports.
204
209
  * @public
205
210
  */
206
- declare const CacheManifest: Schema.Struct<{
211
+ export declare const CacheManifest: Schema.Struct<{
207
212
  readonly updatedAt: Schema.String;
208
213
  readonly cacheDir: Schema.String;
209
214
  readonly projects: Schema.$Array<Schema.Struct<{
@@ -215,14 +220,14 @@ declare const CacheManifest: Schema.Struct<{
215
220
  }>>;
216
221
  }>;
217
222
  /** @public */
218
- type CacheManifest = typeof CacheManifest.Type;
223
+ export type CacheManifest = typeof CacheManifest.Type;
219
224
  //#endregion
220
225
  //#region src/schemas/Coverage.d.ts
221
226
  /**
222
227
  * Per-file coverage data including uncovered line ranges.
223
228
  * @public
224
229
  */
225
- declare const FileCoverageReport: Schema.Struct<{
230
+ export declare const FileCoverageReport: Schema.Struct<{
226
231
  readonly file: Schema.String;
227
232
  readonly summary: Schema.Struct<{
228
233
  readonly statements: Schema.Number;
@@ -233,12 +238,12 @@ declare const FileCoverageReport: Schema.Struct<{
233
238
  readonly uncoveredLines: Schema.String;
234
239
  }>;
235
240
  /** @public */
236
- type FileCoverageReport = typeof FileCoverageReport.Type;
241
+ export type FileCoverageReport = typeof FileCoverageReport.Type;
237
242
  /**
238
243
  * Complete coverage report attached to an AgentReport.
239
244
  * @public
240
245
  */
241
- declare const CoverageReport: Schema.Struct<{
246
+ export declare const CoverageReport: Schema.Struct<{
242
247
  readonly totals: Schema.Struct<{
243
248
  readonly statements: Schema.Number;
244
249
  readonly branches: Schema.Number;
@@ -289,6 +294,7 @@ declare const CoverageReport: Schema.Struct<{
289
294
  }>>;
290
295
  readonly scoped: Schema.withDecodingDefaultKey<Schema.Boolean, never>;
291
296
  readonly scopedFiles: Schema.optional<Schema.$Array<Schema.String>>;
297
+ readonly totalFiles: Schema.optional<Schema.Number>;
292
298
  readonly lowCoverage: Schema.$Array<Schema.Struct<{
293
299
  readonly file: Schema.String;
294
300
  readonly summary: Schema.Struct<{
@@ -313,14 +319,14 @@ declare const CoverageReport: Schema.Struct<{
313
319
  readonly belowTargetFiles: Schema.optional<Schema.$Array<Schema.String>>;
314
320
  }>;
315
321
  /** @public */
316
- type CoverageReport = typeof CoverageReport.Type;
322
+ export type CoverageReport = typeof CoverageReport.Type;
317
323
  //#endregion
318
324
  //#region src/schemas/History.d.ts
319
325
  /**
320
326
  * Per-project history record containing all tracked tests.
321
327
  * @public
322
328
  */
323
- declare const HistoryRecord: Schema.Struct<{
329
+ export declare const HistoryRecord: Schema.Struct<{
324
330
  readonly project: Schema.String;
325
331
  readonly updatedAt: Schema.String;
326
332
  readonly tests: Schema.$Array<Schema.Struct<{
@@ -333,19 +339,19 @@ declare const HistoryRecord: Schema.Struct<{
333
339
  }>>;
334
340
  }>;
335
341
  /** @public */
336
- type HistoryRecord = typeof HistoryRecord.Type;
342
+ export type HistoryRecord = typeof HistoryRecord.Type;
337
343
  //#endregion
338
344
  //#region src/schemas/Tdd.d.ts
339
345
  /** @public */
340
- declare const GoalStatus: Schema.Literals<readonly ["pending", "in_progress", "done", "abandoned"]>;
346
+ export declare const GoalStatus: Schema.Literals<readonly ["pending", "in_progress", "done", "abandoned"]>;
341
347
  /** @public */
342
- type GoalStatus = typeof GoalStatus.Type;
348
+ export type GoalStatus = typeof GoalStatus.Type;
343
349
  /** @public */
344
- declare const BehaviorStatus: Schema.Literals<readonly ["pending", "in_progress", "done", "abandoned"]>;
350
+ export declare const BehaviorStatus: Schema.Literals<readonly ["pending", "in_progress", "done", "abandoned"]>;
345
351
  /** @public */
346
- type BehaviorStatus = typeof BehaviorStatus.Type;
352
+ export type BehaviorStatus = typeof BehaviorStatus.Type;
347
353
  /** @public */
348
- declare const GoalRow: Schema.Struct<{
354
+ export declare const GoalRow: Schema.Struct<{
349
355
  readonly id: Schema.Number;
350
356
  readonly sessionId: Schema.Number;
351
357
  readonly ordinal: Schema.Number;
@@ -354,9 +360,9 @@ declare const GoalRow: Schema.Struct<{
354
360
  readonly createdAt: Schema.String;
355
361
  }>;
356
362
  /** @public */
357
- type GoalRow = typeof GoalRow.Type;
363
+ export type GoalRow = typeof GoalRow.Type;
358
364
  /** @public */
359
- declare const BehaviorRow: Schema.Struct<{
365
+ export declare const BehaviorRow: Schema.Struct<{
360
366
  readonly id: Schema.Number;
361
367
  readonly goalId: Schema.Number;
362
368
  readonly ordinal: Schema.Number;
@@ -366,9 +372,9 @@ declare const BehaviorRow: Schema.Struct<{
366
372
  readonly createdAt: Schema.String;
367
373
  }>;
368
374
  /** @public */
369
- type BehaviorRow = typeof BehaviorRow.Type;
375
+ export type BehaviorRow = typeof BehaviorRow.Type;
370
376
  /** @public */
371
- declare const GoalDetail: Schema.Struct<{
377
+ export declare const GoalDetail: Schema.Struct<{
372
378
  readonly id: Schema.Number;
373
379
  readonly sessionId: Schema.Number;
374
380
  readonly ordinal: Schema.Number;
@@ -386,9 +392,9 @@ declare const GoalDetail: Schema.Struct<{
386
392
  }>>;
387
393
  }>;
388
394
  /** @public */
389
- type GoalDetail = typeof GoalDetail.Type;
395
+ export type GoalDetail = typeof GoalDetail.Type;
390
396
  /** @public */
391
- declare const BehaviorDetail: Schema.Struct<{
397
+ export declare const BehaviorDetail: Schema.Struct<{
392
398
  readonly id: Schema.Number;
393
399
  readonly goalId: Schema.Number;
394
400
  readonly ordinal: Schema.Number;
@@ -412,14 +418,14 @@ declare const BehaviorDetail: Schema.Struct<{
412
418
  }>>;
413
419
  }>;
414
420
  /** @public */
415
- type BehaviorDetail = typeof BehaviorDetail.Type;
421
+ export type BehaviorDetail = typeof BehaviorDetail.Type;
416
422
  //#endregion
417
423
  //#region src/schemas/Trends.d.ts
418
424
  /**
419
425
  * A single coverage trend data point recorded on a full test run.
420
426
  * @public
421
427
  */
422
- declare const TrendEntry: Schema.Struct<{
428
+ export declare const TrendEntry: Schema.Struct<{
423
429
  readonly timestamp: Schema.String;
424
430
  readonly coverage: Schema.Struct<{
425
431
  readonly statements: Schema.Number;
@@ -437,12 +443,12 @@ declare const TrendEntry: Schema.Struct<{
437
443
  readonly targetsHash: Schema.optional<Schema.String>;
438
444
  }>;
439
445
  /** @public */
440
- type TrendEntry = typeof TrendEntry.Type;
446
+ export type TrendEntry = typeof TrendEntry.Type;
441
447
  /**
442
448
  * Per-project trend record with sliding window of entries.
443
449
  * @public
444
450
  */
445
- declare const TrendRecord: Schema.Struct<{
451
+ export declare const TrendRecord: Schema.Struct<{
446
452
  readonly entries: Schema.$Array<Schema.Struct<{
447
453
  readonly timestamp: Schema.String;
448
454
  readonly coverage: Schema.Struct<{
@@ -462,16 +468,35 @@ declare const TrendRecord: Schema.Struct<{
462
468
  }>>;
463
469
  }>;
464
470
  /** @public */
465
- type TrendRecord = typeof TrendRecord.Type;
471
+ export type TrendRecord = typeof TrendRecord.Type;
466
472
  //#endregion
467
473
  //#region src/utils/validate-phase-transition.d.ts
468
474
  /** @public */
469
475
  type Phase = "spike" | "red" | "red.triangulate" | "green" | "green.fake-it" | "refactor" | "extended-red" | "green-without-red";
470
476
  /** @public */
471
477
  type ArtifactKind = "test_written" | "test_failed_run" | "code_written" | "test_passed_run" | "refactor" | "test_weakened";
478
+ /**
479
+ * Explicit test-runner marker on a `tdd_artifacts` row (issue #363). `vitest`
480
+ * artifacts always carry a `test_case_id` when they anchor a specific test;
481
+ * `bats` artifacts never do (there is no `test_cases` row for a bats test),
482
+ * so the D2 binding-rule validator branches on this to accept a bats
483
+ * run-level artifact without weakening the vitest guard.
484
+ * @public
485
+ */
486
+ type ArtifactSuite = "vitest" | "bats";
472
487
  /** @public */
473
488
  interface CitedArtifact {
474
489
  readonly id: number;
490
+ /**
491
+ * `tdd_phases.id` of the phase this artifact was actually recorded in — the
492
+ * artifact's own phase binding. This is the honest anchor for D2 binding
493
+ * rule 1's window check (issue #245): a test_case's first-ever creation
494
+ * turn can predate the current phase (e.g. authored during spike, then
495
+ * re-run inside red) without the evidence itself being stale, so the
496
+ * window check compares this against `PhaseTransitionContext.current_phase_id`
497
+ * rather than `test_case_created_turn_at`.
498
+ */
499
+ readonly phase_id: number;
475
500
  readonly artifact_kind: ArtifactKind;
476
501
  readonly test_case_id: number | null;
477
502
  readonly test_case_created_turn_at: string | null;
@@ -479,6 +504,12 @@ interface CitedArtifact {
479
504
  readonly test_run_id: number | null;
480
505
  readonly test_first_failure_run_id: number | null;
481
506
  readonly behavior_id: number | null;
507
+ /**
508
+ * Issue #363: explicit suite marker distinguishing vitest from bats runs.
509
+ * Optional on the pure type so hand-built contexts default to `vitest`;
510
+ * the DB row always carries the persisted value.
511
+ */
512
+ readonly suite?: ArtifactSuite;
482
513
  }
483
514
  //#endregion
484
515
  //#region src/schemas/Identity.d.ts
@@ -488,9 +519,9 @@ interface CitedArtifact {
488
519
  * agent's lifetime.
489
520
  * @public
490
521
  */
491
- declare const AgentId: Schema.brand<Schema.String, "AgentId">;
522
+ export declare const AgentId: Schema.brand<Schema.String, "AgentId">;
492
523
  /** @public */
493
- type AgentId = Schema.Schema.Type<typeof AgentId>;
524
+ export type AgentId = Schema.Schema.Type<typeof AgentId>;
494
525
  /**
495
526
  * The agent host process's chat id (Claude Code's per-process chat
496
527
  * UUID, etc.). Shorter-lived than a conversation; one conversation can
@@ -498,9 +529,9 @@ type AgentId = Schema.Schema.Type<typeof AgentId>;
498
529
  * `sessions.id` (the SQLite agent-run PK).
499
530
  * @public
500
531
  */
501
- declare const ChatId: Schema.brand<Schema.String, "ChatId">;
532
+ export declare const ChatId: Schema.brand<Schema.String, "ChatId">;
502
533
  /** @public */
503
- type ChatId = Schema.Schema.Type<typeof ChatId>;
534
+ export type ChatId = Schema.Schema.Type<typeof ChatId>;
504
535
  //#endregion
505
536
  //#region src/errors/AgentErrors.d.ts
506
537
  declare const AgentNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
@@ -512,7 +543,7 @@ declare const AgentNotFoundError_base: new <A extends Record<string, any> = {}>(
512
543
  * this agent first.
513
544
  * @public
514
545
  */
515
- declare class AgentNotFoundError extends AgentNotFoundError_base<{
546
+ export declare class AgentNotFoundError extends AgentNotFoundError_base<{
516
547
  readonly agentId: AgentId;
517
548
  readonly chatId?: ChatId;
518
549
  }> {}
@@ -525,7 +556,7 @@ declare const RegistrationConflictError_base: new <A extends Record<string, any>
525
556
  * caller named. Distinct from `IdempotencyHit`, which is a success.
526
557
  * @public
527
558
  */
528
- declare class RegistrationConflictError extends RegistrationConflictError_base<{
559
+ export declare class RegistrationConflictError extends RegistrationConflictError_base<{
529
560
  readonly reason: string;
530
561
  }> {
531
562
  constructor(args: {
@@ -538,7 +569,7 @@ declare const GoalNotFoundError_base: new <A extends Record<string, any> = {}>(a
538
569
  readonly _tag: "GoalNotFoundError";
539
570
  } & Readonly<A>;
540
571
  /** @public */
541
- declare class GoalNotFoundError extends GoalNotFoundError_base<{
572
+ export declare class GoalNotFoundError extends GoalNotFoundError_base<{
542
573
  readonly id: number;
543
574
  readonly reason: string;
544
575
  }> {
@@ -551,7 +582,7 @@ declare const BehaviorNotFoundError_base: new <A extends Record<string, any> = {
551
582
  readonly _tag: "BehaviorNotFoundError";
552
583
  } & Readonly<A>;
553
584
  /** @public */
554
- declare class BehaviorNotFoundError extends BehaviorNotFoundError_base<{
585
+ export declare class BehaviorNotFoundError extends BehaviorNotFoundError_base<{
555
586
  readonly id: number;
556
587
  readonly reason: string;
557
588
  }> {
@@ -564,7 +595,7 @@ declare const TddTaskNotFoundError_base: new <A extends Record<string, any> = {}
564
595
  readonly _tag: "TddTaskNotFoundError";
565
596
  } & Readonly<A>;
566
597
  /** @public */
567
- declare class TddTaskNotFoundError extends TddTaskNotFoundError_base<{
598
+ export declare class TddTaskNotFoundError extends TddTaskNotFoundError_base<{
568
599
  readonly id: number;
569
600
  readonly reason: string;
570
601
  }> {
@@ -579,7 +610,7 @@ declare const TddTaskAlreadyEndedError_base: new <A extends Record<string, any>
579
610
  readonly _tag: "TddTaskAlreadyEndedError";
580
611
  } & Readonly<A>;
581
612
  /** @public */
582
- declare class TddTaskAlreadyEndedError extends TddTaskAlreadyEndedError_base<{
613
+ export declare class TddTaskAlreadyEndedError extends TddTaskAlreadyEndedError_base<{
583
614
  readonly id: number;
584
615
  readonly endedAt: string;
585
616
  readonly outcome: TddTaskEndOutcome;
@@ -596,7 +627,7 @@ declare const IllegalStatusTransitionError_base: new <A extends Record<string, a
596
627
  readonly _tag: "IllegalStatusTransitionError";
597
628
  } & Readonly<A>;
598
629
  /** @public */
599
- declare class IllegalStatusTransitionError extends IllegalStatusTransitionError_base<{
630
+ export declare class IllegalStatusTransitionError extends IllegalStatusTransitionError_base<{
600
631
  readonly entity: IllegalStatusTransitionEntity;
601
632
  readonly id: number;
602
633
  readonly from: string;
@@ -636,7 +667,7 @@ declare const Agent_base: Schema.Class<Agent, Schema.TaggedStruct<"Agent", {
636
667
  * two reveals a mid-session branch switch, which is itself signal.
637
668
  * @public
638
669
  */
639
- declare class Agent extends Agent_base {}
670
+ export declare class Agent extends Agent_base {}
640
671
  declare const IdempotencyHit_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => Readonly<A> & {
641
672
  readonly _tag: "IdempotencyHit";
642
673
  } & import("effect/Pipeable").Pipeable;
@@ -651,10 +682,33 @@ declare const IdempotencyHit_base: new <A extends Record<string, any> = {}>(args
651
682
  * downstream code uses `Match.tag` to branch.
652
683
  * @public
653
684
  */
654
- declare class IdempotencyHit extends IdempotencyHit_base<{
685
+ export declare class IdempotencyHit extends IdempotencyHit_base<{
655
686
  readonly existingAgentId: typeof AgentId.Type;
656
687
  }> {}
657
688
  //#endregion
689
+ //#region src/schemas/Thresholds.d.ts
690
+ /**
691
+ * Fully resolved thresholds ready for evaluation.
692
+ * @public
693
+ */
694
+ declare const ResolvedThresholds: Schema.Struct<{
695
+ readonly global: Schema.Struct<{
696
+ readonly lines: Schema.optional<Schema.Number>;
697
+ readonly functions: Schema.optional<Schema.Number>;
698
+ readonly branches: Schema.optional<Schema.Number>;
699
+ readonly statements: Schema.optional<Schema.Number>;
700
+ }>;
701
+ readonly perFile: Schema.withDecodingDefaultKey<Schema.Boolean, never>;
702
+ readonly patterns: Schema.withDecodingDefaultKey<Schema.$Array<Schema.Tuple<readonly [Schema.String, Schema.Struct<{
703
+ readonly lines: Schema.optional<Schema.Number>;
704
+ readonly functions: Schema.optional<Schema.Number>;
705
+ readonly branches: Schema.optional<Schema.Number>;
706
+ readonly statements: Schema.optional<Schema.Number>;
707
+ }>]>>, never>;
708
+ }>;
709
+ /** @public */
710
+ type ResolvedThresholds = typeof ResolvedThresholds.Type;
711
+ //#endregion
658
712
  //#region src/services/DataStore.d.ts
659
713
  /** @public */
660
714
  interface CreateGoalInput {
@@ -879,6 +933,13 @@ interface SessionInput {
879
933
  readonly parentSessionId?: number;
880
934
  readonly triageWasNonEmpty?: boolean;
881
935
  readonly startedAt: string;
936
+ /**
937
+ * Canonical conversation UUID this session belongs to (issue #144).
938
+ * Set once at INSERT time — `sessions.conversation_id` is immutable
939
+ * thereafter (see the `trg_sessions_conv_id_immutable` trigger), so
940
+ * omit it here rather than trying to backfill via an update.
941
+ */
942
+ readonly conversationId?: string;
882
943
  }
883
944
  /** @public */
884
945
  interface TurnInput {
@@ -956,6 +1017,8 @@ interface WriteTddArtifactInput {
956
1017
  readonly testFirstFailureRunId?: number;
957
1018
  readonly diffExcerpt?: string;
958
1019
  readonly recordedAt: string;
1020
+ /** Issue #363: explicit suite marker. Defaults to `"vitest"` when omitted. */
1021
+ readonly suite?: ArtifactSuite;
959
1022
  }
960
1023
  /** @public */
961
1024
  interface WriteCommitInput {
@@ -1030,6 +1093,18 @@ declare const DataStore_base: Context.ServiceClass<DataStore, "vitest-agent/Data
1030
1093
  readonly writeCoverage: (runId: number, coverage: ReadonlyArray<FileCoverageInput>) => Effect.Effect<void, DataStoreError>;
1031
1094
  readonly writeHistory: (project: string, fullName: string, modulePath: string, runId: number, timestamp: string, state: string, duration: number | null, flaky: boolean, retryCount: number, errorMessage: string | null) => Effect.Effect<void, DataStoreError>;
1032
1095
  readonly writeBaselines: (baselines: CoverageBaselines) => Effect.Effect<void, DataStoreError>;
1096
+ /**
1097
+ * Persist the resolved (enforced) Vitest `coverage.thresholds` for the
1098
+ * current run, distinct from the ratcheted `coverage_baselines` rows.
1099
+ * Stored under `kind='threshold'`. See issue #237.
1100
+ */
1101
+ readonly writeThresholds: (thresholds: ResolvedThresholds) => Effect.Effect<void, DataStoreError>;
1102
+ /**
1103
+ * Persist the resolved aspirational `coverageTargets` for the current
1104
+ * run, distinct from the ratcheted `coverage_baselines` rows. Stored
1105
+ * under `kind='target'`. See issue #237.
1106
+ */
1107
+ readonly writeTargets: (targets: ResolvedThresholds) => Effect.Effect<void, DataStoreError>;
1033
1108
  readonly writeTrends: (project: string, runId: number, entry: TrendEntry) => Effect.Effect<void, DataStoreError>;
1034
1109
  readonly writeSourceMap: (sourceFilePath: string, testModuleId: number, mappingType: string) => Effect.Effect<void, DataStoreError>;
1035
1110
  readonly ensureFile: (filePath: string) => Effect.Effect<number, DataStoreError>;
@@ -1048,6 +1123,20 @@ declare const DataStore_base: Context.ServiceClass<DataStore, "vitest-agent/Data
1048
1123
  * `INSERT ... ON CONFLICT DO NOTHING`.
1049
1124
  */
1050
1125
  readonly upsertSession: (input: SessionInput) => Effect.Effect<number, DataStoreError>;
1126
+ /**
1127
+ * Backfill `sessions.conversation_id` for a row that was inserted
1128
+ * before the canonical conversation id was known (issue #144) —
1129
+ * `record session-start` always precedes `register-agent`, so the
1130
+ * session row exists first. Race-safe and idempotent: the UPDATE's
1131
+ * `WHERE conversation_id IS NULL` guard means a session that
1132
+ * already carries a value is left untouched (zero rows affected),
1133
+ * matching the trigger's null→value-only relaxation rather than
1134
+ * risking an immutability-violation error on a redundant call.
1135
+ */
1136
+ readonly setSessionConversationIdIfNull: (input: {
1137
+ readonly sessionId: number;
1138
+ readonly conversationId: string;
1139
+ }) => Effect.Effect<void, DataStoreError>;
1051
1140
  readonly writeTurn: (input: TurnInput) => Effect.Effect<number, DataStoreError>;
1052
1141
  readonly writeFailureSignature: (input: FailureSignatureWriteInput) => Effect.Effect<void, DataStoreError>;
1053
1142
  readonly endSession: (chatId: string, endedAt: string, endReason: string | null) => Effect.Effect<void, DataStoreError>;
@@ -1098,7 +1187,7 @@ declare const DataStore_base: Context.ServiceClass<DataStore, "vitest-agent/Data
1098
1187
  readonly endAgent: (agentId: string, endedAt: number) => Effect.Effect<void, AgentNotFoundError | DataStoreError>;
1099
1188
  }>;
1100
1189
  /** @public */
1101
- declare class DataStore extends DataStore_base {}
1190
+ export declare class DataStore extends DataStore_base {}
1102
1191
  //#endregion
1103
1192
  //#region src/services/DataReader.d.ts
1104
1193
  /** @public */
@@ -1225,6 +1314,8 @@ interface SessionDetail {
1225
1314
  readonly startedAt: string;
1226
1315
  readonly endedAt: string | null;
1227
1316
  readonly endReason: string | null;
1317
+ /** Canonical conversation UUID this session belongs to (issue #144), null when unset. */
1318
+ readonly conversationId: string | null;
1228
1319
  }
1229
1320
  /** @public */
1230
1321
  interface TurnSummary {
@@ -1406,6 +1497,7 @@ interface TddArtifactRow {
1406
1497
  readonly testRunId: number | null;
1407
1498
  readonly testFirstFailureRunId: number | null;
1408
1499
  readonly recordedAt: string;
1500
+ readonly suite: ArtifactSuite;
1409
1501
  }
1410
1502
  /** @public */
1411
1503
  interface TagInventoryRow {
@@ -1519,7 +1611,32 @@ declare const DataReader_base: Context.ServiceClass<DataReader, "vitest-agent/Da
1519
1611
  * preserves the prior single-session contract.
1520
1612
  */
1521
1613
  readonly walkParents?: boolean;
1614
+ /**
1615
+ * When true AND `sessionId`'s session has a non-null
1616
+ * `conversation_id`, also return tdd_tasks belonging to
1617
+ * any OTHER session sharing that `conversation_id` — the
1618
+ * detached-session fallback (issue #144). A session with
1619
+ * a null `conversation_id` never triggers this fallback.
1620
+ * Rows are ordered so a task owned by an `agent_kind =
1621
+ * 'main'` session sorts first, then by `started_at DESC`.
1622
+ * Default `false` preserves the prior contract.
1623
+ */
1624
+ readonly walkConversation?: boolean;
1522
1625
  }) => Effect.Effect<ReadonlyArray<TddTaskSummary>, DataStoreError>;
1626
+ /**
1627
+ * Diagnostic for the `missing_artifact_evidence` phase-transition
1628
+ * denial (issue #144): counts `tdd_artifacts` rows recorded at or
1629
+ * after `sinceIso` under sessions OTHER than the one that opened
1630
+ * `tddTaskId`, but sharing that session's `conversation_id`. Used
1631
+ * to tell an agent "your hooks may be attributing to a detached
1632
+ * session" rather than a bare "no artifact found". Returns 0 when
1633
+ * `tddTaskId` is unknown or its session's `conversation_id` is
1634
+ * null — the diagnostic never fabricates a signal it cannot back.
1635
+ */
1636
+ readonly countRecentArtifactsInOtherSessionsOfConversation: (input: {
1637
+ readonly tddTaskId: number;
1638
+ readonly sinceIso: string;
1639
+ }) => Effect.Effect<number, DataStoreError>;
1523
1640
  /**
1524
1641
  * List artifacts recorded for a TDD task, optionally filtered
1525
1642
  * by `artifactKind`, `phaseId`, or `behaviorId`. Returns rows in
@@ -1558,25 +1675,25 @@ declare const DataReader_base: Context.ServiceClass<DataReader, "vitest-agent/Da
1558
1675
  }) => Effect.Effect<ReadonlyArray<TestListEntry>, DataStoreError>;
1559
1676
  }>;
1560
1677
  /** @public */
1561
- declare class DataReader extends DataReader_base {}
1678
+ export declare class DataReader extends DataReader_base {}
1562
1679
  //#endregion
1563
1680
  //#region src/testing/layers.d.ts
1564
1681
  /** @public */
1565
- declare function makeTestLayer(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1682
+ export declare function makeTestLayer(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1566
1683
  /** @public */
1567
- declare const DataStoreTestLayer: Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1684
+ export declare const DataStoreTestLayer: Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1568
1685
  //#endregion
1569
1686
  //#region src/testing/index.d.ts
1570
1687
  /** @public */
1571
- declare function empty(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1688
+ export declare function empty(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1572
1689
  /** @public */
1573
- declare function singlePassingRun(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1690
+ export declare function singlePassingRun(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1574
1691
  /** @public */
1575
- declare function withFailures(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1692
+ export declare function withFailures(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1576
1693
  /** @public */
1577
- declare function flaky(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1694
+ export declare function flaky(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, DataStoreError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1578
1695
  /** @public */
1579
- declare function withTddTask(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, BehaviorNotFoundError | DataStoreError | GoalNotFoundError | IllegalStatusTransitionError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError | TddTaskAlreadyEndedError | TddTaskNotFoundError, never>;
1696
+ export declare function withTddTask(filename: string): Layer.Layer<DataReader | DataStore | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect/platform-node/NodeServices").NodeServices, BehaviorNotFoundError | DataStoreError | GoalNotFoundError | IllegalStatusTransitionError | import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError | TddTaskAlreadyEndedError | TddTaskNotFoundError, never>;
1580
1697
  //#endregion
1581
- export { type AcceptanceMetrics, Agent, AgentId, AgentNotFoundError, AgentReport, type ArtifactKind, type AssociateRunSessionInput, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorStatus, CacheManifest, type ChangeKind, ChatId, type CitedArtifact, type CitedArtifactRow, type ClassificationQueryOptions, type CommitChangesEntry, CoverageBaselines, CoverageReport, type CreateBehaviorInput, type CreateGoalInput, type CurrentTddPhase, DataReader, DataStore, DataStoreError, DataStoreTestLayer, type EndTddTaskInput, type FailureSignatureDetail, type FailureSignatureWriteInput, type FileCoverageInput, FileCoverageReport, type FlakyTest, GoalDetail, GoalNotFoundError, GoalRow, GoalStatus, type HistoryQueryOptions, HistoryRecord, type HypothesisDetail, type HypothesisInput, IdempotencyHit, type IdempotentResponseInput, type IllegalStatusTransitionEntity, IllegalStatusTransitionError, type ModuleInput, type ModuleListEntry, type NoteInput, type NoteRow, type PersistentFailure, type Phase, type ProjectRunSummary, type RegisterAgentInput, RegistrationConflictError, type RunChangedFile, type RunInvocationMethod, type SessionDetail, type SessionInput, type SettingsInput, type SettingsListEntry, type SettingsRow, type StackFrameInput, type SuiteInput, type SuiteListEntry, type TagInventoryRow, type TddArtifactDetail, type TddArtifactRow, type TddPhaseDetail, TddTaskAlreadyEndedError, type TddTaskDetail, type TddTaskEndOutcome, type TddTaskInput, TddTaskNotFoundError, type TddTaskSummary, type TestCaseInput, type TestError, type TestErrorInput, type TestListEntry, type TestLookupOptions, type TestRunInput, TrendEntry, TrendRecord, type TurnInput, type TurnSearchOptions, type TurnSummary, type UpdateBehaviorInput, type UpdateGoalInput, type ValidateHypothesisInput, type WriteCommitInput, type WriteRunChangedFilesInput, type WriteTddArtifactInput, type WriteTddPhaseInput, type WriteTddPhaseOutput, empty, flaky, makeTestLayer, singlePassingRun, withFailures, withTddTask };
1698
+ export type { AcceptanceMetrics, ArtifactKind, ArtifactSuite, AssociateRunSessionInput, ChangeKind, CitedArtifact, CitedArtifactRow, ClassificationQueryOptions, CommitChangesEntry, CreateBehaviorInput, CreateGoalInput, CurrentTddPhase, EndTddTaskInput, FailureSignatureDetail, FailureSignatureWriteInput, FileCoverageInput, FlakyTest, HistoryQueryOptions, HypothesisDetail, HypothesisInput, IdempotentResponseInput, IllegalStatusTransitionEntity, ModuleInput, ModuleListEntry, NoteInput, NoteRow, PersistentFailure, Phase, ProjectRunSummary, RegisterAgentInput, ResolvedThresholds, RunChangedFile, RunInvocationMethod, SessionDetail, SessionInput, SettingsInput, SettingsListEntry, SettingsRow, StackFrameInput, SuiteInput, SuiteListEntry, TagInventoryRow, TddArtifactDetail, TddArtifactRow, TddPhaseDetail, TddTaskDetail, TddTaskEndOutcome, TddTaskInput, TddTaskSummary, TestCaseInput, TestError, TestErrorInput, TestListEntry, TestLookupOptions, TestRunInput, TurnInput, TurnSearchOptions, TurnSummary, UpdateBehaviorInput, UpdateGoalInput, ValidateHypothesisInput, WriteCommitInput, WriteRunChangedFilesInput, WriteTddArtifactInput, WriteTddPhaseInput, WriteTddPhaseOutput };
1582
1699
  //# sourceMappingURL=testing.d.ts.map
@@ -10,14 +10,28 @@ function truncateSample(content) {
10
10
  * Aggregate raw console-leak entries into a ConsoleLeaks signal:
11
11
  * bucket by file, split stdout/stderr, collect attributable test names,
12
12
  * capture one truncated sample per file, sort by total writes descending,
13
- * and cap the file list. Returns `undefined` when there are no entries so a
14
- * clean run attaches nothing.
13
+ * and cap the file list. Entries logged inside a failing test (with
14
+ * `failed` set) are excluded from `total`/`byFile` — the actionable leak signal —
15
+ * and summarized instead in `fromFailingTests` (issue #263: a logger-backed
16
+ * assertion failure otherwise makes every red run look like a leak). Returns
17
+ * `undefined` only when there is no output at all, non-failing or failing.
15
18
  * @public
16
19
  */
17
20
  function buildConsoleLeaks(entries) {
18
21
  if (entries.length === 0) return void 0;
22
+ const nonFailing = entries.filter((e) => e.failed !== true);
23
+ const failing = entries.filter((e) => e.failed === true);
24
+ const fromFailingTests = failing.length > 0 ? {
25
+ total: failing.length,
26
+ files: new Set(failing.map((e) => e.file)).size
27
+ } : void 0;
28
+ if (nonFailing.length === 0) return {
29
+ total: 0,
30
+ byFile: [],
31
+ ...fromFailingTests !== void 0 ? { fromFailingTests } : {}
32
+ };
19
33
  const byFile = /* @__PURE__ */ new Map();
20
- for (const e of entries) {
34
+ for (const e of nonFailing) {
21
35
  let acc = byFile.get(e.file);
22
36
  if (acc === void 0) {
23
37
  acc = {
@@ -46,30 +60,43 @@ function buildConsoleLeaks(entries) {
46
60
  files.sort((a, b) => b.stdout + b.stderr - (a.stdout + a.stderr));
47
61
  const truncated = files.length > MAX_FILES;
48
62
  return {
49
- total: entries.length,
63
+ total: nonFailing.length,
50
64
  byFile: truncated ? files.slice(0, MAX_FILES) : files,
51
- ...truncated ? { truncated: true } : {}
65
+ ...truncated ? { truncated: true } : {},
66
+ ...fromFailingTests !== void 0 ? { fromFailingTests } : {}
52
67
  };
53
68
  }
54
69
  /**
55
70
  * Walk a Vitest `File[]` task tree (from `vitest.state.getFiles()`) into flat
56
71
  * {@link ConsoleLeakEntry} values. Each task `log` becomes one entry attributed
57
72
  * to its enclosing file and, when the log sits on a test task, that test's name.
73
+ * An entry is marked `failed: true` when it was logged inside a test whose own
74
+ * `result.state` is `"fail"`, or — for output with no owning test — when the
75
+ * enclosing file itself failed (e.g. a collection/load error).
58
76
  * @public
59
77
  */
60
78
  function collectConsoleLeakEntries(files) {
61
79
  const entries = [];
62
- const visit = (task, file, test) => {
63
- const currentTest = task.type === "test" ? task.fullTestName ?? task.name ?? test : test;
64
- for (const log of task.logs ?? []) entries.push({
65
- file,
66
- ...currentTest !== void 0 ? { test: currentTest } : {},
67
- type: log.type,
68
- content: log.content
69
- });
70
- for (const child of task.tasks ?? []) visit(child, file, currentTest);
80
+ const visit = (task, file, test, testFailed, fileFailed) => {
81
+ const isTest = task.type === "test";
82
+ const currentTest = isTest ? task.fullTestName ?? task.name ?? test : test;
83
+ const currentTestFailed = isTest ? task.result?.state === "fail" : testFailed;
84
+ for (const log of task.logs ?? []) {
85
+ const failed = currentTest !== void 0 ? currentTestFailed : fileFailed;
86
+ entries.push({
87
+ file,
88
+ ...currentTest !== void 0 ? { test: currentTest } : {},
89
+ type: log.type,
90
+ content: log.content,
91
+ ...failed ? { failed: true } : {}
92
+ });
93
+ }
94
+ for (const child of task.tasks ?? []) visit(child, file, currentTest, currentTestFailed, fileFailed);
71
95
  };
72
- for (const file of files) visit(file, file.name ?? "(unknown)", void 0);
96
+ for (const file of files) {
97
+ const fileFailed = file.result?.state === "fail";
98
+ visit(file, file.name ?? "(unknown)", void 0, false, fileFailed);
99
+ }
73
100
  return entries;
74
101
  }
75
102