@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.
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/index.d.ts +2679 -0
- package/index.js +63 -0
- package/layers/ConfigLive.js +46 -0
- package/layers/DataReaderLive.js +1923 -0
- package/layers/DataStoreLive.js +1283 -0
- package/layers/DetailResolverLive.js +9 -0
- package/layers/DiscoveryRegistryLive.js +70 -0
- package/layers/EnvironmentDetectorLive.js +36 -0
- package/layers/EnvironmentDetectorTest.js +13 -0
- package/layers/ExecutorResolverLive.js +9 -0
- package/layers/FormatSelectorLive.js +20 -0
- package/layers/HistoryTrackerLive.js +49 -0
- package/layers/HistoryTrackerTest.js +25 -0
- package/layers/LoggerLive.js +70 -0
- package/layers/OutputPipelineLive.js +20 -0
- package/layers/OutputRendererLive.js +23 -0
- package/layers/PathResolutionLive.js +46 -0
- package/layers/PerClientSessionMapLive.js +145 -0
- package/layers/ProjectDiscoveryLive.js +67 -0
- package/layers/ProjectDiscoveryTest.js +12 -0
- package/layers/ProjectIdentityLive.js +95 -0
- package/layers/RunContextLive.js +82 -0
- package/lib/format-triage.js +103 -0
- package/lib/format-wrapup.js +67 -0
- package/migrations/0001_initial.js +824 -0
- package/migrations/0002_test_artifacts.js +30 -0
- package/migrations/index.js +27 -0
- package/migrations/registry_0001_initial.js +39 -0
- package/migrations/session_map_0001_initial.js +38 -0
- package/package.json +59 -0
- package/platform.js +58 -0
- package/programs/end-agent.js +19 -0
- package/programs/hook-paths.js +115 -0
- package/programs/platform-sidecar.js +37 -0
- package/programs/record-session.js +49 -0
- package/programs/record-tdd-artifact.js +119 -0
- package/programs/record-turn.js +61 -0
- package/programs/record-workspace-changes.js +57 -0
- package/programs/register-agent.js +85 -0
- package/programs/resolve-session-for-recording.js +44 -0
- package/programs/session-env.js +85 -0
- package/project-dir.js +32 -0
- package/services/Config.js +15 -0
- package/services/DataReader.js +8 -0
- package/services/DataStore.js +15 -0
- package/services/DetailResolver.js +8 -0
- package/services/DiscoveryRegistry.js +8 -0
- package/services/EnvironmentDetector.js +8 -0
- package/services/ExecutorResolver.js +8 -0
- package/services/FormatSelector.js +8 -0
- package/services/HistoryTracker.js +20 -0
- package/services/OutputRenderer.js +8 -0
- package/services/PerClientSessionMap.js +22 -0
- package/services/ProjectDiscovery.js +8 -0
- package/services/ProjectIdentity.js +62 -0
- package/services/RunContext.js +53 -0
- package/services/idempotency.js +58 -0
- package/sql/assemblers.js +69 -0
- package/testing/layers.js +16 -0
- package/testing.d.ts +1101 -0
- package/testing.js +243 -0
- package/tsdoc-metadata.json +11 -0
- package/utils/ensure-migrated.js +47 -0
- package/utils/failure-signature.js +34 -0
- package/utils/resolve-data-path.js +64 -0
- package/utils/resolve-project-key-from-cwd.js +52 -0
- package/utils/resolve-workspace-key.js +41 -0
- 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
|