@vitest-agent/reporter 6.0.1 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/defaultReporter.js +15 -5
- package/index.d.ts +82 -1
- package/index.js +1 -1
- package/liveView.js +38 -50
- package/package.json +7 -21
package/defaultReporter.js
CHANGED
|
@@ -4,7 +4,7 @@ import { renderGithubLog, strayOutputOf, toDisplayPath } from "./githubLog.js";
|
|
|
4
4
|
import { LiveViewEnv, startLiveView } from "./liveView.js";
|
|
5
5
|
import { Doc, Fmt, Render, Status } from "@effected/cli";
|
|
6
6
|
import { RUN_REPORT_FILE_SCHEMA_URL, formatStrayOutputNote } from "@vitest-agent/sdk";
|
|
7
|
-
import { classifyOutcome, classifyRunShape, dispatch, reduceRenderStateAll, synthesizeFromAgentReport } from "@vitest-agent/ui";
|
|
7
|
+
import { classifyOutcome, classifyRunShape, dispatch, formatSuggestedActionLines, reduceRenderStateAll, synthesizeFromAgentReport } from "@vitest-agent/ui";
|
|
8
8
|
import { Effect } from "effect";
|
|
9
9
|
|
|
10
10
|
// src/defaultReporter.ts
|
|
@@ -328,13 +328,22 @@ const renderGithubSummary = (input) => {
|
|
|
328
328
|
*/
|
|
329
329
|
const DefaultVitestAgentReporter = (kit) => {
|
|
330
330
|
const live = kit.config.consoleMode === "stream" && kit.runEvents !== void 0 ? startLiveView(kit.runEvents) : void 0;
|
|
331
|
+
let actionLines = [];
|
|
332
|
+
let actionsPrinted = false;
|
|
333
|
+
const closeLive = live !== void 0 ? async () => {
|
|
334
|
+
await live.close();
|
|
335
|
+
if (actionsPrinted || actionLines.length === 0) return;
|
|
336
|
+
actionsPrinted = true;
|
|
337
|
+
process.stdout.write(`\n${actionLines.join("\n")}\n`);
|
|
338
|
+
} : void 0;
|
|
331
339
|
return {
|
|
332
|
-
...live !== void 0 ? {
|
|
333
|
-
close:
|
|
334
|
-
printStrayLine: live.
|
|
340
|
+
...live !== void 0 && closeLive !== void 0 ? {
|
|
341
|
+
close: closeLive,
|
|
342
|
+
printStrayLine: live.printAbove
|
|
335
343
|
} : {},
|
|
336
344
|
render(input, renderKit) {
|
|
337
345
|
const out = [];
|
|
346
|
+
if (live !== void 0) actionLines = formatSuggestedActionLines(input.suggestedActions ?? []);
|
|
338
347
|
if (shouldRenderForMode(renderKit.config.consoleMode)) {
|
|
339
348
|
const events = input.reports.flatMap((r) => synthesizeFromAgentReport(r, { ...input.suggestedActions !== void 0 ? { suggestedActions: input.suggestedActions } : {} }));
|
|
340
349
|
const state = reduceRenderStateAll(events);
|
|
@@ -358,7 +367,8 @@ const DefaultVitestAgentReporter = (kit) => {
|
|
|
358
367
|
$schema: RUN_REPORT_FILE_SCHEMA_URL,
|
|
359
368
|
schemaVersion: 1,
|
|
360
369
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
361
|
-
reports: input.reports
|
|
370
|
+
reports: input.reports,
|
|
371
|
+
...input.runDiagnostics !== void 0 ? { runDiagnostics: input.runDiagnostics } : {}
|
|
362
372
|
}, null, 2)}\n`
|
|
363
373
|
});
|
|
364
374
|
out.push({
|
package/index.d.ts
CHANGED
|
@@ -616,6 +616,85 @@ type Executor = typeof Executor.Type;
|
|
|
616
616
|
declare const DetailLevel: Schema.Literals<readonly ["minimal", "neutral", "standard", "verbose"]>;
|
|
617
617
|
/** @public */
|
|
618
618
|
type DetailLevel = typeof DetailLevel.Type;
|
|
619
|
+
/**
|
|
620
|
+
* Which Vitest performance diagnostic a hint came from.
|
|
621
|
+
* @public
|
|
622
|
+
*/
|
|
623
|
+
declare const PerformanceHintKind: Schema.Literals<readonly ["environment", "import", "transform", "isolate"]>;
|
|
624
|
+
/** @public */
|
|
625
|
+
type PerformanceHintKind = typeof PerformanceHintKind.Type;
|
|
626
|
+
/**
|
|
627
|
+
* One performance hint derived from Vitest's run diagnostics. `project` is
|
|
628
|
+
* omitted for a hint that applies to the whole run (for example `isolate`).
|
|
629
|
+
* @public
|
|
630
|
+
*/
|
|
631
|
+
declare const PerformanceHint: Schema.Struct<{
|
|
632
|
+
readonly kind: Schema.Literals<readonly ["environment", "import", "transform", "isolate"]>;
|
|
633
|
+
readonly project: Schema.optionalKey<Schema.String>;
|
|
634
|
+
readonly message: Schema.String;
|
|
635
|
+
readonly remedy: Schema.String;
|
|
636
|
+
readonly detail: Schema.String;
|
|
637
|
+
readonly learnMoreUrl: Schema.String;
|
|
638
|
+
readonly estimatedSavingMs: Schema.optionalKey<Schema.Finite>;
|
|
639
|
+
readonly share: Schema.optionalKey<Schema.Finite>;
|
|
640
|
+
}>;
|
|
641
|
+
/** @public */
|
|
642
|
+
type PerformanceHint = typeof PerformanceHint.Type;
|
|
643
|
+
/**
|
|
644
|
+
* Wall-clock timing of the plugin's post-run work, in milliseconds.
|
|
645
|
+
* @public
|
|
646
|
+
*/
|
|
647
|
+
declare const PostRunTiming: Schema.Struct<{
|
|
648
|
+
readonly persistMs: Schema.Finite;
|
|
649
|
+
readonly coverageScanMs: Schema.Finite;
|
|
650
|
+
readonly totalMs: Schema.Finite;
|
|
651
|
+
readonly renderMs: Schema.optionalKey<Schema.Finite>;
|
|
652
|
+
readonly vitestDurationMs: Schema.optionalKey<Schema.Finite>;
|
|
653
|
+
}>;
|
|
654
|
+
/** @public */
|
|
655
|
+
type PostRunTiming = typeof PostRunTiming.Type;
|
|
656
|
+
/**
|
|
657
|
+
* Whether the run's results were persisted to the database.
|
|
658
|
+
* @public
|
|
659
|
+
*/
|
|
660
|
+
declare const PersistenceStatus: Schema.Struct<{
|
|
661
|
+
readonly ok: Schema.Boolean;
|
|
662
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
663
|
+
readonly migrationFailed: Schema.optionalKey<Schema.Boolean>;
|
|
664
|
+
}>;
|
|
665
|
+
/** @public */
|
|
666
|
+
type PersistenceStatus = typeof PersistenceStatus.Type;
|
|
667
|
+
/**
|
|
668
|
+
* Run-level diagnostics: performance hints, post-run timing and persistence
|
|
669
|
+
* status (issue #544).
|
|
670
|
+
* @public
|
|
671
|
+
*/
|
|
672
|
+
declare const RunDiagnostics: Schema.Struct<{
|
|
673
|
+
readonly performanceHints: Schema.$Array<Schema.Struct<{
|
|
674
|
+
readonly kind: Schema.Literals<readonly ["environment", "import", "transform", "isolate"]>;
|
|
675
|
+
readonly project: Schema.optionalKey<Schema.String>;
|
|
676
|
+
readonly message: Schema.String;
|
|
677
|
+
readonly remedy: Schema.String;
|
|
678
|
+
readonly detail: Schema.String;
|
|
679
|
+
readonly learnMoreUrl: Schema.String;
|
|
680
|
+
readonly estimatedSavingMs: Schema.optionalKey<Schema.Finite>;
|
|
681
|
+
readonly share: Schema.optionalKey<Schema.Finite>;
|
|
682
|
+
}>>;
|
|
683
|
+
readonly postRun: Schema.optionalKey<Schema.Struct<{
|
|
684
|
+
readonly persistMs: Schema.Finite;
|
|
685
|
+
readonly coverageScanMs: Schema.Finite;
|
|
686
|
+
readonly totalMs: Schema.Finite;
|
|
687
|
+
readonly renderMs: Schema.optionalKey<Schema.Finite>;
|
|
688
|
+
readonly vitestDurationMs: Schema.optionalKey<Schema.Finite>;
|
|
689
|
+
}>>;
|
|
690
|
+
readonly persistence: Schema.optionalKey<Schema.Struct<{
|
|
691
|
+
readonly ok: Schema.Boolean;
|
|
692
|
+
readonly reason: Schema.optionalKey<Schema.String>;
|
|
693
|
+
readonly migrationFailed: Schema.optionalKey<Schema.Boolean>;
|
|
694
|
+
}>>;
|
|
695
|
+
}>;
|
|
696
|
+
/** @public */
|
|
697
|
+
type RunDiagnostics = typeof RunDiagnostics.Type;
|
|
619
698
|
/**
|
|
620
699
|
* The reducer projects this union into `RenderState`. Renderers
|
|
621
700
|
* never read the raw event stream — they read the projected state.
|
|
@@ -1058,6 +1137,8 @@ interface ReporterRenderInput {
|
|
|
1058
1137
|
* when the plugin has nothing to suggest (issue #544).
|
|
1059
1138
|
*/
|
|
1060
1139
|
readonly suggestedActions?: ReadonlyArray<SuggestedActionRecord>;
|
|
1140
|
+
/** Run-level diagnostics (performance hints, post-run timing, persistence status); absent when none were collected (issue #544). */
|
|
1141
|
+
readonly runDiagnostics?: RunDiagnostics;
|
|
1061
1142
|
readonly trendSummary?: {
|
|
1062
1143
|
readonly direction: "improving" | "regressing" | "stable";
|
|
1063
1144
|
readonly runCount: number;
|
|
@@ -1233,5 +1314,5 @@ export declare const DefaultVitestAgentReporter: VitestAgentReporterFactory;
|
|
|
1233
1314
|
* @public
|
|
1234
1315
|
*/
|
|
1235
1316
|
export declare const CURRENT_REPORTER_VERSION: string;
|
|
1236
|
-
export type { AgentReport, CellOptions, ConsoleMode, DetailLevel, DispatchInputs, Environment, Executor, FileCoverageReport, FileLinkTarget, HumanReportRenderOptions, ProjectSummary, RenderState, RenderedOutput, ReportRenderOptions, ReporterKit, ReporterRenderInput, ResolvedReporterConfig, ResolvedThresholds, RunEvent, RunOutcome, RunShape, SuggestedActionRecord, TestClassification, Transport, TrendSummary, VitestAgentReporter, VitestAgentReporterFactory };
|
|
1317
|
+
export type { AgentReport, CellOptions, ConsoleMode, DetailLevel, DispatchInputs, Environment, Executor, FileCoverageReport, FileLinkTarget, HumanReportRenderOptions, PerformanceHint, PerformanceHintKind, PersistenceStatus, PostRunTiming, ProjectSummary, RenderState, RenderedOutput, ReportRenderOptions, ReporterKit, ReporterRenderInput, ResolvedReporterConfig, ResolvedThresholds, RunDiagnostics, RunEvent, RunOutcome, RunShape, SuggestedActionRecord, TestClassification, Transport, TrendSummary, VitestAgentReporter, VitestAgentReporterFactory };
|
|
1237
1318
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -8,6 +8,6 @@ import { DefaultVitestAgentReporter, buildDispatchInputs, renderAgentStringForRe
|
|
|
8
8
|
*
|
|
9
9
|
* @public
|
|
10
10
|
*/
|
|
11
|
-
const CURRENT_REPORTER_VERSION = "6.0
|
|
11
|
+
const CURRENT_REPORTER_VERSION = "6.1.0";
|
|
12
12
|
|
|
13
13
|
export { CURRENT_REPORTER_VERSION, DefaultVitestAgentReporter, buildDispatchInputs, renderAgentStringForReport, renderHumanStringForReport };
|
package/liveView.js
CHANGED
|
@@ -2,7 +2,7 @@ import { plainFileLink, resolveFileLink } from "./fileLinks.js";
|
|
|
2
2
|
import { CliEnv, Doc } from "@effected/cli";
|
|
3
3
|
import { initialRenderState } from "@vitest-agent/sdk";
|
|
4
4
|
import { SPINNER_FRAME_MS, reduceRenderState, renderAgent } from "@vitest-agent/ui";
|
|
5
|
-
import { Cause,
|
|
5
|
+
import { Cause, Effect, Exit, Layer } from "effect";
|
|
6
6
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
7
7
|
import { CliUi } from "@effected/cli/ui";
|
|
8
8
|
|
|
@@ -29,29 +29,35 @@ import { CliUi } from "@effected/cli/ui";
|
|
|
29
29
|
* modules, coverage, suggested actions), each line kept whole; it does not
|
|
30
30
|
* try to reproduce the Ink frame, and drawing it never renders through Ink.
|
|
31
31
|
*
|
|
32
|
-
* Lifetime:
|
|
33
|
-
*
|
|
34
|
-
* the first `RunStarted` is never lost
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* close is kept), then closes the scope. The view never relies on
|
|
32
|
+
* Lifetime: the kit's `CliUi.liveDetached` runs the view outside Effect for
|
|
33
|
+
* the reporter's whole life. It subscribes to the channel synchronously,
|
|
34
|
+
* before the factory returns, so the first `RunStarted` is never lost. At
|
|
35
|
+
* Vitest's close the plugin calls the view's `close` before it shuts the
|
|
36
|
+
* channel down: `close` folds every message still queued in the
|
|
37
|
+
* subscription and commits the last run (so a tail published just before
|
|
38
|
+
* the close is kept), then releases the view. The view never relies on
|
|
40
39
|
* `PubSub.shutdown` to end it: shutdown drops whatever a subscriber has not
|
|
41
40
|
* taken yet. It is never closed at `onTestRunEnd`, which fires on every
|
|
42
41
|
* watch rerun.
|
|
43
42
|
*/
|
|
44
43
|
/**
|
|
44
|
+
* The Ink frame's draw function for a view whose paths are drawn through
|
|
45
|
+
* `link`. The one sanctioned dynamic import outside mcp's `main.ts` (with
|
|
46
|
+
* `humanReport.ts`'s): React and Ink load only when a run draws. The view
|
|
47
|
+
* module exports a factory, so the writer reaches the tree without this
|
|
48
|
+
* module importing React.
|
|
49
|
+
*/
|
|
50
|
+
const streamRender = (link) => CliUi.lazyView(() => import("./streamView.js").then((view) => view.makeStreamView(link)));
|
|
51
|
+
/**
|
|
45
52
|
* The live view's options, everything but `events`, for a view whose paths
|
|
46
|
-
* are drawn through `link
|
|
47
|
-
* resolved the writer from its environment (`resolveFileLink`).
|
|
53
|
+
* are drawn through `link`.
|
|
48
54
|
*
|
|
49
55
|
* @internal
|
|
50
56
|
*/
|
|
51
57
|
const liveViewOptionsWith = (link) => ({
|
|
52
58
|
initial: initialRenderState,
|
|
53
59
|
reduce: reduceRenderState,
|
|
54
|
-
render:
|
|
60
|
+
render: streamRender(link),
|
|
55
61
|
isStart: (event) => event._tag === "RunStarted",
|
|
56
62
|
isTerminal: (event) => event._tag === "RunFinished" || event._tag === "RunTimedOut",
|
|
57
63
|
begins: (event, before, after) => event._tag === "RunStarted" || before.phase === "idle" && after.phase !== "idle",
|
|
@@ -81,21 +87,17 @@ const liveViewOptions = liveViewOptionsWith(plainFileLink);
|
|
|
81
87
|
*/
|
|
82
88
|
const LiveViewEnv = CliEnv.layer().pipe(Layer.provide(NodeServices.layer));
|
|
83
89
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* where the next redraw would strand it.
|
|
90
|
+
* Start a live view over `channel` with the kit's `CliUi.liveDetached`. The
|
|
91
|
+
* subscription is taken before this returns, so an event published right
|
|
92
|
+
* after is seen.
|
|
88
93
|
*
|
|
89
|
-
*
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Start a live view over `channel`. The subscription is taken before this
|
|
98
|
-
* returns, so an event published right after is seen.
|
|
94
|
+
* The returned view's `printAbove` is the reporter's `printStrayLine`: it
|
|
95
|
+
* prints the line above the frame and answers `true` only while a run's
|
|
96
|
+
* frame is mounted, declining (`false`, nothing written) before the view is
|
|
97
|
+
* up, between runs, when the view is not interactive (it never mounts), and
|
|
98
|
+
* once `close` has been called, so the plugin writes the line itself.
|
|
99
|
+
* `close` is idempotent and never rejects; a view that died of anything but
|
|
100
|
+
* an interrupt is logged as a warning.
|
|
99
101
|
*
|
|
100
102
|
* @param channel - the plugin's run-event channel
|
|
101
103
|
* @param env - the environment the view reads; {@link LiveViewEnv} by default (a test
|
|
@@ -104,29 +106,15 @@ const printAbove = (handle) => (stream, line) => {
|
|
|
104
106
|
* @internal
|
|
105
107
|
*/
|
|
106
108
|
const startLiveView = (channel, env = LiveViewEnv) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let print;
|
|
117
|
-
const handle = Effect.runPromise(Deferred.await(mounted));
|
|
118
|
-
handle.then((mountedHandle) => {
|
|
119
|
-
if (closing === void 0) print = printAbove(mountedHandle);
|
|
120
|
-
}, () => void 0);
|
|
121
|
-
return {
|
|
122
|
-
handle,
|
|
123
|
-
printStrayLine: (stream, line) => print?.(stream, line) ?? false,
|
|
124
|
-
close: () => {
|
|
125
|
-
print = void 0;
|
|
126
|
-
closing ??= Effect.runPromise(Deferred.await(mounted).pipe(Effect.flatMap((handle) => handle.close), Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : Effect.logWarning("vitest-agent: the live view ended with an error", cause)), Effect.ensuring(Scope.close(scope, Exit.void))));
|
|
127
|
-
return closing;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
109
|
+
const view = CliUi.liveDetached({
|
|
110
|
+
...liveViewOptions,
|
|
111
|
+
render: Effect.map(resolveFileLink, streamRender),
|
|
112
|
+
events: channel
|
|
113
|
+
}, env);
|
|
114
|
+
view.exit.then((exit) => {
|
|
115
|
+
if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) Effect.runFork(Effect.logWarning("vitest-agent: the live view ended with an error", exit.cause));
|
|
116
|
+
});
|
|
117
|
+
return view;
|
|
130
118
|
};
|
|
131
119
|
|
|
132
|
-
export { LiveViewEnv,
|
|
120
|
+
export { LiveViewEnv, liveViewOptions, liveViewOptionsWith, startLiveView };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/reporter",
|
|
3
|
-
"version": "6.0
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Named VitestAgentReporterFactory implementations for the vitest-agent ecosystem.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,31 +40,17 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@effect/platform-node": "^4.0.6",
|
|
43
|
-
"@vitest-agent/sdk": "
|
|
44
|
-
"@vitest-agent/ui": "5.
|
|
43
|
+
"@vitest-agent/sdk": "9.0.0",
|
|
44
|
+
"@vitest-agent/ui": "5.2.0",
|
|
45
45
|
"effect": "^4.0.6",
|
|
46
46
|
"ink": "^8.0.0",
|
|
47
47
|
"react": "^19.3.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@effected/cli": "^0.
|
|
51
|
-
"@effected/env": "^0.
|
|
52
|
-
"@effected/glob": "^0.
|
|
53
|
-
"@effected/walker": "^0.
|
|
54
|
-
"@vitest/coverage-istanbul": "^5.0.0",
|
|
55
|
-
"@vitest/coverage-v8": "^5.0.0",
|
|
56
|
-
"vitest": "^5.0.0"
|
|
57
|
-
},
|
|
58
|
-
"peerDependenciesMeta": {
|
|
59
|
-
"@vitest/coverage-istanbul": {
|
|
60
|
-
"optional": true
|
|
61
|
-
},
|
|
62
|
-
"@vitest/coverage-v8": {
|
|
63
|
-
"optional": true
|
|
64
|
-
},
|
|
65
|
-
"vitest": {
|
|
66
|
-
"optional": false
|
|
67
|
-
}
|
|
50
|
+
"@effected/cli": "^0.23.0",
|
|
51
|
+
"@effected/env": "^0.6.0",
|
|
52
|
+
"@effected/glob": "^0.15.0",
|
|
53
|
+
"@effected/walker": "^0.21.0"
|
|
68
54
|
},
|
|
69
55
|
"engines": {
|
|
70
56
|
"node": ">=24.11.0"
|