@vitest-agent/sdk 3.1.2 → 4.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.
Files changed (65) hide show
  1. package/README.md +23 -19
  2. package/dispatch.d.ts +25 -6
  3. package/formatters/markdown.js +1 -0
  4. package/formatters/terminal.js +4 -3
  5. package/index.d.ts +448 -2341
  6. package/index.js +10 -68
  7. package/internal-inject-env.js +5 -7
  8. package/package.json +3 -19
  9. package/sidecar-dispatch.js +7 -5
  10. package/utils/format-console.js +9 -10
  11. package/utils/format-terminal.js +7 -7
  12. package/utils/posix-path.js +52 -0
  13. package/utils/test-location.js +11 -5
  14. package/version.js +17 -0
  15. package/layers/ConfigLive.js +0 -46
  16. package/layers/DataReaderLive.js +0 -1923
  17. package/layers/DataStoreLive.js +0 -1287
  18. package/layers/DetailResolverLive.js +0 -9
  19. package/layers/DiscoveryRegistryLive.js +0 -70
  20. package/layers/EnvironmentDetectorLive.js +0 -21
  21. package/layers/EnvironmentDetectorTest.js +0 -13
  22. package/layers/ExecutorResolverLive.js +0 -9
  23. package/layers/FormatSelectorLive.js +0 -20
  24. package/layers/HistoryTrackerLive.js +0 -49
  25. package/layers/HistoryTrackerTest.js +0 -25
  26. package/layers/LoggerLive.js +0 -64
  27. package/layers/OutputPipelineLive.js +0 -13
  28. package/layers/OutputRendererLive.js +0 -28
  29. package/layers/PathResolutionLive.js +0 -40
  30. package/layers/PerClientSessionMapLive.js +0 -145
  31. package/layers/ProjectDiscoveryLive.js +0 -68
  32. package/layers/ProjectDiscoveryTest.js +0 -12
  33. package/layers/ProjectIdentityLive.js +0 -96
  34. package/layers/RunContextLive.js +0 -81
  35. package/lib/format-triage.js +0 -103
  36. package/lib/format-wrapup.js +0 -67
  37. package/migrations/0001_initial.js +0 -824
  38. package/migrations/0002_test_artifacts.js +0 -30
  39. package/migrations/index.js +0 -26
  40. package/migrations/registry_0001_initial.js +0 -39
  41. package/migrations/session_map_0001_initial.js +0 -38
  42. package/services/Config.js +0 -15
  43. package/services/DataReader.js +0 -8
  44. package/services/DataStore.js +0 -15
  45. package/services/DetailResolver.js +0 -8
  46. package/services/DiscoveryRegistry.js +0 -8
  47. package/services/EnvironmentDetector.js +0 -8
  48. package/services/ExecutorResolver.js +0 -8
  49. package/services/FormatSelector.js +0 -8
  50. package/services/HistoryTracker.js +0 -20
  51. package/services/OutputRenderer.js +0 -8
  52. package/services/PerClientSessionMap.js +0 -22
  53. package/services/ProjectDiscovery.js +0 -8
  54. package/services/ProjectIdentity.js +0 -63
  55. package/services/RunContext.js +0 -53
  56. package/services/idempotency.js +0 -58
  57. package/sql/assemblers.js +0 -69
  58. package/testing/layers.js +0 -21
  59. package/testing.d.ts +0 -1862
  60. package/testing.js +0 -254
  61. package/utils/ensure-migrated.js +0 -52
  62. package/utils/failure-signature.js +0 -34
  63. package/utils/resolve-data-path.js +0 -65
  64. package/utils/resolve-project-key-from-cwd.js +0 -53
  65. package/utils/resolve-workspace-key.js +0 -41
