@vitest-agent/sdk 6.0.0 → 7.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/index.d.ts +308 -12
- package/index.js +5 -3
- package/package.json +3 -3
- package/schemas/5.0/run.json +110 -0
- package/schemas/AgentReport.js +3 -1
- package/schemas/Common.js +1 -13
- package/schemas/Coverage.js +20 -2
- package/schemas/RenderState.js +11 -3
- package/schemas/RunEvent.js +11 -3
- package/schemas/StrayOutput.js +38 -0
- package/utils/stray-output.js +143 -0
- package/version.js +1 -1
package/index.d.ts
CHANGED
|
@@ -28,6 +28,35 @@ export declare const FileCoverageReport: Schema.Struct<{
|
|
|
28
28
|
}>;
|
|
29
29
|
/** @public */
|
|
30
30
|
export type FileCoverageReport = typeof FileCoverageReport.Type;
|
|
31
|
+
/**
|
|
32
|
+
* A threshold glob whose AGGREGATE coverage (summed covered/total across
|
|
33
|
+
* every file the glob matches, the same way Vitest evaluates a glob
|
|
34
|
+
* threshold) is below at least one of the glob's metric numbers.
|
|
35
|
+
*
|
|
36
|
+
* This is independent of the per-file lists: with an object `perFile` every
|
|
37
|
+
* matched file can pass while the glob as a whole still fails.
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare const GlobShortfall: Schema.Struct<{
|
|
41
|
+
/** The threshold glob pattern as configured. */
|
|
42
|
+
readonly pattern: Schema.String;
|
|
43
|
+
/** Aggregate coverage percentages over the files the glob matches. */
|
|
44
|
+
readonly summary: Schema.Struct<{
|
|
45
|
+
readonly statements: Schema.Number;
|
|
46
|
+
readonly branches: Schema.Number;
|
|
47
|
+
readonly functions: Schema.Number;
|
|
48
|
+
readonly lines: Schema.Number;
|
|
49
|
+
}>;
|
|
50
|
+
/** The glob's own metric numbers that were set (`perFile` excluded). */
|
|
51
|
+
readonly thresholds: Schema.Struct<{
|
|
52
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
53
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
54
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
55
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
/** @public */
|
|
59
|
+
export type GlobShortfall = typeof GlobShortfall.Type;
|
|
31
60
|
/**
|
|
32
61
|
* Complete coverage report attached to an AgentReport.
|
|
33
62
|
* @public
|
|
@@ -124,6 +153,24 @@ export declare const CoverageReport: Schema.Struct<{
|
|
|
124
153
|
readonly uncoveredLines: Schema.String;
|
|
125
154
|
}>>>;
|
|
126
155
|
readonly belowTargetFiles: Schema.optional<Schema.$Array<Schema.String>>;
|
|
156
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
157
|
+
/** The threshold glob pattern as configured. */
|
|
158
|
+
readonly pattern: Schema.String;
|
|
159
|
+
/** Aggregate coverage percentages over the files the glob matches. */
|
|
160
|
+
readonly summary: Schema.Struct<{
|
|
161
|
+
readonly statements: Schema.Number;
|
|
162
|
+
readonly branches: Schema.Number;
|
|
163
|
+
readonly functions: Schema.Number;
|
|
164
|
+
readonly lines: Schema.Number;
|
|
165
|
+
}>;
|
|
166
|
+
/** The glob's own metric numbers that were set (`perFile` excluded). */
|
|
167
|
+
readonly thresholds: Schema.Struct<{
|
|
168
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
169
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
170
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
171
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
172
|
+
}>;
|
|
173
|
+
}>>>;
|
|
127
174
|
}>;
|
|
128
175
|
/** @public */
|
|
129
176
|
export type CoverageReport = typeof CoverageReport.Type;
|
|
@@ -249,6 +296,21 @@ export declare const CoverageRenderState: Schema.Struct<{
|
|
|
249
296
|
readonly scoped: Schema.optional<Schema.Boolean>;
|
|
250
297
|
readonly scopedFiles: Schema.optional<Schema.Number>;
|
|
251
298
|
readonly totalFiles: Schema.optional<Schema.Number>;
|
|
299
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
300
|
+
readonly pattern: Schema.String;
|
|
301
|
+
readonly summary: Schema.Struct<{
|
|
302
|
+
readonly statements: Schema.Number;
|
|
303
|
+
readonly branches: Schema.Number;
|
|
304
|
+
readonly functions: Schema.Number;
|
|
305
|
+
readonly lines: Schema.Number;
|
|
306
|
+
}>;
|
|
307
|
+
readonly thresholds: Schema.Struct<{
|
|
308
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
309
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
310
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
311
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
312
|
+
}>;
|
|
313
|
+
}>>>;
|
|
252
314
|
}>;
|
|
253
315
|
/** @public */
|
|
254
316
|
export type CoverageRenderState = typeof CoverageRenderState.Type;
|
|
@@ -370,6 +432,21 @@ export declare const RenderState: Schema.Struct<{
|
|
|
370
432
|
readonly scoped: Schema.optional<Schema.Boolean>;
|
|
371
433
|
readonly scopedFiles: Schema.optional<Schema.Number>;
|
|
372
434
|
readonly totalFiles: Schema.optional<Schema.Number>;
|
|
435
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
436
|
+
readonly pattern: Schema.String;
|
|
437
|
+
readonly summary: Schema.Struct<{
|
|
438
|
+
readonly statements: Schema.Number;
|
|
439
|
+
readonly branches: Schema.Number;
|
|
440
|
+
readonly functions: Schema.Number;
|
|
441
|
+
readonly lines: Schema.Number;
|
|
442
|
+
}>;
|
|
443
|
+
readonly thresholds: Schema.Struct<{
|
|
444
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
445
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
446
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
447
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
448
|
+
}>;
|
|
449
|
+
}>>>;
|
|
373
450
|
}>>;
|
|
374
451
|
readonly trend: Schema.NullOr<Schema.Struct<{
|
|
375
452
|
readonly direction: Schema.Literals<readonly ["improving", "regressing", "stable"]>;
|
|
@@ -418,6 +495,21 @@ export declare const RenderState: Schema.Struct<{
|
|
|
418
495
|
readonly expected: Schema.optional<Schema.String>;
|
|
419
496
|
readonly received: Schema.optional<Schema.String>;
|
|
420
497
|
}>>;
|
|
498
|
+
/**
|
|
499
|
+
* What the run wrote straight to the terminal, past Vitest's console
|
|
500
|
+
* capture, folded from `RunFinished.strayOutput`. Absent when the run
|
|
501
|
+
* wrote nothing stray.
|
|
502
|
+
*/
|
|
503
|
+
readonly strayOutput: Schema.optional<Schema.Struct<{
|
|
504
|
+
readonly total: Schema.Number;
|
|
505
|
+
readonly stdout: Schema.Number;
|
|
506
|
+
readonly stderr: Schema.Number;
|
|
507
|
+
readonly bytes: Schema.Number;
|
|
508
|
+
readonly samples: Schema.$Array<Schema.Struct<{
|
|
509
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
510
|
+
readonly text: Schema.String;
|
|
511
|
+
}>>;
|
|
512
|
+
}>>;
|
|
421
513
|
}>;
|
|
422
514
|
/** @public */
|
|
423
515
|
export type RenderState = typeof RenderState.Type;
|
|
@@ -817,6 +909,21 @@ export declare const AgentReport: Schema.Struct<{
|
|
|
817
909
|
readonly uncoveredLines: Schema.String;
|
|
818
910
|
}>>>;
|
|
819
911
|
readonly belowTargetFiles: Schema.optional<Schema.$Array<Schema.String>>;
|
|
912
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
913
|
+
readonly pattern: Schema.String;
|
|
914
|
+
readonly summary: Schema.Struct<{
|
|
915
|
+
readonly statements: Schema.Number;
|
|
916
|
+
readonly branches: Schema.Number;
|
|
917
|
+
readonly functions: Schema.Number;
|
|
918
|
+
readonly lines: Schema.Number;
|
|
919
|
+
}>;
|
|
920
|
+
readonly thresholds: Schema.Struct<{
|
|
921
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
922
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
923
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
924
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
925
|
+
}>;
|
|
926
|
+
}>>>;
|
|
820
927
|
}>>;
|
|
821
928
|
readonly tagCounts: Schema.optional<Schema.$Record<Schema.String, Schema.Struct<{
|
|
822
929
|
readonly passed: Schema.optional<Schema.Number>;
|
|
@@ -838,6 +945,16 @@ export declare const AgentReport: Schema.Struct<{
|
|
|
838
945
|
readonly files: Schema.Number;
|
|
839
946
|
}>>;
|
|
840
947
|
}>>;
|
|
948
|
+
readonly strayOutput: Schema.optional<Schema.Struct<{
|
|
949
|
+
readonly total: Schema.Number;
|
|
950
|
+
readonly stdout: Schema.Number;
|
|
951
|
+
readonly stderr: Schema.Number;
|
|
952
|
+
readonly bytes: Schema.Number;
|
|
953
|
+
readonly samples: Schema.$Array<Schema.Struct<{
|
|
954
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
955
|
+
readonly text: Schema.String;
|
|
956
|
+
}>>;
|
|
957
|
+
}>>;
|
|
841
958
|
}>;
|
|
842
959
|
/** @public */
|
|
843
960
|
export type AgentReport = typeof AgentReport.Type;
|
|
@@ -929,13 +1046,6 @@ export type Environment = typeof Environment.Type;
|
|
|
929
1046
|
export declare const Executor: Schema.Literals<readonly ["human", "agent", "ci"]>;
|
|
930
1047
|
/** @public */
|
|
931
1048
|
export type Executor = typeof Executor.Type;
|
|
932
|
-
/**
|
|
933
|
-
* Output format for the reporter pipeline.
|
|
934
|
-
* @public
|
|
935
|
-
*/
|
|
936
|
-
export declare const OutputFormat: Schema.Literals<readonly ["terminal", "markdown", "json", "vitest-bypass", "silent", "ci-annotations"]>;
|
|
937
|
-
/** @public */
|
|
938
|
-
export type OutputFormat = typeof OutputFormat.Type;
|
|
939
1049
|
/**
|
|
940
1050
|
* Level of detail in reporter output.
|
|
941
1051
|
* @public
|
|
@@ -1173,6 +1283,21 @@ export declare const RunEvent: Schema.Union<readonly [Schema.TaggedStruct<"RunSt
|
|
|
1173
1283
|
readonly scoped: Schema.optional<Schema.Boolean>;
|
|
1174
1284
|
readonly scopedFiles: Schema.optional<Schema.Number>;
|
|
1175
1285
|
readonly totalFiles: Schema.optional<Schema.Number>;
|
|
1286
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
1287
|
+
readonly pattern: Schema.String;
|
|
1288
|
+
readonly summary: Schema.Struct<{
|
|
1289
|
+
readonly statements: Schema.Number;
|
|
1290
|
+
readonly branches: Schema.Number;
|
|
1291
|
+
readonly functions: Schema.Number;
|
|
1292
|
+
readonly lines: Schema.Number;
|
|
1293
|
+
}>;
|
|
1294
|
+
readonly thresholds: Schema.Struct<{
|
|
1295
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
1296
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
1297
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
1298
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
1299
|
+
}>;
|
|
1300
|
+
}>>>;
|
|
1176
1301
|
}>, Schema.TaggedStruct<"ThresholdViolation", {
|
|
1177
1302
|
readonly metric: Schema.Literals<readonly ["lines", "branches", "functions", "statements"]>;
|
|
1178
1303
|
readonly expected: Schema.Number;
|
|
@@ -1215,6 +1340,21 @@ export declare const RunEvent: Schema.Union<readonly [Schema.TaggedStruct<"RunSt
|
|
|
1215
1340
|
readonly expected: Schema.optional<Schema.String>;
|
|
1216
1341
|
readonly received: Schema.optional<Schema.String>;
|
|
1217
1342
|
}>>>;
|
|
1343
|
+
/**
|
|
1344
|
+
* What the run wrote straight to the terminal, past Vitest's console
|
|
1345
|
+
* capture (`AgentReport.strayOutput`). Optional: absent when the run
|
|
1346
|
+
* wrote nothing stray, and in older replay data.
|
|
1347
|
+
*/
|
|
1348
|
+
readonly strayOutput: Schema.optional<Schema.Struct<{
|
|
1349
|
+
readonly total: Schema.Number;
|
|
1350
|
+
readonly stdout: Schema.Number;
|
|
1351
|
+
readonly stderr: Schema.Number;
|
|
1352
|
+
readonly bytes: Schema.Number;
|
|
1353
|
+
readonly samples: Schema.$Array<Schema.Struct<{
|
|
1354
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
1355
|
+
readonly text: Schema.String;
|
|
1356
|
+
}>>;
|
|
1357
|
+
}>>;
|
|
1218
1358
|
}>]>;
|
|
1219
1359
|
/** @public */
|
|
1220
1360
|
export type RunEvent = typeof RunEvent.Type;
|
|
@@ -1354,10 +1494,10 @@ export type Transport = typeof Transport.Type;
|
|
|
1354
1494
|
* plugin always populates it in practice — the option exists for clarity
|
|
1355
1495
|
* and to leave room for future "no-persistence" experiments.
|
|
1356
1496
|
*
|
|
1357
|
-
* `
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1497
|
+
* `detail` is pre-resolved by the plugin (via `DetailResolver`) but
|
|
1498
|
+
* reporters that want to override can ignore it. `noColor` is the resolved
|
|
1499
|
+
* value of the `NO_COLOR` env var; reporters use it to gate ANSI escapes and
|
|
1500
|
+
* OSC-8 hyperlinks.
|
|
1361
1501
|
* @public
|
|
1362
1502
|
*/
|
|
1363
1503
|
export interface ResolvedReporterConfig {
|
|
@@ -1396,7 +1536,6 @@ export interface ResolvedReporterConfig {
|
|
|
1396
1536
|
* @internal
|
|
1397
1537
|
*/
|
|
1398
1538
|
readonly coverageMode: "full" | "ui-only";
|
|
1399
|
-
readonly format: OutputFormat;
|
|
1400
1539
|
readonly detail: DetailLevel;
|
|
1401
1540
|
readonly noColor: boolean;
|
|
1402
1541
|
readonly runCommand?: string;
|
|
@@ -1518,6 +1657,24 @@ export interface VitestAgentReporter {
|
|
|
1518
1657
|
* awaits it and treats a rejection as a logged warning.
|
|
1519
1658
|
*/
|
|
1520
1659
|
readonly close?: () => Promise<void>;
|
|
1660
|
+
/**
|
|
1661
|
+
* Print one whole line of stray output: bytes a test process wrote
|
|
1662
|
+
* straight to the terminal, past Vitest's console capture (a child
|
|
1663
|
+
* process spawned with inherited stdio is the usual source). A reporter
|
|
1664
|
+
* that draws in place (a live view) implements this to print the line
|
|
1665
|
+
* above its drawing instead of under it, where the next redraw would
|
|
1666
|
+
* strand it. Return `true` when the line was taken; `false` sends it to
|
|
1667
|
+
* the terminal unchanged.
|
|
1668
|
+
*
|
|
1669
|
+
* The plugin calls it synchronously, from the factory's return until just
|
|
1670
|
+
* before {@link VitestAgentReporter.close | close}, only for lines bound
|
|
1671
|
+
* for the process's own stdout or stderr (never when Vitest was given
|
|
1672
|
+
* other streams, as MCP's `run_tests` does), and only while it owns the
|
|
1673
|
+
* console (any mode but `passthrough`). The line carries no trailing
|
|
1674
|
+
* newline. Optional; without it every line passes through unchanged. The
|
|
1675
|
+
* run's stray output is reported on `AgentReport.strayOutput` either way.
|
|
1676
|
+
*/
|
|
1677
|
+
readonly printStrayLine?: (stream: "stdout" | "stderr", line: string) => boolean;
|
|
1521
1678
|
}
|
|
1522
1679
|
/**
|
|
1523
1680
|
* Factory that the plugin's `reporter` option accepts. The plugin calls
|
|
@@ -2789,6 +2946,21 @@ export declare const RunReportFile: Schema.Struct<{
|
|
|
2789
2946
|
readonly uncoveredLines: Schema.String;
|
|
2790
2947
|
}>>>;
|
|
2791
2948
|
readonly belowTargetFiles: Schema.optional<Schema.$Array<Schema.String>>;
|
|
2949
|
+
readonly globShortfalls: Schema.optional<Schema.$Array<Schema.Struct<{
|
|
2950
|
+
readonly pattern: Schema.String;
|
|
2951
|
+
readonly summary: Schema.Struct<{
|
|
2952
|
+
readonly statements: Schema.Number;
|
|
2953
|
+
readonly branches: Schema.Number;
|
|
2954
|
+
readonly functions: Schema.Number;
|
|
2955
|
+
readonly lines: Schema.Number;
|
|
2956
|
+
}>;
|
|
2957
|
+
readonly thresholds: Schema.Struct<{
|
|
2958
|
+
readonly lines: Schema.optional<Schema.Number>;
|
|
2959
|
+
readonly functions: Schema.optional<Schema.Number>;
|
|
2960
|
+
readonly branches: Schema.optional<Schema.Number>;
|
|
2961
|
+
readonly statements: Schema.optional<Schema.Number>;
|
|
2962
|
+
}>;
|
|
2963
|
+
}>>>;
|
|
2792
2964
|
}>>;
|
|
2793
2965
|
readonly tagCounts: Schema.optional<Schema.$Record<Schema.String, Schema.Struct<{
|
|
2794
2966
|
readonly passed: Schema.optional<Schema.Number>;
|
|
@@ -2810,11 +2982,62 @@ export declare const RunReportFile: Schema.Struct<{
|
|
|
2810
2982
|
readonly files: Schema.Number;
|
|
2811
2983
|
}>>;
|
|
2812
2984
|
}>>;
|
|
2985
|
+
readonly strayOutput: Schema.optional<Schema.Struct<{
|
|
2986
|
+
readonly total: Schema.Number;
|
|
2987
|
+
readonly stdout: Schema.Number;
|
|
2988
|
+
readonly stderr: Schema.Number;
|
|
2989
|
+
readonly bytes: Schema.Number;
|
|
2990
|
+
readonly samples: Schema.$Array<Schema.Struct<{
|
|
2991
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
2992
|
+
readonly text: Schema.String;
|
|
2993
|
+
}>>;
|
|
2994
|
+
}>>;
|
|
2813
2995
|
}>>;
|
|
2814
2996
|
}>;
|
|
2815
2997
|
/** @public */
|
|
2816
2998
|
export type RunReportFile = typeof RunReportFile.Type;
|
|
2817
2999
|
//#endregion
|
|
3000
|
+
//#region src/schemas/StrayOutput.d.ts
|
|
3001
|
+
/**
|
|
3002
|
+
* One line of stray output, kept as a sample: the stream it was written to,
|
|
3003
|
+
* and its text with escapes stripped, cut to a sane length.
|
|
3004
|
+
* @public
|
|
3005
|
+
*/
|
|
3006
|
+
export declare const StrayOutputSample: Schema.Struct<{
|
|
3007
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
3008
|
+
readonly text: Schema.String;
|
|
3009
|
+
}>;
|
|
3010
|
+
/** @public */
|
|
3011
|
+
export type StrayOutputSample = typeof StrayOutputSample.Type;
|
|
3012
|
+
/**
|
|
3013
|
+
* Output a test run wrote straight to the terminal, past Vitest's console
|
|
3014
|
+
* capture: bytes a worker process (or a child process it spawned with
|
|
3015
|
+
* inherited stdio, such as `execFileSync("git", ...)`) wrote to its own
|
|
3016
|
+
* stdout or stderr, which Vitest pipes through to the main process
|
|
3017
|
+
* untouched. Distinct from `consoleLeaks`, which counts `console.*` calls
|
|
3018
|
+
* Vitest did capture.
|
|
3019
|
+
*
|
|
3020
|
+
* A run-level signal: the bytes arrive on one stream shared by every project,
|
|
3021
|
+
* so nothing attributes them to a project, file or test. Every project report
|
|
3022
|
+
* of a run carries the same value. Counts are of non-blank lines; `bytes`
|
|
3023
|
+
* counts everything recorded. `samples` holds the first few lines. Omitted
|
|
3024
|
+
* when the run wrote nothing stray (and whenever the plugin does not own the
|
|
3025
|
+
* console: `passthrough` mode records nothing).
|
|
3026
|
+
* @public
|
|
3027
|
+
*/
|
|
3028
|
+
export declare const StrayOutput: Schema.Struct<{
|
|
3029
|
+
readonly total: Schema.Number;
|
|
3030
|
+
readonly stdout: Schema.Number;
|
|
3031
|
+
readonly stderr: Schema.Number;
|
|
3032
|
+
readonly bytes: Schema.Number;
|
|
3033
|
+
readonly samples: Schema.$Array<Schema.Struct<{
|
|
3034
|
+
readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
|
|
3035
|
+
readonly text: Schema.String;
|
|
3036
|
+
}>>;
|
|
3037
|
+
}>;
|
|
3038
|
+
/** @public */
|
|
3039
|
+
export type StrayOutput = typeof StrayOutput.Type;
|
|
3040
|
+
//#endregion
|
|
2818
3041
|
//#region src/schemas/Tdd.d.ts
|
|
2819
3042
|
/** @public */
|
|
2820
3043
|
export declare const GoalStatus: Schema.Literals<readonly ["pending", "in_progress", "done", "abandoned"]>;
|
|
@@ -4022,6 +4245,79 @@ export declare const probeHostMetadataFromEnv: (env: Record<string, string | und
|
|
|
4022
4245
|
*/
|
|
4023
4246
|
export declare function safeFilename(name: string): string;
|
|
4024
4247
|
//#endregion
|
|
4248
|
+
//#region src/utils/stray-output.d.ts
|
|
4249
|
+
/**
|
|
4250
|
+
* A stream stray output was written to.
|
|
4251
|
+
* @public
|
|
4252
|
+
*/
|
|
4253
|
+
export type StrayOutputStream = "stdout" | "stderr";
|
|
4254
|
+
/**
|
|
4255
|
+
* Records stray output for one run at a time: counts its non-blank lines per
|
|
4256
|
+
* stream and its bytes, and keeps the first few lines as samples. Memory is
|
|
4257
|
+
* bounded whatever is written: only the samples and one partial line per
|
|
4258
|
+
* stream (itself cut to the sample length) are held.
|
|
4259
|
+
* @public
|
|
4260
|
+
*/
|
|
4261
|
+
export interface StrayOutputRecorder {
|
|
4262
|
+
/** Record text written to `stream`. A write made only of escape sequences is ignored. */
|
|
4263
|
+
readonly write: (stream: StrayOutputStream, text: string) => void;
|
|
4264
|
+
/** What the run has written so far, a trailing partial line included; `undefined` when nothing. */
|
|
4265
|
+
readonly snapshot: () => StrayOutput | undefined;
|
|
4266
|
+
/** Forget everything: a new run starts. */
|
|
4267
|
+
readonly reset: () => void;
|
|
4268
|
+
}
|
|
4269
|
+
/**
|
|
4270
|
+
* Options for {@link makeStrayOutputRecorder}.
|
|
4271
|
+
* @public
|
|
4272
|
+
*/
|
|
4273
|
+
export interface StrayOutputRecorderOptions {
|
|
4274
|
+
/** How many lines to keep as samples. @defaultValue 5 */
|
|
4275
|
+
readonly maxSamples?: number;
|
|
4276
|
+
/** How many characters of a sample to keep before cutting it with `…`. @defaultValue 160 */
|
|
4277
|
+
readonly maxSampleChars?: number;
|
|
4278
|
+
}
|
|
4279
|
+
/**
|
|
4280
|
+
* True when `text` is nothing but terminal escape sequences: the cursor
|
|
4281
|
+
* hide/show, clear-screen and erase-scrollback writes Vitest's own `Logger`
|
|
4282
|
+
* makes straight to its output stream. Empty text is not escape-only.
|
|
4283
|
+
* @public
|
|
4284
|
+
*/
|
|
4285
|
+
export declare const isEscapeOnly: (text: string) => boolean;
|
|
4286
|
+
/**
|
|
4287
|
+
* Make a {@link StrayOutputRecorder}.
|
|
4288
|
+
* @public
|
|
4289
|
+
*/
|
|
4290
|
+
export declare const makeStrayOutputRecorder: (options?: StrayOutputRecorderOptions) => StrayOutputRecorder;
|
|
4291
|
+
/**
|
|
4292
|
+
* The key a stray-output capture publishes its {@link StrayOutputSource}
|
|
4293
|
+
* under, on the Vitest `Logger` whose streams it wraps. `Symbol.for`, so a
|
|
4294
|
+
* plugin and an MCP server that load different copies of this package still
|
|
4295
|
+
* meet on it.
|
|
4296
|
+
* @public
|
|
4297
|
+
*/
|
|
4298
|
+
export declare const STRAY_OUTPUT_SOURCE: unique symbol;
|
|
4299
|
+
/**
|
|
4300
|
+
* What a stray-output capture publishes for a reader that did not install it.
|
|
4301
|
+
* @public
|
|
4302
|
+
*/
|
|
4303
|
+
export interface StrayOutputSource {
|
|
4304
|
+
/** The current run's stray output, or `undefined` when it wrote none. */
|
|
4305
|
+
readonly snapshot: () => StrayOutput | undefined;
|
|
4306
|
+
}
|
|
4307
|
+
/**
|
|
4308
|
+
* Read the current run's stray output from a Vitest `Logger` a capture was
|
|
4309
|
+
* installed on. `undefined` when none was installed, or the run wrote nothing.
|
|
4310
|
+
* @public
|
|
4311
|
+
*/
|
|
4312
|
+
export declare const readStrayOutput: (logger: unknown) => StrayOutput | undefined;
|
|
4313
|
+
/**
|
|
4314
|
+
* The note a renderer prints for a run's stray output: one line naming the
|
|
4315
|
+
* count, the streams, the usual cause and the fix, then up to three sample
|
|
4316
|
+
* lines and how many it left out.
|
|
4317
|
+
* @public
|
|
4318
|
+
*/
|
|
4319
|
+
export declare const formatStrayOutputNote: (stray: StrayOutput) => ReadonlyArray<string>;
|
|
4320
|
+
//#endregion
|
|
4025
4321
|
//#region src/utils/test-location.d.ts
|
|
4026
4322
|
/** Directory holding source files whose tests may be co-located. @public */
|
|
4027
4323
|
export declare const SRC_DIR = "src";
|
package/index.js
CHANGED
|
@@ -7,10 +7,11 @@ import { GitCommandError, ProbeMissError } from "./errors/RunContextError.js";
|
|
|
7
7
|
import { BehaviorNotFoundError, GoalNotFoundError, IllegalStatusTransitionError, TddTaskAlreadyEndedError, TddTaskNotFoundError } from "./errors/TddErrors.js";
|
|
8
8
|
import { ActorType, AgentId, ChatId, ConversationId, HostKind, ProjectKey, TddTaskId } from "./schemas/Identity.js";
|
|
9
9
|
import { Agent, IdempotencyHit } from "./schemas/Agent.js";
|
|
10
|
-
import { AgentConsoleMode, CiConsoleMode, ConsoleMode, ConsoleOutputMode, DetailLevel, Environment, Executor, HumanConsoleMode,
|
|
10
|
+
import { AgentConsoleMode, CiConsoleMode, ConsoleMode, ConsoleOutputMode, DetailLevel, Environment, Executor, HumanConsoleMode, PackageManager, ReportError, TestClassification, TestRunReason, TestState } from "./schemas/Common.js";
|
|
11
11
|
import { ConsoleLeakFile, ConsoleLeaks, ConsoleLeaksFromFailingTests } from "./schemas/ConsoleLeaks.js";
|
|
12
12
|
import { MetricThresholds, PatternMetricThresholds, PatternThresholds, PerFileThresholds, ResolvedThresholds } from "./schemas/Thresholds.js";
|
|
13
|
-
import { CoverageReport, CoverageTotals, FileCoverageReport } from "./schemas/Coverage.js";
|
|
13
|
+
import { CoverageReport, CoverageTotals, FileCoverageReport, GlobShortfall } from "./schemas/Coverage.js";
|
|
14
|
+
import { StrayOutput, StrayOutputSample } from "./schemas/StrayOutput.js";
|
|
14
15
|
import { AgentReport, ModuleReport, ReportSummary, TagCountEntry, TestReport } from "./schemas/AgentReport.js";
|
|
15
16
|
import { CoverageBaselines } from "./schemas/Baselines.js";
|
|
16
17
|
import { CacheManifest, CacheManifestEntry } from "./schemas/CacheManifest.js";
|
|
@@ -57,9 +58,10 @@ import { normalizeWorkspaceKey } from "./utils/normalize-workspace-key.js";
|
|
|
57
58
|
import { basenamePosix, joinPosix, relativePosix, toPosix } from "./utils/posix-path.js";
|
|
58
59
|
import { probeHostMetadataFromEnv } from "./utils/probe-host-metadata.js";
|
|
59
60
|
import { safeFilename } from "./utils/safe-filename.js";
|
|
61
|
+
import { STRAY_OUTPUT_SOURCE, formatStrayOutputNote, isEscapeOnly, makeStrayOutputRecorder, readStrayOutput } from "./utils/stray-output.js";
|
|
60
62
|
import { BATS_FILE_GLOB_SUFFIX, NON_DISCOVERABLE_DIRS, SRC_DIR, TEST_DIR, TEST_FILE_GLOB_SUFFIX, TEST_HELPER_DIRS, classifyTestPath, findOwningWorkspace, isTestFileName } from "./utils/test-location.js";
|
|
61
63
|
import { validateCoverageTargetsShape } from "./utils/validate-coverage-targets-shape.js";
|
|
62
64
|
import { requiredArtifactForTransition, transitionEnforcesBehaviorMatch, validatePhaseTransition } from "./utils/validate-phase-transition.js";
|
|
63
65
|
import { CURRENT_SDK_VERSION } from "./version.js";
|
|
64
66
|
|
|
65
|
-
export { ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, BATS_FILE_GLOB_SUFFIX, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, ChannelEvent, ChatId, CiConsoleMode, ConsoleLeakFile, ConsoleLeaks, ConsoleLeaksFromFailingTests, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, CoverageGap, CoverageLevel, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTotals, DataStoreError, DetailLevel, DiscoveryError, Environment, Executor, FailureRecord, FileCoverageReport, FileEditPayload, GitCommandError, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HumanConsoleMode, HypothesisPayload, IdempotencyHit, IllegalStatusTransitionError, MetricThresholds, ModuleRecord, ModuleReport, NON_DISCOVERABLE_DIRS, NotePayload,
|
|
67
|
+
export { ActionSeverity, ActorType, Agent, AgentConsoleMode, AgentId, AgentNotFoundError, AgentPluginOptions, AgentReport, AgentReporterOptions, BATS_FILE_GLOB_SUFFIX, BehaviorAbandonedEvent, BehaviorAddedEvent, BehaviorCompletedEvent, BehaviorDetail, BehaviorNotFoundError, BehaviorRow, BehaviorScopedEventTypes, BehaviorStartedEvent, BehaviorStatus, BehaviorsReadyEvent, BlockedEvent, CURRENT_SDK_VERSION, CacheManifest, CacheManifestEntry, ChannelEvent, ChatId, CiConsoleMode, ConsoleLeakFile, ConsoleLeaks, ConsoleLeaksFromFailingTests, ConsoleLogLevel, ConsoleMode, ConsoleOutputMode, ConsoleOutputs, ConversationId, ConversationNotFoundError, CoverageBaselines, FileCoverageReport as CoverageFile, CoverageGap, CoverageLevel, CoverageMetric, CoverageRenderState, CoverageReport, CoverageTargets, CoverageTargetsMetrics, CoverageTotals, DataStoreError, DetailLevel, DiscoveryError, Environment, Executor, FailureRecord, FileCoverageReport, FileEditPayload, GitCommandError, GlobShortfall, GoalAbandonedEvent, GoalAddedEvent, GoalCompletedEvent, GoalDetail, GoalNotFoundError, GoalRow, GoalStartedEvent, GoalStatus, GoalsReadyEvent, HistoryRecord, HookFirePayload, HookStatus, HookType, HostKind, HostMetadataParseError, HumanConsoleMode, HypothesisPayload, IdempotencyHit, IllegalStatusTransitionError, MetricThresholds, ModuleRecord, ModuleReport, NON_DISCOVERABLE_DIRS, NotePayload, PackageManager, PathResolutionError, PatternMetricThresholds, PatternThresholds, PerFileThresholds, PhaseTransitionEvent, ProbeMissError, ProjectIdentityNotResolvableError, ProjectKey, RUN_REPORT_FILE_SCHEMA_URL, RegistrationConflictError, RenderState, RenderTotals, ReportError, ReportOption, ReportSettings, ReportSummary, ResolvedThresholds, RunEvent, RunReportFile, SRC_DIR, STRAY_OUTPUT_SOURCE, SessionCompleteEvent, SessionNotFoundError, SessionOutcome, SidecarTimeoutError, StrayOutput, StrayOutputSample, SuggestedActionRecord, TEST_DIR, TEST_FILE_GLOB_SUFFIX, TEST_HELPER_DIRS, TagCountEntry, TddTaskAlreadyEndedError, TddTaskId, TddTaskNotFoundError, TestAnnotation, TestArtifact, TestArtifactLocation, TestAttachment, TestClassification, TestHistory, TestRecord, TestReport, TestRun, TestRunReason, TestState, ToolCallPayload, ToolResultPayload, Transport, TrendEntry, TrendRecord, TurnPayload, UserPromptPayload, VitestAgentConfig, ansi, basenamePosix, buildAgentReport, buildConsoleLeaks, buildEnvPrefix, canonicalizeGitUrl, classifyTest, classifyTestPath, coerceErrorField, coerceErrorText, collectConsoleLeakEntries, compressLines, computeTrend, countSuiteFailures, detectNonDefaultDiscoverStrategy, detectPackageManager, detectVitestScripts, determineTier, extractSqlReason, findFunctionBoundary, findOwningWorkspace, formatConsoleMarkdown, formatFatalError, formatGfm, formatScopedCoverageNote, formatStrayOutputNote, getRecentDirection, getRunCommand, getWorstMetric, gitUrlToProjectKey, hashTargets, initialRenderState, isEscapeOnly, isTestFileName, isTimeoutError, isVitestInvocation, joinPosix, makeStrayOutputRecorder, normalizeWorkspaceKey, osc8, probeHostMetadataFromEnv, readStrayOutput, relativePath, relativePosix, requiredArtifactForTransition, resolveCoverageInput, rewriteBashCommand, safeFilename, stripAnsi, toPosix, transitionEnforcesBehaviorMatch, validateCoverageConfig, validateCoverageTargetsShape, validatePhaseTransition };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Platform-free core for the vitest-agent package family: Effect Schema definitions, reporter and dispatcher contracts, errors, and pure utilities.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"./package.json": "./package.json"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"acorn": "^8.
|
|
44
|
+
"acorn": "^8.19.0",
|
|
45
45
|
"acorn-typescript": "^1.4.13",
|
|
46
|
-
"effect": "^4.0.
|
|
46
|
+
"effect": "^4.0.2"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": ">=24.11.0"
|
package/schemas/5.0/run.json
CHANGED
|
@@ -526,6 +526,22 @@
|
|
|
526
526
|
"required": ["file", "summary", "uncoveredLines"],
|
|
527
527
|
"additionalProperties": true
|
|
528
528
|
},
|
|
529
|
+
"GlobShortfall": {
|
|
530
|
+
"type": "object",
|
|
531
|
+
"properties": {
|
|
532
|
+
"pattern": {
|
|
533
|
+
"type": "string"
|
|
534
|
+
},
|
|
535
|
+
"summary": {
|
|
536
|
+
"$ref": "#/$defs/CoverageTotals"
|
|
537
|
+
},
|
|
538
|
+
"thresholds": {
|
|
539
|
+
"$ref": "#/$defs/MetricThresholds"
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
"required": ["pattern", "summary", "thresholds"],
|
|
543
|
+
"additionalProperties": true
|
|
544
|
+
},
|
|
529
545
|
"CoverageReport": {
|
|
530
546
|
"type": "object",
|
|
531
547
|
"properties": {
|
|
@@ -665,6 +681,19 @@
|
|
|
665
681
|
"type": "null"
|
|
666
682
|
}
|
|
667
683
|
]
|
|
684
|
+
},
|
|
685
|
+
"globShortfalls": {
|
|
686
|
+
"anyOf": [
|
|
687
|
+
{
|
|
688
|
+
"type": "array",
|
|
689
|
+
"items": {
|
|
690
|
+
"$ref": "#/$defs/GlobShortfall"
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"type": "null"
|
|
695
|
+
}
|
|
696
|
+
]
|
|
668
697
|
}
|
|
669
698
|
},
|
|
670
699
|
"required": ["totals", "thresholds", "lowCoverage", "lowCoverageFiles"],
|
|
@@ -858,6 +887,77 @@
|
|
|
858
887
|
"required": ["total", "byFile"],
|
|
859
888
|
"additionalProperties": true
|
|
860
889
|
},
|
|
890
|
+
"StrayOutputSample": {
|
|
891
|
+
"type": "object",
|
|
892
|
+
"properties": {
|
|
893
|
+
"stream": {
|
|
894
|
+
"type": "string",
|
|
895
|
+
"enum": ["stdout", "stderr"]
|
|
896
|
+
},
|
|
897
|
+
"text": {
|
|
898
|
+
"type": "string"
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
"required": ["stream", "text"],
|
|
902
|
+
"additionalProperties": true
|
|
903
|
+
},
|
|
904
|
+
"StrayOutput": {
|
|
905
|
+
"type": "object",
|
|
906
|
+
"properties": {
|
|
907
|
+
"total": {
|
|
908
|
+
"anyOf": [
|
|
909
|
+
{
|
|
910
|
+
"type": "number"
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
"type": "string",
|
|
914
|
+
"enum": ["Infinity", "-Infinity", "NaN"]
|
|
915
|
+
}
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
"stdout": {
|
|
919
|
+
"anyOf": [
|
|
920
|
+
{
|
|
921
|
+
"type": "number"
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
"type": "string",
|
|
925
|
+
"enum": ["Infinity", "-Infinity", "NaN"]
|
|
926
|
+
}
|
|
927
|
+
]
|
|
928
|
+
},
|
|
929
|
+
"stderr": {
|
|
930
|
+
"anyOf": [
|
|
931
|
+
{
|
|
932
|
+
"type": "number"
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
"type": "string",
|
|
936
|
+
"enum": ["Infinity", "-Infinity", "NaN"]
|
|
937
|
+
}
|
|
938
|
+
]
|
|
939
|
+
},
|
|
940
|
+
"bytes": {
|
|
941
|
+
"anyOf": [
|
|
942
|
+
{
|
|
943
|
+
"type": "number"
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
"type": "string",
|
|
947
|
+
"enum": ["Infinity", "-Infinity", "NaN"]
|
|
948
|
+
}
|
|
949
|
+
]
|
|
950
|
+
},
|
|
951
|
+
"samples": {
|
|
952
|
+
"type": "array",
|
|
953
|
+
"items": {
|
|
954
|
+
"$ref": "#/$defs/StrayOutputSample"
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
"required": ["total", "stdout", "stderr", "bytes", "samples"],
|
|
959
|
+
"additionalProperties": true
|
|
960
|
+
},
|
|
861
961
|
"AgentReport": {
|
|
862
962
|
"type": "object",
|
|
863
963
|
"properties": {
|
|
@@ -930,6 +1030,16 @@
|
|
|
930
1030
|
"type": "null"
|
|
931
1031
|
}
|
|
932
1032
|
]
|
|
1033
|
+
},
|
|
1034
|
+
"strayOutput": {
|
|
1035
|
+
"anyOf": [
|
|
1036
|
+
{
|
|
1037
|
+
"$ref": "#/$defs/StrayOutput"
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
"type": "null"
|
|
1041
|
+
}
|
|
1042
|
+
]
|
|
933
1043
|
}
|
|
934
1044
|
},
|
|
935
1045
|
"required": ["timestamp", "reason", "summary", "failed", "unhandledErrors", "failedFiles"],
|
package/schemas/AgentReport.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReportError, TestClassification, TestRunReason, TestState } from "./Common.js";
|
|
2
2
|
import { ConsoleLeaks } from "./ConsoleLeaks.js";
|
|
3
3
|
import { CoverageReport } from "./Coverage.js";
|
|
4
|
+
import { StrayOutput } from "./StrayOutput.js";
|
|
4
5
|
import { Schema } from "effect";
|
|
5
6
|
|
|
6
7
|
//#region src/schemas/AgentReport.ts
|
|
@@ -71,7 +72,8 @@ const AgentReport = Schema.Struct({
|
|
|
71
72
|
failedFiles: Schema.Array(Schema.String),
|
|
72
73
|
coverage: Schema.optional(CoverageReport),
|
|
73
74
|
tagCounts: Schema.optional(Schema.Record(Schema.String, TagCountEntry)),
|
|
74
|
-
consoleLeaks: Schema.optional(ConsoleLeaks)
|
|
75
|
+
consoleLeaks: Schema.optional(ConsoleLeaks),
|
|
76
|
+
strayOutput: Schema.optional(StrayOutput)
|
|
75
77
|
}).annotate({ identifier: "AgentReport" });
|
|
76
78
|
|
|
77
79
|
//#endregion
|
package/schemas/Common.js
CHANGED
|
@@ -116,18 +116,6 @@ const Executor = Schema.Literals([
|
|
|
116
116
|
"ci"
|
|
117
117
|
]).annotate({ identifier: "Executor" });
|
|
118
118
|
/**
|
|
119
|
-
* Output format for the reporter pipeline.
|
|
120
|
-
* @public
|
|
121
|
-
*/
|
|
122
|
-
const OutputFormat = Schema.Literals([
|
|
123
|
-
"terminal",
|
|
124
|
-
"markdown",
|
|
125
|
-
"json",
|
|
126
|
-
"vitest-bypass",
|
|
127
|
-
"silent",
|
|
128
|
-
"ci-annotations"
|
|
129
|
-
]).annotate({ identifier: "OutputFormat" });
|
|
130
|
-
/**
|
|
131
119
|
* Level of detail in reporter output.
|
|
132
120
|
* @public
|
|
133
121
|
*/
|
|
@@ -158,4 +146,4 @@ const ReportError = Schema.Struct({
|
|
|
158
146
|
}).annotate({ identifier: "ReportError" });
|
|
159
147
|
|
|
160
148
|
//#endregion
|
|
161
|
-
export { AgentConsoleMode, CiConsoleMode, ConsoleMode, ConsoleOutputMode, DetailLevel, Environment, Executor, HumanConsoleMode,
|
|
149
|
+
export { AgentConsoleMode, CiConsoleMode, ConsoleMode, ConsoleOutputMode, DetailLevel, Environment, Executor, HumanConsoleMode, PackageManager, ReportError, TestClassification, TestRunReason, TestState };
|
package/schemas/Coverage.js
CHANGED
|
@@ -22,6 +22,23 @@ const FileCoverageReport = Schema.Struct({
|
|
|
22
22
|
uncoveredLines: Schema.String
|
|
23
23
|
}).annotate({ identifier: "FileCoverageReport" });
|
|
24
24
|
/**
|
|
25
|
+
* A threshold glob whose AGGREGATE coverage (summed covered/total across
|
|
26
|
+
* every file the glob matches, the same way Vitest evaluates a glob
|
|
27
|
+
* threshold) is below at least one of the glob's metric numbers.
|
|
28
|
+
*
|
|
29
|
+
* This is independent of the per-file lists: with an object `perFile` every
|
|
30
|
+
* matched file can pass while the glob as a whole still fails.
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
const GlobShortfall = Schema.Struct({
|
|
34
|
+
/** The threshold glob pattern as configured. */
|
|
35
|
+
pattern: Schema.String,
|
|
36
|
+
/** Aggregate coverage percentages over the files the glob matches. */
|
|
37
|
+
summary: CoverageTotals,
|
|
38
|
+
/** The glob's own metric numbers that were set (`perFile` excluded). */
|
|
39
|
+
thresholds: MetricThresholds
|
|
40
|
+
}).annotate({ identifier: "GlobShortfall" });
|
|
41
|
+
/**
|
|
25
42
|
* Complete coverage report attached to an AgentReport.
|
|
26
43
|
* @public
|
|
27
44
|
*/
|
|
@@ -45,8 +62,9 @@ const CoverageReport = Schema.Struct({
|
|
|
45
62
|
lowCoverage: Schema.Array(FileCoverageReport),
|
|
46
63
|
lowCoverageFiles: Schema.Array(Schema.String),
|
|
47
64
|
belowTarget: Schema.optional(Schema.Array(FileCoverageReport)),
|
|
48
|
-
belowTargetFiles: Schema.optional(Schema.Array(Schema.String))
|
|
65
|
+
belowTargetFiles: Schema.optional(Schema.Array(Schema.String)),
|
|
66
|
+
globShortfalls: Schema.optional(Schema.Array(GlobShortfall))
|
|
49
67
|
}).annotate({ identifier: "CoverageReport" });
|
|
50
68
|
|
|
51
69
|
//#endregion
|
|
52
|
-
export { CoverageReport, CoverageTotals, FileCoverageReport };
|
|
70
|
+
export { CoverageReport, CoverageTotals, FileCoverageReport, GlobShortfall };
|
package/schemas/RenderState.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReportError, TestClassification, TestState } from "./Common.js";
|
|
2
2
|
import { MetricThresholds } from "./Thresholds.js";
|
|
3
|
-
import { CoverageTotals } from "./Coverage.js";
|
|
3
|
+
import { CoverageTotals, GlobShortfall } from "./Coverage.js";
|
|
4
|
+
import { StrayOutput } from "./StrayOutput.js";
|
|
4
5
|
import { ActionSeverity, CoverageGap, CoverageMetric } from "./RunEvent.js";
|
|
5
6
|
import { Schema } from "effect";
|
|
6
7
|
|
|
@@ -79,7 +80,8 @@ const CoverageRenderState = Schema.Struct({
|
|
|
79
80
|
})),
|
|
80
81
|
scoped: Schema.optional(Schema.Boolean),
|
|
81
82
|
scopedFiles: Schema.optional(Schema.Number),
|
|
82
|
-
totalFiles: Schema.optional(Schema.Number)
|
|
83
|
+
totalFiles: Schema.optional(Schema.Number),
|
|
84
|
+
globShortfalls: Schema.optional(Schema.Array(GlobShortfall))
|
|
83
85
|
}).annotate({ identifier: "CoverageRenderState" });
|
|
84
86
|
/**
|
|
85
87
|
* A `SuggestedAction` event, denormalized into the queue the renderer reads.
|
|
@@ -155,7 +157,13 @@ const RenderState = Schema.Struct({
|
|
|
155
157
|
* (older replay data, hand-built fixtures) defaults to `[]`. See
|
|
156
158
|
* issue #240.
|
|
157
159
|
*/
|
|
158
|
-
unhandledErrors: Schema.Array(ReportError)
|
|
160
|
+
unhandledErrors: Schema.Array(ReportError),
|
|
161
|
+
/**
|
|
162
|
+
* What the run wrote straight to the terminal, past Vitest's console
|
|
163
|
+
* capture, folded from `RunFinished.strayOutput`. Absent when the run
|
|
164
|
+
* wrote nothing stray.
|
|
165
|
+
*/
|
|
166
|
+
strayOutput: Schema.optional(StrayOutput)
|
|
159
167
|
}).annotate({ identifier: "RenderState" });
|
|
160
168
|
/**
|
|
161
169
|
* Initial state — what the reducer returns when no events have been
|
package/schemas/RunEvent.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReportError, TestClassification, TestState } from "./Common.js";
|
|
2
2
|
import { MetricThresholds } from "./Thresholds.js";
|
|
3
|
-
import { CoverageTotals, FileCoverageReport } from "./Coverage.js";
|
|
3
|
+
import { CoverageTotals, FileCoverageReport, GlobShortfall } from "./Coverage.js";
|
|
4
|
+
import { StrayOutput } from "./StrayOutput.js";
|
|
4
5
|
import { TestArtifactLocation, TestAttachment } from "./TestArtifacts.js";
|
|
5
6
|
import { Schema } from "effect";
|
|
6
7
|
|
|
@@ -178,7 +179,8 @@ const RunEvent = Schema.Union([
|
|
|
178
179
|
gaps: Schema.Array(CoverageGap),
|
|
179
180
|
scoped: Schema.optional(Schema.Boolean),
|
|
180
181
|
scopedFiles: Schema.optional(Schema.Number),
|
|
181
|
-
totalFiles: Schema.optional(Schema.Number)
|
|
182
|
+
totalFiles: Schema.optional(Schema.Number),
|
|
183
|
+
globShortfalls: Schema.optional(Schema.Array(GlobShortfall))
|
|
182
184
|
}),
|
|
183
185
|
Schema.TaggedStruct("ThresholdViolation", {
|
|
184
186
|
metric: CoverageMetric,
|
|
@@ -218,7 +220,13 @@ const RunEvent = Schema.Union([
|
|
|
218
220
|
* argument to `onTestRunEnd`. Optional so hand-built fixtures
|
|
219
221
|
* and older replay data keep decoding. See issue #240.
|
|
220
222
|
*/
|
|
221
|
-
unhandledErrors: Schema.optional(Schema.Array(ReportError))
|
|
223
|
+
unhandledErrors: Schema.optional(Schema.Array(ReportError)),
|
|
224
|
+
/**
|
|
225
|
+
* What the run wrote straight to the terminal, past Vitest's console
|
|
226
|
+
* capture (`AgentReport.strayOutput`). Optional: absent when the run
|
|
227
|
+
* wrote nothing stray, and in older replay data.
|
|
228
|
+
*/
|
|
229
|
+
strayOutput: Schema.optional(StrayOutput)
|
|
222
230
|
})
|
|
223
231
|
]).annotate({ identifier: "RunEvent" });
|
|
224
232
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/schemas/StrayOutput.ts
|
|
4
|
+
/**
|
|
5
|
+
* One line of stray output, kept as a sample: the stream it was written to,
|
|
6
|
+
* and its text with escapes stripped, cut to a sane length.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
const StrayOutputSample = Schema.Struct({
|
|
10
|
+
stream: Schema.Literals(["stdout", "stderr"]),
|
|
11
|
+
text: Schema.String
|
|
12
|
+
}).annotate({ identifier: "StrayOutputSample" });
|
|
13
|
+
/**
|
|
14
|
+
* Output a test run wrote straight to the terminal, past Vitest's console
|
|
15
|
+
* capture: bytes a worker process (or a child process it spawned with
|
|
16
|
+
* inherited stdio, such as `execFileSync("git", ...)`) wrote to its own
|
|
17
|
+
* stdout or stderr, which Vitest pipes through to the main process
|
|
18
|
+
* untouched. Distinct from `consoleLeaks`, which counts `console.*` calls
|
|
19
|
+
* Vitest did capture.
|
|
20
|
+
*
|
|
21
|
+
* A run-level signal: the bytes arrive on one stream shared by every project,
|
|
22
|
+
* so nothing attributes them to a project, file or test. Every project report
|
|
23
|
+
* of a run carries the same value. Counts are of non-blank lines; `bytes`
|
|
24
|
+
* counts everything recorded. `samples` holds the first few lines. Omitted
|
|
25
|
+
* when the run wrote nothing stray (and whenever the plugin does not own the
|
|
26
|
+
* console: `passthrough` mode records nothing).
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
const StrayOutput = Schema.Struct({
|
|
30
|
+
total: Schema.Number,
|
|
31
|
+
stdout: Schema.Number,
|
|
32
|
+
stderr: Schema.Number,
|
|
33
|
+
bytes: Schema.Number,
|
|
34
|
+
samples: Schema.Array(StrayOutputSample)
|
|
35
|
+
}).annotate({ identifier: "StrayOutput" });
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { StrayOutput, StrayOutputSample };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//#region src/utils/stray-output.ts
|
|
2
|
+
const ESCAPE = /\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07\x1b]*(?:\x07|\x1b\\)|[@-Z\\-_]|c)/g;
|
|
3
|
+
const CONTROL = /[\x00-\x08\x0b-\x1f\x7f]/g;
|
|
4
|
+
/**
|
|
5
|
+
* True when `text` is nothing but terminal escape sequences: the cursor
|
|
6
|
+
* hide/show, clear-screen and erase-scrollback writes Vitest's own `Logger`
|
|
7
|
+
* makes straight to its output stream. Empty text is not escape-only.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
const isEscapeOnly = (text) => text.length > 0 && text.replace(ESCAPE, "").length === 0;
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
/**
|
|
13
|
+
* Make a {@link StrayOutputRecorder}.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
const makeStrayOutputRecorder = (options = {}) => {
|
|
17
|
+
const maxSamples = options.maxSamples ?? 5;
|
|
18
|
+
const maxChars = options.maxSampleChars ?? 160;
|
|
19
|
+
let counts = {
|
|
20
|
+
stdout: 0,
|
|
21
|
+
stderr: 0
|
|
22
|
+
};
|
|
23
|
+
let bytes = 0;
|
|
24
|
+
let samples = [];
|
|
25
|
+
let pending = {
|
|
26
|
+
stdout: {
|
|
27
|
+
text: "",
|
|
28
|
+
cut: false
|
|
29
|
+
},
|
|
30
|
+
stderr: {
|
|
31
|
+
text: "",
|
|
32
|
+
cut: false
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const clean = (line) => line.replace(ESCAPE, "").replace(CONTROL, "").trim();
|
|
36
|
+
const sampleOf = (line) => {
|
|
37
|
+
const text = clean(line.text);
|
|
38
|
+
return line.cut || text.length > maxChars ? `${text.slice(0, maxChars)}…` : text;
|
|
39
|
+
};
|
|
40
|
+
const finish = (stream, line, into, out) => {
|
|
41
|
+
if (clean(line.text) === "") return;
|
|
42
|
+
into[stream]++;
|
|
43
|
+
if (out.length < maxSamples) out.push({
|
|
44
|
+
stream,
|
|
45
|
+
text: sampleOf(line)
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const append = (line, text) => {
|
|
49
|
+
const room = maxChars * 4 - line.text.length;
|
|
50
|
+
if (text.length <= room) line.text += text;
|
|
51
|
+
else {
|
|
52
|
+
line.text += text.slice(0, Math.max(0, room));
|
|
53
|
+
line.cut = true;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
write: (stream, text) => {
|
|
58
|
+
if (text.length === 0 || isEscapeOnly(text)) return;
|
|
59
|
+
bytes += encoder.encode(text).length;
|
|
60
|
+
const parts = text.split("\n");
|
|
61
|
+
const line = pending[stream];
|
|
62
|
+
append(line, parts[0] ?? "");
|
|
63
|
+
for (let i = 1; i < parts.length; i++) {
|
|
64
|
+
finish(stream, line, counts, samples);
|
|
65
|
+
line.text = "";
|
|
66
|
+
line.cut = false;
|
|
67
|
+
append(line, parts[i] ?? "");
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
snapshot: () => {
|
|
71
|
+
const totals = { ...counts };
|
|
72
|
+
const out = [...samples];
|
|
73
|
+
finish("stdout", pending.stdout, totals, out);
|
|
74
|
+
finish("stderr", pending.stderr, totals, out);
|
|
75
|
+
const total = totals.stdout + totals.stderr;
|
|
76
|
+
if (total === 0) return void 0;
|
|
77
|
+
return {
|
|
78
|
+
total,
|
|
79
|
+
stdout: totals.stdout,
|
|
80
|
+
stderr: totals.stderr,
|
|
81
|
+
bytes,
|
|
82
|
+
samples: out
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
reset: () => {
|
|
86
|
+
counts = {
|
|
87
|
+
stdout: 0,
|
|
88
|
+
stderr: 0
|
|
89
|
+
};
|
|
90
|
+
bytes = 0;
|
|
91
|
+
samples = [];
|
|
92
|
+
pending = {
|
|
93
|
+
stdout: {
|
|
94
|
+
text: "",
|
|
95
|
+
cut: false
|
|
96
|
+
},
|
|
97
|
+
stderr: {
|
|
98
|
+
text: "",
|
|
99
|
+
cut: false
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The key a stray-output capture publishes its {@link StrayOutputSource}
|
|
107
|
+
* under, on the Vitest `Logger` whose streams it wraps. `Symbol.for`, so a
|
|
108
|
+
* plugin and an MCP server that load different copies of this package still
|
|
109
|
+
* meet on it.
|
|
110
|
+
* @public
|
|
111
|
+
*/
|
|
112
|
+
const STRAY_OUTPUT_SOURCE = Symbol.for("vitest-agent/stray-output");
|
|
113
|
+
/**
|
|
114
|
+
* Read the current run's stray output from a Vitest `Logger` a capture was
|
|
115
|
+
* installed on. `undefined` when none was installed, or the run wrote nothing.
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
118
|
+
const readStrayOutput = (logger) => {
|
|
119
|
+
if (logger === null || typeof logger !== "object") return void 0;
|
|
120
|
+
const source = logger[STRAY_OUTPUT_SOURCE];
|
|
121
|
+
if (source === null || typeof source !== "object") return void 0;
|
|
122
|
+
const snapshot = source.snapshot;
|
|
123
|
+
return typeof snapshot === "function" ? snapshot() : void 0;
|
|
124
|
+
};
|
|
125
|
+
const MAX_NOTE_SAMPLES = 3;
|
|
126
|
+
/**
|
|
127
|
+
* The note a renderer prints for a run's stray output: one line naming the
|
|
128
|
+
* count, the streams, the usual cause and the fix, then up to three sample
|
|
129
|
+
* lines and how many it left out.
|
|
130
|
+
* @public
|
|
131
|
+
*/
|
|
132
|
+
const formatStrayOutputNote = (stray) => {
|
|
133
|
+
const streams = stray.stdout > 0 && stray.stderr > 0 ? "stdout and stderr" : stray.stdout > 0 ? "stdout" : "stderr";
|
|
134
|
+
const lines = [`Stray output: tests wrote ${stray.total} ${stray.total === 1 ? "line" : "lines"} directly to ${streams}, bypassing Vitest's console capture. A child process with inherited stdio is the usual cause; pass \`stdio: "pipe"\`.`];
|
|
135
|
+
const shown = stray.samples.slice(0, MAX_NOTE_SAMPLES);
|
|
136
|
+
for (const sample of shown) lines.push(` ${sample.stream}: ${sample.text}`);
|
|
137
|
+
const more = stray.total - shown.length;
|
|
138
|
+
if (more > 0 && shown.length > 0) lines.push(` (+${more} more)`);
|
|
139
|
+
return lines;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
export { STRAY_OUTPUT_SOURCE, formatStrayOutputNote, isEscapeOnly, makeStrayOutputRecorder, readStrayOutput };
|