@vitest-agent/engine 0.1.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 (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +32 -0
  3. package/index.d.ts +2679 -0
  4. package/index.js +63 -0
  5. package/layers/ConfigLive.js +46 -0
  6. package/layers/DataReaderLive.js +1923 -0
  7. package/layers/DataStoreLive.js +1283 -0
  8. package/layers/DetailResolverLive.js +9 -0
  9. package/layers/DiscoveryRegistryLive.js +70 -0
  10. package/layers/EnvironmentDetectorLive.js +36 -0
  11. package/layers/EnvironmentDetectorTest.js +13 -0
  12. package/layers/ExecutorResolverLive.js +9 -0
  13. package/layers/FormatSelectorLive.js +20 -0
  14. package/layers/HistoryTrackerLive.js +49 -0
  15. package/layers/HistoryTrackerTest.js +25 -0
  16. package/layers/LoggerLive.js +70 -0
  17. package/layers/OutputPipelineLive.js +20 -0
  18. package/layers/OutputRendererLive.js +23 -0
  19. package/layers/PathResolutionLive.js +46 -0
  20. package/layers/PerClientSessionMapLive.js +145 -0
  21. package/layers/ProjectDiscoveryLive.js +67 -0
  22. package/layers/ProjectDiscoveryTest.js +12 -0
  23. package/layers/ProjectIdentityLive.js +95 -0
  24. package/layers/RunContextLive.js +82 -0
  25. package/lib/format-triage.js +103 -0
  26. package/lib/format-wrapup.js +67 -0
  27. package/migrations/0001_initial.js +824 -0
  28. package/migrations/0002_test_artifacts.js +30 -0
  29. package/migrations/index.js +27 -0
  30. package/migrations/registry_0001_initial.js +39 -0
  31. package/migrations/session_map_0001_initial.js +38 -0
  32. package/package.json +59 -0
  33. package/platform.js +58 -0
  34. package/programs/end-agent.js +19 -0
  35. package/programs/hook-paths.js +115 -0
  36. package/programs/platform-sidecar.js +37 -0
  37. package/programs/record-session.js +49 -0
  38. package/programs/record-tdd-artifact.js +119 -0
  39. package/programs/record-turn.js +61 -0
  40. package/programs/record-workspace-changes.js +57 -0
  41. package/programs/register-agent.js +85 -0
  42. package/programs/resolve-session-for-recording.js +44 -0
  43. package/programs/session-env.js +85 -0
  44. package/project-dir.js +32 -0
  45. package/services/Config.js +15 -0
  46. package/services/DataReader.js +8 -0
  47. package/services/DataStore.js +15 -0
  48. package/services/DetailResolver.js +8 -0
  49. package/services/DiscoveryRegistry.js +8 -0
  50. package/services/EnvironmentDetector.js +8 -0
  51. package/services/ExecutorResolver.js +8 -0
  52. package/services/FormatSelector.js +8 -0
  53. package/services/HistoryTracker.js +20 -0
  54. package/services/OutputRenderer.js +8 -0
  55. package/services/PerClientSessionMap.js +22 -0
  56. package/services/ProjectDiscovery.js +8 -0
  57. package/services/ProjectIdentity.js +62 -0
  58. package/services/RunContext.js +53 -0
  59. package/services/idempotency.js +58 -0
  60. package/sql/assemblers.js +69 -0
  61. package/testing/layers.js +16 -0
  62. package/testing.d.ts +1101 -0
  63. package/testing.js +243 -0
  64. package/tsdoc-metadata.json +11 -0
  65. package/utils/ensure-migrated.js +47 -0
  66. package/utils/failure-signature.js +34 -0
  67. package/utils/resolve-data-path.js +64 -0
  68. package/utils/resolve-project-key-from-cwd.js +52 -0
  69. package/utils/resolve-workspace-key.js +41 -0
  70. package/version.js +6 -0
package/index.d.ts ADDED
@@ -0,0 +1,2679 @@
1
+ import { Context, Effect, FileSystem, Layer, LogLevel, Option, Path, Schema } from "effect";
2
+ import { ConfigFileShape } from "@effected/config-file";
3
+ import { Agent, AgentNotFoundError, AgentReport, ArtifactKind, ArtifactKind as ArtifactKind$1, ArtifactSuite, ArtifactSuite as ArtifactSuite$1, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorStatus, CacheManifest, CitedArtifact, CoverageBaselines, CoverageReport, DataStoreError, DetailLevel, DiscoveryError, Environment, Executor, FileCoverageReport, FormatterContext, GoalDetail, GoalNotFoundError, GoalRow, GoalStatus, HistoryRecord, IdempotencyHit, IllegalStatusTransitionError, OutputFormat, Phase, ProjectIdentityNotResolvableError, RegistrationConflictError, RenderedOutput, ResolvedThresholds, TddTaskAlreadyEndedError, TddTaskNotFoundError, TestClassification, TestRun, TrendEntry, TrendRecord, TurnPayload, VitestAgentConfig } from "@vitest-agent/sdk";
4
+ import { SqlClient } from "effect/unstable/sql/SqlClient";
5
+ import { WorkspaceDiscovery, WorkspaceDiscoveryFailure, WorkspaceRootNotFoundError } from "@effected/workspaces";
6
+ import { AppDirs, AppDirsError, XdgEnvError } from "@effected/xdg";
7
+ import { ChildProcessSpawner } from "effect/unstable/process";
8
+ import * as NodeServices from "@effect/platform-node/NodeServices";
9
+ import { SqliteClient } from "@effect/sql-sqlite-node/SqliteClient";
10
+ import { MigrationError } from "effect/unstable/sql/Migrator";
11
+ import { SqlError } from "effect/unstable/sql/SqlError";
12
+ import { PlatformError } from "effect/PlatformError";
13
+ //#region src/services/Config.d.ts
14
+ /**
15
+ * Service shape that `ConfigLive(projectDir)` provides to downstream
16
+ * consumers. Re-exported so callers can spell out the concrete service
17
+ * type without referencing the `ConfigFileShape<A>` generic directly.
18
+ * @public
19
+ */
20
+ export type VitestAgentConfigFileService = ConfigFileShape<VitestAgentConfig>;
21
+ declare const VitestAgentConfigFile_base: import("effect/Context").ServiceClass<VitestAgentConfigFile, "vitest-agent/Config", ConfigFileShape<VitestAgentConfig>>;
22
+ /**
23
+ * Typed service class (Context tag) for the vitest-agent config file service.
24
+ *
25
+ * Both runtime packages (reporter, MCP) yield this tag to access the loaded
26
+ * `VitestAgentConfig`. The live layer is built per `projectDir` via
27
+ * `ConfigLive(projectDir)`.
28
+ * @public
29
+ */
30
+ export declare class VitestAgentConfigFile extends VitestAgentConfigFile_base {}
31
+ //#endregion
32
+ //#region src/layers/ConfigLive.d.ts
33
+ /**
34
+ * Build the live `ConfigFile` layer for a given project directory.
35
+ *
36
+ * Resolves the optional `vitest-agent.config.toml` from (in order):
37
+ *
38
+ * 1. The workspace root (when `projectDir` is inside a pnpm/npm/yarn workspace).
39
+ * 2. The git repository root (when `projectDir` is inside a git repo).
40
+ * 3. Walking upward from `projectDir`.
41
+ *
42
+ * The first found file wins (`MergeStrategy.firstMatch()`). If no file is
43
+ * present, downstream callers use `loadOrDefault(new VitestAgentConfig({}))`
44
+ * to get an empty config.
45
+ *
46
+ * @param projectDir - Absolute path inside the user's workspace. Resolvers
47
+ * anchor here rather than `process.cwd()` so the plugin-spawned MCP server
48
+ * sees the right config even when invoked from elsewhere.
49
+ * @public
50
+ */
51
+ export declare const ConfigLive: (projectDir: string) => Layer.Layer<VitestAgentConfigFile, never, FileSystem.FileSystem | Path.Path>;
52
+ //#endregion
53
+ //#region src/services/DataStore.d.ts
54
+ /** @public */
55
+ export interface CreateGoalInput {
56
+ readonly tddTaskId: number;
57
+ readonly goal: string;
58
+ }
59
+ /** @public */
60
+ export interface UpdateGoalInput {
61
+ readonly id: number;
62
+ readonly goal?: string;
63
+ readonly status?: GoalStatus;
64
+ }
65
+ /** @public */
66
+ export interface CreateBehaviorInput {
67
+ readonly goalId: number;
68
+ readonly behavior: string;
69
+ readonly suggestedTestName?: string;
70
+ readonly dependsOnBehaviorIds?: ReadonlyArray<number>;
71
+ }
72
+ /** @public */
73
+ export interface UpdateBehaviorInput {
74
+ readonly id: number;
75
+ readonly behavior?: string;
76
+ readonly suggestedTestName?: string | null;
77
+ readonly status?: BehaviorStatus;
78
+ readonly dependsOnBehaviorIds?: ReadonlyArray<number>;
79
+ }
80
+ /** @public */
81
+ export interface SettingsInput {
82
+ readonly vitestVersion: string;
83
+ readonly pool?: string;
84
+ readonly environment?: string;
85
+ readonly testTimeout?: number;
86
+ readonly hookTimeout?: number;
87
+ readonly slowTestThreshold?: number;
88
+ readonly maxConcurrency?: number;
89
+ readonly maxWorkers?: number;
90
+ readonly isolate?: boolean;
91
+ readonly bail?: number;
92
+ readonly globals?: boolean;
93
+ readonly fileParallelism?: boolean;
94
+ readonly sequenceSeed?: number;
95
+ readonly coverageProvider?: string;
96
+ }
97
+ /** @public */
98
+ export interface TestRunInput {
99
+ readonly invocationId: string;
100
+ readonly project: string;
101
+ readonly settingsHash: string;
102
+ readonly timestamp: string;
103
+ readonly commitSha: string | null;
104
+ readonly branch: string | null;
105
+ readonly reason: "passed" | "failed" | "interrupted";
106
+ readonly duration: number;
107
+ readonly total: number;
108
+ readonly passed: number;
109
+ readonly failed: number;
110
+ readonly skipped: number;
111
+ readonly scoped: boolean;
112
+ readonly snapshotAdded?: number;
113
+ readonly snapshotMatched?: number;
114
+ readonly snapshotUnmatched?: number;
115
+ readonly snapshotUpdated?: number;
116
+ readonly snapshotUnchecked?: number;
117
+ readonly snapshotTotal?: number;
118
+ readonly snapshotFailure?: boolean;
119
+ readonly snapshotDidUpdate?: boolean;
120
+ readonly snapshotFilesAdded?: number;
121
+ readonly snapshotFilesRemoved?: number;
122
+ readonly snapshotFilesUnmatched?: number;
123
+ readonly snapshotFilesUpdated?: number;
124
+ /**
125
+ * Attribution columns added by the agent-agnostic taxonomy work. The
126
+ * reporter walks env vars / session map to populate these; un-attributed
127
+ * runs default to actor_type='system' and NULL agent/conversation ids.
128
+ */
129
+ readonly actorType?: "agent" | "user" | "system";
130
+ readonly agentId?: string | null;
131
+ readonly conversationId?: string | null;
132
+ /**
133
+ * Git context the run executed against. NULL for non-git workspaces.
134
+ */
135
+ readonly gitBranch?: string | null;
136
+ readonly gitCommitSha?: string | null;
137
+ readonly gitDirty?: boolean | null;
138
+ readonly gitUpstream?: string | null;
139
+ readonly gitWorktreeDir?: string | null;
140
+ /**
141
+ * Host metadata probe result (terminal pane, CI runner). NULL when no
142
+ * probe in the priority chain matched.
143
+ * @public
144
+ */
145
+ readonly hostSource?: string | null;
146
+ readonly hostValue?: string | null;
147
+ readonly hostMetadata?: Record<string, unknown> | null;
148
+ }
149
+ /** @public */
150
+ export interface ModuleInput {
151
+ readonly fileId: number;
152
+ readonly relativeModuleId: string;
153
+ readonly state: string;
154
+ readonly duration?: number;
155
+ readonly environmentSetupDuration?: number;
156
+ readonly prepareDuration?: number;
157
+ readonly collectDuration?: number;
158
+ readonly setupDuration?: number;
159
+ readonly heap?: number;
160
+ }
161
+ /** @public */
162
+ export interface TestCaseInput {
163
+ readonly suiteId?: number;
164
+ readonly vitestId?: string;
165
+ readonly name: string;
166
+ readonly fullName: string;
167
+ readonly state: string;
168
+ readonly classification?: string;
169
+ readonly duration?: number;
170
+ readonly startTime?: number;
171
+ readonly flaky?: boolean;
172
+ readonly slow?: boolean;
173
+ readonly retryCount?: number;
174
+ readonly repeatCount?: number;
175
+ readonly heap?: number;
176
+ readonly mode?: string;
177
+ readonly each?: boolean;
178
+ readonly fails?: boolean;
179
+ readonly concurrent?: boolean;
180
+ readonly shuffle?: boolean;
181
+ readonly timeout?: number;
182
+ readonly skipNote?: string;
183
+ readonly locationLine?: number;
184
+ readonly locationColumn?: number;
185
+ readonly tags?: readonly string[];
186
+ /**
187
+ * FK to `turns(id)`. Set by the reporter when the test case row was
188
+ * authored within a recorded turn (D2 binding rule 1).
189
+ * @public
190
+ */
191
+ readonly createdTurnId?: number;
192
+ }
193
+ /** @public */
194
+ export interface StackFrameInput {
195
+ readonly ordinal: number;
196
+ readonly method: string | null;
197
+ readonly filePath: string;
198
+ readonly line: number;
199
+ readonly col: number;
200
+ readonly sourceMappedLine?: number;
201
+ readonly functionBoundaryLine?: number;
202
+ }
203
+ /** @public */
204
+ export interface TestErrorInput {
205
+ readonly testCaseId?: number;
206
+ readonly testSuiteId?: number;
207
+ readonly moduleId?: number;
208
+ readonly scope: "test" | "suite" | "module" | "unhandled";
209
+ readonly name?: string;
210
+ readonly message: string;
211
+ readonly diff?: string;
212
+ readonly actual?: string;
213
+ readonly expected?: string;
214
+ readonly stack?: string;
215
+ readonly causeErrorId?: number;
216
+ readonly signatureHash?: string;
217
+ readonly frames?: ReadonlyArray<StackFrameInput>;
218
+ readonly ordinal?: number;
219
+ }
220
+ /**
221
+ * Ceiling on an inline attachment body. Vitest has already copied file
222
+ * attachments into `.vitest/attachments/`, so a large body is referenced
223
+ * by `path` rather than duplicated into `data.db`.
224
+ * @public
225
+ */
226
+ export declare const INLINE_ATTACHMENT_BODY_CAP_BYTES: number;
227
+ /** @public */
228
+ export interface TestAttachmentInput {
229
+ readonly contentType?: string;
230
+ /** Post-resolution path under `.vitest/attachments/`, or an http(s) URL. */
231
+ readonly path?: string;
232
+ /** Inline body; persisted only when `byteSize` is under the 64 KiB cap. */
233
+ readonly body?: string;
234
+ /** How to read `body`. Vitest treats a string body as base64 unless `"utf-8"`. */
235
+ readonly bodyEncoding?: "base64" | "utf-8";
236
+ readonly byteSize: number;
237
+ }
238
+ /** @public */
239
+ export interface TestAnnotationInput {
240
+ readonly testCaseId: number;
241
+ /** Arbitrary Vitest annotation type -- not an enum. */
242
+ readonly type: string;
243
+ readonly message: string;
244
+ readonly locationFile?: string;
245
+ readonly locationLine?: number;
246
+ readonly locationColumn?: number;
247
+ readonly attachments?: ReadonlyArray<TestAttachmentInput>;
248
+ }
249
+ /** @public */
250
+ export interface TestArtifactInput {
251
+ readonly testCaseId: number;
252
+ /** `pkg:name`; `internal:` types are Vitest's own and are never written. */
253
+ readonly type: string;
254
+ readonly message?: string;
255
+ /** JSON of the artifact's custom fields, minus attachments and location. */
256
+ readonly data?: string;
257
+ readonly locationFile?: string;
258
+ readonly locationLine?: number;
259
+ readonly locationColumn?: number;
260
+ readonly attachments?: ReadonlyArray<TestAttachmentInput>;
261
+ }
262
+ /** @public */
263
+ export interface FileCoverageInput {
264
+ readonly fileId: number;
265
+ readonly statements: number;
266
+ readonly branches: number;
267
+ readonly functions: number;
268
+ readonly lines: number;
269
+ readonly uncoveredLines?: string;
270
+ /**
271
+ * Coverage tier this row represents. `'below_threshold'` is the
272
+ * build-failing tier (file falls below the configured minimum
273
+ * coverage thresholds). `'below_target'` is the warning tier (file
274
+ * is above thresholds but below the aspirational target).
275
+ *
276
+ * Defaults to `'below_threshold'` when omitted, matching the only
277
+ * tier that existed before migration 0005.
278
+ * @public
279
+ */
280
+ readonly tier?: "below_threshold" | "below_target";
281
+ }
282
+ /** @public */
283
+ export interface SuiteInput {
284
+ readonly parentSuiteId?: number;
285
+ readonly name: string;
286
+ readonly fullName: string;
287
+ readonly state: "pending" | "passed" | "failed" | "skipped";
288
+ readonly mode?: "run" | "only" | "skip" | "todo";
289
+ readonly concurrent?: boolean;
290
+ readonly shuffle?: boolean;
291
+ readonly retry?: number;
292
+ readonly repeats?: number;
293
+ readonly locationLine?: number;
294
+ readonly locationColumn?: number;
295
+ }
296
+ /** @public */
297
+ export interface NoteInput {
298
+ readonly title: string;
299
+ readonly content: string;
300
+ readonly scope: "global" | "project" | "module" | "suite" | "test" | "note";
301
+ readonly project?: string;
302
+ readonly testFullName?: string;
303
+ readonly modulePath?: string;
304
+ readonly parentNoteId?: number;
305
+ readonly createdBy?: string;
306
+ readonly expiresAt?: string;
307
+ readonly pinned?: boolean;
308
+ }
309
+ /** @public */
310
+ export interface SessionInput {
311
+ readonly chatId: string;
312
+ readonly project: string;
313
+ readonly cwd: string;
314
+ readonly agentKind: "main" | "subagent";
315
+ readonly agentType?: string;
316
+ readonly parentSessionId?: number;
317
+ readonly triageWasNonEmpty?: boolean;
318
+ readonly startedAt: string;
319
+ /**
320
+ * Canonical conversation UUID this session belongs to (issue #144).
321
+ * Set once at INSERT time — `sessions.conversation_id` is immutable
322
+ * thereafter (see the `trg_sessions_conv_id_immutable` trigger), so
323
+ * omit it here rather than trying to backfill via an update.
324
+ */
325
+ readonly conversationId?: string;
326
+ }
327
+ /** @public */
328
+ export interface TurnInput {
329
+ readonly sessionId: number;
330
+ /** When omitted, writeTurn computes MAX(turnNo) + 1 for the session. */
331
+ readonly turnNo?: number;
332
+ readonly type: "user_prompt" | "tool_call" | "tool_result" | "file_edit" | "hook_fire" | "note" | "hypothesis";
333
+ readonly payload: string;
334
+ readonly occurredAt: string;
335
+ }
336
+ /** @public */
337
+ export interface FailureSignatureWriteInput {
338
+ readonly signatureHash: string;
339
+ readonly runId: number;
340
+ readonly seenAt: string;
341
+ }
342
+ /** @public */
343
+ export interface HypothesisInput {
344
+ readonly sessionId: number;
345
+ readonly content: string;
346
+ readonly createdTurnId?: number;
347
+ readonly citedTestErrorId?: number;
348
+ readonly citedStackFrameId?: number;
349
+ }
350
+ /** @public */
351
+ export interface ValidateHypothesisInput {
352
+ readonly id: number;
353
+ readonly outcome: "confirmed" | "refuted" | "abandoned";
354
+ readonly validatedTurnId?: number;
355
+ readonly validatedAt: string;
356
+ }
357
+ /** @public */
358
+ export interface IdempotentResponseInput {
359
+ readonly procedurePath: string;
360
+ readonly key: string;
361
+ readonly resultJson: string;
362
+ readonly createdAt: string;
363
+ }
364
+ /** @public */
365
+ export interface TddTaskInput {
366
+ readonly sessionId: number;
367
+ readonly goal: string;
368
+ readonly startedAt: string;
369
+ readonly parentTddTaskId?: number;
370
+ readonly runId?: string;
371
+ }
372
+ /** @public */
373
+ export interface EndTddTaskInput {
374
+ readonly id: number;
375
+ readonly endedAt: string;
376
+ readonly outcome: "succeeded" | "blocked" | "abandoned";
377
+ readonly summaryNoteId?: number;
378
+ }
379
+ /** @public */
380
+ export interface WriteTddPhaseInput {
381
+ readonly tddTaskId: number;
382
+ readonly behaviorId?: number;
383
+ readonly phase: Phase;
384
+ readonly startedAt: string;
385
+ readonly transitionReason?: string;
386
+ readonly parentPhaseId?: number;
387
+ }
388
+ /** @public */
389
+ export interface WriteTddPhaseOutput {
390
+ readonly id: number;
391
+ readonly previousPhaseId: number | null;
392
+ }
393
+ /** @public */
394
+ export interface WriteTddArtifactInput {
395
+ readonly phaseId: number;
396
+ readonly artifactKind: ArtifactKind;
397
+ readonly fileId?: number;
398
+ readonly testCaseId?: number;
399
+ readonly testRunId?: number;
400
+ readonly testFirstFailureRunId?: number;
401
+ readonly diffExcerpt?: string;
402
+ readonly recordedAt: string;
403
+ /** Issue #363: explicit suite marker. Defaults to `"vitest"` when omitted. */
404
+ readonly suite?: ArtifactSuite;
405
+ }
406
+ /** @public */
407
+ export interface WriteCommitInput {
408
+ readonly sha: string;
409
+ readonly parentSha?: string;
410
+ readonly message?: string;
411
+ readonly author?: string;
412
+ readonly committedAt?: string;
413
+ readonly branch?: string;
414
+ }
415
+ /** @public */
416
+ export type ChangeKind = "added" | "modified" | "deleted" | "renamed" | "untracked-modified";
417
+ /** @public */
418
+ export interface RunChangedFile {
419
+ readonly filePath: string;
420
+ readonly changeKind: ChangeKind;
421
+ readonly commitSha?: string;
422
+ }
423
+ /** @public */
424
+ export interface WriteRunChangedFilesInput {
425
+ readonly runId: number;
426
+ readonly files: ReadonlyArray<RunChangedFile>;
427
+ }
428
+ /** @public */
429
+ export type RunInvocationMethod = "bash" | "mcp" | "cli";
430
+ /**
431
+ * Input to `DataStore.registerAgent`.
432
+ *
433
+ * `sessionId` is the FK to `sessions.id` (integer PK), NOT the host's
434
+ * chat UUID string. Callers that hold only the chat UUID must resolve
435
+ * it through `getSessionByChatId` first.
436
+ *
437
+ * `idempotencyKey` is pre-derived by the caller via
438
+ * `deriveIdempotencyKey(...)` — both the sidecar CLI and the MCP
439
+ * server compute it the same way so a hook retry collapses to the
440
+ * same row.
441
+ * @public
442
+ */
443
+ export interface RegisterAgentInput {
444
+ readonly sessionId: number;
445
+ readonly agentType: string;
446
+ readonly parentAgentId: string | null;
447
+ readonly conversationId: string | null;
448
+ readonly startedAt: number;
449
+ readonly startGitBranch?: string;
450
+ readonly startGitCommitSha?: string;
451
+ readonly startWorktreeDir?: string;
452
+ readonly idempotencyKey: string;
453
+ /**
454
+ * Pre-allocated `agents.agent_id` UUID. The sidecar passes
455
+ * `PerClientSessionMapWriter.mapSession()`'s `main_agent_id` here so
456
+ * the per-project `agents` row and the per-client session_map row
457
+ * agree on a single canonical id — the same value the SessionStart
458
+ * hook exports as `VITEST_AGENT_MAIN_AGENT_ID` / `_AGENT_ID`. When
459
+ * omitted, the implementation generates a fresh UUID (used by tests
460
+ * and any caller without a session map).
461
+ */
462
+ readonly agentId?: string;
463
+ }
464
+ /** @public */
465
+ export interface AssociateRunSessionInput {
466
+ readonly chatId: string;
467
+ readonly invocationMethod: RunInvocationMethod;
468
+ }
469
+ declare const DataStore_base: Context.ServiceClass<DataStore, "vitest-agent/DataStore", {
470
+ readonly writeSettings: (hash: string, settings: SettingsInput, envVars: Record<string, string>) => Effect.Effect<void, DataStoreError>;
471
+ readonly writeRun: (input: TestRunInput) => Effect.Effect<number, DataStoreError>;
472
+ readonly writeModules: (runId: number, modules: ReadonlyArray<ModuleInput>) => Effect.Effect<ReadonlyArray<number>, DataStoreError>;
473
+ readonly writeSuites: (moduleId: number, suites: ReadonlyArray<SuiteInput>) => Effect.Effect<ReadonlyArray<number>, DataStoreError>;
474
+ readonly writeTestCases: (moduleId: number, tests: ReadonlyArray<TestCaseInput>) => Effect.Effect<ReadonlyArray<number>, DataStoreError>;
475
+ readonly writeErrors: (runId: number, errors: ReadonlyArray<TestErrorInput>) => Effect.Effect<void, DataStoreError>;
476
+ /**
477
+ * Persist `context.annotate` notes and their attachment descriptors.
478
+ * `runId` is carried for log correlation only -- `test_annotations`
479
+ * rows are reachable through `test_cases`.
480
+ */
481
+ readonly writeAnnotations: (runId: number, annotations: ReadonlyArray<TestAnnotationInput>) => Effect.Effect<void, DataStoreError>;
482
+ /**
483
+ * Persist `recordArtifact` payloads and their attachment
484
+ * descriptors. `runId` is carried for log correlation only.
485
+ */
486
+ readonly writeArtifacts: (runId: number, artifacts: ReadonlyArray<TestArtifactInput>) => Effect.Effect<void, DataStoreError>;
487
+ readonly writeCoverage: (runId: number, coverage: ReadonlyArray<FileCoverageInput>) => Effect.Effect<void, DataStoreError>;
488
+ 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>;
489
+ readonly writeBaselines: (baselines: CoverageBaselines) => Effect.Effect<void, DataStoreError>;
490
+ /**
491
+ * Persist the resolved (enforced) Vitest `coverage.thresholds` for the
492
+ * current run, distinct from the ratcheted `coverage_baselines` rows.
493
+ * Stored under `kind='threshold'`. See issue #237.
494
+ */
495
+ readonly writeThresholds: (thresholds: ResolvedThresholds) => Effect.Effect<void, DataStoreError>;
496
+ /**
497
+ * Persist the resolved aspirational `coverageTargets` for the current
498
+ * run, distinct from the ratcheted `coverage_baselines` rows. Stored
499
+ * under `kind='target'`. See issue #237.
500
+ */
501
+ readonly writeTargets: (targets: ResolvedThresholds) => Effect.Effect<void, DataStoreError>;
502
+ readonly writeTrends: (project: string, runId: number, entry: TrendEntry) => Effect.Effect<void, DataStoreError>;
503
+ readonly writeSourceMap: (sourceFilePath: string, testModuleId: number, mappingType: string) => Effect.Effect<void, DataStoreError>;
504
+ readonly ensureFile: (filePath: string) => Effect.Effect<number, DataStoreError>;
505
+ readonly writeNote: (note: NoteInput) => Effect.Effect<number, DataStoreError>;
506
+ readonly updateNote: (id: number, fields: Partial<NoteInput>) => Effect.Effect<void, DataStoreError>;
507
+ readonly deleteNote: (id: number) => Effect.Effect<void, DataStoreError>;
508
+ readonly writeSession: (input: SessionInput) => Effect.Effect<number, DataStoreError>;
509
+ /**
510
+ * Idempotent variant of `writeSession`: if a row with this
511
+ * `chat_id` already exists, return its id and leave the stored
512
+ * fields untouched; otherwise insert a new row. Used by
513
+ * hook-triggered recording paths (artifacts, turns) that fire
514
+ * for sessions whose original `SessionStart` may have missed —
515
+ * e.g. when Claude Code rotates `chat_id` mid-window after a
516
+ * continuation or compaction. Race-safe via
517
+ * `INSERT ... ON CONFLICT DO NOTHING`.
518
+ */
519
+ readonly upsertSession: (input: SessionInput) => Effect.Effect<number, DataStoreError>;
520
+ /**
521
+ * Backfill `sessions.conversation_id` for a row that was inserted
522
+ * before the canonical conversation id was known (issue #144) —
523
+ * `record session-start` always precedes `register-agent`, so the
524
+ * session row exists first. Race-safe and idempotent: the UPDATE's
525
+ * `WHERE conversation_id IS NULL` guard means a session that
526
+ * already carries a value is left untouched (zero rows affected),
527
+ * matching the trigger's null→value-only relaxation rather than
528
+ * risking an immutability-violation error on a redundant call.
529
+ */
530
+ readonly setSessionConversationIdIfNull: (input: {
531
+ readonly sessionId: number;
532
+ readonly conversationId: string;
533
+ }) => Effect.Effect<void, DataStoreError>;
534
+ readonly writeTurn: (input: TurnInput) => Effect.Effect<number, DataStoreError>;
535
+ readonly writeFailureSignature: (input: FailureSignatureWriteInput) => Effect.Effect<void, DataStoreError>;
536
+ readonly endSession: (chatId: string, endedAt: string, endReason: string | null) => Effect.Effect<void, DataStoreError>;
537
+ readonly writeHypothesis: (input: HypothesisInput) => Effect.Effect<number, DataStoreError>;
538
+ readonly validateHypothesis: (input: ValidateHypothesisInput) => Effect.Effect<void, DataStoreError>;
539
+ readonly writeTddTask: (input: TddTaskInput) => Effect.Effect<number, DataStoreError>;
540
+ readonly endTddTask: (input: EndTddTaskInput) => Effect.Effect<void, DataStoreError>;
541
+ readonly createGoal: (input: CreateGoalInput) => Effect.Effect<GoalRow, DataStoreError | TddTaskNotFoundError | TddTaskAlreadyEndedError>;
542
+ readonly getGoal: (id: number) => Effect.Effect<Option.Option<GoalRow>, DataStoreError>;
543
+ readonly updateGoal: (input: UpdateGoalInput) => Effect.Effect<GoalRow, DataStoreError | GoalNotFoundError | TddTaskAlreadyEndedError | IllegalStatusTransitionError>;
544
+ readonly deleteGoal: (id: number) => Effect.Effect<void, DataStoreError | GoalNotFoundError>;
545
+ readonly listGoalsByTddTask: (tddTaskId: number) => Effect.Effect<ReadonlyArray<GoalRow>, DataStoreError | TddTaskNotFoundError>;
546
+ readonly createBehavior: (input: CreateBehaviorInput) => Effect.Effect<BehaviorRow, DataStoreError | GoalNotFoundError | BehaviorNotFoundError | TddTaskAlreadyEndedError | IllegalStatusTransitionError>;
547
+ readonly getBehavior: (id: number) => Effect.Effect<Option.Option<BehaviorRow>, DataStoreError>;
548
+ readonly updateBehavior: (input: UpdateBehaviorInput) => Effect.Effect<BehaviorRow, DataStoreError | BehaviorNotFoundError | TddTaskAlreadyEndedError | IllegalStatusTransitionError>;
549
+ readonly deleteBehavior: (id: number) => Effect.Effect<void, DataStoreError | BehaviorNotFoundError>;
550
+ readonly listBehaviorsByGoal: (goalId: number) => Effect.Effect<ReadonlyArray<BehaviorRow>, DataStoreError | GoalNotFoundError>;
551
+ readonly listBehaviorsByTddTask: (tddTaskId: number) => Effect.Effect<ReadonlyArray<BehaviorRow>, DataStoreError | TddTaskNotFoundError>;
552
+ readonly writeTddPhase: (input: WriteTddPhaseInput) => Effect.Effect<WriteTddPhaseOutput, DataStoreError>;
553
+ readonly writeTddArtifact: (input: WriteTddArtifactInput) => Effect.Effect<number, DataStoreError>;
554
+ readonly writeCommit: (input: WriteCommitInput) => Effect.Effect<void, DataStoreError>;
555
+ readonly writeRunChangedFiles: (input: WriteRunChangedFilesInput) => Effect.Effect<void, DataStoreError>;
556
+ readonly recordIdempotentResponse: (input: IdempotentResponseInput) => Effect.Effect<void, DataStoreError>;
557
+ readonly pruneSessions: (keepRecent: number) => Effect.Effect<{
558
+ readonly affectedSessions: number;
559
+ readonly prunedTurns: number;
560
+ }, DataStoreError>;
561
+ readonly associateLatestRunWithSession: (input: AssociateRunSessionInput) => Effect.Effect<void, DataStoreError>;
562
+ readonly backfillTestCaseTurns: (chatId: string) => Effect.Effect<number, DataStoreError>;
563
+ /**
564
+ * Idempotently insert an `agents` row.
565
+ *
566
+ * Returns `Agent` on a fresh insert, or `IdempotencyHit` carrying
567
+ * the existing `agentId` when the `(session_id, idempotency_key)`
568
+ * UNIQUE constraint already has a row. The caller treats the latter
569
+ * as a successful recovery (same logical agent), not an error.
570
+ *
571
+ * Fails with `RegistrationConflictError` when the supplied
572
+ * `parentAgentId` references an agent in a different session, or
573
+ * when no such agent exists. Surface to the caller for true
574
+ * mis-configuration cases; idempotency hits never produce this.
575
+ */
576
+ readonly registerAgent: (input: RegisterAgentInput) => Effect.Effect<Agent | IdempotencyHit, RegistrationConflictError | DataStoreError>;
577
+ /**
578
+ * Mark an agent as ended. Sets `agents.ended_at` to the supplied
579
+ * timestamp. Fails with `AgentNotFoundError` when no row exists.
580
+ */
581
+ readonly endAgent: (agentId: string, endedAt: number) => Effect.Effect<void, AgentNotFoundError | DataStoreError>;
582
+ }>;
583
+ /** @public */
584
+ export declare class DataStore extends DataStore_base {}
585
+ //#endregion
586
+ //#region src/services/DataReader.d.ts
587
+ /** @public */
588
+ export interface ProjectRunSummary {
589
+ readonly project: string;
590
+ readonly lastRun: string | null;
591
+ readonly lastResult: "passed" | "failed" | "interrupted" | null;
592
+ readonly total: number;
593
+ readonly passed: number;
594
+ readonly failed: number;
595
+ readonly skipped: number;
596
+ }
597
+ /** @public */
598
+ export interface FlakyTest {
599
+ readonly fullName: string;
600
+ readonly modulePath: string;
601
+ readonly project: string;
602
+ readonly passCount: number;
603
+ readonly failCount: number;
604
+ readonly lastState: "passed" | "failed";
605
+ readonly lastTimestamp: string;
606
+ }
607
+ /** @public */
608
+ export interface PersistentFailure {
609
+ readonly fullName: string;
610
+ readonly modulePath: string;
611
+ readonly project: string;
612
+ readonly consecutiveFailures: number;
613
+ readonly firstFailedAt: string;
614
+ readonly lastFailedAt: string;
615
+ readonly lastErrorMessage: string | null;
616
+ }
617
+ /** @public */
618
+ export interface TestError {
619
+ /** `test_errors.id` — required by `hypothesis (action: record).citedTestErrorId`. */
620
+ readonly id: number;
621
+ /**
622
+ * `stack_frames.id` for the top frame of this error (ordinal 0), or
623
+ * `null` if no frames were captured. Required by
624
+ * `hypothesis (action: record).citedStackFrameId`.
625
+ */
626
+ readonly topStackFrameId: number | null;
627
+ readonly name: string | null;
628
+ readonly message: string;
629
+ readonly diff: string | null;
630
+ readonly actual: string | null;
631
+ readonly expected: string | null;
632
+ readonly stack: string | null;
633
+ readonly scope: "test" | "suite" | "module" | "unhandled";
634
+ readonly testFullName: string | null;
635
+ readonly moduleFile: string | null;
636
+ }
637
+ /** @public */
638
+ export interface NoteRow {
639
+ readonly id: number;
640
+ readonly title: string;
641
+ readonly content: string;
642
+ readonly scope: "global" | "project" | "module" | "suite" | "test" | "note";
643
+ readonly project: string | null;
644
+ readonly testFullName: string | null;
645
+ readonly modulePath: string | null;
646
+ readonly parentNoteId: number | null;
647
+ readonly createdBy: string | null;
648
+ readonly expiresAt: string | null;
649
+ readonly pinned: boolean;
650
+ readonly createdAt: string;
651
+ readonly updatedAt: string;
652
+ }
653
+ /** @public */
654
+ export interface SettingsRow {
655
+ readonly hash: string;
656
+ readonly reporters: string | null;
657
+ readonly coverageEnabled: boolean;
658
+ readonly coverageProvider: string | null;
659
+ readonly coverageThresholds: string | null;
660
+ readonly coverageTargets: string | null;
661
+ readonly pool: string | null;
662
+ readonly shard: string | null;
663
+ readonly project: string | null;
664
+ readonly environment: string | null;
665
+ readonly envVars: Record<string, string>;
666
+ readonly capturedAt: string;
667
+ }
668
+ /** @public */
669
+ export interface TestListEntry {
670
+ readonly id: number;
671
+ readonly fullName: string;
672
+ readonly state: string;
673
+ readonly duration: number | null;
674
+ readonly module: string;
675
+ readonly classification: string | null;
676
+ }
677
+ /** @public */
678
+ export interface ModuleListEntry {
679
+ readonly id: number;
680
+ readonly file: string;
681
+ readonly state: string;
682
+ readonly testCount: number;
683
+ readonly duration: number | null;
684
+ }
685
+ /** @public */
686
+ export interface SuiteListEntry {
687
+ readonly id: number;
688
+ readonly name: string;
689
+ readonly module: string;
690
+ readonly state: string;
691
+ readonly testCount: number;
692
+ }
693
+ /** @public */
694
+ export interface SettingsListEntry {
695
+ readonly hash: string;
696
+ readonly capturedAt: string;
697
+ }
698
+ /** @public */
699
+ export interface SessionDetail {
700
+ readonly id: number;
701
+ readonly chatId: string;
702
+ readonly project: string;
703
+ readonly cwd: string;
704
+ readonly agentKind: "main" | "subagent";
705
+ readonly agentType: string | null;
706
+ readonly parentSessionId: number | null;
707
+ readonly triageWasNonEmpty: boolean;
708
+ readonly startedAt: string;
709
+ readonly endedAt: string | null;
710
+ readonly endReason: string | null;
711
+ /** Canonical conversation UUID this session belongs to (issue #144), null when unset. */
712
+ readonly conversationId: string | null;
713
+ }
714
+ /** @public */
715
+ export interface TurnSummary {
716
+ readonly id: number;
717
+ readonly sessionId: number;
718
+ readonly turnNo: number;
719
+ readonly type: string;
720
+ readonly payload: string;
721
+ readonly occurredAt: string;
722
+ }
723
+ /** @public */
724
+ export interface HistoryQueryOptions {
725
+ /** Exact `full_name` match — narrows to a single test's history. */
726
+ readonly testName?: string;
727
+ /** Exact `module_path` match — narrows to tests in one file. */
728
+ readonly modulePath?: string;
729
+ /** Max runs kept per (module_path, full_name) pair, most-recent-first. Default 20. */
730
+ readonly limit?: number;
731
+ }
732
+ /**
733
+ * Narrowing options shared by the classification reads
734
+ * (`DataReader.getFlaky` / `getPersistentFailures`). Mirrors the
735
+ * `testName` / `modulePath` half of {@link HistoryQueryOptions} so a
736
+ * caller that scoped `getHistory` to one test can scope the derived
737
+ * classifications to the same test instead of receiving the whole
738
+ * project's rows.
739
+ *
740
+ * @public
741
+ */
742
+ export interface ClassificationQueryOptions {
743
+ /** Exact `full_name` match — narrows to a single test's classification. */
744
+ readonly testName?: string;
745
+ /** Exact `module_path` match — narrows to tests in one file. */
746
+ readonly modulePath?: string;
747
+ }
748
+ /**
749
+ * Narrowing options for `DataReader.getTestByFullName`. A
750
+ * `full_name` is not file-qualified (Decision D20), so the same name can
751
+ * exist in more than one module; `modulePath` disambiguates.
752
+ *
753
+ * @public
754
+ */
755
+ export interface TestLookupOptions {
756
+ /** Exact `module_path` match — picks one variant of an ambiguous `full_name`. */
757
+ readonly modulePath?: string;
758
+ }
759
+ /** @public */
760
+ export interface TurnSearchOptions {
761
+ readonly sessionId?: number;
762
+ readonly type?: string;
763
+ readonly since?: string;
764
+ readonly limit?: number;
765
+ }
766
+ /** @public */
767
+ export interface AcceptanceMetrics {
768
+ readonly phaseEvidenceIntegrity: {
769
+ total: number;
770
+ compliant: number;
771
+ ratio: number;
772
+ };
773
+ readonly complianceHookResponsiveness: {
774
+ total: number;
775
+ withFollowup: number;
776
+ ratio: number;
777
+ };
778
+ readonly orientationUsefulness: {
779
+ total: number;
780
+ referencedCount: number;
781
+ ratio: number;
782
+ };
783
+ readonly antiPatternDetectionRate: {
784
+ total: number;
785
+ cleanSessions: number;
786
+ ratio: number;
787
+ };
788
+ }
789
+ /** @public */
790
+ export interface FailureSignatureDetail {
791
+ readonly signatureHash: string;
792
+ readonly firstSeenRunId: number | null;
793
+ readonly firstSeenAt: string;
794
+ readonly lastSeenAt: string | null;
795
+ readonly occurrenceCount: number;
796
+ readonly recentErrors: ReadonlyArray<{
797
+ readonly runId: number;
798
+ readonly message: string;
799
+ readonly errorName: string | null;
800
+ }>;
801
+ }
802
+ /** @public */
803
+ export interface TddPhaseDetail {
804
+ readonly id: number;
805
+ readonly behaviorId: number | null;
806
+ readonly phase: string;
807
+ readonly startedAt: string;
808
+ readonly endedAt: string | null;
809
+ readonly transitionReason: string | null;
810
+ }
811
+ /** @public */
812
+ export interface TddArtifactDetail {
813
+ readonly id: number;
814
+ readonly phaseId: number;
815
+ readonly artifactKind: string;
816
+ readonly testCaseId: number | null;
817
+ readonly testRunId: number | null;
818
+ readonly recordedAt: string;
819
+ }
820
+ /** @public */
821
+ export interface TddTaskDetail {
822
+ readonly id: number;
823
+ readonly sessionId: number;
824
+ readonly goal: string;
825
+ readonly startedAt: string;
826
+ readonly endedAt: string | null;
827
+ readonly outcome: string | null;
828
+ readonly runId: string | null;
829
+ readonly goals: ReadonlyArray<GoalDetail>;
830
+ readonly phases: ReadonlyArray<TddPhaseDetail>;
831
+ readonly artifacts: ReadonlyArray<TddArtifactDetail>;
832
+ }
833
+ /** @public */
834
+ export interface CurrentTddPhase {
835
+ readonly id: number;
836
+ readonly phase: Phase;
837
+ readonly startedAt: string;
838
+ readonly behaviorId: number | null;
839
+ }
840
+ /** @public */
841
+ export interface CitedArtifactRow extends CitedArtifact {
842
+ readonly phase_id: number;
843
+ }
844
+ /** @public */
845
+ export interface CommitChangesEntry {
846
+ readonly sha: string;
847
+ readonly parentSha: string | null;
848
+ readonly message: string | null;
849
+ readonly author: string | null;
850
+ readonly committedAt: string | null;
851
+ readonly branch: string | null;
852
+ readonly files: ReadonlyArray<{
853
+ readonly filePath: string;
854
+ readonly changeKind: ChangeKind;
855
+ }>;
856
+ }
857
+ /** @public */
858
+ export interface HypothesisDetail {
859
+ readonly id: number;
860
+ readonly sessionId: number;
861
+ readonly content: string;
862
+ readonly citedTestErrorId: number | null;
863
+ readonly citedStackFrameId: number | null;
864
+ readonly validationOutcome: "confirmed" | "refuted" | "abandoned" | null;
865
+ readonly validatedAt: string | null;
866
+ }
867
+ /** @public */
868
+ export interface TddTaskSummary {
869
+ readonly id: number;
870
+ readonly sessionId: number;
871
+ readonly goal: string;
872
+ readonly startedAt: string;
873
+ readonly endedAt: string | null;
874
+ readonly outcome: "succeeded" | "blocked" | "abandoned" | null;
875
+ }
876
+ /**
877
+ * Row shape returned by `listTddArtifactsForTask`. Carries every
878
+ * field an agent typically needs to cite an artifact in a subsequent
879
+ * `tdd_phase_transition_request` call without further lookups.
880
+ *
881
+ * @public
882
+ */
883
+ export interface TddArtifactRow {
884
+ readonly id: number;
885
+ readonly tddTaskId: number;
886
+ readonly phaseId: number;
887
+ readonly phaseName: Phase;
888
+ readonly artifactKind: ArtifactKind$1;
889
+ readonly behaviorId: number | null;
890
+ readonly testCaseId: number | null;
891
+ readonly testRunId: number | null;
892
+ readonly testFirstFailureRunId: number | null;
893
+ readonly recordedAt: string;
894
+ readonly suite: ArtifactSuite$1;
895
+ }
896
+ /** @public */
897
+ export interface TagInventoryRow {
898
+ /** The tag name (e.g. `"int"`, `"e2e"`, `"unit"`). */
899
+ readonly tag: string;
900
+ /** The Vitest project this tag was observed in. */
901
+ readonly project: string;
902
+ /**
903
+ * Number of distinct test modules in the project's latest run that contain
904
+ * at least one test case carrying this tag.
905
+ */
906
+ readonly moduleCount: number;
907
+ /**
908
+ * Number of test cases in the project's latest run that carry this tag.
909
+ */
910
+ readonly testCount: number;
911
+ }
912
+ /** @public */
913
+ export interface TestArtifactQueryOptions {
914
+ /** Disambiguates a fullName that exists in more than one module. */
915
+ readonly modulePath?: string;
916
+ }
917
+ /** @public */
918
+ export interface PersistedAttachment {
919
+ readonly contentType?: string;
920
+ readonly path?: string;
921
+ readonly body?: string;
922
+ /** How to read `body`. Absent when nothing was stored inline. */
923
+ readonly bodyEncoding?: "base64" | "utf-8";
924
+ readonly byteSize: number | null;
925
+ }
926
+ /** @public */
927
+ export interface TestAnnotationRow {
928
+ readonly id: number;
929
+ readonly type: string;
930
+ readonly message: string;
931
+ readonly location?: {
932
+ readonly file: string;
933
+ readonly line: number;
934
+ readonly column: number;
935
+ };
936
+ readonly attachments: ReadonlyArray<PersistedAttachment>;
937
+ }
938
+ /** @public */
939
+ export interface TestArtifactRow {
940
+ readonly id: number;
941
+ readonly type: string;
942
+ readonly message: string | null;
943
+ readonly data: string | null;
944
+ readonly location?: {
945
+ readonly file: string;
946
+ readonly line: number;
947
+ readonly column: number;
948
+ };
949
+ readonly attachments: ReadonlyArray<PersistedAttachment>;
950
+ }
951
+ declare const DataReader_base: Context.ServiceClass<DataReader, "vitest-agent/DataReader", {
952
+ readonly getLatestRun: (project: string) => Effect.Effect<Option.Option<AgentReport>, DataStoreError>;
953
+ readonly getRunsByProject: () => Effect.Effect<ReadonlyArray<ProjectRunSummary>, DataStoreError>;
954
+ readonly getHistory: (project: string, options?: HistoryQueryOptions) => Effect.Effect<HistoryRecord, DataStoreError>;
955
+ readonly getBaselines: (project: string) => Effect.Effect<Option.Option<CoverageBaselines>, DataStoreError>;
956
+ readonly getTrends: (project: string, limit?: number) => Effect.Effect<Option.Option<TrendRecord>, DataStoreError>;
957
+ readonly getFlaky: (project: string, options?: ClassificationQueryOptions) => Effect.Effect<ReadonlyArray<FlakyTest>, DataStoreError>;
958
+ readonly getPersistentFailures: (project: string, options?: ClassificationQueryOptions) => Effect.Effect<ReadonlyArray<PersistentFailure>, DataStoreError>;
959
+ readonly getFileCoverage: (runId: number) => Effect.Effect<ReadonlyArray<FileCoverageReport>, DataStoreError>;
960
+ readonly getCoverage: (project: string) => Effect.Effect<Option.Option<CoverageReport>, DataStoreError>;
961
+ readonly getTestsForFile: (filePath: string) => Effect.Effect<ReadonlyArray<string>, DataStoreError>;
962
+ readonly getErrors: (project: string, errorName?: string) => Effect.Effect<ReadonlyArray<TestError>, DataStoreError>;
963
+ /** Annotations recorded for a test in the project's latest run. */
964
+ readonly getAnnotationsForTest: (project: string, fullName: string, options?: TestArtifactQueryOptions) => Effect.Effect<ReadonlyArray<TestAnnotationRow>, DataStoreError>;
965
+ /** Artifacts recorded for a test in the project's latest run. */
966
+ readonly getArtifactsForTest: (project: string, fullName: string, options?: TestArtifactQueryOptions) => Effect.Effect<ReadonlyArray<TestArtifactRow>, DataStoreError>;
967
+ readonly getNotes: (scope?: string, project?: string, testFullName?: string) => Effect.Effect<ReadonlyArray<NoteRow>, DataStoreError>;
968
+ readonly getNoteById: (id: number) => Effect.Effect<Option.Option<NoteRow>, DataStoreError>;
969
+ readonly searchNotes: (query: string) => Effect.Effect<ReadonlyArray<NoteRow>, DataStoreError>;
970
+ readonly getManifest: () => Effect.Effect<Option.Option<CacheManifest>, DataStoreError>;
971
+ readonly getSettings: (hash: string) => Effect.Effect<Option.Option<SettingsRow>, DataStoreError>;
972
+ readonly getLatestSettings: () => Effect.Effect<Option.Option<SettingsRow>, DataStoreError>;
973
+ readonly getTestByFullName: (project: string, fullName: string, options?: TestLookupOptions) => Effect.Effect<Option.Option<TestListEntry>, DataStoreError>;
974
+ /**
975
+ * Every module path in the project's latest run that carries a test
976
+ * case with this exact `full_name`, ordered ascending. Length > 1
977
+ * means the name is ambiguous and callers must disambiguate with
978
+ * {@link TestLookupOptions.modulePath} rather than guess.
979
+ */
980
+ readonly getTestModulesByFullName: (project: string, fullName: string) => Effect.Effect<ReadonlyArray<string>, DataStoreError>;
981
+ readonly listTests: (project: string, options?: {
982
+ state?: string;
983
+ module?: string;
984
+ limit?: number;
985
+ }) => Effect.Effect<ReadonlyArray<TestListEntry>, DataStoreError>;
986
+ readonly listModules: (project: string) => Effect.Effect<ReadonlyArray<ModuleListEntry>, DataStoreError>;
987
+ readonly listSuites: (project: string, options?: {
988
+ module?: string;
989
+ }) => Effect.Effect<ReadonlyArray<SuiteListEntry>, DataStoreError>;
990
+ readonly listSettings: () => Effect.Effect<ReadonlyArray<SettingsListEntry>, DataStoreError>;
991
+ readonly getSessionById: (id: number) => Effect.Effect<Option.Option<SessionDetail>, DataStoreError>;
992
+ readonly getSessionByChatId: (chatId: string) => Effect.Effect<Option.Option<SessionDetail>, DataStoreError>;
993
+ /**
994
+ * Find every session row whose `chat_id` begins with `prefix`.
995
+ * Used to recover the synthetic subagent row created by the
996
+ * SubagentStart hook (`<parentChatId>-subagent-<ts>-<pid>`)
997
+ * when subsequent PostToolUse hooks fire under the bare
998
+ * parent chat_id. Returns most recent first.
999
+ */
1000
+ readonly findSessionsByChatPrefix: (prefix: string) => Effect.Effect<ReadonlyArray<SessionDetail>, DataStoreError>;
1001
+ /**
1002
+ * Find the most-recently-started subagent session whose
1003
+ * `parent_session_id` is `parentSessionId` and that has not ended
1004
+ * (`ended_at IS NULL`). Used to attribute orchestrator (subagent)
1005
+ * MCP writes — e.g. `hypothesis record` — to the running subagent's
1006
+ * own session row instead of the parent main session, since the MCP
1007
+ * server's recovered context only ever names the main agent.
1008
+ */
1009
+ readonly findActiveSubagentSession: (parentSessionId: number) => Effect.Effect<Option.Option<SessionDetail>, DataStoreError>;
1010
+ /**
1011
+ * Resolve the session a TDD task was opened under: the `sessions`
1012
+ * row whose `id` equals `tdd_tasks.session_id` for `tddTaskId`.
1013
+ * Returns `Option.none` when the task — or its session — does not
1014
+ * exist. Lets `hypothesis (action: record)` bind a hypothesis
1015
+ * deterministically from the orchestrator's unambiguous
1016
+ * `tddTaskId` (returned by `tdd_task (action: start)`) instead of
1017
+ * the fragile recovered host context or a caller-guessed
1018
+ * `sessionId`.
1019
+ */
1020
+ readonly getSessionByTddTaskId: (tddTaskId: number) => Effect.Effect<Option.Option<SessionDetail>, DataStoreError>;
1021
+ readonly listSessions: (options: {
1022
+ readonly project?: string;
1023
+ readonly agentKind?: "main" | "subagent";
1024
+ readonly limit?: number;
1025
+ }) => Effect.Effect<ReadonlyArray<SessionDetail>, DataStoreError>;
1026
+ readonly searchTurns: (options: TurnSearchOptions) => Effect.Effect<ReadonlyArray<TurnSummary>, DataStoreError>;
1027
+ readonly computeAcceptanceMetrics: () => Effect.Effect<AcceptanceMetrics, DataStoreError>;
1028
+ readonly getFailureSignatureByHash: (hash: string) => Effect.Effect<Option.Option<FailureSignatureDetail>, DataStoreError>;
1029
+ readonly getTddTaskById: (id: number) => Effect.Effect<Option.Option<TddTaskDetail>, DataStoreError>;
1030
+ readonly getGoalById: (id: number) => Effect.Effect<Option.Option<GoalDetail>, DataStoreError>;
1031
+ readonly getGoalsByTddTask: (tddTaskId: number) => Effect.Effect<ReadonlyArray<GoalDetail>, DataStoreError>;
1032
+ readonly getBehaviorById: (id: number) => Effect.Effect<Option.Option<BehaviorDetail>, DataStoreError>;
1033
+ readonly getBehaviorsByGoal: (goalId: number) => Effect.Effect<ReadonlyArray<BehaviorRow>, DataStoreError>;
1034
+ readonly getBehaviorsByTddTask: (tddTaskId: number) => Effect.Effect<ReadonlyArray<BehaviorRow>, DataStoreError>;
1035
+ readonly getBehaviorDependencies: (behaviorId: number) => Effect.Effect<ReadonlyArray<BehaviorRow>, DataStoreError>;
1036
+ readonly resolveGoalIdForBehavior: (behaviorId: number) => Effect.Effect<Option.Option<number>, DataStoreError>;
1037
+ readonly getCurrentTddPhase: (tddTaskId: number) => Effect.Effect<Option.Option<CurrentTddPhase>, DataStoreError>;
1038
+ readonly getTddArtifactWithContext: (artifactId: number) => Effect.Effect<Option.Option<CitedArtifactRow>, DataStoreError>;
1039
+ readonly getCommitChanges: (sha?: string) => Effect.Effect<ReadonlyArray<CommitChangesEntry>, DataStoreError>;
1040
+ readonly listTddTasksForSession: (sessionId: number, options?: {
1041
+ /**
1042
+ * When true, also return tdd_tasks belonging to any
1043
+ * ancestor of `sessionId` via `parent_session_id`. Used
1044
+ * by hook-driven artifact recording where the
1045
+ * orchestrator opened the tdd task under the parent
1046
+ * main row but the subagent's own session row is the
1047
+ * one carrying the calling chat_id. Default `false`
1048
+ * preserves the prior single-session contract.
1049
+ */
1050
+ readonly walkParents?: boolean;
1051
+ /**
1052
+ * When true AND `sessionId`'s session has a non-null
1053
+ * `conversation_id`, also return tdd_tasks belonging to
1054
+ * any OTHER session sharing that `conversation_id` — the
1055
+ * detached-session fallback (issue #144). A session with
1056
+ * a null `conversation_id` never triggers this fallback.
1057
+ * Rows are ordered so a task owned by an `agent_kind =
1058
+ * 'main'` session sorts first, then by `started_at DESC`.
1059
+ * Default `false` preserves the prior contract.
1060
+ */
1061
+ readonly walkConversation?: boolean;
1062
+ }) => Effect.Effect<ReadonlyArray<TddTaskSummary>, DataStoreError>;
1063
+ /**
1064
+ * Diagnostic for the `missing_artifact_evidence` phase-transition
1065
+ * denial (issue #144): counts `tdd_artifacts` rows recorded at or
1066
+ * after `sinceIso` under sessions OTHER than the one that opened
1067
+ * `tddTaskId`, but sharing that session's `conversation_id`. Used
1068
+ * to tell an agent "your hooks may be attributing to a detached
1069
+ * session" rather than a bare "no artifact found". Returns 0 when
1070
+ * `tddTaskId` is unknown or its session's `conversation_id` is
1071
+ * null — the diagnostic never fabricates a signal it cannot back.
1072
+ */
1073
+ readonly countRecentArtifactsInOtherSessionsOfConversation: (input: {
1074
+ readonly tddTaskId: number;
1075
+ readonly sinceIso: string;
1076
+ }) => Effect.Effect<number, DataStoreError>;
1077
+ /**
1078
+ * List artifacts recorded for a TDD task, optionally filtered
1079
+ * by `artifactKind`, `phaseId`, or `behaviorId`. Returns rows in
1080
+ * recorded_at DESC order so the most recently captured artifact
1081
+ * (the typical citation target for a phase transition) appears
1082
+ * first. `limit` defaults to 50.
1083
+ */
1084
+ readonly listTddArtifactsForTask: (input: {
1085
+ readonly tddTaskId: number;
1086
+ readonly artifactKind?: ArtifactKind$1;
1087
+ readonly phaseId?: number;
1088
+ readonly behaviorId?: number;
1089
+ readonly limit?: number;
1090
+ }) => Effect.Effect<ReadonlyArray<TddArtifactRow>, DataStoreError>;
1091
+ readonly listHypotheses: (options: {
1092
+ readonly sessionId?: number;
1093
+ readonly outcome?: "confirmed" | "refuted" | "abandoned" | "open";
1094
+ readonly limit?: number;
1095
+ }) => Effect.Effect<ReadonlyArray<HypothesisDetail>, DataStoreError>;
1096
+ readonly findIdempotentResponse: (procedurePath: string, key: string) => Effect.Effect<Option.Option<string>, DataStoreError>;
1097
+ readonly getLatestTestCaseForSession: (chatId: string) => Effect.Effect<Option.Option<number>, DataStoreError>;
1098
+ /**
1099
+ * Returns one `TagInventoryRow` per `(tag, project)` pair observed in
1100
+ * each project's latest test run. When `project` is supplied, results
1101
+ * are restricted to that project's latest run.
1102
+ */
1103
+ readonly listTagInventory: (options?: {
1104
+ readonly project?: string;
1105
+ }) => Effect.Effect<ReadonlyArray<TagInventoryRow>, DataStoreError>;
1106
+ /**
1107
+ * Returns every `TestListEntry` from the latest run of each project
1108
+ * (or the specified project) whose test case carries `tag`.
1109
+ */
1110
+ readonly listTestsForTag: (tag: string, options?: {
1111
+ readonly project?: string;
1112
+ }) => Effect.Effect<ReadonlyArray<TestListEntry>, DataStoreError>;
1113
+ }>;
1114
+ /** @public */
1115
+ export declare class DataReader extends DataReader_base {}
1116
+ //#endregion
1117
+ //#region src/layers/DataReaderLive.d.ts
1118
+ /** @public */
1119
+ export declare const DataReaderLive: Layer.Layer<DataReader, never, SqlClient>;
1120
+ //#endregion
1121
+ //#region src/layers/DataStoreLive.d.ts
1122
+ /** @public */
1123
+ export declare const DataStoreLive: Layer.Layer<DataStore, never, SqlClient>;
1124
+ //#endregion
1125
+ //#region src/services/DetailResolver.d.ts
1126
+ /** @public */
1127
+ export interface RunHealth {
1128
+ readonly hasFailures: boolean;
1129
+ readonly belowTargets: boolean;
1130
+ readonly hasTargets?: boolean;
1131
+ }
1132
+ declare const DetailResolver_base: Context.ServiceClass<DetailResolver, "vitest-agent/DetailResolver", {
1133
+ readonly resolve: (executor: Executor, health: RunHealth, explicit?: DetailLevel) => Effect.Effect<DetailLevel>;
1134
+ }>;
1135
+ /** @public */
1136
+ export declare class DetailResolver extends DetailResolver_base {}
1137
+ //#endregion
1138
+ //#region src/layers/DetailResolverLive.d.ts
1139
+ /** @public */
1140
+ export declare const DetailResolverLive: Layer.Layer<DetailResolver, never, never>;
1141
+ //#endregion
1142
+ //#region src/services/DiscoveryRegistry.d.ts
1143
+ /**
1144
+ * Input for upserting a known project into the global discovery registry.
1145
+ *
1146
+ * @public
1147
+ */
1148
+ export interface KnownProjectInput {
1149
+ readonly projectKey: string;
1150
+ readonly canonicalForm: string;
1151
+ readonly dataDbPath: string;
1152
+ readonly gitRemoteOrigin: string | null;
1153
+ readonly workspaceRoot: string;
1154
+ }
1155
+ /**
1156
+ * A project record as stored in the global discovery registry.
1157
+ *
1158
+ * @public
1159
+ */
1160
+ export interface KnownProject {
1161
+ readonly projectKey: string;
1162
+ readonly canonicalForm: string;
1163
+ readonly dataDbPath: string;
1164
+ readonly gitRemoteOrigin: string | null;
1165
+ readonly workspaceRoot: string;
1166
+ readonly firstSeenAt: number;
1167
+ readonly lastSeenAt: number;
1168
+ }
1169
+ declare const DiscoveryRegistry_base: Context.ServiceClass<DiscoveryRegistry, "vitest-agent/DiscoveryRegistry", {
1170
+ /**
1171
+ * Upsert this project into the registry. Sets `first_seen_at` on
1172
+ * insert; updates `last_seen_at` plus all mutable fields on
1173
+ * conflict. Returns nothing — the call is fire-and-observe.
1174
+ */
1175
+ readonly recordProject: (input: KnownProjectInput) => Effect.Effect<void, DataStoreError>;
1176
+ /**
1177
+ * List all projects ordered by most recent activity first. Used by
1178
+ * cross-project discovery tooling.
1179
+ */
1180
+ readonly listProjects: () => Effect.Effect<ReadonlyArray<KnownProject>, DataStoreError>;
1181
+ /**
1182
+ * Drop registry rows whose `last_seen_at` is older than `maxAgeDays`
1183
+ * days ago. The corresponding `data.db` files are NOT deleted; only
1184
+ * the index entry is pruned. Returns the count of removed rows.
1185
+ */
1186
+ readonly prune: (maxAgeDays: number) => Effect.Effect<number, DataStoreError>;
1187
+ }>;
1188
+ /** @public */
1189
+ export declare class DiscoveryRegistry extends DiscoveryRegistry_base {}
1190
+ //#endregion
1191
+ //#region src/layers/DiscoveryRegistryLive.d.ts
1192
+ /** @public */
1193
+ export declare const DiscoveryRegistryLive: Layer.Layer<DiscoveryRegistry, never, SqlClient>;
1194
+ //#endregion
1195
+ //#region src/services/EnvironmentDetector.d.ts
1196
+ declare const EnvironmentDetector_base: Context.ServiceClass<EnvironmentDetector, "vitest-agent/EnvironmentDetector", {
1197
+ readonly detect: () => Effect.Effect<Environment>;
1198
+ readonly isAgent: Effect.Effect<boolean>;
1199
+ readonly agentName: Effect.Effect<string | undefined>;
1200
+ }>;
1201
+ /** @public */
1202
+ export declare class EnvironmentDetector extends EnvironmentDetector_base {}
1203
+ //#endregion
1204
+ //#region src/layers/EnvironmentDetectorLive.d.ts
1205
+ /**
1206
+ * Pure classification behind {@link EnvironmentDetectorLive}: an agent shell
1207
+ * wins, then GitHub Actions, then generic CI, else a terminal.
1208
+ *
1209
+ * @param env - the environment map to consult
1210
+ * @param agentShell - whether the process runs under an AI agent (`std-env`'s `isAgent`)
1211
+ * @public
1212
+ */
1213
+ export declare const classifyEnvironment: (env: Record<string, string | undefined>, agentShell: boolean) => Environment;
1214
+ /**
1215
+ * Live environment detector. CI detection reads `GITHUB_ACTIONS` / `CI`
1216
+ * from the injected `env` map; agent detection comes from `std-env`.
1217
+ *
1218
+ * @param env - the environment map to consult (the front end passes `process.env`)
1219
+ * @public
1220
+ */
1221
+ export declare const EnvironmentDetectorLive: (env: Record<string, string | undefined>) => Layer.Layer<EnvironmentDetector>;
1222
+ //#endregion
1223
+ //#region src/layers/EnvironmentDetectorTest.d.ts
1224
+ /** @public */
1225
+ export declare const EnvironmentDetectorTest: {
1226
+ layer: (env?: Environment) => Layer.Layer<EnvironmentDetector, never, never>;
1227
+ };
1228
+ //#endregion
1229
+ //#region src/services/ExecutorResolver.d.ts
1230
+ declare const ExecutorResolver_base: Context.ServiceClass<ExecutorResolver, "vitest-agent/ExecutorResolver", {
1231
+ readonly resolve: (env: Environment) => Effect.Effect<Executor>;
1232
+ }>;
1233
+ /** @public */
1234
+ export declare class ExecutorResolver extends ExecutorResolver_base {}
1235
+ //#endregion
1236
+ //#region src/layers/ExecutorResolverLive.d.ts
1237
+ /** @public */
1238
+ export declare const ExecutorResolverLive: Layer.Layer<ExecutorResolver, never, never>;
1239
+ //#endregion
1240
+ //#region src/services/FormatSelector.d.ts
1241
+ declare const FormatSelector_base: Context.ServiceClass<FormatSelector, "vitest-agent/FormatSelector", {
1242
+ readonly select: (executor: Executor, explicitFormat?: OutputFormat, environment?: Environment) => Effect.Effect<OutputFormat>;
1243
+ }>;
1244
+ /** @public */
1245
+ export declare class FormatSelector extends FormatSelector_base {}
1246
+ //#endregion
1247
+ //#region src/layers/FormatSelectorLive.d.ts
1248
+ /**
1249
+ * Default format dispatch:
1250
+ *
1251
+ * - GitHub Actions CI executor: `ci-annotations` (renders as `::error::`).
1252
+ * - Human executor: `silent` (Vitest's own reporters handle the user
1253
+ * experience; we just write to the database).
1254
+ * - Anyone else (agent-shell, terminal-bound CI): `terminal` — plain
1255
+ * text + ANSI color, no markdown syntax in the place that doesn't
1256
+ * render it. Markdown stays available via explicit `format: "markdown"`
1257
+ * for surfaces that *do* render it (MCP tools, GitHub step summary).
1258
+ * @public
1259
+ */
1260
+ export declare const FormatSelectorLive: Layer.Layer<FormatSelector, never, never>;
1261
+ //#endregion
1262
+ //#region src/services/HistoryTracker.d.ts
1263
+ /**
1264
+ * Lightweight test outcome for history classification.
1265
+ * @public
1266
+ */
1267
+ export interface TestOutcome {
1268
+ readonly modulePath: string;
1269
+ readonly fullName: string;
1270
+ readonly state: "passed" | "failed";
1271
+ }
1272
+ /**
1273
+ * Builds the composite (modulePath, fullName) key used to key the internal
1274
+ * testMap and the returned classifications Map, so identically-named tests
1275
+ * in different files classify independently instead of colliding.
1276
+ *
1277
+ * Uses `JSON.stringify` for an injective encoding: a plain delimiter such as
1278
+ * a space is not collision-proof (e.g. `("a b", "c")` and `("a", "b c")` would
1279
+ * both yield `"a b c"`), which would reintroduce the very collision class this
1280
+ * key exists to prevent.
1281
+ * @public
1282
+ */
1283
+ export declare const historyKey: (modulePath: string, fullName: string) => string;
1284
+ declare const HistoryTracker_base: Context.ServiceClass<HistoryTracker, "vitest-agent/HistoryTracker", {
1285
+ readonly classify: (project: string, testOutcomes: ReadonlyArray<TestOutcome>, timestamp: string) => Effect.Effect<{
1286
+ history: HistoryRecord;
1287
+ classifications: Map<string, TestClassification>;
1288
+ }, DataStoreError>;
1289
+ }>;
1290
+ /** @public */
1291
+ export declare class HistoryTracker extends HistoryTracker_base {}
1292
+ //#endregion
1293
+ //#region src/layers/HistoryTrackerLive.d.ts
1294
+ /** @public */
1295
+ export declare const HistoryTrackerLive: Layer.Layer<HistoryTracker, never, DataReader>;
1296
+ //#endregion
1297
+ //#region src/layers/HistoryTrackerTest.d.ts
1298
+ /** @public */
1299
+ export interface HistoryTrackerTestState {
1300
+ readonly classifyCalls: Array<{
1301
+ project: string;
1302
+ timestamp: string;
1303
+ }>;
1304
+ }
1305
+ /** @public */
1306
+ export declare const HistoryTrackerTest: {
1307
+ readonly empty: () => HistoryTrackerTestState;
1308
+ readonly layer: (state: HistoryTrackerTestState, cannedResult?: {
1309
+ history: HistoryRecord;
1310
+ classifications: Map<string, TestClassification>;
1311
+ }) => Layer.Layer<HistoryTracker>;
1312
+ };
1313
+ //#endregion
1314
+ //#region src/layers/LoggerLive.d.ts
1315
+ /**
1316
+ * Create a structured JSON (NDJSON) logger layer for stderr.
1317
+ *
1318
+ * When level is undefined or `"None"`, installs an empty logger set (silent).
1319
+ * When logFile is set, composes the stderr logger with a file logger.
1320
+ * Uses `Logger.formatJson` / `Logger.formatStructured` for machine-readable
1321
+ * output.
1322
+ * @public
1323
+ */
1324
+ export declare const LoggerLive: (level?: LogLevel.LogLevel, logFile?: string) => Layer.Layer<never>;
1325
+ /**
1326
+ * Resolve log level from option or environment variable.
1327
+ * Priority: explicit option \> `VITEST_REPORTER_LOG_LEVEL` in `env` \> undefined.
1328
+ *
1329
+ * @param env - the environment map to consult (the front end passes `process.env`)
1330
+ * @param option - explicit override
1331
+ * @public
1332
+ */
1333
+ export declare function resolveLogLevel(env: Record<string, string | undefined>, option?: string): LogLevel.LogLevel | undefined;
1334
+ /**
1335
+ * Resolve log file from option or environment variable
1336
+ * (`VITEST_REPORTER_LOG_FILE` in `env`).
1337
+ *
1338
+ * @param env - the environment map to consult (the front end passes `process.env`)
1339
+ * @param option - explicit override
1340
+ * @public
1341
+ */
1342
+ export declare function resolveLogFile(env: Record<string, string | undefined>, option?: string): string | undefined;
1343
+ //#endregion
1344
+ //#region src/layers/OutputPipelineLive.d.ts
1345
+ /**
1346
+ * The output pipeline: environment detection, executor resolution, format
1347
+ * selection, detail resolution and rendering.
1348
+ *
1349
+ * @param env - the environment map `EnvironmentDetectorLive` consults
1350
+ * (the front end passes `process.env`)
1351
+ * @public
1352
+ */
1353
+ export declare const OutputPipelineLive: (env: Record<string, string | undefined>) => Layer.Layer<DetailResolver | EnvironmentDetector | ExecutorResolver | FormatSelector | OutputRenderer, never, never>;
1354
+ //#endregion
1355
+ //#region src/services/OutputRenderer.d.ts
1356
+ declare const OutputRenderer_base: Context.ServiceClass<OutputRenderer, "vitest-agent/OutputRenderer", {
1357
+ readonly render: (reports: ReadonlyArray<AgentReport>, format: OutputFormat, context: FormatterContext) => Effect.Effect<ReadonlyArray<RenderedOutput>>;
1358
+ }>;
1359
+ /** @public */
1360
+ export declare class OutputRenderer extends OutputRenderer_base {}
1361
+ //#endregion
1362
+ //#region src/layers/OutputRendererLive.d.ts
1363
+ /** @public */
1364
+ export declare const OutputRendererLive: Layer.Layer<OutputRenderer, never, never>;
1365
+ //#endregion
1366
+ //#region src/layers/PathResolutionLive.d.ts
1367
+ /**
1368
+ * The XDG namespace every vitest-agent data directory lives under —
1369
+ * `<XDG data>/vitest-agent`. The one place the name exists.
1370
+ * @public
1371
+ */
1372
+ export declare const APP_NAMESPACE = "vitest-agent";
1373
+ /**
1374
+ * Composite layer providing every service `resolveDataPath` requires:
1375
+ * `AppDirs` (XDG path resolution), `VitestAgentConfigFile` (TOML
1376
+ * config loader), and `WorkspaceDiscovery` / `WorkspaceRoot` (workspace name
1377
+ * lookup).
1378
+ *
1379
+ * Callers still need to provide `FileSystem` and `Path` from
1380
+ * `@effect/platform-node`'s `NodeServices.layer` (or the equivalent on Bun).
1381
+ *
1382
+ * `WorkspaceDiscovery` is pinned to `projectDir` as its `cwd`, which sets the
1383
+ * root for the layer-bound methods (`listPackages`, `info`, `refresh`). The
1384
+ * per-root methods (`listPackagesIn`, `infoIn`, `refreshIn`) take a directory
1385
+ * per call and ignore that pin — `resolveWorkspaceKey` and
1386
+ * `ProjectIdentityLive` use them, so a long-lived host built against one root
1387
+ * still answers correctly for a git worktree or an unrelated project.
1388
+ *
1389
+ * @param projectDir - Absolute path inside the user's workspace, used to
1390
+ * anchor the config file resolvers and workspace discovery.
1391
+ * @public
1392
+ */
1393
+ export declare const PathResolutionLive: (projectDir: string) => Layer.Layer<AppDirs | VitestAgentConfigFile | WorkspaceDiscovery, import("@effected/xdg").XdgEnvError, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
1394
+ //#endregion
1395
+ //#region src/services/PerClientSessionMap.d.ts
1396
+ /** @public */
1397
+ export interface MapSessionInput {
1398
+ readonly hostSessionId: string;
1399
+ readonly conversationId: string;
1400
+ readonly projectKey: string;
1401
+ readonly projectDir: string;
1402
+ }
1403
+ /** @public */
1404
+ export interface MapSessionOutput {
1405
+ readonly mainAgentId: string;
1406
+ readonly conversationId: string;
1407
+ }
1408
+ /** @public */
1409
+ export interface SessionContextRow {
1410
+ readonly hostSessionId: string;
1411
+ readonly conversationId: string;
1412
+ readonly projectKey: string;
1413
+ readonly projectDir: string;
1414
+ readonly mainAgentId: string;
1415
+ readonly startedAt: number;
1416
+ readonly endedAt: number | null;
1417
+ }
1418
+ declare const PerClientSessionMapReader_base: Context.ServiceClass<PerClientSessionMapReader, "vitest-agent/PerClientSessionMapReader", {
1419
+ /**
1420
+ * Look up an existing conversation_id for a given transcript
1421
+ * path. Returns `Option.none()` when the transcript hasn't been
1422
+ * seen before. Read-only — does not insert.
1423
+ */
1424
+ readonly lookupConversation: (transcriptPath: string) => Effect.Effect<Option.Option<string>, DataStoreError>;
1425
+ /**
1426
+ * Return the most recent open session for a project_dir
1427
+ * (`ended_at IS NULL`). The MCP server uses this to recover
1428
+ * `currentSessionContext` after `/reload-plugins`. The compound
1429
+ * index `idx_session_map_active` covers the predicate.
1430
+ */
1431
+ readonly lookupByProjectDir: (projectDir: string) => Effect.Effect<Option.Option<SessionContextRow>, DataStoreError>;
1432
+ }>;
1433
+ /**
1434
+ * Read-only side of the session map.
1435
+ *
1436
+ * Provided by `PerClientSessionMapReaderLive` (opens SQLite with
1437
+ * `?mode=ro`). MCP server depends on this tag — calls to write
1438
+ * methods would be a type error.
1439
+ * @public
1440
+ */
1441
+ export declare class PerClientSessionMapReader extends PerClientSessionMapReader_base {}
1442
+ declare const PerClientSessionMapWriter_base: Context.ServiceClass<PerClientSessionMapWriter, "vitest-agent/PerClientSessionMapWriter", {
1443
+ /**
1444
+ * Upsert a conversation row. Returns the canonical conversation_id
1445
+ * for the given transcript_path (existing if seen before, freshly
1446
+ * generated otherwise).
1447
+ */
1448
+ readonly mapConversation: (transcriptPath: string) => Effect.Effect<string, DataStoreError>;
1449
+ /**
1450
+ * Upsert a session row. Returns the canonical main_agent_id and
1451
+ * conversation_id (existing if `host_session_id` was seen before,
1452
+ * freshly generated otherwise).
1453
+ *
1454
+ * The caller is responsible for having already mapped the
1455
+ * conversation; this method only records the
1456
+ * (host_session_id, conversation_id, project) tuple.
1457
+ */
1458
+ readonly mapSession: (input: MapSessionInput) => Effect.Effect<MapSessionOutput, DataStoreError>;
1459
+ /**
1460
+ * Mark a session as ended. Sets `ended_at` to the supplied
1461
+ * timestamp. No-op if the session is unknown — endSession is
1462
+ * best-effort cleanup.
1463
+ */
1464
+ readonly endSession: (hostSessionId: string, endedAt: number) => Effect.Effect<void, DataStoreError>;
1465
+ /**
1466
+ * Read methods so the Writer also satisfies the Reader tag's
1467
+ * surface.
1468
+ */
1469
+ readonly lookupConversation: (transcriptPath: string) => Effect.Effect<Option.Option<string>, DataStoreError>;
1470
+ readonly lookupByProjectDir: (projectDir: string) => Effect.Effect<Option.Option<SessionContextRow>, DataStoreError>;
1471
+ }>;
1472
+ /**
1473
+ * Read-write side of the session map. Sidecar provides this; the
1474
+ * Writer layer also satisfies the Reader tag so consumers of either
1475
+ * one resolve.
1476
+ * @public
1477
+ */
1478
+ export declare class PerClientSessionMapWriter extends PerClientSessionMapWriter_base {}
1479
+ //#endregion
1480
+ //#region src/layers/PerClientSessionMapLive.d.ts
1481
+ /**
1482
+ * Read-only layer. The entry point provides an `SqlClient` configured
1483
+ * with the `?mode=ro` URI parameter; this layer wraps the read
1484
+ * methods and never declares write methods.
1485
+ * @public
1486
+ */
1487
+ export declare const PerClientSessionMapReaderLive: Layer.Layer<PerClientSessionMapReader, never, SqlClient>;
1488
+ /**
1489
+ * Read-write layer. Provides both write methods and the Reader's read
1490
+ * methods so the same layer instance satisfies callers of either
1491
+ * tag.
1492
+ * @public
1493
+ */
1494
+ export declare const PerClientSessionMapWriterLive: Layer.Layer<PerClientSessionMapWriter | PerClientSessionMapReader, never, SqlClient>;
1495
+ //#endregion
1496
+ //#region src/services/ProjectDiscovery.d.ts
1497
+ /** @public */
1498
+ export interface TestFileEntry {
1499
+ readonly testFile: string;
1500
+ readonly sourceFiles: ReadonlyArray<string>;
1501
+ }
1502
+ declare const ProjectDiscovery_base: Context.ServiceClass<ProjectDiscovery, "vitest-agent/ProjectDiscovery", {
1503
+ readonly discoverTestFiles: (rootDir: string) => Effect.Effect<ReadonlyArray<TestFileEntry>, DiscoveryError>;
1504
+ readonly mapTestToSource: (testFile: string) => Effect.Effect<ReadonlyArray<string>, DiscoveryError>;
1505
+ }>;
1506
+ /** @public */
1507
+ export declare class ProjectDiscovery extends ProjectDiscovery_base {}
1508
+ //#endregion
1509
+ //#region src/layers/ProjectDiscoveryLive.d.ts
1510
+ /** @public */
1511
+ export declare const ProjectDiscoveryLive: Layer.Layer<ProjectDiscovery, never, FileSystem.FileSystem>;
1512
+ //#endregion
1513
+ //#region src/layers/ProjectDiscoveryTest.d.ts
1514
+ /** @public */
1515
+ export declare const ProjectDiscoveryTest: {
1516
+ readonly layer: (entries: ReadonlyArray<TestFileEntry>) => Layer.Layer<ProjectDiscovery>;
1517
+ };
1518
+ //#endregion
1519
+ //#region src/services/ProjectIdentity.d.ts
1520
+ /**
1521
+ * Result of a successful identity resolution.
1522
+ *
1523
+ * - `projectKey` — filesystem-safe single segment for the per-project
1524
+ * data store directory under `$XDG_DATA_HOME/vitest-agent/`.
1525
+ * - `canonicalForm` — human-readable form for display in the discovery
1526
+ * registry. Equal to `projectKey` for non-git sources; for git
1527
+ * sources, the original `host/path` shape (with slashes preserved).
1528
+ * - `source` — which source matched. Useful for diagnostics and the
1529
+ * `vitest-agent doctor`-style commands.
1530
+ * @public
1531
+ */
1532
+ export interface ResolvedIdentity {
1533
+ readonly projectKey: string;
1534
+ readonly canonicalForm: string;
1535
+ readonly source: ProjectIdentitySource;
1536
+ }
1537
+ /** @public */
1538
+ export type ProjectIdentitySource = "explicit" | "toml" | "git-remote" | "package-repository" | "package-name";
1539
+ /**
1540
+ * Per-source candidate values. Each is optional — an absent or empty
1541
+ * value causes the resolver to fall through to the next source.
1542
+ *
1543
+ * The Live layer collects these from real I/O (config file, git
1544
+ * subprocess, `package.json` read). Tests pass a literal object.
1545
+ * @public
1546
+ */
1547
+ export interface ProjectIdentityCandidates {
1548
+ readonly explicit?: string;
1549
+ readonly toml?: string;
1550
+ readonly gitRemote?: string;
1551
+ readonly packageJsonRepoUrl?: string;
1552
+ readonly packageJsonName?: string;
1553
+ }
1554
+ /**
1555
+ * Options accepted by the `ProjectIdentity.resolve` service method.
1556
+ *
1557
+ * `projectId` is the priority-1 escape hatch — pass when the user has
1558
+ * configured `AgentPlugin({ projectId: "..." })` in `vitest.config.ts`.
1559
+ * @public
1560
+ */
1561
+ export interface ResolveProjectIdentityOptions {
1562
+ readonly projectId?: string;
1563
+ }
1564
+ /**
1565
+ * Pure priority resolver. Returns `null` when no candidate produces a
1566
+ * usable value — the caller wraps `null` into a tagged error.
1567
+ *
1568
+ * For non-git sources the `canonicalForm` equals the original
1569
+ * (un-normalized) input so the discovery registry can display
1570
+ * `@spencerbeggs/vitest-agent` rather than the underscored form. For
1571
+ * git sources, `canonicalForm` is the slash-preserving `host/path`
1572
+ * shape from `canonicalizeGitUrl`.
1573
+ * @public
1574
+ */
1575
+ export declare const resolveProjectIdentityFromCandidates: (candidates: ProjectIdentityCandidates) => ResolvedIdentity | null;
1576
+ declare const ProjectIdentity_base: Context.ServiceClass<ProjectIdentity, "vitest-agent/ProjectIdentity", {
1577
+ readonly resolve: (workspaceRoot: string, options?: ResolveProjectIdentityOptions) => Effect.Effect<ResolvedIdentity, ProjectIdentityNotResolvableError>;
1578
+ }>;
1579
+ /**
1580
+ * Service tag. The Live layer (in `layers/ProjectIdentityLive.ts`)
1581
+ * wires up the I/O sources; tests provide a stub that returns a
1582
+ * pre-built `ResolvedIdentity`.
1583
+ * @public
1584
+ */
1585
+ export declare class ProjectIdentity extends ProjectIdentity_base {}
1586
+ //#endregion
1587
+ //#region src/layers/ProjectIdentityLive.d.ts
1588
+ /**
1589
+ * Effect environment type required by `collectCandidates` and the
1590
+ * `ProjectIdentityLive` layer. Exported only so the layer's
1591
+ * `Layer.Layer<ProjectIdentity, never, CandidateContext>` signature
1592
+ * has a named referent — consumers should provide the four named
1593
+ * services (FileSystem, WorkspaceDiscovery, VitestAgentConfigFile,
1594
+ * CommandExecutor) rather than reference this type directly.
1595
+ *
1596
+ * @public
1597
+ */
1598
+ export type CandidateContext = FileSystem.FileSystem | WorkspaceDiscovery | VitestAgentConfigFile | ChildProcessSpawner.ChildProcessSpawner;
1599
+ /**
1600
+ * Live layer that wires the resolver into real I/O. Requires
1601
+ * `FileSystem`, `CommandExecutor`, `WorkspaceDiscovery`, and
1602
+ * `VitestAgentConfigFile`. The platform context comes from
1603
+ * `NodeServices.layer` at the entry point.
1604
+ * @public
1605
+ */
1606
+ export declare const ProjectIdentityLive: Layer.Layer<ProjectIdentity, never, CandidateContext>;
1607
+ /**
1608
+ * Build a Test layer that returns a fixed `ResolvedIdentity` (or
1609
+ * fails with `ProjectIdentityNotResolvableError`). Use in unit tests
1610
+ * that depend on `ProjectIdentity` but don't want to wire upstream
1611
+ * services.
1612
+ * @public
1613
+ */
1614
+ export declare const ProjectIdentityTest: (result: ResolvedIdentity | ProjectIdentityNotResolvableError) => Layer.Layer<ProjectIdentity, never, never>;
1615
+ //#endregion
1616
+ //#region src/services/RunContext.d.ts
1617
+ declare const RunContext_base: Schema.Class<RunContext, Schema.Struct<{
1618
+ readonly gitBranch: Schema.NullOr<Schema.String>;
1619
+ readonly gitCommitSha: Schema.NullOr<Schema.String>;
1620
+ readonly gitDirty: Schema.NullOr<Schema.Boolean>;
1621
+ readonly gitUpstream: Schema.NullOr<Schema.String>;
1622
+ readonly gitWorktreeDir: Schema.NullOr<Schema.String>;
1623
+ readonly hostSource: Schema.NullOr<Schema.String>;
1624
+ readonly hostValue: Schema.NullOr<Schema.String>;
1625
+ readonly hostMetadata: Schema.NullOr<Schema.Unknown>;
1626
+ }>, {}>;
1627
+ /**
1628
+ * Per-run snapshot of the workspace's git state and host context.
1629
+ * Every field is nullable: a non-git workspace has all-NULL git
1630
+ * fields, a CI run with no terminal probe match has all-NULL host
1631
+ * fields, and a worker that can't read upstream info has a NULL
1632
+ * `gitUpstream` while everything else is set.
1633
+ *
1634
+ * Declared as a `Schema.Class` so callers can `new RunContext({...})`
1635
+ * and `Schema.encode(...)` for the SQLite row mapping.
1636
+ * @public
1637
+ */
1638
+ export declare class RunContext extends RunContext_base {}
1639
+ declare const AgentContext_base: Schema.Class<AgentContext, Schema.Struct<{
1640
+ readonly startGitBranch: Schema.NullOr<Schema.String>;
1641
+ readonly startGitCommitSha: Schema.NullOr<Schema.String>;
1642
+ readonly startWorktreeDir: Schema.NullOr<Schema.String>;
1643
+ }>, {}>;
1644
+ /**
1645
+ * Subset of {@link RunContext} captured at agent registration. Only
1646
+ * the inheritable git context — branch, sha, worktree path. Mid-run
1647
+ * dirty-tree state and upstream tracking are per-run concerns.
1648
+ * @public
1649
+ */
1650
+ export declare class AgentContext extends AgentContext_base {}
1651
+ declare const RunContext$_base: Context.ServiceClass<RunContext$, "vitest-agent/RunContextService", {
1652
+ readonly captureRunContext: (cwd: string) => Effect.Effect<RunContext>;
1653
+ readonly captureAgentContext: (cwd: string) => Effect.Effect<AgentContext>;
1654
+ }>;
1655
+ /**
1656
+ * Service tag. The Live layer captures real I/O; the Test layer
1657
+ * returns whatever the test fixture passes.
1658
+ * @public
1659
+ */
1660
+ export declare class RunContext$ extends RunContext$_base {}
1661
+ /**
1662
+ * Re-export the service tag under a less-collision-prone name. The
1663
+ * `RunContext` Schema.Class above shares its symbol-name with the
1664
+ * service tag concept; the `$` suffix on the Context.Tag class name
1665
+ * keeps both addressable from the same module.
1666
+ *
1667
+ * @public
1668
+ */
1669
+ export declare const RunContextService: typeof RunContext$;
1670
+ /** @public */
1671
+ export type RunContextService = RunContext$;
1672
+ //#endregion
1673
+ //#region src/layers/RunContextLive.d.ts
1674
+ /**
1675
+ * Live layer. Requires `ChildProcessSpawner` (provided by
1676
+ * `NodeServices.layer` at the entry point). Host-metadata probes read
1677
+ * the injected `env` map — the env walk is pure and the map is captured
1678
+ * once when the layer is built.
1679
+ *
1680
+ * @param env - the environment map to probe (the front end passes `process.env`)
1681
+ * @public
1682
+ */
1683
+ export declare const RunContextLive: (env: Record<string, string | undefined>) => Layer.Layer<RunContextService, never, ChildProcessSpawner.ChildProcessSpawner>;
1684
+ /**
1685
+ * Build a Test layer that returns fixed `RunContext` and
1686
+ * `AgentContext` values regardless of `cwd`.
1687
+ * @public
1688
+ */
1689
+ export declare const RunContextTest: (fixture: {
1690
+ readonly runContext: RunContext;
1691
+ readonly agentContext: AgentContext;
1692
+ }) => Layer.Layer<RunContextService, never, never>;
1693
+ //#endregion
1694
+ //#region src/lib/format-triage.d.ts
1695
+ /** @public */
1696
+ interface FormatTriageOptions {
1697
+ readonly project?: string;
1698
+ readonly maxLines?: number;
1699
+ }
1700
+ /**
1701
+ * Generates an orientation triage markdown string for LLM agents.
1702
+ * Summarises recent test runs, active sessions, acceptance metrics,
1703
+ * and (forward-compat) the most recent TDD session.
1704
+ *
1705
+ * Error channel is `never` — all DataReader errors are swallowed and
1706
+ * replaced with empty defaults so the caller is guaranteed a string.
1707
+ * @public
1708
+ */
1709
+ export declare const formatTriageEffect: (options?: FormatTriageOptions) => Effect.Effect<string, never, DataReader>;
1710
+ //#endregion
1711
+ //#region src/lib/format-wrapup.d.ts
1712
+ /** @public */
1713
+ type WrapupKind = "stop" | "session_end" | "pre_compact" | "tdd_handoff" | "user_prompt_nudge";
1714
+ /** @public */
1715
+ interface FormatWrapupOptions {
1716
+ readonly sessionId?: number;
1717
+ readonly chatId?: string;
1718
+ readonly kind: WrapupKind;
1719
+ readonly userPromptHint?: string;
1720
+ }
1721
+ /** @public */
1722
+ export declare const formatWrapupEffect: (options: FormatWrapupOptions) => Effect.Effect<string, never, DataReader>;
1723
+ //#endregion
1724
+ //#region src/migrations/0001_initial.d.ts
1725
+ /** @internal */
1726
+ declare const migration: Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient>;
1727
+ //#endregion
1728
+ //#region src/migrations/0002_test_artifacts.d.ts
1729
+ /** @internal */
1730
+ declare const migration$1: Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient>;
1731
+ //#endregion
1732
+ //#region src/migrations/index.d.ts
1733
+ /**
1734
+ * Every migration that must run against a per-project `data.db`, keyed by
1735
+ * migration id in application order.
1736
+ *
1737
+ * This is the single source of truth for the project database's migration
1738
+ * set: `makeSqliteStack` (and through it `PlatformLive`, `ensureMigrated`,
1739
+ * the testing layers, `ReporterLive` and `SidecarLive`) defaults to it when
1740
+ * calling `SqliteMigrator.fromRecord`, so adding a migration file and
1741
+ * registering it here is enough to reach every process that opens a project
1742
+ * database.
1743
+ *
1744
+ * The session-map and discovery-registry databases are separate schemas with
1745
+ * their own migrations and are deliberately not listed here.
1746
+ *
1747
+ * @public
1748
+ */
1749
+ export declare const PROJECT_MIGRATIONS: {
1750
+ readonly "0001_initial": import("effect/Effect").Effect<void, import("effect/unstable/sql/SqlError").SqlError, import("effect/unstable/sql/SqlClient").SqlClient>;
1751
+ readonly "0002_test_artifacts": import("effect/Effect").Effect<void, import("effect/unstable/sql/SqlError").SqlError, import("effect/unstable/sql/SqlClient").SqlClient>;
1752
+ };
1753
+ //#endregion
1754
+ //#region src/migrations/registry_0001_initial.d.ts
1755
+ /**
1756
+ * Migration for the global discovery registry SQLite at
1757
+ * `$XDG_DATA_HOME/vitest-agent/registry.db`.
1758
+ *
1759
+ * Single table `known_projects` indexed by `project_key` (the
1760
+ * filesystem-safe form from {@link ProjectIdentity}). Tooling like
1761
+ * `mcp-app` queries this table to enumerate every vitest-agent
1762
+ * project the user has ever run on this machine.
1763
+ *
1764
+ * The registry never blocks anything — its writes are best-effort.
1765
+ * Concurrent writers from multiple Claude Code windows converge via
1766
+ * the `ON CONFLICT(project_key) DO UPDATE` upsert.
1767
+ * @public
1768
+ */
1769
+ declare const migration$2: Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient>;
1770
+ //#endregion
1771
+ //#region src/migrations/session_map_0001_initial.d.ts
1772
+ /** @internal */
1773
+ declare const migration$3: Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient>;
1774
+ //#endregion
1775
+ //#region src/platform.d.ts
1776
+ /**
1777
+ * A migration set in the shape `SqliteMigrator.fromRecord` accepts: migration
1778
+ * id → loader.
1779
+ * @public
1780
+ */
1781
+ export type MigrationRecord = Record<string, Effect.Effect<void, unknown, SqlClient>>;
1782
+ /**
1783
+ * A SQLite connection plus the migrator that brings it to the head of a
1784
+ * migration set. Returned by {@link makeSqliteStack}.
1785
+ * @public
1786
+ */
1787
+ export interface SqliteStack {
1788
+ /** The `SqlClient` layer for `filename`. */
1789
+ readonly SqliteLayer: Layer.Layer<SqliteClient | SqlClient>;
1790
+ /**
1791
+ * `Layer.effectDiscard`-shaped: provides nothing, runs the migrations as a
1792
+ * side effect of layer acquisition. Already fed its `SqlClient` and the
1793
+ * Node platform services.
1794
+ */
1795
+ readonly MigratorLayer: Layer.Layer<never, MigrationError | SqlError>;
1796
+ }
1797
+ /**
1798
+ * The Node platform services every SQLite stack and every Live layer share.
1799
+ * `NodeServices.layer` aggregates FileSystem | Path | ChildProcessSpawner |
1800
+ * Crypto | Stdio | Terminal.
1801
+ * @public
1802
+ */
1803
+ export declare const NodePlatformLayer: Layer.Layer<NodeServices.NodeServices, never, never>;
1804
+ /**
1805
+ * Build one SQLite database stack: the client layer for `filename` and a
1806
+ * migrator over `migrations` that is already provided with that client and
1807
+ * the Node platform services. The single assembly the CLI, MCP server,
1808
+ * plugin, `ensureMigrated` and the testing layers all share.
1809
+ *
1810
+ * @param filename - SQLite file path, or `":memory:"`
1811
+ * @param migrations - the migration record to run; defaults to the project
1812
+ * `data.db` set (`PROJECT_MIGRATIONS`)
1813
+ * @public
1814
+ */
1815
+ export declare const makeSqliteStack: (filename: string, migrations?: MigrationRecord) => SqliteStack;
1816
+ /**
1817
+ * Options for {@link PlatformLive}.
1818
+ * @public
1819
+ */
1820
+ export interface PlatformOptions {
1821
+ /** Absolute path to the per-project `data.db`, or `":memory:"`. */
1822
+ readonly dbPath: string;
1823
+ /** The environment map the env-reading layers consult (the front end passes `process.env`). */
1824
+ readonly env: Record<string, string | undefined>;
1825
+ /** Optional log level override; when absent the logger is silent. */
1826
+ readonly logLevel?: LogLevel.LogLevel | undefined;
1827
+ /** Optional path for structured NDJSON log output. */
1828
+ readonly logFile?: string | undefined;
1829
+ }
1830
+ /**
1831
+ * The services {@link PlatformLive} provides.
1832
+ * @public
1833
+ */
1834
+ export type PlatformServices = DataReader | DataStore | ProjectDiscovery | HistoryTracker | EnvironmentDetector | ExecutorResolver | FormatSelector | DetailResolver | OutputRenderer | NodeServices.NodeServices | SqliteClient | SqlClient;
1835
+ /**
1836
+ * The one platform assembly shared by the CLI, the MCP server and the Vitest
1837
+ * plugin: SQLite + migrator + Node platform services + Logger, with
1838
+ * `DataReader`, `DataStore`, `ProjectDiscovery`, `HistoryTracker` and the
1839
+ * output pipeline (`EnvironmentDetector`, `ExecutorResolver`,
1840
+ * `FormatSelector`, `DetailResolver`, `OutputRenderer`) built over them.
1841
+ *
1842
+ * Every env read goes through `options.env`; the engine never touches
1843
+ * `process` itself.
1844
+ *
1845
+ * @param options - database path, env map and optional logging overrides
1846
+ * @public
1847
+ */
1848
+ export declare const PlatformLive: (options: PlatformOptions) => Layer.Layer<PlatformServices, MigrationError | SqlError>;
1849
+ //#endregion
1850
+ //#region src/programs/end-agent.d.ts
1851
+ /**
1852
+ * Input for {@link endAgentEffect}: which `agents` row to close and when.
1853
+ *
1854
+ * @public
1855
+ */
1856
+ export interface EndAgentInput {
1857
+ /** The `agents.id` row to close. */
1858
+ readonly agentId: string;
1859
+ /** Epoch-millisecond timestamp written to `agents.ended_at`. */
1860
+ readonly endedAt: number;
1861
+ /**
1862
+ * When set, also marks the session map row for this host_session_id
1863
+ * as ended. Used by SessionEnd; omitted by SubagentStop.
1864
+ */
1865
+ readonly hostSessionId?: string;
1866
+ }
1867
+ /**
1868
+ * End an agent. Closes the `agents` row, optionally also closes the
1869
+ * `session_map` row.
1870
+ *
1871
+ * @param input - the agent id, end timestamp, and optional host session id
1872
+ * @public
1873
+ */
1874
+ export declare const endAgentEffect: (input: EndAgentInput) => Effect.Effect<void, import("@vitest-agent/sdk").AgentNotFoundError | import("@vitest-agent/sdk").DataStoreError, DataStore | PerClientSessionMapWriter>;
1875
+ //#endregion
1876
+ //#region src/programs/hook-paths.d.ts
1877
+ /**
1878
+ * Filename of the per-project test-data SQLite database.
1879
+ *
1880
+ * @public
1881
+ */
1882
+ export declare const DATA_DB_FILENAME = "data.db";
1883
+ /**
1884
+ * Filename of the per-client session-map SQLite database.
1885
+ *
1886
+ * @public
1887
+ */
1888
+ export declare const SESSIONS_DB_FILENAME = "sessions.db";
1889
+ /**
1890
+ * Filename of the global discovery-registry SQLite database.
1891
+ *
1892
+ * @public
1893
+ */
1894
+ export declare const REGISTRY_DB_FILENAME = "registry.db";
1895
+ /**
1896
+ * The environment map every hook-path resolver reads from. The front end
1897
+ * passes `process.env`; the engine never reads `process` itself.
1898
+ *
1899
+ * @public
1900
+ */
1901
+ export type HookEnv = Record<string, string | undefined>;
1902
+ /**
1903
+ * The paths the sidecar-family subcommands open. Every directory has been
1904
+ * created by the time this value is returned.
1905
+ *
1906
+ * @public
1907
+ */
1908
+ export interface HookPaths {
1909
+ /** `<XDG data>/vitest-agent` — holds `registry.db` and the per-project dirs. */
1910
+ readonly dataRoot: string;
1911
+ /** `<dataRoot>/<projectKey>` — holds the per-project `data.db`. */
1912
+ readonly projectDataDir: string;
1913
+ /** Absolute path to the per-project `data.db`. */
1914
+ readonly perProjectDbPath: string;
1915
+ /** Absolute path to the global `registry.db`. */
1916
+ readonly registryDbPath: string;
1917
+ /** Absolute path to the per-client `sessions.db`. */
1918
+ readonly sessionMapDbPath: string;
1919
+ }
1920
+ /**
1921
+ * Failures {@link resolveHookPaths} can surface: an unset `HOME` /
1922
+ * `USERPROFILE` (`XdgEnvError` for the data root,
1923
+ * `ProjectIdentityNotResolvableError` for the session map), a directory
1924
+ * that could not be created (`AppDirsError` / `PlatformError`).
1925
+ *
1926
+ * @public
1927
+ */
1928
+ export type HookPathsError = XdgEnvError | AppDirsError | PlatformError | ProjectIdentityNotResolvableError;
1929
+ /**
1930
+ * Resolve the per-client `sessions.db` path.
1931
+ *
1932
+ * Precedence: the `CLAUDE_PLUGIN_DATA` env var, then
1933
+ * `VITEST_AGENT_SESSION_MAP_DIR`, then `~/.vitest-agent/` (`HOME`, then
1934
+ * `USERPROFILE`). The chosen directory is created. Fails with
1935
+ * `ProjectIdentityNotResolvableError` when no home directory is resolvable.
1936
+ *
1937
+ * @param env - the environment map to consult (the front end passes `process.env`)
1938
+ * @returns an Effect resolving to the absolute `sessions.db` path
1939
+ * @public
1940
+ */
1941
+ export declare const resolveSessionMapPath: (env: HookEnv) => Effect.Effect<string, ProjectIdentityNotResolvableError | PlatformError, FileSystem.FileSystem | Path.Path>;
1942
+ /**
1943
+ * Resolve (and create) every path the sidecar-family subcommands open for
1944
+ * `projectKey`: the per-project `data.db`, the global `registry.db` and the
1945
+ * per-client `sessions.db`. See the module header for the precedence rules.
1946
+ *
1947
+ * @param input - the environment map (the front end passes `process.env`)
1948
+ * and the normalized project key (e.g. `@org__pkg`)
1949
+ * @returns an Effect resolving to the created {@link HookPaths}
1950
+ * @public
1951
+ */
1952
+ export declare const resolveHookPaths: (input: {
1953
+ readonly env: HookEnv;
1954
+ readonly projectKey: string;
1955
+ }) => Effect.Effect<HookPaths, HookPathsError, FileSystem.FileSystem | Path.Path>;
1956
+ //#endregion
1957
+ //#region src/programs/platform-sidecar.d.ts
1958
+ /**
1959
+ * SQLite database paths consumed by {@link SidecarPlatformLive}.
1960
+ * Structurally a subset of `HookPaths` from `resolveHookPaths`, so the
1961
+ * resolver's result can be passed straight in.
1962
+ *
1963
+ * @public
1964
+ */
1965
+ export interface SidecarPaths {
1966
+ /** Absolute path to the per-project `data.db`. */
1967
+ readonly perProjectDbPath: string;
1968
+ /** Absolute path to the per-client `sessions.db`. */
1969
+ readonly sessionMapDbPath: string;
1970
+ /** Absolute path to the global `registry.db`. */
1971
+ readonly registryDbPath: string;
1972
+ }
1973
+ /**
1974
+ * Build the sidecar Live layer for the supplied SQLite paths.
1975
+ *
1976
+ * Each store gets its own `SqlClient` connection (separate scopes,
1977
+ * independent migrators, all built through the engine's shared
1978
+ * `makeSqliteStack`) so concurrent operations on the three stores
1979
+ * don't share lock state.
1980
+ *
1981
+ * @param paths - the three SQLite database paths to open
1982
+ * @param env - the environment map `RunContextLive` probes for host
1983
+ * metadata (the bin passes `process.env`)
1984
+ * @public
1985
+ */
1986
+ export declare const SidecarPlatformLive: (paths: SidecarPaths, env: Record<string, string | undefined>) => Layer.Layer<DataReader | DataStore | DiscoveryRegistry | PerClientSessionMapReader | PerClientSessionMapWriter | RunContext$ | import("@effect/platform-node/NodeServices").NodeServices, import("@effect/sql-sqlite-node/SqliteMigrator").MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
1987
+ //#endregion
1988
+ //#region src/programs/record-session.d.ts
1989
+ /**
1990
+ * Input for {@link recordSessionStart}: the identity of the session row to upsert.
1991
+ *
1992
+ * @public
1993
+ */
1994
+ export interface RecordSessionStartInput {
1995
+ /** Host chat id (Claude Code `session_id`) keying the `sessions` row. */
1996
+ readonly chatId: string;
1997
+ /** Project name the session runs under. */
1998
+ readonly project: string;
1999
+ /** Working directory of the session. */
2000
+ readonly cwd: string;
2001
+ /** Whether this is the main agent or a dispatched subagent. */
2002
+ readonly agentKind: "main" | "subagent";
2003
+ /** Subagent type name, when `agentKind` is `"subagent"`. */
2004
+ readonly agentType?: string;
2005
+ /** Chat id of the parent session, used to link subagent rows to their parent. */
2006
+ readonly parentChatId?: string;
2007
+ /** Whether the SessionStart triage brief had content. */
2008
+ readonly triageWasNonEmpty: boolean;
2009
+ /** ISO-8601 start timestamp. */
2010
+ readonly startedAt: string;
2011
+ }
2012
+ /**
2013
+ * Upsert a `sessions` row for a SessionStart / SubagentStart hook, resolving
2014
+ * `parentChatId` to the parent's numeric session id when present.
2015
+ *
2016
+ * @param input - the session identity to record
2017
+ * @returns the numeric `sessions.id`
2018
+ * @public
2019
+ */
2020
+ export declare const recordSessionStart: (input: RecordSessionStartInput) => Effect.Effect<{
2021
+ sessionId: number;
2022
+ }, Error, DataReader | DataStore>;
2023
+ /**
2024
+ * Input for {@link recordSessionEnd}: which session to close and why.
2025
+ *
2026
+ * @public
2027
+ */
2028
+ export interface RecordSessionEndInput {
2029
+ /** Host chat id of the session to close. */
2030
+ readonly chatId: string;
2031
+ /** ISO-8601 end timestamp. */
2032
+ readonly endedAt: string;
2033
+ /** Claude Code's SessionEnd reason, or `null` when unknown. */
2034
+ readonly endReason: string | null;
2035
+ }
2036
+ /**
2037
+ * Close a `sessions` row for a SessionEnd hook. Fails with an `Error`
2038
+ * when no session exists for `chatId`.
2039
+ *
2040
+ * @param input - the session to close
2041
+ * @public
2042
+ */
2043
+ export declare const recordSessionEnd: (input: RecordSessionEndInput) => Effect.Effect<{
2044
+ ok: true;
2045
+ }, Error, DataReader | DataStore>;
2046
+ //#endregion
2047
+ //#region src/programs/record-tdd-artifact.d.ts
2048
+ /**
2049
+ * Input for {@link recordTddArtifactEffect}: an artifact keyed by the host
2050
+ * chat id, resolved to the open TDD task under that session.
2051
+ *
2052
+ * @public
2053
+ */
2054
+ export interface RecordTddArtifactInput {
2055
+ /** Host chat id whose open TDD task receives the artifact. */
2056
+ readonly chatId: string;
2057
+ /** Kind of evidence being recorded. */
2058
+ readonly artifactKind: ArtifactKind$1;
2059
+ /** `files.id` the artifact refers to, when file-scoped. */
2060
+ readonly fileId?: number;
2061
+ /** `test_cases.id` the artifact refers to, when test-scoped. */
2062
+ readonly testCaseId?: number;
2063
+ /** `test_runs.id` that produced the evidence. */
2064
+ readonly testRunId?: number;
2065
+ /** Run id of the first observed failure for a red-phase artifact. */
2066
+ readonly testFirstFailureRunId?: number;
2067
+ /** Short diff excerpt attached to the artifact. */
2068
+ readonly diffExcerpt?: string;
2069
+ /** ISO-8601 timestamp of the artifact. */
2070
+ readonly recordedAt: string;
2071
+ /** Issue #363: explicit suite marker. Defaults to `"vitest"` when omitted. */
2072
+ readonly suite?: ArtifactSuite$1;
2073
+ /**
2074
+ * Working directory of the calling process (ambient input — the CLI
2075
+ * command passes its own `process.cwd()` when no `--cwd` flag was
2076
+ * given). Used to bootstrap a missing session row when the chat id
2077
+ * has no exact match.
2078
+ */
2079
+ readonly cwd: string;
2080
+ /**
2081
+ * Project name for bootstrapped session rows. When omitted, the
2082
+ * resolver reads `package.json#name` from `cwd`.
2083
+ */
2084
+ readonly project?: string;
2085
+ }
2086
+ /**
2087
+ * Result of a TDD artifact write: the new artifact row and the phase it landed under.
2088
+ *
2089
+ * @public
2090
+ */
2091
+ export interface RecordTddArtifactResult {
2092
+ /** The new `tdd_artifacts.id`. */
2093
+ readonly id: number;
2094
+ /** The `tdd_phases.id` the artifact was written under. */
2095
+ readonly phaseId: number;
2096
+ }
2097
+ /**
2098
+ * Record a TDD artifact under the open TDD task for `chatId`, walking
2099
+ * parent and conversation links to find the task and auto-opening a
2100
+ * `spike` phase when the task has none.
2101
+ *
2102
+ * @param input - the artifact to record, keyed by host chat id
2103
+ * @public
2104
+ */
2105
+ export declare const recordTddArtifactEffect: (input: RecordTddArtifactInput) => Effect.Effect<RecordTddArtifactResult, DataStoreError | Error, DataReader | DataStore | FileSystem.FileSystem>;
2106
+ /**
2107
+ * Input for {@link recordTddArtifactByTaskIdEffect}: an artifact keyed by an
2108
+ * explicit TDD task id.
2109
+ *
2110
+ * @public
2111
+ */
2112
+ export interface RecordTddArtifactByTaskIdInput {
2113
+ /** The `tdd_tasks.id` that receives the artifact. */
2114
+ readonly tddTaskId: number;
2115
+ /** Kind of evidence being recorded. */
2116
+ readonly artifactKind: ArtifactKind$1;
2117
+ /** `files.id` the artifact refers to, when file-scoped. */
2118
+ readonly fileId?: number;
2119
+ /** `test_cases.id` the artifact refers to, when test-scoped. */
2120
+ readonly testCaseId?: number;
2121
+ /** `test_runs.id` that produced the evidence. */
2122
+ readonly testRunId?: number;
2123
+ /** Run id of the first observed failure for a red-phase artifact. */
2124
+ readonly testFirstFailureRunId?: number;
2125
+ /** Short diff excerpt attached to the artifact. */
2126
+ readonly diffExcerpt?: string;
2127
+ /** ISO-8601 timestamp of the artifact. */
2128
+ readonly recordedAt: string;
2129
+ /** Issue #363: explicit suite marker. Defaults to `"vitest"` when omitted. */
2130
+ readonly suite?: ArtifactSuite$1;
2131
+ }
2132
+ /**
2133
+ * Explicit task-id escape hatch (issue #144). Bypasses `chat_id` →
2134
+ * session → task resolution entirely — the caller already knows which
2135
+ * TDD task the artifact belongs to (e.g. a hook seeded with
2136
+ * `VITEST_AGENT_TDD_TASK_ID` in a detached-session environment where
2137
+ * neither the parent walk nor the conversation-id fallback resolves
2138
+ * the right task). Fails loudly when the task does not exist or has
2139
+ * already ended — writing to a closed task's phase would silently
2140
+ * corrupt the evidence trail.
2141
+ *
2142
+ * @param input - the artifact to record, keyed by TDD task id
2143
+ * @public
2144
+ */
2145
+ export declare const recordTddArtifactByTaskIdEffect: (input: RecordTddArtifactByTaskIdInput) => Effect.Effect<RecordTddArtifactResult, DataStoreError | Error, DataReader | DataStore>;
2146
+ /**
2147
+ * Input for {@link dispatchRecordTddArtifactEffect}: the union of the chat-id
2148
+ * and task-id recording shapes, with `tddTaskId` taking priority.
2149
+ *
2150
+ * @public
2151
+ */
2152
+ export interface DispatchRecordTddArtifactInput {
2153
+ /** Host chat id to resolve the open TDD task from (used when `tddTaskId` is absent). */
2154
+ readonly chatId?: string;
2155
+ /** Explicit `tdd_tasks.id`; takes priority over `chatId`. */
2156
+ readonly tddTaskId?: number;
2157
+ /** Kind of evidence being recorded. */
2158
+ readonly artifactKind: ArtifactKind$1;
2159
+ /** `files.id` the artifact refers to, when file-scoped. */
2160
+ readonly fileId?: number;
2161
+ /** `test_cases.id` the artifact refers to, when test-scoped. */
2162
+ readonly testCaseId?: number;
2163
+ /** `test_runs.id` that produced the evidence. */
2164
+ readonly testRunId?: number;
2165
+ /** Run id of the first observed failure for a red-phase artifact. */
2166
+ readonly testFirstFailureRunId?: number;
2167
+ /** Short diff excerpt attached to the artifact. */
2168
+ readonly diffExcerpt?: string;
2169
+ /** ISO-8601 timestamp of the artifact. */
2170
+ readonly recordedAt: string;
2171
+ /** Ambient input (see `RecordTddArtifactInput.cwd`); only consulted on the `chatId` branch. */
2172
+ readonly cwd: string;
2173
+ /** Project name for bootstrapped session rows; only consulted on the `chatId` branch. */
2174
+ readonly project?: string;
2175
+ /** Issue #363: explicit suite marker. Defaults to `"vitest"` when omitted. */
2176
+ readonly suite?: ArtifactSuite$1;
2177
+ }
2178
+ /**
2179
+ * CLI-command-facing dispatcher (issue #144). Keeps `commands/record.ts`
2180
+ * a thin flag-parsing wrapper per this package's convention. `tddTaskId`
2181
+ * takes priority when both are supplied — it is the explicit escape
2182
+ * hatch and should never silently fall back to (weaker) session
2183
+ * resolution.
2184
+ *
2185
+ * @param input - the artifact plus either a chat id or a TDD task id
2186
+ * @public
2187
+ */
2188
+ export declare const dispatchRecordTddArtifactEffect: (input: DispatchRecordTddArtifactInput) => Effect.Effect<RecordTddArtifactResult, DataStoreError | Error, DataReader | DataStore | FileSystem.FileSystem>;
2189
+ //#endregion
2190
+ //#region src/programs/record-turn.d.ts
2191
+ /**
2192
+ * Outcome of {@link parseAndValidateTurnPayload}: the decoded `TurnPayload`
2193
+ * on success, or a human-readable error string.
2194
+ *
2195
+ * @public
2196
+ */
2197
+ export type ParseResult = {
2198
+ ok: true;
2199
+ payload: typeof TurnPayload.Type;
2200
+ } | {
2201
+ ok: false;
2202
+ error: string;
2203
+ };
2204
+ /**
2205
+ * Parse a raw JSON string and validate it against the `TurnPayload` schema
2206
+ * without throwing.
2207
+ *
2208
+ * @param raw - the JSON text delivered by the hook
2209
+ * @returns the decoded payload, or an error describing why it was rejected
2210
+ * @public
2211
+ */
2212
+ export declare const parseAndValidateTurnPayload: (raw: string) => ParseResult;
2213
+ /**
2214
+ * Input for {@link recordTurnEffect}: a turn payload keyed by host chat id.
2215
+ *
2216
+ * @public
2217
+ */
2218
+ export interface RecordTurnInput {
2219
+ /** Host chat id whose session receives the turn. */
2220
+ readonly chatId: string;
2221
+ /** Raw JSON text of the `TurnPayload`; stored verbatim after validation. */
2222
+ readonly payloadJson: string;
2223
+ /** ISO-8601 timestamp of the turn. */
2224
+ readonly occurredAt: string;
2225
+ /**
2226
+ * Working directory of the calling process (ambient input — the CLI
2227
+ * command passes its own `process.cwd()` when no `--cwd` flag was
2228
+ * given). Used to bootstrap a session row when no exact `chat_id`
2229
+ * match exists, which happens after Claude Code rotates the chat id
2230
+ * mid-window without `SessionStart` re-firing for the new id.
2231
+ */
2232
+ readonly cwd: string;
2233
+ /**
2234
+ * Project name for bootstrapped session rows. When omitted, the
2235
+ * resolver reads `package.json#name` from `cwd`, falling back to
2236
+ * `"unknown"`.
2237
+ */
2238
+ readonly project?: string;
2239
+ }
2240
+ /**
2241
+ * Validate a turn payload and write it as a `turns` row under the session
2242
+ * resolved for `chatId` (bootstrapping the session row when needed).
2243
+ *
2244
+ * @param input - the turn to record
2245
+ * @returns the new `turns.id`
2246
+ * @public
2247
+ */
2248
+ export declare const recordTurnEffect: (input: RecordTurnInput) => Effect.Effect<{
2249
+ turnId: number;
2250
+ }, Error, DataReader | DataStore | FileSystem.FileSystem>;
2251
+ //#endregion
2252
+ //#region src/programs/record-workspace-changes.d.ts
2253
+ /**
2254
+ * Input for {@link recordRunWorkspaceChangesEffect}: one commit plus the
2255
+ * files it touched.
2256
+ *
2257
+ * @public
2258
+ */
2259
+ export interface RecordWorkspaceChangesInput {
2260
+ /** Commit sha; the `commits` row is idempotent on it. */
2261
+ readonly sha: string;
2262
+ /** Parent commit sha, when known. */
2263
+ readonly parentSha?: string;
2264
+ /** Commit message. */
2265
+ readonly message?: string;
2266
+ /** Commit author. */
2267
+ readonly author?: string;
2268
+ /** ISO-8601 commit timestamp. */
2269
+ readonly committedAt?: string;
2270
+ /** Branch the commit landed on. */
2271
+ readonly branch?: string;
2272
+ /** When provided, scope the most-recent-run lookup to this project. */
2273
+ readonly project?: string;
2274
+ /** Files changed by the commit, each with its change kind. */
2275
+ readonly files: ReadonlyArray<{
2276
+ readonly filePath: string;
2277
+ readonly changeKind: ChangeKind;
2278
+ }>;
2279
+ }
2280
+ /**
2281
+ * Result of a workspace-changes write.
2282
+ *
2283
+ * @public
2284
+ */
2285
+ export interface RecordWorkspaceChangesResult {
2286
+ /** The commit sha that was recorded. */
2287
+ readonly sha: string;
2288
+ /** Number of `run_changed_files` rows written (0 when no test run exists yet). */
2289
+ readonly fileRowsWritten: number;
2290
+ }
2291
+ /**
2292
+ * Record a commit and, best-effort, associate its changed files with the
2293
+ * most recent test run for the project.
2294
+ *
2295
+ * @param input - the commit and its changed files
2296
+ * @public
2297
+ */
2298
+ export declare const recordRunWorkspaceChangesEffect: (input: RecordWorkspaceChangesInput) => Effect.Effect<RecordWorkspaceChangesResult, DataStoreError, DataStore | SqlClient>;
2299
+ //#endregion
2300
+ //#region src/programs/register-agent.d.ts
2301
+ /**
2302
+ * Input for the end-to-end agent registration effect.
2303
+ *
2304
+ * @public
2305
+ */
2306
+ export interface RegisterAgentProgramInput {
2307
+ /** The host's native session identifier (e.g. Claude's `session_id`). */
2308
+ readonly hostSessionId: string;
2309
+ /** Absolute path to the host's conversation transcript file. */
2310
+ readonly transcriptPath: string;
2311
+ /** Working directory of the agent process. */
2312
+ readonly cwd: string;
2313
+ /** Host kind string (e.g. `"claude-code"`). */
2314
+ readonly hostKind: string;
2315
+ /** Agent type label (e.g. `"main"` or `"subagent"`). */
2316
+ readonly agentType: string;
2317
+ /** Normalized project key derived from the workspace root `package.json#name`. */
2318
+ readonly projectKey: string;
2319
+ /** Agent ID of the parent when registering a subagent. */
2320
+ readonly parentAgentId?: string;
2321
+ /** Optional idempotency nonce; derived from `hostSessionId + agentType + parentAgentId` when omitted. */
2322
+ readonly clientNonce?: string;
2323
+ }
2324
+ /**
2325
+ * Output of the end-to-end agent registration effect.
2326
+ *
2327
+ * @public
2328
+ */
2329
+ export interface RegisterAgentProgramOutput {
2330
+ /** Canonical UUID assigned to this agent in the per-project store. */
2331
+ readonly agentId: string;
2332
+ /** UUID of the conversation this agent belongs to. */
2333
+ readonly conversationId: string;
2334
+ /** Idempotency key used for the `registerAgent` upsert. */
2335
+ readonly idempotencyKey: string;
2336
+ /** `true` when an existing agent row was recovered rather than inserted. */
2337
+ readonly idempotencyHit: boolean;
2338
+ }
2339
+ /**
2340
+ * End-to-end agent registration.
2341
+ *
2342
+ * Returns the canonical `agentId` + the conversation it belongs to +
2343
+ * the resolved `idempotencyKey`. The `idempotencyHit` flag is `true`
2344
+ * when the per-project store recovered an existing agent row instead
2345
+ * of inserting a new one.
2346
+ *
2347
+ * @param input - registration inputs including host identifiers and agent metadata
2348
+ * @returns an Effect resolving to `RegisterAgentProgramOutput`
2349
+ * @public
2350
+ */
2351
+ export declare const registerAgentEffect: (input: RegisterAgentProgramInput) => Effect.Effect<{
2352
+ agentId: string;
2353
+ conversationId: string;
2354
+ mainAgentId: string;
2355
+ idempotencyKey: string;
2356
+ idempotencyHit: boolean;
2357
+ }, import("@vitest-agent/sdk").DataStoreError | import("@vitest-agent/sdk").RegistrationConflictError, DataReader | DataStore | PerClientSessionMapWriter | RunContext$>;
2358
+ //#endregion
2359
+ //#region src/programs/resolve-session-for-recording.d.ts
2360
+ /**
2361
+ * Input for {@link resolveSessionForRecording}.
2362
+ *
2363
+ * @public
2364
+ */
2365
+ export interface ResolveSessionForRecordingInput {
2366
+ /** Host chat id to resolve. */
2367
+ readonly chatId: string;
2368
+ /** ISO-8601 timestamp used as `started_at` for a bootstrapped row. */
2369
+ readonly recordedAt: string;
2370
+ /**
2371
+ * Project name for the bootstrapped row. Defaults to
2372
+ * `package.json#name` in `cwd`, then `"unknown"`.
2373
+ */
2374
+ readonly project?: string;
2375
+ /**
2376
+ * Working directory for the bootstrapped row and the `package.json`
2377
+ * probe. Ambient input: the caller (a CLI command) passes its own
2378
+ * `process.cwd()`; the engine never reads `process` itself.
2379
+ */
2380
+ readonly cwd: string;
2381
+ }
2382
+ /**
2383
+ * Resolve the `sessions` row for a hook-delivered chat id: exact match,
2384
+ * then the synthetic `-subagent-` prefix, then an idempotent bootstrap of
2385
+ * a `main` row so recording never fails with "Unknown chat_id".
2386
+ *
2387
+ * @param input - the chat id and ambient bootstrap inputs
2388
+ * @returns the resolved (or newly created) session row
2389
+ * @public
2390
+ */
2391
+ export declare const resolveSessionForRecording: (input: ResolveSessionForRecordingInput) => Effect.Effect<SessionDetail, DataStoreError, DataReader | DataStore | FileSystem.FileSystem>;
2392
+ //#endregion
2393
+ //#region src/programs/session-env.d.ts
2394
+ /**
2395
+ * Recovered session attribution context — the canonical UUIDs the
2396
+ * SessionStart hook wrote to `${CLAUDE_ENV_FILE}` (auto-sourced into the
2397
+ * MCP server child's `process.env`) and to the per-session
2398
+ * `~/.claude/session-env/<chat_id>/vitest-agent-hook.sh` surface this
2399
+ * module reads back.
2400
+ *
2401
+ * Read by the MCP server's `run_tests` to populate `VITEST_AGENT_AGENT_ID`
2402
+ * and friends on the Vitest child process so the reporter attributes runs
2403
+ * back to the active agent.
2404
+ *
2405
+ * @public
2406
+ */
2407
+ export interface SessionContext {
2408
+ readonly chatId: string;
2409
+ readonly conversationId: string;
2410
+ readonly mainAgentId: string;
2411
+ }
2412
+ /**
2413
+ * Parse `export KEY=value` lines from a session-env hook file into a
2414
+ * plain record. Non-export lines are ignored.
2415
+ *
2416
+ * @param content - the raw text of a session-env hook file
2417
+ * @returns a record of export names to unquoted values
2418
+ * @public
2419
+ */
2420
+ export declare const parseSessionEnvExports: (content: string) => Record<string, string>;
2421
+ /**
2422
+ * Recover a {@link SessionContext} from the newest session-env hook file
2423
+ * whose `VITEST_AGENT_PROJECT_DIR` matches `projectDir`.
2424
+ *
2425
+ * Returns `null` when the session-env root is missing, unreadable, or no
2426
+ * session dir matches the project. Never throws — recovery is best-effort
2427
+ * and callers fall back to their existing null-context behavior.
2428
+ *
2429
+ * Synchronous by contract: the MCP server calls it from the lazy
2430
+ * `SessionContextRef.get()` recover thunk, which is itself synchronous.
2431
+ *
2432
+ * @param opts - `projectDir` to match against; `homeDir` is the caller's
2433
+ * home directory (ambient input — the MCP bin passes `os.homedir()`),
2434
+ * under which `.claude/session-env` is read
2435
+ * @public
2436
+ */
2437
+ export declare const recoverSessionContextFromSessionEnv: (opts: {
2438
+ readonly projectDir: string;
2439
+ readonly homeDir: string;
2440
+ }) => SessionContext | null;
2441
+ //#endregion
2442
+ //#region src/project-dir.d.ts
2443
+ /**
2444
+ * Resolve the project directory the front ends anchor on.
2445
+ *
2446
+ * Precedence: `VITEST_AGENT_PROJECT_DIR` (hook-driven override), then
2447
+ * `VITEST_AGENT_REPORTER_PROJECT_DIR` (the plugin-spawned MCP server's
2448
+ * hand-off), then `CLAUDE_PROJECT_DIR` (Claude Code's own convention),
2449
+ * then `cwd`. An empty string counts as unset. Pure: both the env map and
2450
+ * the working directory are injected by the caller.
2451
+ *
2452
+ * @param input - the env map and the fallback working directory
2453
+ * @public
2454
+ */
2455
+ export declare const resolveProjectDir: (input: {
2456
+ readonly env: Record<string, string | undefined>;
2457
+ readonly cwd: string;
2458
+ }) => string;
2459
+ //#endregion
2460
+ //#region src/services/idempotency.d.ts
2461
+ /**
2462
+ * Sentinel substituted for `parentAgentId` when the value is `null`.
2463
+ * Avoids ambiguity around hashing the literal string "null" or empty
2464
+ * string, both of which could collide with caller-supplied values.
2465
+ * @public
2466
+ */
2467
+ export declare const IDEMPOTENCY_ROOT_SENTINEL = "__ROOT__";
2468
+ /** @public */
2469
+ export interface IdempotencyInput {
2470
+ readonly agentType: string;
2471
+ readonly parentAgentId: string | null;
2472
+ readonly clientNonce: string;
2473
+ }
2474
+ /**
2475
+ * Derive the canonical idempotency key for an `agents` row.
2476
+ *
2477
+ * Algorithm:
2478
+ * sha256(agentType + "|" + (parentAgentId ?? "__ROOT__") + "|" + clientNonce)
2479
+ * then base32 (RFC 4648 alphabet, lowercased) truncated to 26 chars.
2480
+ *
2481
+ * 26 base32 chars = 130 bits, far beyond the birthday-bound for the
2482
+ * scoping (UNIQUE per session). The base32 alphabet is a-z2-7 — all
2483
+ * lowercase to keep the column lexicographically friendly and
2484
+ * case-insensitive on filesystems that we never hit but might in
2485
+ * future debugging.
2486
+ * @public
2487
+ */
2488
+ export declare const deriveIdempotencyKey: (input: IdempotencyInput) => string;
2489
+ //#endregion
2490
+ //#region src/sql/assemblers.d.ts
2491
+ /**
2492
+ * Minimal shape of a test_runs aggregation row used to build the manifest.
2493
+ * @public
2494
+ */
2495
+ export interface ManifestRow {
2496
+ project: string;
2497
+ sub_project: string | null;
2498
+ timestamp: string;
2499
+ reason: string;
2500
+ }
2501
+ /**
2502
+ * Minimal shape of a test_history row used to build a history record.
2503
+ * @public
2504
+ */
2505
+ export interface HistoryRow {
2506
+ module_path: string;
2507
+ full_name: string;
2508
+ timestamp: string;
2509
+ state: string;
2510
+ }
2511
+ /**
2512
+ * A `Record<compositeKey, { modulePath, fullName, runs: TestRun[] }>` keyed by
2513
+ * the injective `historyKey(modulePath, fullName)` string, so identically-named
2514
+ * tests in different files are tracked as distinct entries.
2515
+ *
2516
+ * This is the internal representation returned by `assembleHistoryRecord`.
2517
+ * Callers that need the Effect Schema `HistoryRecord` type should adapt this
2518
+ * into the `tests` array format.
2519
+ * @public
2520
+ */
2521
+ export interface AssembledHistoryRecord {
2522
+ [compositeKey: string]: {
2523
+ modulePath: string;
2524
+ fullName: string;
2525
+ runs: TestRun[];
2526
+ };
2527
+ }
2528
+ /**
2529
+ * Builds a `CacheManifest` from an array of test_runs aggregation rows.
2530
+ *
2531
+ * Each row represents the latest run for a project/sub_project pair.
2532
+ * The `dbPath` is stored as `cacheDir` so CLI tools can locate the source.
2533
+ * @public
2534
+ */
2535
+ export declare function assembleManifest(rows: ManifestRow[], dbPath: string): CacheManifest;
2536
+ /**
2537
+ * Groups test_history rows by the composite (module_path, full_name) key
2538
+ * into a keyed record.
2539
+ *
2540
+ * Returns `Record<compositeKey, { modulePath, fullName, runs: TestRun[] }>`
2541
+ * where `runs` are the accumulated test runs for that test, in the order
2542
+ * they appear in `rows`. Two rows sharing `full_name` but differing
2543
+ * `module_path` are tracked as distinct entries rather than merged.
2544
+ *
2545
+ * Only rows with state `"passed"` or `"failed"` are included in runs
2546
+ * (matching the `TestRun` schema constraint).
2547
+ * @public
2548
+ */
2549
+ export declare function assembleHistoryRecord(rows: HistoryRow[]): AssembledHistoryRecord;
2550
+ //#endregion
2551
+ //#region src/utils/ensure-migrated.d.ts
2552
+ /**
2553
+ * Ensure the SQLite database at `dbPath` is migrated. Runs migrations at
2554
+ * most once per dbPath in the current process; concurrent calls share the
2555
+ * same in-flight promise. Subsequent calls (after the first resolves) are
2556
+ * no-ops.
2557
+ * @public
2558
+ */
2559
+ export declare function ensureMigrated(dbPath: string, logLevel?: LogLevel.LogLevel, logFile?: string): Promise<void>;
2560
+ /**
2561
+ * Reset the migration cache. Test-only.
2562
+ *
2563
+ * @internal
2564
+ */
2565
+ export declare function _resetMigrationCacheForTesting(): void;
2566
+ //#endregion
2567
+ //#region src/utils/failure-signature.d.ts
2568
+ /** @public */
2569
+ export interface FailureSignatureInput {
2570
+ readonly error_name: string;
2571
+ readonly assertion_message: string;
2572
+ readonly top_frame_function_name: string;
2573
+ readonly top_frame_function_boundary_line: number | null;
2574
+ readonly top_frame_raw_line?: number;
2575
+ }
2576
+ /** @public */
2577
+ export declare const normalizeAssertionShape: (message: string) => string | null;
2578
+ /** @public */
2579
+ export declare const computeFailureSignature: (input: FailureSignatureInput) => string;
2580
+ //#endregion
2581
+ //#region src/utils/resolve-data-path.d.ts
2582
+ /**
2583
+ * Filename of the SQLite database that stores all reporter data.
2584
+ * @public
2585
+ */
2586
+ export declare const DATABASE_FILENAME = "data.db";
2587
+ /**
2588
+ * Caller-supplied overrides for `resolveDataPath`.
2589
+ * @public
2590
+ */
2591
+ export interface ResolveDataPathOptions {
2592
+ /**
2593
+ * Programmatic override for the entire data directory. Highest precedence.
2594
+ *
2595
+ * Use this when the reporter or plugin user has explicitly set
2596
+ * `reporter.cacheDir`. The returned path is `<cacheDir>/data.db`.
2597
+ */
2598
+ readonly cacheDir?: string;
2599
+ }
2600
+ /**
2601
+ * Resolve the absolute path to the SQLite database for `projectDir`.
2602
+ *
2603
+ * The directory containing the database is ensured to exist before the
2604
+ * function returns, so callers can open the database immediately without
2605
+ * needing to create parent directories. The SQLite driver creates the file
2606
+ * but not its parent.
2607
+ *
2608
+ * Precedence (highest first):
2609
+ *
2610
+ * 1. `options.cacheDir` — programmatic override.
2611
+ * 2. `cacheDir` from `vitest-agent.config.toml`.
2612
+ * 3. `<XDG data>/<normalized projectKey from config>/data.db`.
2613
+ * 4. `<XDG data>/<projectKey resolved from cwd's package.json>/data.db`.
2614
+ * Source 4 prefers `repository.url` (canonicalized to `host__path`),
2615
+ * falling back to the normalized `name`. This matches the sidecar
2616
+ * CLI's `_internal register-agent` resolver so the reporter and
2617
+ * sidecar always write to the same `data.db`.
2618
+ *
2619
+ * The XDG data directory is namespaced via `AppDirs` (typically
2620
+ * `$XDG_DATA_HOME/vitest-agent`, defaulting to
2621
+ * `~/.local/share/vitest-agent`).
2622
+ *
2623
+ * The path is a function of identity, not filesystem layout. When no
2624
+ * `package.json` is reachable from `projectDir`, the cwd basename is used
2625
+ * as the final fallback so the function never throws on identity lookup.
2626
+ *
2627
+ * @param projectDir - Absolute path inside the user's workspace.
2628
+ * @param options - Optional programmatic overrides.
2629
+ * @public
2630
+ */
2631
+ export declare const resolveDataPath: (projectDir: string, options?: ResolveDataPathOptions) => Effect.Effect<any, import("@effected/xdg").AppDirsError | import("effect/PlatformError").PlatformError | import("@effected/config-file").ConfigReadError, AppDirs | FileSystem.FileSystem | VitestAgentConfigFile>;
2632
+ //#endregion
2633
+ //#region src/utils/resolve-project-key-from-cwd.d.ts
2634
+ /**
2635
+ * Compute the project key for a workspace by reading `package.json`
2636
+ * fields directly. Returns the canonical `host__path` form when a git
2637
+ * remote URL is present, otherwise the normalized package name.
2638
+ *
2639
+ * Always returns a non-empty string — falls back to the cwd basename
2640
+ * (or `"anonymous-project"`) so callers don't have to handle the
2641
+ * empty case.
2642
+ * @public
2643
+ */
2644
+ export declare const resolveProjectKeyFromCwd: (cwd: string) => string;
2645
+ //#endregion
2646
+ //#region src/utils/resolve-workspace-key.d.ts
2647
+ /**
2648
+ * Resolve the normalized workspace key for the workspace containing
2649
+ * `projectDir`.
2650
+ *
2651
+ * The key is the root `package.json`'s `name`, normalized via
2652
+ * `normalizeWorkspaceKey`. This becomes the directory segment under
2653
+ * `$XDG_DATA_HOME/vitest-agent/` where the SQLite database lives.
2654
+ *
2655
+ * Fails with `WorkspaceRootNotFoundError` when no root workspace is
2656
+ * discoverable. `WorkspacePackage.name` is enforced non-empty by
2657
+ * `@effected/workspaces`'s schema, so a successful root lookup always yields a
2658
+ * usable name.
2659
+ *
2660
+ * Discovery is anchored at `projectDir` per call via `listPackagesIn`, not at
2661
+ * the `WorkspaceDiscovery` layer's `cwd`: patterns, member manifests and names
2662
+ * are read from beneath `projectDir`'s own root, so one long-lived layer
2663
+ * answers correctly for a git worktree, a nested repository, or an unrelated
2664
+ * project. Fails with the library's `WorkspaceRootNotFoundError` when
2665
+ * `projectDir` sits in no workspace at all; results are memoized per resolved
2666
+ * root, so many directories in one workspace share a single discovery.
2667
+ *
2668
+ * @param projectDir - Absolute path inside the workspace. Typically the
2669
+ * reporter's resolved `projectDir` (CLAUDE_PROJECT_DIR or process.cwd()).
2670
+ * @public
2671
+ */
2672
+ export declare const resolveWorkspaceKey: (projectDir: string) => Effect.Effect<string, WorkspaceRootNotFoundError | WorkspaceDiscoveryFailure, WorkspaceDiscovery>;
2673
+ //#endregion
2674
+ //#region src/version.d.ts
2675
+ /** Build-time injected package version (see architecture.md D36). @public */
2676
+ export declare const CURRENT_ENGINE_VERSION: string;
2677
+ //#endregion
2678
+ export { type ArtifactKind, type ArtifactSuite, type FormatTriageOptions, type FormatWrapupOptions, type Phase, type WrapupKind, migration as migration0001, migration$1 as migration0002, migration$2 as registryMigration0001, migration$3 as sessionMapMigration0001 };
2679
+ //# sourceMappingURL=index.d.ts.map