vdelta 0.2.1 → 0.3.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/README.md +32 -2
- package/dist/adapter.d.ts +155 -0
- package/dist/adapter.js +30 -0
- package/dist/adapter.js.map +1 -0
- package/dist/adapters/registry.d.ts +72 -0
- package/dist/adapters/registry.js +78 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/vitest/adapter.d.ts +19 -0
- package/dist/adapters/vitest/adapter.js +192 -0
- package/dist/adapters/vitest/adapter.js.map +1 -0
- package/dist/adapters/vitest/capture.d.ts +11 -1
- package/dist/adapters/vitest/capture.js +1 -1
- package/dist/adapters/vitest/recorder.d.ts +19 -19
- package/dist/adapters/vitest/recorder.js +40 -17
- package/dist/adapters/vitest/recorder.js.map +1 -1
- package/dist/adapters/vitest/reporter.d.ts +8 -0
- package/dist/adapters/vitest/reporter.js +38 -0
- package/dist/adapters/vitest/reporter.js.map +1 -1
- package/dist/cli.js +25 -5
- package/dist/cli.js.map +1 -1
- package/dist/compare.js +45 -11
- package/dist/compare.js.map +1 -1
- package/dist/gate.js +15 -3
- package/dist/gate.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/run.d.ts +22 -14
- package/dist/run.js +118 -123
- package/dist/run.js.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.js.map +1 -1
- package/dist/store.js +6 -2
- package/dist/store.js.map +1 -1
- package/package.json +2 -1
- package/spec/veridelta-1.md +32 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ another" — a verification delta can, and when two runs are not comparable it
|
|
|
18
18
|
- Runner support (MVP): **vitest v4** (native reporter, structured channel only)
|
|
19
19
|
- Zero runtime dependencies; Node ≥ 22
|
|
20
20
|
- Machine-verified against the [conformance suite](conformance/) —
|
|
21
|
-
|
|
21
|
+
46 fixtures covering the spec's invariants, adversarial inputs, and a
|
|
22
22
|
10-mutation cheating corpus with 100% detection recall
|
|
23
23
|
|
|
24
24
|
## Quickstart (5 minutes)
|
|
@@ -225,7 +225,7 @@ intended success mode.
|
|
|
225
225
|
|
|
226
226
|
```bash
|
|
227
227
|
npm test # unit + full conformance suite
|
|
228
|
-
npm run test:conformance # the
|
|
228
|
+
npm run test:conformance # the 46-fixture suite only
|
|
229
229
|
```
|
|
230
230
|
|
|
231
231
|
The suite is authored independently of this implementation (the fixture
|
|
@@ -239,6 +239,36 @@ staleness (INV-11), and read-only object-database recording (tree
|
|
|
239
239
|
digesting never writes loose objects into the observed repository's
|
|
240
240
|
`.git`, even when it is not writable).
|
|
241
241
|
|
|
242
|
+
## Supported platforms
|
|
243
|
+
|
|
244
|
+
vdelta requires Node.js ≥ 22 (see `engines.node`) and is developed and
|
|
245
|
+
tested on Linux and macOS. Windows support is experimental.
|
|
246
|
+
|
|
247
|
+
| OS | Support level |
|
|
248
|
+
|---|---|
|
|
249
|
+
| Linux (ubuntu) | Fully tested in CI: unit + full conformance suite, on every PR, across Node 22 and 24 |
|
|
250
|
+
| macOS | Tested in CI: unit + CLI suites on every PR (Node 24); full conformance suite runs weekly and on manual `workflow_dispatch` |
|
|
251
|
+
| Windows | Experimental: unit + CLI suites run on every PR as a non-blocking check (Node 24); failures do not block merges. Full conformance suite runs weekly and on manual `workflow_dispatch` |
|
|
252
|
+
|
|
253
|
+
### CI coverage policy
|
|
254
|
+
|
|
255
|
+
The full conformance suite (46 fixtures, ~230 seconds, spawning real
|
|
256
|
+
`vitest` child processes per fixture) runs on every pull request for
|
|
257
|
+
Linux only. macOS and Windows run a lighter `unit` + `cli` suite on every
|
|
258
|
+
PR instead, and the full conformance suite for those two platforms is
|
|
259
|
+
deferred to a weekly scheduled run and to manual `workflow_dispatch`
|
|
260
|
+
runs. This keeps required PR checks fast and keeps runner cost down —
|
|
261
|
+
macOS and Windows GitHub-hosted runners are billed at several times the
|
|
262
|
+
Linux rate, and the `cli` project already exercises real CLI process
|
|
263
|
+
spawning, temp-file handling, and path handling, which gives
|
|
264
|
+
representative cross-platform coverage without paying the full
|
|
265
|
+
conformance suite's runtime on every PR.
|
|
266
|
+
|
|
267
|
+
The Windows leg runs as a non-blocking check (`continue-on-error`), so
|
|
268
|
+
its pass/fail status never blocks a merge; results are still visible in
|
|
269
|
+
the CI run logs. If it stays consistently green over time, it can be
|
|
270
|
+
promoted to a required, blocking check in a follow-up change.
|
|
271
|
+
|
|
242
272
|
## License
|
|
243
273
|
|
|
244
274
|
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adapter seam. The core (`run` / `compare` / `gate`) never reaches into a
|
|
3
|
+
* concrete runner: it resolves an {@link Adapter} descriptor from the registry
|
|
4
|
+
* (`src/adapters/registry.ts`) and talks to it through this interface only.
|
|
5
|
+
*
|
|
6
|
+
* Every type here is a promotion of a shape that already existed on the vitest
|
|
7
|
+
* side, so the seam is a rearrangement of what already ran rather than a new
|
|
8
|
+
* mechanism: {@link RecordContext} is the recorder's context object verbatim,
|
|
9
|
+
* {@link DetectResult} is the runner-token scan's return value,
|
|
10
|
+
* {@link InstrumentedChild} is the argv/env injection `vdelta run` already
|
|
11
|
+
* performed, and {@link CommandSelector} is the §6.4 inclusion-intent split.
|
|
12
|
+
*
|
|
13
|
+
* Dependency direction inside an adapter is one-way: `detect` / `instrument` /
|
|
14
|
+
* `splitCommandSelector` know only the runner's *argv surface*, `record` knows
|
|
15
|
+
* only its *structured channel*.
|
|
16
|
+
*/
|
|
17
|
+
import type { RunRecord } from './schema.js';
|
|
18
|
+
/**
|
|
19
|
+
* The three-valued capability convention (§3.4). The value set is closed
|
|
20
|
+
* (§14); capability *names* stay open so an adapter may declare its own.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CAPABILITY_VALUES: readonly ["pass", "fail", "unsupported"];
|
|
23
|
+
export type CapabilityValue = (typeof CAPABILITY_VALUES)[number];
|
|
24
|
+
export type CapabilityDeclaration = Readonly<Record<string, CapabilityValue>>;
|
|
25
|
+
/**
|
|
26
|
+
* Where the adapter's structured channel lands. A single capture file is the
|
|
27
|
+
* only kind today; per-process channels are follow-up F-2, at which point the
|
|
28
|
+
* channel's creation and teardown move from the core into the adapter.
|
|
29
|
+
*/
|
|
30
|
+
export interface CaptureChannel {
|
|
31
|
+
readonly kind: 'single-file';
|
|
32
|
+
readonly path: string;
|
|
33
|
+
}
|
|
34
|
+
/** What {@link Adapter.detect} returns; `null` means only "not mine". */
|
|
35
|
+
export interface DetectResult {
|
|
36
|
+
/** argv index of the runner binary token. */
|
|
37
|
+
readonly tokenIndex: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The instrumented child invocation. `argv` fully replaces the caller's argv;
|
|
41
|
+
* `env` carries only the additions to layer onto the inherited environment.
|
|
42
|
+
*/
|
|
43
|
+
export interface InstrumentedChild {
|
|
44
|
+
readonly argv: readonly string[];
|
|
45
|
+
readonly env: Readonly<Record<string, string>>;
|
|
46
|
+
}
|
|
47
|
+
/** The §6.4 inclusion-intent split of a child argv (§5.1 canonical command). */
|
|
48
|
+
export interface CommandSelector {
|
|
49
|
+
command: string[];
|
|
50
|
+
selector: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Everything the recorder needs beyond the runner's own structured channel:
|
|
54
|
+
* repo identity, provenance, the canonicalized invocation and the child's raw
|
|
55
|
+
* streams. Runner-neutral by construction — no field carries runner vocabulary.
|
|
56
|
+
*/
|
|
57
|
+
export interface RecordContext {
|
|
58
|
+
worktree: string;
|
|
59
|
+
repoIdentity: string;
|
|
60
|
+
branch: string;
|
|
61
|
+
cwdRel: string;
|
|
62
|
+
command: string[];
|
|
63
|
+
selector: string[];
|
|
64
|
+
head: string | null;
|
|
65
|
+
treeDigest: string;
|
|
66
|
+
dirtyDiffDigest: string;
|
|
67
|
+
childExitCode: number;
|
|
68
|
+
rawStdout: string;
|
|
69
|
+
rawStderr: string;
|
|
70
|
+
adapterVersion: string;
|
|
71
|
+
recordedAtMs: number;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The capability names a declaration says the composition cannot meet, sorted
|
|
75
|
+
* (§4.2 disclosure rule). `unsupported` is the only degraded value: `fail`
|
|
76
|
+
* means the capability is met and the observation is red, not that evidence is
|
|
77
|
+
* missing. This is what a report's `failure_evidence.degraded_capabilities`
|
|
78
|
+
* and every per-test claim that carries it are derived from.
|
|
79
|
+
*/
|
|
80
|
+
export declare function degradedCapabilities(caps: CapabilityDeclaration): string[];
|
|
81
|
+
/** §6.4 selector containment, as declared by an adapter that can decide it. */
|
|
82
|
+
export type SelectorRelation = 'equal' | 'subset' | 'superset' | 'disjoint' | 'unknown';
|
|
83
|
+
export type SelectorMatch = 'yes' | 'no' | 'unknown';
|
|
84
|
+
/**
|
|
85
|
+
* The capture channel is unreadable, of an unsupported version, or malformed.
|
|
86
|
+
* The core maps this onto degraded raw passthrough (INV-5): veridelta is never
|
|
87
|
+
* worse than its absence.
|
|
88
|
+
*/
|
|
89
|
+
export declare class AdapterCaptureError extends Error {
|
|
90
|
+
constructor(message: string);
|
|
91
|
+
}
|
|
92
|
+
export interface Adapter {
|
|
93
|
+
readonly name: string;
|
|
94
|
+
readonly compositionId: string;
|
|
95
|
+
readonly declaredCapabilities: CapabilityDeclaration;
|
|
96
|
+
readonly declaredEnvVars: readonly string[];
|
|
97
|
+
/**
|
|
98
|
+
* Whether this argv is this adapter's invocation. `null` means "not mine"
|
|
99
|
+
* and nothing else — an adapter alone can never conclude "this is a wrapper
|
|
100
|
+
* command"; that is a registry-level conclusion.
|
|
101
|
+
*/
|
|
102
|
+
detect(argv: readonly string[]): DetectResult | null;
|
|
103
|
+
/**
|
|
104
|
+
* The env that points this adapter's reporter at the channel.
|
|
105
|
+
*
|
|
106
|
+
* Exported to the child *whether or not* the adapter claimed the argv. A
|
|
107
|
+
* reporter registered in the project's own configuration (spec §4.2 ambient
|
|
108
|
+
* recording — the RECOMMENDED deployment) has no other way to find the
|
|
109
|
+
* channel, and it is deliberately inert without it. Gating this on argv
|
|
110
|
+
* detection would silently stop recording every wrapper invocation
|
|
111
|
+
* (`vdelta run -- npm test`), which is exactly the stream-severing §4.2
|
|
112
|
+
* warns about.
|
|
113
|
+
*
|
|
114
|
+
* The channel is one file today, so two adapters pointing their reporters at
|
|
115
|
+
* it would race (last writer wins). That is the pre-existing single-channel
|
|
116
|
+
* hazard follow-up F-2 exists for, not something detection was protecting
|
|
117
|
+
* against — pre-seam this env was exported unconditionally.
|
|
118
|
+
*/
|
|
119
|
+
channelEnv(channel: CaptureChannel): Readonly<Record<string, string>>;
|
|
120
|
+
/**
|
|
121
|
+
* The reporter-injected argv plus the env additions for the child. Only
|
|
122
|
+
* applied when this adapter recognizes the argv: injecting runner flags into
|
|
123
|
+
* a command that is not that runner kills it outright (INV-5 — veridelta is
|
|
124
|
+
* never worse than its absence), and a wrapper cannot forward them anyway
|
|
125
|
+
* (§4.3-7). {@link channelEnv} is what covers the uninstrumented case.
|
|
126
|
+
*/
|
|
127
|
+
instrument(argv: readonly string[], channel: CaptureChannel): InstrumentedChild;
|
|
128
|
+
/**
|
|
129
|
+
* Whether the capture now sitting in the channel is this adapter's, decided
|
|
130
|
+
* on the channel's own payload rather than on argv.
|
|
131
|
+
*
|
|
132
|
+
* Consulted only when no adapter claimed the argv: the ambient case, where
|
|
133
|
+
* the reporter came from the project's configuration instead of from
|
|
134
|
+
* {@link instrument}, so the argv carries no evidence of which runner ran.
|
|
135
|
+
* MUST NOT throw — an absent, empty, foreign or malformed channel is simply
|
|
136
|
+
* not a claim. A claim asserts authorship only; a payload this adapter owns
|
|
137
|
+
* but cannot use still fails in {@link record}, with its own diagnostic.
|
|
138
|
+
*/
|
|
139
|
+
claimsCapture(channel: CaptureChannel): boolean;
|
|
140
|
+
/** §6.4 inclusion intent, decided purely on the runner's own CLI surface. */
|
|
141
|
+
splitCommandSelector(argv: readonly string[]): CommandSelector;
|
|
142
|
+
/**
|
|
143
|
+
* Read the capture channel, validate it, and build the Run record. Parsing
|
|
144
|
+
* and version checking belong to the *adapter* — the core knows nothing
|
|
145
|
+
* about the channel's payload. Failures throw {@link AdapterCaptureError},
|
|
146
|
+
* which the core maps onto degraded passthrough.
|
|
147
|
+
*/
|
|
148
|
+
record(channel: CaptureChannel, ctx: RecordContext): RunRecord;
|
|
149
|
+
/**
|
|
150
|
+
* §6.4, optional. Undeclared means every relation is `unknown`, which is
|
|
151
|
+
* exactly the comparator's pre-seam behavior (`selector-relation-unknown`).
|
|
152
|
+
*/
|
|
153
|
+
selectorRelation?(a: readonly string[], b: readonly string[]): SelectorRelation;
|
|
154
|
+
selectorMatches?(selector: readonly string[], testId: string): SelectorMatch;
|
|
155
|
+
}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three-valued capability convention (§3.4). The value set is closed
|
|
3
|
+
* (§14); capability *names* stay open so an adapter may declare its own.
|
|
4
|
+
*/
|
|
5
|
+
export const CAPABILITY_VALUES = ['pass', 'fail', 'unsupported'];
|
|
6
|
+
/**
|
|
7
|
+
* The capability names a declaration says the composition cannot meet, sorted
|
|
8
|
+
* (§4.2 disclosure rule). `unsupported` is the only degraded value: `fail`
|
|
9
|
+
* means the capability is met and the observation is red, not that evidence is
|
|
10
|
+
* missing. This is what a report's `failure_evidence.degraded_capabilities`
|
|
11
|
+
* and every per-test claim that carries it are derived from.
|
|
12
|
+
*/
|
|
13
|
+
export function degradedCapabilities(caps) {
|
|
14
|
+
return Object.entries(caps)
|
|
15
|
+
.filter(([, value]) => value === 'unsupported')
|
|
16
|
+
.map(([name]) => name)
|
|
17
|
+
.sort();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The capture channel is unreadable, of an unsupported version, or malformed.
|
|
21
|
+
* The core maps this onto degraded raw passthrough (INV-5): veridelta is never
|
|
22
|
+
* worse than its absence.
|
|
23
|
+
*/
|
|
24
|
+
export class AdapterCaptureError extends Error {
|
|
25
|
+
constructor(message) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = 'AdapterCaptureError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAU,CAAA;AAyDzE;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA2B;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,aAAa,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;SACrB,IAAI,EAAE,CAAA;AACX,CAAC;AAWD;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The adapter registry: the one place the core is allowed to know which
|
|
3
|
+
* concrete adapters exist. A static array in a fixed order — no registration
|
|
4
|
+
* API until adapters become external plugins.
|
|
5
|
+
*
|
|
6
|
+
* Detection is deliberately *total*: every adapter's `detect` is evaluated and
|
|
7
|
+
* the outcome distinguishes zero, one, and several matches, because only the
|
|
8
|
+
* registry can tell "no adapter recognizes this argv" (a wrapper command such
|
|
9
|
+
* as `pnpm test`) from "this adapter is not the one". Zero and ambiguous both
|
|
10
|
+
* stay recordable-but-degraded at the call site, never a hard failure (INV-5).
|
|
11
|
+
*/
|
|
12
|
+
import type { Adapter, CaptureChannel, DetectResult } from '../adapter.js';
|
|
13
|
+
/** Every known adapter, in a deterministic order. */
|
|
14
|
+
export declare const ADAPTERS: readonly Adapter[];
|
|
15
|
+
/** Known adapter names, in registry order — for diagnostics and `--adapter`. */
|
|
16
|
+
export declare function adapterNames(adapters?: readonly Adapter[]): readonly string[];
|
|
17
|
+
/**
|
|
18
|
+
* Look an adapter up by name without failing. Callers that must stay
|
|
19
|
+
* fail-closed rather than abort — the comparator and the gate, which resolve
|
|
20
|
+
* `record.instrument.adapter` from records they did not write — use this.
|
|
21
|
+
*/
|
|
22
|
+
export declare function findAdapter(name: string, adapters?: readonly Adapter[]): Adapter | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve an explicitly requested adapter name. An unknown name is user input
|
|
25
|
+
* error, not a degradation path: silently passing through would turn a typo
|
|
26
|
+
* into a silent loss of recording, which is the opposite of INV-5's intent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveAdapter(name: string, adapters?: readonly Adapter[]): Adapter;
|
|
29
|
+
/**
|
|
30
|
+
* The env additions every registered adapter needs to find the channel, in
|
|
31
|
+
* registry order. Exported to the child unconditionally, detection or no
|
|
32
|
+
* detection: a reporter configured in the project itself (spec §4.2 ambient
|
|
33
|
+
* recording) is inert without it, and pre-seam `vdelta run` set it on every
|
|
34
|
+
* child for exactly that reason.
|
|
35
|
+
*
|
|
36
|
+
* Later adapters win on a colliding name. With one single-file channel that
|
|
37
|
+
* collision is the F-2 hazard, not a decision this function can make.
|
|
38
|
+
*/
|
|
39
|
+
export declare function ambientChannelEnv(channel: CaptureChannel, adapters?: readonly Adapter[]): Record<string, string>;
|
|
40
|
+
/**
|
|
41
|
+
* Which adapter owns the capture that landed in the channel, or `null` when
|
|
42
|
+
* none claims it. The ambient counterpart of {@link detectAdapter}: the argv
|
|
43
|
+
* said nothing, so the payload decides.
|
|
44
|
+
*
|
|
45
|
+
* Registry order breaks a tie. Two adapters claiming one capture would mean
|
|
46
|
+
* two reporters wrote to the same single-file channel, which is the F-2
|
|
47
|
+
* last-writer-wins hazard rather than an ambiguity the user could resolve —
|
|
48
|
+
* there is no argv to name a winner with, so degrading here would discard a
|
|
49
|
+
* capture that is genuinely present.
|
|
50
|
+
*/
|
|
51
|
+
export declare function claimCapture(channel: CaptureChannel, adapters?: readonly Adapter[]): Adapter | null;
|
|
52
|
+
/**
|
|
53
|
+
* Outcome of evaluating every adapter's `detect` against one child argv.
|
|
54
|
+
* `none` and `ambiguous` are both "the registry declines to choose": the
|
|
55
|
+
* caller degrades to raw passthrough and says why.
|
|
56
|
+
*/
|
|
57
|
+
export type AdapterDetection = {
|
|
58
|
+
readonly kind: 'none';
|
|
59
|
+
} | {
|
|
60
|
+
readonly kind: 'unique';
|
|
61
|
+
readonly adapter: Adapter;
|
|
62
|
+
readonly detected: DetectResult;
|
|
63
|
+
} | {
|
|
64
|
+
readonly kind: 'ambiguous';
|
|
65
|
+
readonly candidates: readonly Adapter[];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Evaluate *all* adapters against the argv. Never short-circuits on the first
|
|
69
|
+
* match: two adapters claiming the same argv is a distinguishable outcome that
|
|
70
|
+
* must reach the user as a candidate list, not be hidden by registry order.
|
|
71
|
+
*/
|
|
72
|
+
export declare function detectAdapter(argv: readonly string[], adapters?: readonly Adapter[]): AdapterDetection;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { vitestAdapter } from './vitest/adapter.js';
|
|
2
|
+
/** Every known adapter, in a deterministic order. */
|
|
3
|
+
export const ADAPTERS = [vitestAdapter];
|
|
4
|
+
/** Known adapter names, in registry order — for diagnostics and `--adapter`. */
|
|
5
|
+
export function adapterNames(adapters = ADAPTERS) {
|
|
6
|
+
return adapters.map((a) => a.name);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Look an adapter up by name without failing. Callers that must stay
|
|
10
|
+
* fail-closed rather than abort — the comparator and the gate, which resolve
|
|
11
|
+
* `record.instrument.adapter` from records they did not write — use this.
|
|
12
|
+
*/
|
|
13
|
+
export function findAdapter(name, adapters = ADAPTERS) {
|
|
14
|
+
return adapters.find((a) => a.name === name);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve an explicitly requested adapter name. An unknown name is user input
|
|
18
|
+
* error, not a degradation path: silently passing through would turn a typo
|
|
19
|
+
* into a silent loss of recording, which is the opposite of INV-5's intent.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveAdapter(name, adapters = ADAPTERS) {
|
|
22
|
+
const adapter = findAdapter(name, adapters);
|
|
23
|
+
if (adapter === undefined) {
|
|
24
|
+
throw new Error(`unknown adapter '${name}' — known adapters: ${adapterNames(adapters).join(', ')}`);
|
|
25
|
+
}
|
|
26
|
+
return adapter;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The env additions every registered adapter needs to find the channel, in
|
|
30
|
+
* registry order. Exported to the child unconditionally, detection or no
|
|
31
|
+
* detection: a reporter configured in the project itself (spec §4.2 ambient
|
|
32
|
+
* recording) is inert without it, and pre-seam `vdelta run` set it on every
|
|
33
|
+
* child for exactly that reason.
|
|
34
|
+
*
|
|
35
|
+
* Later adapters win on a colliding name. With one single-file channel that
|
|
36
|
+
* collision is the F-2 hazard, not a decision this function can make.
|
|
37
|
+
*/
|
|
38
|
+
export function ambientChannelEnv(channel, adapters = ADAPTERS) {
|
|
39
|
+
const env = {};
|
|
40
|
+
for (const adapter of adapters) {
|
|
41
|
+
Object.assign(env, adapter.channelEnv(channel));
|
|
42
|
+
}
|
|
43
|
+
return env;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Which adapter owns the capture that landed in the channel, or `null` when
|
|
47
|
+
* none claims it. The ambient counterpart of {@link detectAdapter}: the argv
|
|
48
|
+
* said nothing, so the payload decides.
|
|
49
|
+
*
|
|
50
|
+
* Registry order breaks a tie. Two adapters claiming one capture would mean
|
|
51
|
+
* two reporters wrote to the same single-file channel, which is the F-2
|
|
52
|
+
* last-writer-wins hazard rather than an ambiguity the user could resolve —
|
|
53
|
+
* there is no argv to name a winner with, so degrading here would discard a
|
|
54
|
+
* capture that is genuinely present.
|
|
55
|
+
*/
|
|
56
|
+
export function claimCapture(channel, adapters = ADAPTERS) {
|
|
57
|
+
return adapters.find((a) => a.claimsCapture(channel)) ?? null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Evaluate *all* adapters against the argv. Never short-circuits on the first
|
|
61
|
+
* match: two adapters claiming the same argv is a distinguishable outcome that
|
|
62
|
+
* must reach the user as a candidate list, not be hidden by registry order.
|
|
63
|
+
*/
|
|
64
|
+
export function detectAdapter(argv, adapters = ADAPTERS) {
|
|
65
|
+
const matches = [];
|
|
66
|
+
for (const adapter of adapters) {
|
|
67
|
+
const detected = adapter.detect(argv);
|
|
68
|
+
if (detected !== null)
|
|
69
|
+
matches.push({ adapter, detected });
|
|
70
|
+
}
|
|
71
|
+
if (matches.length === 0)
|
|
72
|
+
return { kind: 'none' };
|
|
73
|
+
if (matches.length > 1)
|
|
74
|
+
return { kind: 'ambiguous', candidates: matches.map((m) => m.adapter) };
|
|
75
|
+
const only = matches[0];
|
|
76
|
+
return { kind: 'unique', adapter: only.adapter, detected: only.detected };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,qDAAqD;AACrD,MAAM,CAAC,MAAM,QAAQ,GAAuB,CAAC,aAAa,CAAC,CAAA;AAE3D,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAC1B,WAA+B,QAAQ;IAEvC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,WAA+B,QAAQ;IAEvC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,WAA+B,QAAQ;IAEvC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAC3C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,uBAAuB,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnF,CAAA;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAuB,EACvB,WAA+B,QAAQ;IAEvC,MAAM,GAAG,GAA2B,EAAE,CAAA;IACtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;IACjD,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAuB,EACvB,WAA+B,QAAQ;IAEvC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,CAAA;AAC/D,CAAC;AAgBD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAuB,EACvB,WAA+B,QAAQ;IAEvC,MAAM,OAAO,GAAmD,EAAE,CAAA;IAClE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACrC,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC5D,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;IACjD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAA;IACzE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;IACxB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;AAC3E,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Adapter, type CapabilityDeclaration, type CommandSelector } from '../../adapter.js';
|
|
2
|
+
/**
|
|
3
|
+
* The invocation's selector is its inclusion intent (§6.4): the vitest CLI
|
|
4
|
+
* positional filters. The canonical command excludes them (§5.1).
|
|
5
|
+
*
|
|
6
|
+
* `--flag value` pairs for known value-taking flags (see
|
|
7
|
+
* {@link VITEST_VALUE_FLAGS}) are folded into a single `--flag=value`
|
|
8
|
+
* canonical token so that this form and the pre-joined `--flag=value` form
|
|
9
|
+
* produce byte-identical `command` arrays (and thus the same stream key).
|
|
10
|
+
*/
|
|
11
|
+
export declare function splitCommandSelector(cmd: readonly string[]): CommandSelector;
|
|
12
|
+
/**
|
|
13
|
+
* Initial capability declaration for `vitest-native/1` (§3.4). Reproduces the
|
|
14
|
+
* composition's documented standing byte for byte: only `source-region-text`
|
|
15
|
+
* is degraded (CE-1 — vitest's structured channel carries no failing-source
|
|
16
|
+
* region text), everything else this composition claims is met.
|
|
17
|
+
*/
|
|
18
|
+
export declare const VITEST_CAPABILITIES: CapabilityDeclaration;
|
|
19
|
+
export declare const vitestAdapter: Adapter;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vitest adapter, descriptor side: the runner-facing half of the seam
|
|
3
|
+
* (`src/adapter.ts`). Everything vitest-specific about *invoking* a run lives
|
|
4
|
+
* here — locating the vitest binary in the child argv, injecting the capture
|
|
5
|
+
* reporter, and splitting inclusion intent out of the command (§6.4) using
|
|
6
|
+
* vitest's own CLI surface. The recorder half (capture → RunRecord) stays in
|
|
7
|
+
* `./recorder.ts`; this module only owns reading and parsing the channel.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync } from 'node:fs';
|
|
10
|
+
import { dirname, join } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { AdapterCaptureError, } from '../../adapter.js';
|
|
13
|
+
import { ADAPTER_NAME, buildRunRecord, COMPOSITION_ID, DECLARED_ENV_VARS, } from './recorder.js';
|
|
14
|
+
/**
|
|
15
|
+
* Absolute path of the in-process vitest reporter that writes the capture.
|
|
16
|
+
* Resolved relative to this module so it points at the built sibling
|
|
17
|
+
* (`dist/adapters/vitest/reporter.js`) rather than at a source path.
|
|
18
|
+
*/
|
|
19
|
+
function reporterModulePath() {
|
|
20
|
+
return join(dirname(fileURLToPath(import.meta.url)), 'reporter.js');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The one env var the capture reporter reads (`reporter.ts:61`). Held here
|
|
24
|
+
* rather than inline so `channelEnv` and the reporter's contract stay a single
|
|
25
|
+
* fact; the reporter is inert without it, by design, so that it can sit
|
|
26
|
+
* permanently in a project's vitest config (spec §4.2 ambient recording).
|
|
27
|
+
*/
|
|
28
|
+
const CAPTURE_FILE_ENV = 'VDELTA_CAPTURE_FILE';
|
|
29
|
+
function channelEnv(channel) {
|
|
30
|
+
return { [CAPTURE_FILE_ENV]: channel.path };
|
|
31
|
+
}
|
|
32
|
+
/** Parse the channel, or `undefined` when there is nothing readable in it. */
|
|
33
|
+
function readCapture(channel) {
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(readFileSync(channel.path, 'utf8'));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Locate the vitest invocation inside the child argv; null when absent. */
|
|
42
|
+
function findVitestToken(cmd) {
|
|
43
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
44
|
+
const token = cmd[i];
|
|
45
|
+
if (/(^|[\\/])vitest(\.mjs|\.js)?$/.test(token) || token === 'vitest')
|
|
46
|
+
return i;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* vitest 4.x CLI flags that always take their value as a *separate* argv
|
|
52
|
+
* token (`--flag value`), never combined into the flag token itself. Used
|
|
53
|
+
* by {@link splitCommandSelector} to recognize `--flag value` pairs and fold
|
|
54
|
+
* them into a single `--flag=value` canonical token so that space-separated
|
|
55
|
+
* and `=`-joined invocations normalize to the same command array (and
|
|
56
|
+
* therefore the same stream key — see `streamKey` in src/compare.ts).
|
|
57
|
+
*
|
|
58
|
+
* Deliberately excludes flags whose value is *optional*
|
|
59
|
+
* (`--changed`, `--silent`, `--coverage`, `--browser`, `--inspect`, etc.):
|
|
60
|
+
* for those, the token following the flag cannot be distinguished from a
|
|
61
|
+
* positional selector without vitest's own arg-parsing rules, so folding
|
|
62
|
+
* them here would risk silently swallowing a selector token. Flags outside
|
|
63
|
+
* this list keep the historical (pre-fix) behavior: a space-separated value
|
|
64
|
+
* is treated as a selector token, which may cause selector-based stream
|
|
65
|
+
* splitting and an abstain (`comparability: 'none'`) rather than a
|
|
66
|
+
* false-positive comparison.
|
|
67
|
+
*
|
|
68
|
+
* Maintenance: this list targets vitest 4.x. Revisit when bumping the
|
|
69
|
+
* vitest minor/major version (see issue #15 Open Question — no automated
|
|
70
|
+
* mechanism keeps this in sync with vitest's own CLI surface).
|
|
71
|
+
*/
|
|
72
|
+
const VITEST_VALUE_FLAGS = new Set([
|
|
73
|
+
'--project',
|
|
74
|
+
'--config',
|
|
75
|
+
'-c',
|
|
76
|
+
'--root',
|
|
77
|
+
'-r',
|
|
78
|
+
'--dir',
|
|
79
|
+
'--reporter',
|
|
80
|
+
'--outputFile',
|
|
81
|
+
'--pool',
|
|
82
|
+
'--maxWorkers',
|
|
83
|
+
'--minWorkers',
|
|
84
|
+
'--environment',
|
|
85
|
+
'--testNamePattern',
|
|
86
|
+
'-t',
|
|
87
|
+
'--testTimeout',
|
|
88
|
+
'--hookTimeout',
|
|
89
|
+
'--teardownTimeout',
|
|
90
|
+
'--retry',
|
|
91
|
+
'--bail',
|
|
92
|
+
'--maxConcurrency',
|
|
93
|
+
'--shard',
|
|
94
|
+
'--exclude',
|
|
95
|
+
'--mode',
|
|
96
|
+
'--workspace',
|
|
97
|
+
]);
|
|
98
|
+
/**
|
|
99
|
+
* The invocation's selector is its inclusion intent (§6.4): the vitest CLI
|
|
100
|
+
* positional filters. The canonical command excludes them (§5.1).
|
|
101
|
+
*
|
|
102
|
+
* `--flag value` pairs for known value-taking flags (see
|
|
103
|
+
* {@link VITEST_VALUE_FLAGS}) are folded into a single `--flag=value`
|
|
104
|
+
* canonical token so that this form and the pre-joined `--flag=value` form
|
|
105
|
+
* produce byte-identical `command` arrays (and thus the same stream key).
|
|
106
|
+
*/
|
|
107
|
+
export function splitCommandSelector(cmd) {
|
|
108
|
+
const idx = findVitestToken(cmd);
|
|
109
|
+
if (idx === null)
|
|
110
|
+
return { command: [...cmd], selector: [] };
|
|
111
|
+
const command = cmd.slice(0, idx + 1);
|
|
112
|
+
const selector = [];
|
|
113
|
+
for (let i = idx + 1; i < cmd.length; i++) {
|
|
114
|
+
const token = cmd[i];
|
|
115
|
+
if (token === 'run' && i === idx + 1) {
|
|
116
|
+
command.push(token);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (!token.startsWith('-')) {
|
|
120
|
+
selector.push(token);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (token.includes('=')) {
|
|
124
|
+
command.push(token);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const next = cmd[i + 1];
|
|
128
|
+
if (VITEST_VALUE_FLAGS.has(token) &&
|
|
129
|
+
next !== undefined &&
|
|
130
|
+
!next.startsWith('-')) {
|
|
131
|
+
command.push(`${token}=${next}`);
|
|
132
|
+
i++;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
command.push(token);
|
|
136
|
+
}
|
|
137
|
+
return { command, selector };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Initial capability declaration for `vitest-native/1` (§3.4). Reproduces the
|
|
141
|
+
* composition's documented standing byte for byte: only `source-region-text`
|
|
142
|
+
* is degraded (CE-1 — vitest's structured channel carries no failing-source
|
|
143
|
+
* region text), everything else this composition claims is met.
|
|
144
|
+
*/
|
|
145
|
+
export const VITEST_CAPABILITIES = {
|
|
146
|
+
verdicts: 'pass',
|
|
147
|
+
'source-location': 'pass',
|
|
148
|
+
suppression: 'pass',
|
|
149
|
+
inventory: 'pass',
|
|
150
|
+
'failure-evidence': 'pass',
|
|
151
|
+
'source-region-text': 'unsupported',
|
|
152
|
+
};
|
|
153
|
+
export const vitestAdapter = {
|
|
154
|
+
name: ADAPTER_NAME,
|
|
155
|
+
compositionId: COMPOSITION_ID,
|
|
156
|
+
declaredCapabilities: VITEST_CAPABILITIES,
|
|
157
|
+
declaredEnvVars: DECLARED_ENV_VARS,
|
|
158
|
+
detect(argv) {
|
|
159
|
+
const i = findVitestToken(argv);
|
|
160
|
+
return i === null ? null : { tokenIndex: i };
|
|
161
|
+
},
|
|
162
|
+
channelEnv,
|
|
163
|
+
instrument(argv, channel) {
|
|
164
|
+
return {
|
|
165
|
+
argv: [
|
|
166
|
+
...argv,
|
|
167
|
+
'--reporter=default',
|
|
168
|
+
`--reporter=${reporterModulePath()}`,
|
|
169
|
+
'--includeTaskLocation',
|
|
170
|
+
],
|
|
171
|
+
env: channelEnv(channel),
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
splitCommandSelector,
|
|
175
|
+
claimsCapture(channel) {
|
|
176
|
+
// Authorship only, and from the payload's own self-identification
|
|
177
|
+
// (`capture.ts:34`, a literal `'vitest'`). Deliberately not a version or
|
|
178
|
+
// shape check: a capture this adapter wrote but cannot read must reach
|
|
179
|
+
// `record` so the run degrades with *that* diagnostic ("unsupported
|
|
180
|
+
// capture version N") instead of the generic "is the child a vitest
|
|
181
|
+
// invocation?", which is what the pre-seam code path said.
|
|
182
|
+
return readCapture(channel)?.runner === 'vitest';
|
|
183
|
+
},
|
|
184
|
+
record(channel, ctx) {
|
|
185
|
+
const capture = readCapture(channel);
|
|
186
|
+
if (capture === undefined) {
|
|
187
|
+
throw new AdapterCaptureError('no capture from the vitest reporter — is the child a vitest invocation?');
|
|
188
|
+
}
|
|
189
|
+
return buildRunRecord(capture, ctx);
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/vitest/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAEL,mBAAmB,GAIpB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,eAAe,CAAA;AAEtB;;;;GAIG;AACH,SAAS,kBAAkB;IACzB,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAA;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,qBAAqB,CAAA;AAE9C,SAAS,UAAU,CAAC,OAAuB;IACzC,OAAO,EAAE,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,IAAI,EAAE,CAAA;AAC7C,CAAC;AAED,8EAA8E;AAC9E,SAAS,WAAW,CAAC,OAAuB;IAC1C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAA;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,SAAS,eAAe,CAAC,GAAsB;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,KAAK,QAAQ;YACnE,OAAO,CAAC,CAAA;IACZ,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IACtD,WAAW;IACX,UAAU;IACV,IAAI;IACJ,QAAQ;IACR,IAAI;IACJ,OAAO;IACP,YAAY;IACZ,cAAc;IACd,QAAQ;IACR,cAAc;IACd,cAAc;IACd,eAAe;IACf,mBAAmB;IACnB,IAAI;IACJ,eAAe;IACf,eAAe;IACf,mBAAmB;IACnB,SAAS;IACT,QAAQ;IACR,kBAAkB;IAClB,SAAS;IACT,WAAW;IACX,QAAQ;IACR,aAAa;CACd,CAAC,CAAA;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAsB;IACzD,MAAM,GAAG,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAChC,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IAC5D,MAAM,OAAO,GAAa,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;IAC/C,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,KAAK,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAE,CAAA;QACrB,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnB,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnB,SAAQ;QACV,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACvB,IACE,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC;YAC7B,IAAI,KAAK,SAAS;YAClB,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EACrB,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAA;YAChC,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrB,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA0B;IACxD,QAAQ,EAAE,MAAM;IAChB,iBAAiB,EAAE,MAAM;IACzB,WAAW,EAAE,MAAM;IACnB,SAAS,EAAE,MAAM;IACjB,kBAAkB,EAAE,MAAM;IAC1B,oBAAoB,EAAE,aAAa;CACpC,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,IAAI,EAAE,YAAY;IAClB,aAAa,EAAE,cAAc;IAC7B,oBAAoB,EAAE,mBAAmB;IACzC,eAAe,EAAE,iBAAiB;IAElC,MAAM,CAAC,IAAI;QACT,MAAM,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;QAC/B,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;IAC9C,CAAC;IAED,UAAU;IAEV,UAAU,CAAC,IAAI,EAAE,OAAO;QACtB,OAAO;YACL,IAAI,EAAE;gBACJ,GAAG,IAAI;gBACP,oBAAoB;gBACpB,cAAc,kBAAkB,EAAE,EAAE;gBACpC,uBAAuB;aACxB;YACD,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC;SACzB,CAAA;IACH,CAAC;IAED,oBAAoB;IAEpB,aAAa,CAAC,OAAO;QACnB,kEAAkE;QAClE,yEAAyE;QACzE,uEAAuE;QACvE,oEAAoE;QACpE,oEAAoE;QACpE,2DAA2D;QAC3D,OAAO,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,QAAQ,CAAA;IAClD,CAAC;IAED,MAAM,CAAC,OAAO,EAAE,GAAG;QACjB,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAC3B,yEAAyE,CAC1E,CAAA;QACH,CAAC;QACD,OAAO,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IACrC,CAAC;CACF,CAAA"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* out-of-process recorder (`vdelta run`). Raw structured-channel data only;
|
|
4
4
|
* canonicalization/redaction/digesting happen in the recorder.
|
|
5
5
|
*/
|
|
6
|
-
export declare const CAPTURE_VERSION =
|
|
6
|
+
export declare const CAPTURE_VERSION = 2;
|
|
7
7
|
export interface CapturedError {
|
|
8
8
|
name: string;
|
|
9
9
|
message: string;
|
|
@@ -47,4 +47,14 @@ export interface Capture {
|
|
|
47
47
|
rel: string;
|
|
48
48
|
messages: string[];
|
|
49
49
|
}[];
|
|
50
|
+
/**
|
|
51
|
+
* Absolute paths of the config files vite/vitest actually resolved for this
|
|
52
|
+
* run: the union of `configFile` and `configFileDependencies` across the
|
|
53
|
+
* global vite dev server and every workspace `TestProject`'s dev server.
|
|
54
|
+
* Sorted and deduped by the reporter. The recorder digests each of these
|
|
55
|
+
* paths directly (no more decide-file-name guessing) and keys the result
|
|
56
|
+
* with a worktree-relative path, or `external:<abs path>` for anything
|
|
57
|
+
* outside the worktree.
|
|
58
|
+
*/
|
|
59
|
+
config_files: string[];
|
|
50
60
|
}
|