package/README.md CHANGED
@@ -4,18 +4,20 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-4caf50.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript 6.0](https://img.shields.io/badge/TypeScript-6.0-3178c6.svg)](https://www.typescriptlang.org/)
6
6
 
7
- > **Part of the [vitest-agent](https://vitest-agent.dev) ecosystem.** Most users want **[@vitest-agent/plugin](https://www.npmjs.com/package/@vitest-agent/plugin)**, which pulls this package in automatically. Install `@vitest-agent/sdk` directly only if you build tooling on the shared schemas or data layer.
7
+ > **Part of the [vitest-agent](https://vitest-agent.dev) ecosystem.** Most users want **[@vitest-agent/plugin](https://www.npmjs.com/package/@vitest-agent/plugin)**, which pulls this package in automatically. Install `@vitest-agent/sdk` directly only if you build tooling on the shared schemas or contract types.
8
8
 
9
- The no-internal-deps base for the vitest-agent ecosystem. Carries the Effect Schemas, SQLite migrations and data layer, services and live layers, formatters, XDG path resolution, the public reporter and dispatcher contract types, and testing utilities.
9
+ The platform-free core of the vitest-agent ecosystem. Carries the Effect Schemas, the public reporter and dispatcher contract types, the tagged errors, the pure formatters and utilities, the pure sidecar `dispatch` entry, and the published JSON Schemas. It has no workspace dependencies and never imports `node:*`, so it runs anywhere Effect does.
10
+
11
+ Everything that touches a filesystem, a process, or SQLite — the `DataStore` / `DataReader` services and their live layers, migrations, `ensureMigrated`, `PlatformLive`, `resolveDataPath`, and the test-layer helpers — lives in **[@vitest-agent/engine](https://www.npmjs.com/package/@vitest-agent/engine)**.
10
12
 
11
13
  ## Features
12
14
 
13
- - **Effect Schemas** — all domain types (`RunEvent`, `RenderState`, `CoverageTargets`, `TurnPayload`, identity types) defined with Effect Schema; runtime validation and TypeScript types from one source
14
- - **SQLite data layer** — `DataStore` and `DataReader` Effect services with live and `:memory:` test layers; `ensureMigrated` for safe multi-project setups
15
- - **XDG path resolution** — deterministic `dbPath` derivation from workspace identity with a five-source fallback chain
15
+ - **Effect Schemas** — all domain types (`AgentReport`, `RunEvent`, `RenderState`, `CoverageTargets`, `TurnPayload`, identity types) defined with Effect Schema; runtime validation and TypeScript types from one source
16
16
  - **Reporter and dispatcher contracts** — `VitestAgentReporterFactory`, `ReporterKit`, `ResolvedReporterConfig`, `DispatchInputs` and the types consumed by every other package
17
+ - **Tagged errors** — `Data.TaggedError` families for data-store, discovery, path-resolution, project-identity, run-context, TDD and agent failures
18
+ - **Pure formatters and utilities** — terminal, markdown, GFM, JSON and CI-annotation formatters, plus `classifyTestPath`, `buildAgentReport`, `validatePhaseTransition` and the posix path helpers
17
19
  - **Sidecar dispatch core** — `dispatch`, `injectEnv` and `exitCodeForTag` on the `@vitest-agent/sdk/dispatch` sub-path for a minimal SEA bundle
18
- - **Test utilities** — `makeTestLayer`, `DataStoreTestLayer` and five preset factory functions on the `@vitest-agent/sdk/testing` sub-path
20
+ - **JSON Schemas** — generated schemas on the `@vitest-agent/sdk/schemas/*.json` sub-path (for example the run-report file schema)
19
21
 
20
22
  ## Install
21
23
 
@@ -28,19 +30,21 @@ pnpm add @vitest-agent/sdk
28
30
  ## Quick start
29
31
 
30
32
  ```ts
31
- import { Effect } from "effect";
32
- import { DataReader } from "@vitest-agent/sdk";
33
- import { singlePassingRun } from "@vitest-agent/sdk/testing";
34
-
35
- const layer = singlePassingRun(":memory:");
36
-
37
- await Effect.runPromise(
38
- Effect.provide(
39
- Effect.flatMap(DataReader, (r) => r.getLatestRun("default", null)),
40
- layer,
41
- ),
42
- );
43
- // returns the seeded run row
33
+ import { Schema } from "effect";
34
+ import { AgentReport, CoverageLevel } from "@vitest-agent/sdk";
35
+
36
+ // Decode a persisted run report with the shared schema
37
+ const report = Schema.decodeUnknownSync(AgentReport)(JSON.parse(raw));
38
+
39
+ // Reuse the coverage presets that AgentPlugin.COVERAGE_LEVELS is built on
40
+ const targets = CoverageLevel.standard.withPerFile();
41
+ ```
42
+
43
+ Need the data layer, services, or an in-memory test layer? Reach for the engine:
44
+
45
+ ```ts
46
+ import { DataReader } from "@vitest-agent/engine";
47
+ import { singlePassingRun } from "@vitest-agent/engine/testing";
44
48
  ```
45
49
 
46
50
  ## Documentation
package/dispatch.d.ts CHANGED
@@ -12,6 +12,11 @@ interface InjectEnvInput {
12
12
  readonly command: string;
13
13
  readonly cwd: string;
14
14
  readonly env: Record<string, string | undefined>;
15
+ /**
16
+ * Synchronous file reader, injected so the core never touches
17
+ * `node:fs`. Throws on a missing file; {@link injectEnv} catches.
18
+ */
19
+ readonly readFile: (path: string) => string;
15
20
  }
16
21
  /**
17
22
  * Compute the (possibly rewritten) Bash command. Returns the original
@@ -21,13 +26,26 @@ interface InjectEnvInput {
21
26
  * - `VITEST_AGENT_CONVERSATION_ID` or `VITEST_AGENT_AGENT_ID` is
22
27
  * missing from env (no agent context to attribute to)
23
28
  *
24
- * Always synchronous — the package.json read is the only I/O and is
25
- * fast enough not to need Effect wrapping.
29
+ * Always synchronous — the package.json read is the only I/O, goes through
30
+ * the injected `readFile`, and is fast enough not to need Effect wrapping.
26
31
  * @public
27
32
  */
28
33
  export declare const injectEnv: (input: InjectEnvInput) => string;
29
34
  //#endregion
30
35
  //#region src/sidecar-dispatch.d.ts
36
+ /**
37
+ * The process-level inputs {@link dispatch} needs, supplied by the bin
38
+ * runner so the dispatch core itself never reads `process` or `node:fs`.
39
+ * @public
40
+ */
41
+ interface DispatchIo {
42
+ /** Default working directory when `--cwd` is not passed. */
43
+ readonly cwd: string;
44
+ /** Environment map (`process.env` in the sidecar bins). */
45
+ readonly env: Record<string, string | undefined>;
46
+ /** Synchronous file reader; throws on a miss — dispatch/injectEnv catch. */
47
+ readonly readFile: (path: string) => string;
48
+ }
31
49
  /** Result of a {@link dispatch} call: captured stdout/stderr + exit code.
32
50
  * @public
33
51
  */
@@ -38,11 +56,12 @@ interface DispatchResult {
38
56
  }
39
57
  /**
40
58
  * Dispatch one argv invocation. `argv` is the post-`node post-bin`
41
- * slice — i.e. `process.argv.slice(2)`. Never throws: every failure is
42
- * folded into the returned {@link DispatchResult}.
59
+ * slice — i.e. `process.argv.slice(2)` — and `io` carries the process
60
+ * facts (cwd, env, a file reader) the runner owns. Never throws: every
61
+ * failure is folded into the returned {@link DispatchResult}.
43
62
  * @public
44
63
  */
45
- export declare const dispatch: (argv: readonly string[]) => Promise<DispatchResult>;
64
+ export declare const dispatch: (argv: readonly string[], io: DispatchIo) => Promise<DispatchResult>;
46
65
  //#endregion
47
- export type { DispatchResult, InjectEnvInput };
66
+ export type { DispatchIo, DispatchResult, InjectEnvInput };
48
67
  //# sourceMappingURL=dispatch.d.ts.map
@@ -20,6 +20,7 @@ const MarkdownFormatter = {
20
20
  const md = formatConsoleMarkdown(report, {
21
21
  consoleOutput: context.detail === "minimal" ? "failures" : "full",
22
22
  coverageConsoleLimit: context.coverageConsoleLimit,
23
+ cwd: context.cwd,
23
24
  noColor: context.noColor,
24
25
  ...context.trendSummary !== void 0 ? { trendSummary: context.trendSummary } : {},
25
26
  ...context.runCommand !== void 0 ? { runCommand: context.runCommand } : {},
@@ -1,6 +1,6 @@
1
1
  import { formatTerminal } from "../utils/format-terminal.js";
2
2
  import { osc8 } from "../utils/hyperlink.js";
3
- import * as path from "node:path";
3
+ import { joinPosix } from "../utils/posix-path.js";
4
4
 
5
5
  //#region src/formatters/terminal.ts
6
6
  /**
@@ -25,13 +25,13 @@ import * as path from "node:path";
25
25
  * requires an absolute filesystem path inside a `file://` URL —
26
26
  * iTerm2 / WezTerm / Kitty / VSCode all silently fail to open
27
27
  * relative targets. Resolve the captured value back to absolute
28
- * against the cwd before handing it to `osc8`. The display label
28
+ * against `ctx.cwd` before handing it to `osc8`. The display label
29
29
  * stays relative so the rendered output is unchanged.
30
30
  * @public
31
31
  */
32
32
  const FAILED_TEST_ROW = /^( {4}(?:\x1b\[\d+m)?✗(?:\x1b\[\d+m)? )([^ ]+)( > )/gm;
33
33
  const wrapHyperlinks = (text, ctx) => text.replace(FAILED_TEST_ROW, (_match, prefix, captured, suffix) => {
34
- const absolute = path.resolve(process.cwd(), captured);
34
+ const absolute = captured.startsWith("/") ? captured : joinPosix(ctx.cwd, captured);
35
35
  return `${prefix}${osc8(`file://${absolute}`, captured, { enabled: !ctx.noColor })}${suffix}`;
36
36
  });
37
37
  /** @public */
@@ -39,6 +39,7 @@ const TerminalFormatter = {
39
39
  format: "terminal",
40
40
  render: (reports, context) => {
41
41
  const text = formatTerminal(reports, {
42
+ cwd: context.cwd,
42
43
  noColor: context.noColor,
43
44
  coverageConsoleLimit: context.coverageConsoleLimit,
44
45
  ...context.trendSummary !== void 0 ? { trendSummary: context.trendSummary } : {},