@vitest-agent/sdk 1.0.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/DataReader-2kJ9I9Hh.d.ts +1809 -0
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/dispatch.d.ts +48 -0
- package/dispatch.js +5 -0
- package/errors/AgentErrors.js +65 -0
- package/errors/DataStoreError.js +44 -0
- package/errors/DiscoveryError.js +21 -0
- package/errors/PathResolutionError.js +27 -0
- package/errors/ProjectIdentityError.js +29 -0
- package/errors/RunContextError.js +35 -0
- package/errors/TddErrors.js +66 -0
- package/exit-code-for-tag.js +18 -0
- package/formatters/ci-annotations.js +61 -0
- package/formatters/gfm.js +20 -0
- package/formatters/json.js +18 -0
- package/formatters/markdown.js +39 -0
- package/formatters/silent.js +9 -0
- package/formatters/terminal.js +56 -0
- package/index.d.ts +3334 -0
- package/index.js +120 -0
- package/internal-inject-env.js +42 -0
- package/layers/ConfigLive.js +47 -0
- package/layers/DataReaderLive.js +1666 -0
- package/layers/DataStoreLive.js +1185 -0
- package/layers/DetailResolverLive.js +9 -0
- package/layers/DiscoveryRegistryLive.js +70 -0
- package/layers/EnvironmentDetectorLive.js +21 -0
- package/layers/EnvironmentDetectorTest.js +13 -0
- package/layers/ExecutorResolverLive.js +9 -0
- package/layers/FormatSelectorLive.js +20 -0
- package/layers/HistoryTrackerLive.js +47 -0
- package/layers/HistoryTrackerTest.js +25 -0
- package/layers/LoggerLive.js +64 -0
- package/layers/OutputPipelineLive.js +13 -0
- package/layers/OutputRendererLive.js +28 -0
- package/layers/PathResolutionLive.js +36 -0
- package/layers/PerClientSessionMapLive.js +145 -0
- package/layers/ProjectDiscoveryLive.js +70 -0
- package/layers/ProjectDiscoveryTest.js +12 -0
- package/layers/ProjectIdentityLive.js +92 -0
- package/layers/RunContextLive.js +81 -0
- package/lib/format-triage.js +103 -0
- package/lib/format-wrapup.js +67 -0
- package/migrations/0001_initial.js +849 -0
- package/migrations/registry_0001_initial.js +39 -0
- package/migrations/session_map_0001_initial.js +61 -0
- package/package.json +64 -0
- package/schemas/Agent.js +42 -0
- package/schemas/AgentReport.js +71 -0
- package/schemas/Baselines.js +16 -0
- package/schemas/CacheManifest.js +27 -0
- package/schemas/ChannelEvent.js +138 -0
- package/schemas/Common.js +105 -0
- package/schemas/Config.js +28 -0
- package/schemas/Coverage.js +51 -0
- package/schemas/CoverageLevel.js +117 -0
- package/schemas/CoverageTargets.js +39 -0
- package/schemas/History.js +31 -0
- package/schemas/Identity.js +64 -0
- package/schemas/Options.js +57 -0
- package/schemas/RenderState.js +161 -0
- package/schemas/RunEvent.js +163 -0
- package/schemas/Tdd.js +44 -0
- package/schemas/Thresholds.js +30 -0
- package/schemas/Transport.js +16 -0
- package/schemas/Trends.js +23 -0
- package/schemas/turns/FileEditPayload.js +15 -0
- package/schemas/turns/HookFirePayload.js +13 -0
- package/schemas/turns/HypothesisPayload.js +13 -0
- package/schemas/turns/NotePayload.js +13 -0
- package/schemas/turns/ToolCallPayload.js +13 -0
- package/schemas/turns/ToolResultPayload.js +15 -0
- package/schemas/turns/UserPromptPayload.js +12 -0
- package/schemas/turns/index.js +15 -0
- package/services/Config.js +15 -0
- package/services/DataReader.js +8 -0
- package/services/DataStore.js +8 -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 +8 -0
- package/services/OutputRenderer.js +8 -0
- package/services/PerClientSessionMap.js +22 -0
- package/services/ProjectDiscovery.js +8 -0
- package/services/ProjectIdentity.js +63 -0
- package/services/RunContext.js +53 -0
- package/services/idempotency.js +57 -0
- package/sidecar-dispatch.js +84 -0
- package/sql/assemblers.js +59 -0
- package/testing/layers.js +21 -0
- package/testing.d.ts +25 -0
- package/testing.js +243 -0
- package/tsdoc-metadata.json +11 -0
- package/utils/ansi.js +49 -0
- package/utils/build-report.js +130 -0
- package/utils/canonicalize-git-url.js +66 -0
- package/utils/classify-test.js +22 -0
- package/utils/compress-lines.js +45 -0
- package/utils/compute-trend.js +88 -0
- package/utils/detect-pm.js +58 -0
- package/utils/detect-timeout.js +17 -0
- package/utils/ensure-migrated.js +52 -0
- package/utils/failure-signature.js +33 -0
- package/utils/format-console.js +219 -0
- package/utils/format-fatal-error.js +35 -0
- package/utils/format-gfm.js +161 -0
- package/utils/format-terminal.js +480 -0
- package/utils/function-boundary.js +75 -0
- package/utils/hyperlink.js +11 -0
- package/utils/match-vitest-command.js +88 -0
- package/utils/normalize-workspace-key.js +34 -0
- package/utils/probe-host-metadata.js +99 -0
- package/utils/resolve-data-path.js +66 -0
- package/utils/resolve-project-key-from-cwd.js +52 -0
- package/utils/resolve-workspace-key.js +33 -0
- package/utils/safe-filename.js +34 -0
- package/utils/validate-coverage-targets-shape.js +84 -0
- package/utils/validate-phase-transition.js +113 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "@effect/sql/SqlClient";
|
|
3
|
+
|
|
4
|
+
//#region src/migrations/registry_0001_initial.ts
|
|
5
|
+
/**
|
|
6
|
+
* Migration for the global discovery registry SQLite at
|
|
7
|
+
* `$XDG_DATA_HOME/vitest-agent/registry.db`.
|
|
8
|
+
*
|
|
9
|
+
* Single table `known_projects` indexed by `project_key` (the
|
|
10
|
+
* filesystem-safe form from {@link ProjectIdentity}). Tooling like
|
|
11
|
+
* `mcp-app` queries this table to enumerate every vitest-agent
|
|
12
|
+
* project the user has ever run on this machine.
|
|
13
|
+
*
|
|
14
|
+
* The registry never blocks anything — its writes are best-effort.
|
|
15
|
+
* Concurrent writers from multiple Claude Code windows converge via
|
|
16
|
+
* the `ON CONFLICT(project_key) DO UPDATE` upsert.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
const migration = Effect.gen(function* () {
|
|
20
|
+
const sql = yield* SqlClient;
|
|
21
|
+
yield* sql`PRAGMA journal_mode=WAL`;
|
|
22
|
+
yield* sql`PRAGMA foreign_keys=ON`;
|
|
23
|
+
yield* sql`PRAGMA busy_timeout=5000`;
|
|
24
|
+
yield* sql`
|
|
25
|
+
CREATE TABLE known_projects (
|
|
26
|
+
project_key TEXT PRIMARY KEY,
|
|
27
|
+
canonical_form TEXT NOT NULL,
|
|
28
|
+
data_db_path TEXT NOT NULL,
|
|
29
|
+
git_remote_origin TEXT,
|
|
30
|
+
workspace_root TEXT NOT NULL,
|
|
31
|
+
first_seen_at INTEGER NOT NULL,
|
|
32
|
+
last_seen_at INTEGER NOT NULL
|
|
33
|
+
) STRICT
|
|
34
|
+
`;
|
|
35
|
+
yield* sql`CREATE INDEX idx_known_projects_workspace_root ON known_projects(workspace_root)`;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { migration as default };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { SqlClient } from "@effect/sql/SqlClient";
|
|
3
|
+
|
|
4
|
+
//#region src/migrations/session_map_0001_initial.ts
|
|
5
|
+
/**
|
|
6
|
+
* Migration for the per-client session map SQLite at
|
|
7
|
+
* `${CLAUDE_PLUGIN_DATA}/sessions.db` (Claude Code) or the
|
|
8
|
+
* client-specific equivalent.
|
|
9
|
+
*
|
|
10
|
+
* The session map is a host-specific side-channel that translates
|
|
11
|
+
* client-native identifiers (transcript path, hook-payload session id)
|
|
12
|
+
* into the canonical UUIDs the per-project `data.db` expects. It lets
|
|
13
|
+
* `claude --resume` reuse the same `conversation_id` UUID across
|
|
14
|
+
* restarts.
|
|
15
|
+
*
|
|
16
|
+
* Two STRICT tables:
|
|
17
|
+
* - `conversation_map` keyed on the transcript filename UUID
|
|
18
|
+
* (already a UUID per Claude Code's convention)
|
|
19
|
+
* - `session_map` keyed on the host's native session id (the chat
|
|
20
|
+
* UUID — `session_id` from the Claude Code hook payload, exposed
|
|
21
|
+
* to agents as `chatId` post the 2026-05 rename)
|
|
22
|
+
*
|
|
23
|
+
* Concurrent writers from multiple Claude Code windows converge via
|
|
24
|
+
* idempotent UPSERTs on the native-id keys; WAL mode plus 5s
|
|
25
|
+
* busy_timeout absorb contention.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
/** @internal */
|
|
29
|
+
const migration = Effect.gen(function* () {
|
|
30
|
+
const sql = yield* SqlClient;
|
|
31
|
+
yield* sql`PRAGMA journal_mode=WAL`;
|
|
32
|
+
yield* sql`PRAGMA foreign_keys=ON`;
|
|
33
|
+
yield* sql`PRAGMA busy_timeout=5000`;
|
|
34
|
+
yield* sql`
|
|
35
|
+
CREATE TABLE conversation_map (
|
|
36
|
+
transcript_uuid TEXT PRIMARY KEY,
|
|
37
|
+
transcript_path TEXT NOT NULL,
|
|
38
|
+
conversation_id TEXT NOT NULL UNIQUE,
|
|
39
|
+
first_seen_at INTEGER NOT NULL,
|
|
40
|
+
last_seen_at INTEGER NOT NULL
|
|
41
|
+
) STRICT
|
|
42
|
+
`;
|
|
43
|
+
yield* sql`
|
|
44
|
+
CREATE TABLE session_map (
|
|
45
|
+
host_session_id TEXT PRIMARY KEY,
|
|
46
|
+
conversation_id TEXT NOT NULL REFERENCES conversation_map(conversation_id) ON DELETE RESTRICT,
|
|
47
|
+
project_key TEXT NOT NULL,
|
|
48
|
+
project_dir TEXT NOT NULL,
|
|
49
|
+
main_agent_id TEXT NOT NULL,
|
|
50
|
+
started_at INTEGER NOT NULL,
|
|
51
|
+
ended_at INTEGER
|
|
52
|
+
) STRICT
|
|
53
|
+
`;
|
|
54
|
+
yield* sql`CREATE INDEX idx_session_map_project_key ON session_map(project_key)`;
|
|
55
|
+
yield* sql`CREATE INDEX idx_session_map_project_dir ON session_map(project_dir)`;
|
|
56
|
+
yield* sql`CREATE INDEX idx_session_map_active ON session_map(project_dir) WHERE ended_at IS NULL`;
|
|
57
|
+
yield* sql`CREATE INDEX idx_session_map_conversation_id ON session_map(conversation_id)`;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
export { migration as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vitest-agent/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Shared Effect Schema, SQLite migrations, data layer, services, formatters, and utilities for vitest-agent packages.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"vitest",
|
|
8
|
+
"agent",
|
|
9
|
+
"shared",
|
|
10
|
+
"effect",
|
|
11
|
+
"sqlite"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/spencerbeggs/vitest-agent#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/spencerbeggs/vitest-agent/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/spencerbeggs/vitest-agent.git",
|
|
20
|
+
"directory": "packages/sdk"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": {
|
|
24
|
+
"name": "C. Spencer Beggs",
|
|
25
|
+
"email": "spencer@beggs.codes",
|
|
26
|
+
"url": "https://spencerbeg.gs"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./index.d.ts",
|
|
32
|
+
"import": "./index.js"
|
|
33
|
+
},
|
|
34
|
+
"./dispatch": {
|
|
35
|
+
"types": "./dispatch.d.ts",
|
|
36
|
+
"import": "./dispatch.js"
|
|
37
|
+
},
|
|
38
|
+
"./testing": {
|
|
39
|
+
"types": "./testing.d.ts",
|
|
40
|
+
"import": "./testing.js"
|
|
41
|
+
},
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@effect/cluster": "^0.59.0",
|
|
46
|
+
"@effect/platform": "^0.96.2",
|
|
47
|
+
"@effect/platform-node": "^0.107.0",
|
|
48
|
+
"@effect/rpc": "^0.75.1",
|
|
49
|
+
"@effect/sql": "^0.51.1",
|
|
50
|
+
"@effect/sql-sqlite-node": "^0.52.0",
|
|
51
|
+
"@types/acorn": "^6.0.4",
|
|
52
|
+
"acorn": "^8.17.0",
|
|
53
|
+
"acorn-typescript": "^1.4.13",
|
|
54
|
+
"ajv": "^8.20.0",
|
|
55
|
+
"config-file-effect": "^0.2.3",
|
|
56
|
+
"effect": "^3.21.4",
|
|
57
|
+
"std-env": "^4.1.0",
|
|
58
|
+
"workspaces-effect": "^1.2.0",
|
|
59
|
+
"xdg-effect": "^2.0.1"
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=24.11.0"
|
|
63
|
+
}
|
|
64
|
+
}
|
package/schemas/Agent.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AgentId, ConversationId } from "./Identity.js";
|
|
2
|
+
import { Data, Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/Agent.ts
|
|
5
|
+
/**
|
|
6
|
+
* Successful registration row. The fields mirror the `agents` SQLite
|
|
7
|
+
* table 1:1 in camelCase.
|
|
8
|
+
*
|
|
9
|
+
* `startGitBranch`, `startGitCommitSha`, `startWorktreeDir` capture
|
|
10
|
+
* *what the agent inherited at registration time* — distinct from the
|
|
11
|
+
* per-run git context recorded on `runs`. A divergence between the
|
|
12
|
+
* two reveals a mid-session branch switch, which is itself signal.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
var Agent = class extends Schema.TaggedClass()("Agent", {
|
|
16
|
+
agentId: AgentId,
|
|
17
|
+
sessionId: Schema.Number,
|
|
18
|
+
parentAgentId: Schema.NullOr(AgentId),
|
|
19
|
+
conversationId: Schema.NullOr(ConversationId),
|
|
20
|
+
agentType: Schema.String,
|
|
21
|
+
startedAt: Schema.Number,
|
|
22
|
+
endedAt: Schema.NullOr(Schema.Number),
|
|
23
|
+
startGitBranch: Schema.NullOr(Schema.String),
|
|
24
|
+
startGitCommitSha: Schema.NullOr(Schema.String),
|
|
25
|
+
startWorktreeDir: Schema.NullOr(Schema.String),
|
|
26
|
+
idempotencyKey: Schema.String
|
|
27
|
+
}) {};
|
|
28
|
+
/**
|
|
29
|
+
* Returned by `DataStore.registerAgent` when the
|
|
30
|
+
* `(session_id, idempotency_key)` UNIQUE constraint already has a
|
|
31
|
+
* row. Not an error — the caller treats it as a successful recovery
|
|
32
|
+
* of the existing `agentId`.
|
|
33
|
+
*
|
|
34
|
+
* Modeled as a `Data.TaggedClass` so the success channel of
|
|
35
|
+
* `registerAgent` is `Effect<Agent | IdempotencyHit, ...>` and
|
|
36
|
+
* downstream code uses `Match.tag` to branch.
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
var IdempotencyHit = class extends Data.TaggedClass("IdempotencyHit") {};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Agent, IdempotencyHit };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ReportError, TestClassification, TestRunReason, TestState } from "./Common.js";
|
|
2
|
+
import { CoverageReport } from "./Coverage.js";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/schemas/AgentReport.ts
|
|
6
|
+
/**
|
|
7
|
+
* Aggregate test run statistics.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
const ReportSummary = Schema.Struct({
|
|
11
|
+
total: Schema.Number,
|
|
12
|
+
passed: Schema.Number,
|
|
13
|
+
failed: Schema.Number,
|
|
14
|
+
skipped: Schema.Number,
|
|
15
|
+
duration: Schema.Number
|
|
16
|
+
}).annotations({ identifier: "ReportSummary" });
|
|
17
|
+
/**
|
|
18
|
+
* An individual test case result.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
const TestReport = Schema.Struct({
|
|
22
|
+
name: Schema.String,
|
|
23
|
+
fullName: Schema.String,
|
|
24
|
+
state: TestState,
|
|
25
|
+
duration: Schema.optional(Schema.Number),
|
|
26
|
+
flaky: Schema.optional(Schema.Boolean),
|
|
27
|
+
slow: Schema.optional(Schema.Boolean),
|
|
28
|
+
errors: Schema.optional(Schema.Array(ReportError)),
|
|
29
|
+
classification: Schema.optional(TestClassification)
|
|
30
|
+
}).annotations({ identifier: "TestReport" });
|
|
31
|
+
/**
|
|
32
|
+
* A test module (file) and its contained test cases.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
const ModuleReport = Schema.Struct({
|
|
36
|
+
file: Schema.String,
|
|
37
|
+
state: TestState,
|
|
38
|
+
duration: Schema.optional(Schema.Number),
|
|
39
|
+
errors: Schema.optional(Schema.Array(ReportError)),
|
|
40
|
+
tests: Schema.Array(TestReport)
|
|
41
|
+
}).annotations({ identifier: "ModuleReport" });
|
|
42
|
+
/**
|
|
43
|
+
* Per-tag pass/fail/skip aggregates for a single project run.
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
const TagCountEntry = Schema.Struct({
|
|
47
|
+
passed: Schema.optional(Schema.Number),
|
|
48
|
+
failed: Schema.optional(Schema.Number),
|
|
49
|
+
skipped: Schema.optional(Schema.Number)
|
|
50
|
+
}).annotations({ identifier: "TagCountEntry" });
|
|
51
|
+
/**
|
|
52
|
+
* Complete per-project test report written to disk as JSON.
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
const AgentReport = Schema.Struct({
|
|
56
|
+
timestamp: Schema.String,
|
|
57
|
+
project: Schema.optional(Schema.String),
|
|
58
|
+
reason: TestRunReason,
|
|
59
|
+
summary: ReportSummary,
|
|
60
|
+
failed: Schema.Array(ModuleReport),
|
|
61
|
+
unhandledErrors: Schema.Array(ReportError),
|
|
62
|
+
failedFiles: Schema.Array(Schema.String),
|
|
63
|
+
coverage: Schema.optional(CoverageReport),
|
|
64
|
+
tagCounts: Schema.optional(Schema.Record({
|
|
65
|
+
key: Schema.String,
|
|
66
|
+
value: TagCountEntry
|
|
67
|
+
}))
|
|
68
|
+
}).annotations({ identifier: "AgentReport" });
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { AgentReport, ModuleReport, ReportSummary, TagCountEntry, TestReport };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MetricThresholds, PatternThresholds } from "./Thresholds.js";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/Baselines.ts
|
|
5
|
+
/**
|
|
6
|
+
* Coverage baselines -- the auto-ratcheting high-water mark.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
const CoverageBaselines = Schema.Struct({
|
|
10
|
+
updatedAt: Schema.String,
|
|
11
|
+
global: MetricThresholds,
|
|
12
|
+
patterns: Schema.optionalWith(Schema.Array(PatternThresholds), { default: () => [] })
|
|
13
|
+
}).annotations({ identifier: "CoverageBaselines" });
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { CoverageBaselines };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TestRunReason } from "./Common.js";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/CacheManifest.ts
|
|
5
|
+
/**
|
|
6
|
+
* A single project entry in the cache manifest.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
const CacheManifestEntry = Schema.Struct({
|
|
10
|
+
project: Schema.String,
|
|
11
|
+
reportFile: Schema.String,
|
|
12
|
+
historyFile: Schema.optional(Schema.String),
|
|
13
|
+
lastRun: Schema.NullOr(Schema.String),
|
|
14
|
+
lastResult: Schema.NullOr(TestRunReason)
|
|
15
|
+
}).annotations({ identifier: "CacheManifestEntry" });
|
|
16
|
+
/**
|
|
17
|
+
* Root manifest file that indexes all project reports.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
const CacheManifest = Schema.Struct({
|
|
21
|
+
updatedAt: Schema.String,
|
|
22
|
+
cacheDir: Schema.String,
|
|
23
|
+
projects: Schema.Array(CacheManifestEntry)
|
|
24
|
+
}).annotations({ identifier: "CacheManifest" });
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { CacheManifest, CacheManifestEntry };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/ChannelEvent.ts
|
|
4
|
+
/**
|
|
5
|
+
* Channel event schemas for the orchestrator → main-agent progress push.
|
|
6
|
+
*
|
|
7
|
+
* All payloads share a `type` discriminator and pass through
|
|
8
|
+
* `tdd_progress_push`. Behavior-level events declare goalId/sessionId
|
|
9
|
+
* fields, but the MCP server resolves those server-side from
|
|
10
|
+
* behaviorId via `DataReader.resolveGoalIdForBehavior` before emitting
|
|
11
|
+
* the notification — caller-supplied values for goalId/sessionId on
|
|
12
|
+
* behavior events are advisory and may be overwritten.
|
|
13
|
+
*/
|
|
14
|
+
/** @public */
|
|
15
|
+
const SessionOutcome = Schema.Literal("succeeded", "blocked", "abandoned");
|
|
16
|
+
const PhaseLiteral = Schema.Literal("spike", "red", "red.triangulate", "green", "green.fake-it", "refactor", "extended-red", "green-without-red");
|
|
17
|
+
const GoalSummary = Schema.Struct({
|
|
18
|
+
id: Schema.Number,
|
|
19
|
+
ordinal: Schema.Number,
|
|
20
|
+
goal: Schema.String
|
|
21
|
+
});
|
|
22
|
+
const BehaviorSummary = Schema.Struct({
|
|
23
|
+
id: Schema.Number,
|
|
24
|
+
ordinal: Schema.Number,
|
|
25
|
+
behavior: Schema.String
|
|
26
|
+
});
|
|
27
|
+
/** @public */
|
|
28
|
+
const GoalsReadyEvent = Schema.Struct({
|
|
29
|
+
type: Schema.Literal("goals_ready"),
|
|
30
|
+
sessionId: Schema.Number,
|
|
31
|
+
goals: Schema.Array(GoalSummary)
|
|
32
|
+
});
|
|
33
|
+
/** @public */
|
|
34
|
+
const GoalAddedEvent = Schema.Struct({
|
|
35
|
+
type: Schema.Literal("goal_added"),
|
|
36
|
+
sessionId: Schema.Number,
|
|
37
|
+
goal: GoalSummary
|
|
38
|
+
});
|
|
39
|
+
/** @public */
|
|
40
|
+
const GoalStartedEvent = Schema.Struct({
|
|
41
|
+
type: Schema.Literal("goal_started"),
|
|
42
|
+
sessionId: Schema.Number,
|
|
43
|
+
goalId: Schema.Number
|
|
44
|
+
});
|
|
45
|
+
/** @public */
|
|
46
|
+
const GoalCompletedEvent = Schema.Struct({
|
|
47
|
+
type: Schema.Literal("goal_completed"),
|
|
48
|
+
sessionId: Schema.Number,
|
|
49
|
+
goalId: Schema.Number,
|
|
50
|
+
behaviorIds: Schema.Array(Schema.Number)
|
|
51
|
+
});
|
|
52
|
+
/** @public */
|
|
53
|
+
const GoalAbandonedEvent = Schema.Struct({
|
|
54
|
+
type: Schema.Literal("goal_abandoned"),
|
|
55
|
+
sessionId: Schema.Number,
|
|
56
|
+
goalId: Schema.Number,
|
|
57
|
+
reason: Schema.String
|
|
58
|
+
});
|
|
59
|
+
/** @public */
|
|
60
|
+
const BehaviorsReadyEvent = Schema.Struct({
|
|
61
|
+
type: Schema.Literal("behaviors_ready"),
|
|
62
|
+
sessionId: Schema.Number,
|
|
63
|
+
goalId: Schema.Number,
|
|
64
|
+
behaviors: Schema.Array(BehaviorSummary)
|
|
65
|
+
});
|
|
66
|
+
/** @public */
|
|
67
|
+
const BehaviorAddedEvent = Schema.Struct({
|
|
68
|
+
type: Schema.Literal("behavior_added"),
|
|
69
|
+
sessionId: Schema.Number,
|
|
70
|
+
goalId: Schema.Number,
|
|
71
|
+
behavior: BehaviorSummary
|
|
72
|
+
});
|
|
73
|
+
/** @public */
|
|
74
|
+
const BehaviorStartedEvent = Schema.Struct({
|
|
75
|
+
type: Schema.Literal("behavior_started"),
|
|
76
|
+
sessionId: Schema.Number,
|
|
77
|
+
goalId: Schema.Number,
|
|
78
|
+
behaviorId: Schema.Number
|
|
79
|
+
});
|
|
80
|
+
/** @public */
|
|
81
|
+
const PhaseTransitionEvent = Schema.Struct({
|
|
82
|
+
type: Schema.Literal("phase_transition"),
|
|
83
|
+
sessionId: Schema.Number,
|
|
84
|
+
goalId: Schema.Number,
|
|
85
|
+
behaviorId: Schema.Number,
|
|
86
|
+
from: PhaseLiteral,
|
|
87
|
+
to: PhaseLiteral
|
|
88
|
+
});
|
|
89
|
+
/** @public */
|
|
90
|
+
const BehaviorCompletedEvent = Schema.Struct({
|
|
91
|
+
type: Schema.Literal("behavior_completed"),
|
|
92
|
+
sessionId: Schema.Number,
|
|
93
|
+
goalId: Schema.Number,
|
|
94
|
+
behaviorId: Schema.Number
|
|
95
|
+
});
|
|
96
|
+
/** @public */
|
|
97
|
+
const BehaviorAbandonedEvent = Schema.Struct({
|
|
98
|
+
type: Schema.Literal("behavior_abandoned"),
|
|
99
|
+
sessionId: Schema.Number,
|
|
100
|
+
goalId: Schema.Number,
|
|
101
|
+
behaviorId: Schema.Number,
|
|
102
|
+
reason: Schema.String
|
|
103
|
+
});
|
|
104
|
+
/** @public */
|
|
105
|
+
const BlockedEvent = Schema.Struct({
|
|
106
|
+
type: Schema.Literal("blocked"),
|
|
107
|
+
sessionId: Schema.Number,
|
|
108
|
+
goalId: Schema.Number,
|
|
109
|
+
behaviorId: Schema.Number,
|
|
110
|
+
reason: Schema.String,
|
|
111
|
+
failureSignatureHash: Schema.optional(Schema.String)
|
|
112
|
+
});
|
|
113
|
+
/** @public */
|
|
114
|
+
const SessionCompleteEvent = Schema.Struct({
|
|
115
|
+
type: Schema.Literal("session_complete"),
|
|
116
|
+
sessionId: Schema.Number,
|
|
117
|
+
goalIds: Schema.Array(Schema.Number),
|
|
118
|
+
outcome: SessionOutcome
|
|
119
|
+
});
|
|
120
|
+
/** @public */
|
|
121
|
+
const ChannelEvent = Schema.Union(GoalsReadyEvent, GoalAddedEvent, GoalStartedEvent, GoalCompletedEvent, GoalAbandonedEvent, BehaviorsReadyEvent, BehaviorAddedEvent, BehaviorStartedEvent, PhaseTransitionEvent, BehaviorCompletedEvent, BehaviorAbandonedEvent, BlockedEvent, SessionCompleteEvent);
|
|
122
|
+
/**
|
|
123
|
+
* Event types whose `goalId` and `sessionId` should be resolved
|
|
124
|
+
* server-side from `behaviorId` (per spec: "not trusting the
|
|
125
|
+
* orchestrator's request"). Listed explicitly so the resolver knows
|
|
126
|
+
* which subset to enrich vs pass through.
|
|
127
|
+
* @public
|
|
128
|
+
*/
|
|
129
|
+
const BehaviorScopedEventTypes = [
|
|
130
|
+
"behavior_started",
|
|
131
|
+
"phase_transition",
|
|
132
|
+
"behavior_completed",
|
|
133
|
+
"behavior_abandoned",
|
|
134
|
+
"blocked"
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
//#endregion
|
|
138
|
+
export { BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorsReadyEvent, BlockedEvent, ChannelEvent, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalStartedEvent, GoalsReadyEvent, PhaseTransitionEvent, SessionCompleteEvent, SessionOutcome };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/Common.ts
|
|
4
|
+
/**
|
|
5
|
+
* Common schemas shared across multiple modules.
|
|
6
|
+
*
|
|
7
|
+
* Defines enums/literals and the ReportError struct used by
|
|
8
|
+
* both AgentReport and CacheManifest schemas.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Possible states for an individual test case.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
const TestState = Schema.Literal("passed", "failed", "skipped", "pending").annotations({ identifier: "TestState" });
|
|
15
|
+
/**
|
|
16
|
+
* Overall outcome of a test run.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
const TestRunReason = Schema.Literal("passed", "failed", "interrupted").annotations({ identifier: "TestRunReason" });
|
|
20
|
+
/**
|
|
21
|
+
* Classification of a test's failure history across runs.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
const TestClassification = Schema.Literal("stable", "new-failure", "persistent", "flaky", "recovered").annotations({ identifier: "TestClassification" });
|
|
25
|
+
/**
|
|
26
|
+
* Console output verbosity mode for AgentReporter.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
const ConsoleOutputMode = Schema.Literal("failures", "full", "silent").annotations({ identifier: "ConsoleOutputMode" });
|
|
30
|
+
/**
|
|
31
|
+
* Console output choices per executor type.
|
|
32
|
+
*
|
|
33
|
+
* - `passthrough` — plugin emits nothing observable; Vitest's own reporters
|
|
34
|
+
* do the visible work. Persistence still runs. Default for `human` and `ci`.
|
|
35
|
+
* - `silent` — strip Vitest's reporters AND emit nothing from the plugin.
|
|
36
|
+
* True silence. Persistence still runs.
|
|
37
|
+
* - `agent` — markdown-flavored final-frame string tuned for token economy.
|
|
38
|
+
* Default for `agent` executor. Set on `human` as the debugging mode for
|
|
39
|
+
* inspecting the exact plain-text output an agent consumes.
|
|
40
|
+
* - `stream` — progressively-drawn, colored, animated rendering of the
|
|
41
|
+
* agent's run-shape view. Strips Vitest's reporters and owns stdout for
|
|
42
|
+
* the duration of the run. Human executor only.
|
|
43
|
+
* - `ci-annotations` — GitHub Actions `::error::` annotations. Opt-in for
|
|
44
|
+
* the `ci` executor; the matching dedicated emitter is not yet shipped,
|
|
45
|
+
* so the default for `ci` is `passthrough` until it lands.
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
const HumanConsoleMode = Schema.Literal("passthrough", "silent", "stream", "agent").annotations({ identifier: "HumanConsoleMode" });
|
|
49
|
+
/** @public */
|
|
50
|
+
const AgentConsoleMode = Schema.Literal("passthrough", "silent", "agent").annotations({ identifier: "AgentConsoleMode" });
|
|
51
|
+
/** @public */
|
|
52
|
+
const CiConsoleMode = Schema.Literal("passthrough", "silent", "ci-annotations").annotations({ identifier: "CiConsoleMode" });
|
|
53
|
+
/**
|
|
54
|
+
* Union of every legal console-output value across the three executor slots.
|
|
55
|
+
* Useful for type-narrowing in renderers that take the resolved value.
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
const ConsoleMode = Schema.Union(HumanConsoleMode, AgentConsoleMode, CiConsoleMode).annotations({ identifier: "ConsoleMode" });
|
|
59
|
+
/**
|
|
60
|
+
* Supported package managers for run command generation.
|
|
61
|
+
* @public
|
|
62
|
+
*/
|
|
63
|
+
const PackageManager = Schema.Literal("pnpm", "npm", "yarn", "bun").annotations({ identifier: "PackageManager" });
|
|
64
|
+
/**
|
|
65
|
+
* Runtime environment where tests are being executed.
|
|
66
|
+
* @public
|
|
67
|
+
*/
|
|
68
|
+
const Environment = Schema.Literal("agent-shell", "terminal", "ci-github", "ci-generic").annotations({ identifier: "Environment" });
|
|
69
|
+
/**
|
|
70
|
+
* Who or what is executing the test run.
|
|
71
|
+
* @public
|
|
72
|
+
*/
|
|
73
|
+
const Executor = Schema.Literal("human", "agent", "ci").annotations({ identifier: "Executor" });
|
|
74
|
+
/**
|
|
75
|
+
* Output format for the reporter pipeline.
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
const OutputFormat = Schema.Literal("terminal", "markdown", "json", "vitest-bypass", "silent", "ci-annotations").annotations({ identifier: "OutputFormat" });
|
|
79
|
+
/**
|
|
80
|
+
* Level of detail in reporter output.
|
|
81
|
+
* @public
|
|
82
|
+
*/
|
|
83
|
+
const DetailLevel = Schema.Literal("minimal", "neutral", "standard", "verbose").annotations({ identifier: "DetailLevel" });
|
|
84
|
+
/**
|
|
85
|
+
* A single test or module error with optional stack trace, diff, and
|
|
86
|
+
* structured assertion values.
|
|
87
|
+
*
|
|
88
|
+
* `expected` / `received` are pre-stringified, one-line representations
|
|
89
|
+
* of the assertion's expected and received JS values. They are populated
|
|
90
|
+
* only when the underlying test runner error carries structured `.expected`
|
|
91
|
+
* / `.actual` properties (assertion errors). The raw JS values stay in
|
|
92
|
+
* Vitest's internal error object; only the string representation crosses
|
|
93
|
+
* the schema boundary.
|
|
94
|
+
* @public
|
|
95
|
+
*/
|
|
96
|
+
const ReportError = Schema.Struct({
|
|
97
|
+
message: Schema.String,
|
|
98
|
+
stack: Schema.optional(Schema.String),
|
|
99
|
+
diff: Schema.optional(Schema.String),
|
|
100
|
+
expected: Schema.optional(Schema.String),
|
|
101
|
+
received: Schema.optional(Schema.String)
|
|
102
|
+
}).annotations({ identifier: "ReportError" });
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { AgentConsoleMode, CiConsoleMode, ConsoleMode, ConsoleOutputMode, DetailLevel, Environment, Executor, HumanConsoleMode, OutputFormat, PackageManager, ReportError, TestClassification, TestRunReason, TestState };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/Config.ts
|
|
4
|
+
/**
|
|
5
|
+
* Schema for the optional `vitest-agent.config.toml` file.
|
|
6
|
+
*
|
|
7
|
+
* Both fields are optional. When the file is absent or these fields are
|
|
8
|
+
* unset, `resolveDataPath` falls back to deriving the path from the
|
|
9
|
+
* workspace's `package.json` `name` under the XDG data directory.
|
|
10
|
+
*
|
|
11
|
+
* Fields:
|
|
12
|
+
* - `cacheDir` — absolute path overriding the entire data directory. Highest
|
|
13
|
+
* precedence after the programmatic option. Use this to relocate the SQLite
|
|
14
|
+
* database (e.g. project-local `.vitest-agent/`) instead of the
|
|
15
|
+
* default XDG location.
|
|
16
|
+
* - `projectKey` — overrides the workspace key segment under the XDG data
|
|
17
|
+
* directory. Use this when two unrelated projects on the same machine
|
|
18
|
+
* share a `package.json` `name` (the collision case for workspace-name
|
|
19
|
+
* keying), or when you want a stable key independent of `name` changes.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
var VitestAgentConfig = class extends Schema.Class("VitestAgentConfig")({
|
|
23
|
+
cacheDir: Schema.optional(Schema.String),
|
|
24
|
+
projectKey: Schema.optional(Schema.String)
|
|
25
|
+
}) {};
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { VitestAgentConfig };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { MetricThresholds, PatternThresholds } from "./Thresholds.js";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/Coverage.ts
|
|
5
|
+
/**
|
|
6
|
+
* Aggregate coverage percentages across four istanbul metrics.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
const CoverageTotals = Schema.Struct({
|
|
10
|
+
statements: Schema.Number,
|
|
11
|
+
branches: Schema.Number,
|
|
12
|
+
functions: Schema.Number,
|
|
13
|
+
lines: Schema.Number
|
|
14
|
+
}).annotations({ identifier: "CoverageTotals" });
|
|
15
|
+
/**
|
|
16
|
+
* Per-file coverage data including uncovered line ranges.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
const FileCoverageReport = Schema.Struct({
|
|
20
|
+
file: Schema.String,
|
|
21
|
+
summary: CoverageTotals,
|
|
22
|
+
uncoveredLines: Schema.String
|
|
23
|
+
}).annotations({ identifier: "FileCoverageReport" });
|
|
24
|
+
/**
|
|
25
|
+
* Complete coverage report attached to an AgentReport.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
const CoverageReport = Schema.Struct({
|
|
29
|
+
totals: CoverageTotals,
|
|
30
|
+
thresholds: Schema.Struct({
|
|
31
|
+
global: MetricThresholds,
|
|
32
|
+
patterns: Schema.optionalWith(Schema.Array(PatternThresholds), { default: () => [] })
|
|
33
|
+
}),
|
|
34
|
+
targets: Schema.optional(Schema.Struct({
|
|
35
|
+
global: MetricThresholds,
|
|
36
|
+
patterns: Schema.optionalWith(Schema.Array(PatternThresholds), { default: () => [] })
|
|
37
|
+
})),
|
|
38
|
+
baselines: Schema.optional(Schema.Struct({
|
|
39
|
+
global: MetricThresholds,
|
|
40
|
+
patterns: Schema.optionalWith(Schema.Array(PatternThresholds), { default: () => [] })
|
|
41
|
+
})),
|
|
42
|
+
scoped: Schema.optionalWith(Schema.Boolean, { default: () => false }),
|
|
43
|
+
scopedFiles: Schema.optional(Schema.Array(Schema.String)),
|
|
44
|
+
lowCoverage: Schema.Array(FileCoverageReport),
|
|
45
|
+
lowCoverageFiles: Schema.Array(Schema.String),
|
|
46
|
+
belowTarget: Schema.optional(Schema.Array(FileCoverageReport)),
|
|
47
|
+
belowTargetFiles: Schema.optional(Schema.Array(Schema.String))
|
|
48
|
+
}).annotations({ identifier: "CoverageReport" });
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { CoverageReport, CoverageTotals, FileCoverageReport };
|