@vitest-agent/ui 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/index.d.ts +1 -306
- package/index.js +2 -6
- package/package.json +2 -2
- package/render-agent.js +2 -8
- package/pubsub/Channel.js +0 -30
- package/pubsub/Publisher.js +0 -37
- package/pubsub/Subscriber.js +0 -77
- package/pubsub/index.js +0 -5
package/README.md
CHANGED
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
> **Part of the [vitest-agent](https://vitest-agent.dev) ecosystem.** Most users want **[@vitest-agent/plugin](https://www.npmjs.com/package/@vitest-agent/plugin)**, which pulls this package in automatically. Install `@vitest-agent/ui` directly only if you build custom rendering on the primitives.
|
|
8
8
|
|
|
9
|
-
Pure rendering primitives for vitest-agent. Owns the `RunEvent` reducer, the shape-tailored 12-cell dispatcher matrix, two render paths (agent string and React Ink tree),
|
|
9
|
+
Pure rendering primitives for vitest-agent. Owns the `RunEvent` reducer, the shape-tailored 12-cell dispatcher matrix, two render paths (agent string and React Ink tree), and the synthesizers that bridge live Vitest data and stored reports into the event taxonomy. React and Ink are required peer dependencies.
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
13
|
- **Reducer** — pure `(state, event) => state` fold over the `RunEvent` discriminated union; `reduceRenderStateAll` for one-shot replay
|
|
14
14
|
- **Dispatcher matrix** — `dispatch` and `dispatchInk` route a `DispatchInputs` to the matching `(RunShape, RunOutcome)` cell; `classifyRunShape` and `classifyOutcome` derive the coordinates
|
|
15
15
|
- **Ink components** — `StreamApp` and the supporting primitives (`ModuleHeader`, `TestRow`, `CoverageBlock`, `TrendLine`, `FailureSection`, etc.) for live `stream`-mode frames
|
|
16
|
-
- **PubSub channel** — `RunEventChannel` Effect tag and helpers (`accumulateUntilFinished`, `forEachRenderState`, `renderStateStream`) for live event transport
|
|
17
16
|
- **Synthesizers** — `synthesizeRunEvents` from live Vitest modules; `synthesizeFromAgentReport` from a stored `AgentReport`
|
|
18
17
|
- **Footer builder** — `buildFooter` assembles the L1 MCP-tool-pointer footer; `dominantClassification` picks the most actionable failure class
|
|
19
18
|
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Schema } from "effect";
|
|
2
2
|
import { FC, ReactElement } from "react";
|
|
3
3
|
import { CoreStatusName, GlyphSet, Status, Style, TokenName } from "@effected/cli";
|
|
4
4
|
//#region ../sdk/dist/dev/pkg/index.d.ts
|
|
@@ -1193,311 +1193,6 @@ export declare const buildFooter: (inputs: DispatchInputs) => string;
|
|
|
1193
1193
|
*/
|
|
1194
1194
|
export declare const formatDisplayDuration: (ms: number) => string;
|
|
1195
1195
|
//#endregion
|
|
1196
|
-
//#region src/pubsub/Channel.d.ts
|
|
1197
|
-
declare const RunEventChannel_base: Context.ServiceClass<RunEventChannel, "vitest-agent-ui/RunEventChannel", PubSub.PubSub<{
|
|
1198
|
-
readonly _tag: "RunStarted";
|
|
1199
|
-
readonly runId: string;
|
|
1200
|
-
readonly startedAt: string;
|
|
1201
|
-
readonly configHash: string;
|
|
1202
|
-
} | {
|
|
1203
|
-
readonly _tag: "ModuleQueued";
|
|
1204
|
-
readonly modulePath: string;
|
|
1205
|
-
readonly projectName?: string | undefined;
|
|
1206
|
-
} | {
|
|
1207
|
-
readonly _tag: "ModuleStarted";
|
|
1208
|
-
readonly modulePath: string;
|
|
1209
|
-
readonly startedAt: string;
|
|
1210
|
-
readonly projectName?: string | undefined;
|
|
1211
|
-
} | {
|
|
1212
|
-
readonly _tag: "TestStarted";
|
|
1213
|
-
readonly modulePath: string;
|
|
1214
|
-
readonly testName: string;
|
|
1215
|
-
readonly suitePath: readonly string[];
|
|
1216
|
-
} | {
|
|
1217
|
-
readonly _tag: "TestFinished";
|
|
1218
|
-
readonly modulePath: string;
|
|
1219
|
-
readonly testName: string;
|
|
1220
|
-
readonly suitePath: readonly string[];
|
|
1221
|
-
readonly status: "failed" | "passed" | "pending" | "skipped";
|
|
1222
|
-
readonly durationMs: number;
|
|
1223
|
-
readonly error?: {
|
|
1224
|
-
readonly message: string;
|
|
1225
|
-
readonly stack?: string | undefined;
|
|
1226
|
-
readonly diff?: string | undefined;
|
|
1227
|
-
readonly expected?: string | undefined;
|
|
1228
|
-
readonly received?: string | undefined;
|
|
1229
|
-
} | undefined;
|
|
1230
|
-
readonly timedOut?: boolean | undefined;
|
|
1231
|
-
} | {
|
|
1232
|
-
readonly _tag: "ModuleFinished";
|
|
1233
|
-
readonly modulePath: string;
|
|
1234
|
-
readonly passCount: number;
|
|
1235
|
-
readonly failCount: number;
|
|
1236
|
-
readonly skipCount: number;
|
|
1237
|
-
readonly durationMs: number;
|
|
1238
|
-
readonly projectName?: string | undefined;
|
|
1239
|
-
readonly timeoutCount?: number | undefined;
|
|
1240
|
-
readonly tagCounts?: {
|
|
1241
|
-
readonly [x: string]: number;
|
|
1242
|
-
} | undefined;
|
|
1243
|
-
} | {
|
|
1244
|
-
readonly _tag: "ModuleCollected";
|
|
1245
|
-
readonly modulePath: string;
|
|
1246
|
-
readonly testCount: number;
|
|
1247
|
-
readonly suiteCount: number;
|
|
1248
|
-
} | {
|
|
1249
|
-
readonly _tag: "SuiteStarted";
|
|
1250
|
-
readonly modulePath: string;
|
|
1251
|
-
readonly suitePath: readonly string[];
|
|
1252
|
-
readonly suiteName: string;
|
|
1253
|
-
} | {
|
|
1254
|
-
readonly _tag: "SuiteFinished";
|
|
1255
|
-
readonly modulePath: string;
|
|
1256
|
-
readonly suitePath: readonly string[];
|
|
1257
|
-
readonly suiteName: string;
|
|
1258
|
-
readonly passCount: number;
|
|
1259
|
-
readonly failCount: number;
|
|
1260
|
-
readonly skipCount: number;
|
|
1261
|
-
} | {
|
|
1262
|
-
readonly _tag: "HookStarted";
|
|
1263
|
-
readonly modulePath: string;
|
|
1264
|
-
readonly hookType: "afterAll" | "afterEach" | "beforeAll" | "beforeEach";
|
|
1265
|
-
readonly scopeName: string;
|
|
1266
|
-
} | {
|
|
1267
|
-
readonly _tag: "HookFinished";
|
|
1268
|
-
readonly modulePath: string;
|
|
1269
|
-
readonly hookType: "afterAll" | "afterEach" | "beforeAll" | "beforeEach";
|
|
1270
|
-
readonly scopeName: string;
|
|
1271
|
-
readonly durationMs: number;
|
|
1272
|
-
readonly status: "failed" | "passed";
|
|
1273
|
-
readonly error?: {
|
|
1274
|
-
readonly message: string;
|
|
1275
|
-
readonly stack?: string | undefined;
|
|
1276
|
-
readonly diff?: string | undefined;
|
|
1277
|
-
readonly expected?: string | undefined;
|
|
1278
|
-
readonly received?: string | undefined;
|
|
1279
|
-
} | undefined;
|
|
1280
|
-
} | {
|
|
1281
|
-
readonly _tag: "ConsoleLog";
|
|
1282
|
-
readonly modulePath?: string | undefined;
|
|
1283
|
-
readonly testName?: string | undefined;
|
|
1284
|
-
readonly level: "stderr" | "stdout";
|
|
1285
|
-
readonly content: string;
|
|
1286
|
-
readonly time: number;
|
|
1287
|
-
} | {
|
|
1288
|
-
readonly _tag: "RunTimedOut";
|
|
1289
|
-
readonly message: string;
|
|
1290
|
-
} | {
|
|
1291
|
-
readonly _tag: "TestAnnotated";
|
|
1292
|
-
readonly modulePath: string;
|
|
1293
|
-
readonly testName: string;
|
|
1294
|
-
readonly suitePath: readonly string[];
|
|
1295
|
-
readonly annotation: string;
|
|
1296
|
-
readonly annotationType: string;
|
|
1297
|
-
readonly location?: {
|
|
1298
|
-
readonly file: string;
|
|
1299
|
-
readonly line: number;
|
|
1300
|
-
readonly column: number;
|
|
1301
|
-
} | undefined;
|
|
1302
|
-
readonly attachments: readonly {
|
|
1303
|
-
readonly contentType?: string | undefined;
|
|
1304
|
-
readonly path?: string | undefined;
|
|
1305
|
-
readonly body?: string | undefined;
|
|
1306
|
-
readonly bodyEncoding?: "base64" | "utf-8" | undefined;
|
|
1307
|
-
readonly byteSize: number;
|
|
1308
|
-
}[];
|
|
1309
|
-
} | {
|
|
1310
|
-
readonly _tag: "TestArtifactRecorded";
|
|
1311
|
-
readonly modulePath: string;
|
|
1312
|
-
readonly testName: string;
|
|
1313
|
-
readonly suitePath: readonly string[];
|
|
1314
|
-
readonly artifact: string;
|
|
1315
|
-
readonly location?: {
|
|
1316
|
-
readonly file: string;
|
|
1317
|
-
readonly line: number;
|
|
1318
|
-
readonly column: number;
|
|
1319
|
-
} | undefined;
|
|
1320
|
-
readonly attachments: readonly {
|
|
1321
|
-
readonly contentType?: string | undefined;
|
|
1322
|
-
readonly path?: string | undefined;
|
|
1323
|
-
readonly body?: string | undefined;
|
|
1324
|
-
readonly bodyEncoding?: "base64" | "utf-8" | undefined;
|
|
1325
|
-
readonly byteSize: number;
|
|
1326
|
-
}[];
|
|
1327
|
-
} | {
|
|
1328
|
-
readonly _tag: "WatcherReady";
|
|
1329
|
-
} | {
|
|
1330
|
-
readonly _tag: "WatcherRerun";
|
|
1331
|
-
readonly triggerFiles: readonly string[];
|
|
1332
|
-
readonly reason?: string | undefined;
|
|
1333
|
-
} | {
|
|
1334
|
-
readonly _tag: "TrendComputed";
|
|
1335
|
-
readonly direction: "improving" | "regressing" | "stable";
|
|
1336
|
-
readonly runCount: number;
|
|
1337
|
-
} | {
|
|
1338
|
-
readonly _tag: "CoverageReady";
|
|
1339
|
-
readonly metrics: {
|
|
1340
|
-
readonly statements: number;
|
|
1341
|
-
readonly branches: number;
|
|
1342
|
-
readonly functions: number;
|
|
1343
|
-
readonly lines: number;
|
|
1344
|
-
};
|
|
1345
|
-
readonly thresholds: {
|
|
1346
|
-
readonly lines?: number | undefined;
|
|
1347
|
-
readonly functions?: number | undefined;
|
|
1348
|
-
readonly branches?: number | undefined;
|
|
1349
|
-
readonly statements?: number | undefined;
|
|
1350
|
-
};
|
|
1351
|
-
readonly gaps: readonly {
|
|
1352
|
-
readonly file: string;
|
|
1353
|
-
readonly missing: {
|
|
1354
|
-
readonly statements: number;
|
|
1355
|
-
readonly branches: number;
|
|
1356
|
-
readonly functions: number;
|
|
1357
|
-
readonly lines: number;
|
|
1358
|
-
};
|
|
1359
|
-
readonly uncoveredLines?: string | undefined;
|
|
1360
|
-
}[];
|
|
1361
|
-
readonly scoped?: boolean | undefined;
|
|
1362
|
-
readonly scopedFiles?: number | undefined;
|
|
1363
|
-
readonly totalFiles?: number | undefined;
|
|
1364
|
-
} | {
|
|
1365
|
-
readonly _tag: "ThresholdViolation";
|
|
1366
|
-
readonly metric: "branches" | "functions" | "lines" | "statements";
|
|
1367
|
-
readonly expected: number;
|
|
1368
|
-
readonly actual: number;
|
|
1369
|
-
} | {
|
|
1370
|
-
readonly _tag: "FailureClassified";
|
|
1371
|
-
readonly modulePath: string;
|
|
1372
|
-
readonly testName: string;
|
|
1373
|
-
readonly classification: "flaky" | "new-failure" | "persistent" | "recovered" | "stable";
|
|
1374
|
-
} | {
|
|
1375
|
-
readonly _tag: "SuggestedAction";
|
|
1376
|
-
readonly severity: "blocker" | "info" | "warn";
|
|
1377
|
-
readonly title: string;
|
|
1378
|
-
readonly detail: string;
|
|
1379
|
-
readonly targetTool?: string | undefined;
|
|
1380
|
-
} | {
|
|
1381
|
-
readonly _tag: "RunFinished";
|
|
1382
|
-
readonly runId: string;
|
|
1383
|
-
readonly finishedAt: string;
|
|
1384
|
-
readonly passCount: number;
|
|
1385
|
-
readonly failCount: number;
|
|
1386
|
-
readonly skipCount: number;
|
|
1387
|
-
readonly durationMs: number;
|
|
1388
|
-
readonly timeoutCount?: number | undefined;
|
|
1389
|
-
readonly collectedModules?: number | undefined;
|
|
1390
|
-
readonly unhandledErrors?: readonly {
|
|
1391
|
-
readonly message: string;
|
|
1392
|
-
readonly stack?: string | undefined;
|
|
1393
|
-
readonly diff?: string | undefined;
|
|
1394
|
-
readonly expected?: string | undefined;
|
|
1395
|
-
readonly received?: string | undefined;
|
|
1396
|
-
}[] | undefined;
|
|
1397
|
-
}>>;
|
|
1398
|
-
/**
|
|
1399
|
-
* Service tag for the run-event channel. Consumers depend on this tag;
|
|
1400
|
-
* the {@link RunEventChannelLive} layer is the single point at which
|
|
1401
|
-
* the underlying Effect `PubSub` is constructed.
|
|
1402
|
-
*
|
|
1403
|
-
* @public
|
|
1404
|
-
*/
|
|
1405
|
-
export declare class RunEventChannel extends RunEventChannel_base {}
|
|
1406
|
-
/**
|
|
1407
|
-
* Default live layer providing an unbounded Effect `PubSub` for
|
|
1408
|
-
* the run-event channel. The PubSub is scoped — when the surrounding
|
|
1409
|
-
* scope closes, the channel shuts down and any pending subscribers
|
|
1410
|
-
* receive their dequeue closure.
|
|
1411
|
-
*
|
|
1412
|
-
* Unbounded is the right default for the plugin and CLI: events arrive
|
|
1413
|
-
* faster than a slow renderer can drain (e.g., several `TestFinished`
|
|
1414
|
-
* per millisecond during a large suite), and dropping events would
|
|
1415
|
-
* leave the rendered state inconsistent with the runner's truth.
|
|
1416
|
-
* If memory pressure becomes a concern, swap in `PubSub.sliding`
|
|
1417
|
-
* with a tuned capacity at the call site.
|
|
1418
|
-
*
|
|
1419
|
-
* @public
|
|
1420
|
-
*/
|
|
1421
|
-
export declare const RunEventChannelLive: Layer.Layer<RunEventChannel>;
|
|
1422
|
-
//#endregion
|
|
1423
|
-
//#region src/pubsub/Publisher.d.ts
|
|
1424
|
-
/**
|
|
1425
|
-
* Emit one event onto the channel.
|
|
1426
|
-
*
|
|
1427
|
-
* Resolves when the event is enqueued. Returns the success boolean
|
|
1428
|
-
* from `PubSub.publish` so callers can detect a shutdown
|
|
1429
|
-
* channel if needed; in normal operation the result is always `true`.
|
|
1430
|
-
*
|
|
1431
|
-
* @param event - the run event to publish
|
|
1432
|
-
* @returns an Effect that resolves to the publish success boolean
|
|
1433
|
-
* @public
|
|
1434
|
-
*/
|
|
1435
|
-
export declare const publish: (event: RunEvent) => Effect.Effect<boolean, never, RunEventChannel>;
|
|
1436
|
-
/**
|
|
1437
|
-
* Emit a batch of events onto the channel in order.
|
|
1438
|
-
*
|
|
1439
|
-
* Useful for the CLI replay path where the entire event sequence is
|
|
1440
|
-
* materialized synchronously from a database query before any
|
|
1441
|
-
* subscriber needs to read it.
|
|
1442
|
-
*
|
|
1443
|
-
* @param events - iterable of run events to publish in order
|
|
1444
|
-
* @returns an Effect that resolves when all events are enqueued
|
|
1445
|
-
* @public
|
|
1446
|
-
*/
|
|
1447
|
-
export declare const publishAll: (events: Iterable<RunEvent>) => Effect.Effect<void, never, RunEventChannel>;
|
|
1448
|
-
//#endregion
|
|
1449
|
-
//#region src/pubsub/Subscriber.d.ts
|
|
1450
|
-
/**
|
|
1451
|
-
* Subscribe, fold the run-event stream into a terminal
|
|
1452
|
-
* `RenderState`, and return when `RunFinished` arrives.
|
|
1453
|
-
*
|
|
1454
|
-
* The subscription is scoped — when this effect completes (or is
|
|
1455
|
-
* interrupted), the underlying PubSub releases its slot.
|
|
1456
|
-
*
|
|
1457
|
-
* @param initial - the initial render state to fold from
|
|
1458
|
-
* @returns an Effect that resolves to the terminal render state
|
|
1459
|
-
* @public
|
|
1460
|
-
*/
|
|
1461
|
-
export declare const accumulateUntilFinished: (initial?: RenderState) => Effect.Effect<RenderState, never, RunEventChannel>;
|
|
1462
|
-
/**
|
|
1463
|
-
* Run a callback for every projected `RenderState` as events
|
|
1464
|
-
* arrive. The stream terminates when the PubSub shuts down (typically
|
|
1465
|
-
* when the surrounding scope closes).
|
|
1466
|
-
*
|
|
1467
|
-
* The host runs this in a forked fiber so the publisher and the
|
|
1468
|
-
* renderer can make progress concurrently. Returning an Effect from
|
|
1469
|
-
* the callback lets the host suspend further rendering on backpressure
|
|
1470
|
-
* (e.g. throttling redraws to the next animation frame).
|
|
1471
|
-
*
|
|
1472
|
-
* @param onState - callback invoked with each projected render state
|
|
1473
|
-
* @param initial - the initial render state to fold from
|
|
1474
|
-
* @returns an Effect that completes when the PubSub shuts down
|
|
1475
|
-
* @public
|
|
1476
|
-
*/
|
|
1477
|
-
export declare const forEachRenderState: <R, E>(onState: (state: RenderState) => Effect.Effect<void, E, R>, initial?: RenderState) => Effect.Effect<void, E, R | RunEventChannel>;
|
|
1478
|
-
/**
|
|
1479
|
-
* Build an Effect `Stream` of accumulated states over the channel.
|
|
1480
|
-
*
|
|
1481
|
-
* Lower-level than {@link forEachRenderState} — useful when the host
|
|
1482
|
-
* wants to compose with other stream operators (debouncing, throttling,
|
|
1483
|
-
* tee-to-file) before running the terminal sink.
|
|
1484
|
-
*
|
|
1485
|
-
* @param initial - the initial render state to fold from
|
|
1486
|
-
* @returns an Effect that resolves to a Stream of render states
|
|
1487
|
-
* @public
|
|
1488
|
-
*/
|
|
1489
|
-
export declare const renderStateStream: (initial?: RenderState) => Effect.Effect<Stream.Stream<RenderState>, never, RunEventChannel>;
|
|
1490
|
-
/**
|
|
1491
|
-
* Convenience: subscribe and produce a low-level dequeue of raw
|
|
1492
|
-
* `RunEvent` values. Mostly for tests and ad-hoc consumers; most
|
|
1493
|
-
* application code should prefer {@link forEachRenderState} or
|
|
1494
|
-
* {@link renderStateStream}.
|
|
1495
|
-
*
|
|
1496
|
-
* @returns an Effect that resolves to a dequeue of raw run events
|
|
1497
|
-
* @public
|
|
1498
|
-
*/
|
|
1499
|
-
export declare const subscribeRaw: () => Effect.Effect<PubSub.Subscription<RunEvent>, never, RunEventChannel | Scope.Scope>;
|
|
1500
|
-
//#endregion
|
|
1501
1196
|
//#region src/reducer.d.ts
|
|
1502
1197
|
/**
|
|
1503
1198
|
* Apply a single event to the previous state and return the next.
|
package/index.js
CHANGED
|
@@ -3,11 +3,7 @@ import { buildFooter, dominantClassification } from "./dispatcher/footer.js";
|
|
|
3
3
|
import { VitestAgentStatus, VitestAgentTokens, inkStyle, statusGlyph, statusInkStyle } from "./theme.js";
|
|
4
4
|
import { formatDisplayDuration } from "./format-duration.js";
|
|
5
5
|
import { dispatch, dispatchInk, dispatcherTable } from "./dispatcher/dispatch.js";
|
|
6
|
-
import { RunEventChannel, RunEventChannelLive } from "./pubsub/Channel.js";
|
|
7
|
-
import { publish, publishAll } from "./pubsub/Publisher.js";
|
|
8
6
|
import { reduceRenderState, reduceRenderStateAll } from "./reducer.js";
|
|
9
|
-
import { accumulateUntilFinished, forEachRenderState, renderStateStream, subscribeRaw } from "./pubsub/Subscriber.js";
|
|
10
|
-
import "./pubsub/index.js";
|
|
11
7
|
import { renderAgent } from "./render-agent.js";
|
|
12
8
|
import { CountColumns, DURATION_CELL_WIDTH } from "./render-ink/CountColumns.js";
|
|
13
9
|
import { CoverageBlock } from "./render-ink/CoverageBlock.js";
|
|
@@ -34,7 +30,7 @@ import { ActionSeverity, CoverageFile, CoverageGap, CoverageMetric, CoverageRend
|
|
|
34
30
|
*
|
|
35
31
|
* @public
|
|
36
32
|
*/
|
|
37
|
-
const CURRENT_UI_VERSION = "
|
|
33
|
+
const CURRENT_UI_VERSION = "4.0.0";
|
|
38
34
|
|
|
39
35
|
//#endregion
|
|
40
|
-
export { ActionSeverity, CURRENT_UI_VERSION, CountColumns, CoverageBlock, CoverageFile, CoverageGap, CoverageMetric, CoverageRenderState, DURATION_CELL_WIDTH, FailureRecord, FailureSection, FailuresSection, ModuleHeader, ModuleRecord, ProjectRow, RenderState, RenderTotals, RunEvent,
|
|
36
|
+
export { ActionSeverity, CURRENT_UI_VERSION, CountColumns, CoverageBlock, CoverageFile, CoverageGap, CoverageMetric, CoverageRenderState, DURATION_CELL_WIDTH, FailureRecord, FailureSection, FailuresSection, ModuleHeader, ModuleRecord, ProjectRow, RenderState, RenderTotals, RunEvent, SPINNER_FRAMES, SPINNER_FRAME_MS, SUITE_LOAD_FAILURE_LABEL, StatusIcon, StreamApp, SuggestedActionRecord, SuggestedActions, TagColumns, TestRecord, TestRow, TrendLine, VitestAgentStatus, VitestAgentTokens, buildFooter, classifyOutcome, classifyRunShape, dispatch, dispatchInk, dispatcherTable, dominantClassification, formatDisplayDuration, initialRenderState, inkStyle, reduceRenderState, reduceRenderStateAll, renderAgent, spinnerFrame, statusGlyph, statusInkStyle, synthesizeFromAgentReport, synthesizeRunEvents, tagUnion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Shared event-sourced renderer for vitest-agent. React Ink view for humans, plain-string view for agents, both fed by the same reducer over a RunEvent stream.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"./package.json": "./package.json"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@vitest-agent/sdk": "
|
|
42
|
+
"@vitest-agent/sdk": "6.0.0",
|
|
43
43
|
"effect": "^4.0.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
package/render-agent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatTotalsLine } from "./counts.js";
|
|
2
|
+
import { formatFailure as formatFailure$1 } from "./dispatcher/helpers.js";
|
|
2
3
|
import { Fmt } from "@effected/cli";
|
|
3
4
|
|
|
4
5
|
//#region src/render-agent.ts
|
|
@@ -47,14 +48,7 @@ const formatModulesSection = (state) => {
|
|
|
47
48
|
};
|
|
48
49
|
const truncate = (line, max) => Fmt.truncate(line, max);
|
|
49
50
|
const formatFailure = (f, width, includeStack) => {
|
|
50
|
-
const
|
|
51
|
-
const classification = f.classification !== null ? ` [${f.classification}]` : "";
|
|
52
|
-
const lines = [`- ${f.modulePath} > ${suite}${f.testName}${classification}`];
|
|
53
|
-
if (f.error?.message !== void 0) {
|
|
54
|
-
const firstLine = f.error.message.split("\n", 1)[0] ?? "";
|
|
55
|
-
lines.push(` ${truncate(firstLine, Math.max(20, width - 2))}`);
|
|
56
|
-
}
|
|
57
|
-
if (f.error?.diff !== void 0) for (const diffLine of f.error.diff.split("\n")) lines.push(` ${truncate(diffLine, Math.max(20, width - 2))}`);
|
|
51
|
+
const lines = [...formatFailure$1(f, width)];
|
|
58
52
|
if (includeStack && f.error?.stack !== void 0) for (const stackLine of f.error.stack.split("\n")) lines.push(` ${truncate(stackLine, Math.max(20, width - 2))}`);
|
|
59
53
|
return lines.join("\n");
|
|
60
54
|
};
|
package/pubsub/Channel.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Context, Layer, PubSub } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src/pubsub/Channel.ts
|
|
4
|
-
/**
|
|
5
|
-
* Service tag for the run-event channel. Consumers depend on this tag;
|
|
6
|
-
* the {@link RunEventChannelLive} layer is the single point at which
|
|
7
|
-
* the underlying Effect `PubSub` is constructed.
|
|
8
|
-
*
|
|
9
|
-
* @public
|
|
10
|
-
*/
|
|
11
|
-
var RunEventChannel = class extends Context.Service()("vitest-agent-ui/RunEventChannel") {};
|
|
12
|
-
/**
|
|
13
|
-
* Default live layer providing an unbounded Effect `PubSub` for
|
|
14
|
-
* the run-event channel. The PubSub is scoped — when the surrounding
|
|
15
|
-
* scope closes, the channel shuts down and any pending subscribers
|
|
16
|
-
* receive their dequeue closure.
|
|
17
|
-
*
|
|
18
|
-
* Unbounded is the right default for the plugin and CLI: events arrive
|
|
19
|
-
* faster than a slow renderer can drain (e.g., several `TestFinished`
|
|
20
|
-
* per millisecond during a large suite), and dropping events would
|
|
21
|
-
* leave the rendered state inconsistent with the runner's truth.
|
|
22
|
-
* If memory pressure becomes a concern, swap in `PubSub.sliding`
|
|
23
|
-
* with a tuned capacity at the call site.
|
|
24
|
-
*
|
|
25
|
-
* @public
|
|
26
|
-
*/
|
|
27
|
-
const RunEventChannelLive = Layer.effect(RunEventChannel, PubSub.unbounded());
|
|
28
|
-
|
|
29
|
-
//#endregion
|
|
30
|
-
export { RunEventChannel, RunEventChannelLive };
|
package/pubsub/Publisher.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { RunEventChannel } from "./Channel.js";
|
|
2
|
-
import { Effect, PubSub } from "effect";
|
|
3
|
-
|
|
4
|
-
//#region src/pubsub/Publisher.ts
|
|
5
|
-
/**
|
|
6
|
-
* Emit one event onto the channel.
|
|
7
|
-
*
|
|
8
|
-
* Resolves when the event is enqueued. Returns the success boolean
|
|
9
|
-
* from `PubSub.publish` so callers can detect a shutdown
|
|
10
|
-
* channel if needed; in normal operation the result is always `true`.
|
|
11
|
-
*
|
|
12
|
-
* @param event - the run event to publish
|
|
13
|
-
* @returns an Effect that resolves to the publish success boolean
|
|
14
|
-
* @public
|
|
15
|
-
*/
|
|
16
|
-
const publish = (event) => Effect.gen(function* () {
|
|
17
|
-
const channel = yield* RunEventChannel;
|
|
18
|
-
return yield* PubSub.publish(channel, event);
|
|
19
|
-
});
|
|
20
|
-
/**
|
|
21
|
-
* Emit a batch of events onto the channel in order.
|
|
22
|
-
*
|
|
23
|
-
* Useful for the CLI replay path where the entire event sequence is
|
|
24
|
-
* materialized synchronously from a database query before any
|
|
25
|
-
* subscriber needs to read it.
|
|
26
|
-
*
|
|
27
|
-
* @param events - iterable of run events to publish in order
|
|
28
|
-
* @returns an Effect that resolves when all events are enqueued
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
const publishAll = (events) => Effect.gen(function* () {
|
|
32
|
-
const channel = yield* RunEventChannel;
|
|
33
|
-
yield* PubSub.publishAll(channel, events);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
//#endregion
|
|
37
|
-
export { publish, publishAll };
|
package/pubsub/Subscriber.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { RunEventChannel } from "./Channel.js";
|
|
2
|
-
import { reduceRenderState } from "../reducer.js";
|
|
3
|
-
import { initialRenderState } from "@vitest-agent/sdk";
|
|
4
|
-
import { Effect, PubSub, Stream } from "effect";
|
|
5
|
-
|
|
6
|
-
//#region src/pubsub/Subscriber.ts
|
|
7
|
-
/**
|
|
8
|
-
* Subscribe, fold the run-event stream into a terminal
|
|
9
|
-
* `RenderState`, and return when `RunFinished` arrives.
|
|
10
|
-
*
|
|
11
|
-
* The subscription is scoped — when this effect completes (or is
|
|
12
|
-
* interrupted), the underlying PubSub releases its slot.
|
|
13
|
-
*
|
|
14
|
-
* @param initial - the initial render state to fold from
|
|
15
|
-
* @returns an Effect that resolves to the terminal render state
|
|
16
|
-
* @public
|
|
17
|
-
*/
|
|
18
|
-
const accumulateUntilFinished = (initial = initialRenderState) => Effect.scoped(Effect.gen(function* () {
|
|
19
|
-
const channel = yield* RunEventChannel;
|
|
20
|
-
const subscription = yield* PubSub.subscribe(channel);
|
|
21
|
-
let state = initial;
|
|
22
|
-
while (state.phase !== "finished" && state.phase !== "timed-out") {
|
|
23
|
-
const event = yield* PubSub.take(subscription);
|
|
24
|
-
state = reduceRenderState(state, event);
|
|
25
|
-
}
|
|
26
|
-
return state;
|
|
27
|
-
}));
|
|
28
|
-
/**
|
|
29
|
-
* Run a callback for every projected `RenderState` as events
|
|
30
|
-
* arrive. The stream terminates when the PubSub shuts down (typically
|
|
31
|
-
* when the surrounding scope closes).
|
|
32
|
-
*
|
|
33
|
-
* The host runs this in a forked fiber so the publisher and the
|
|
34
|
-
* renderer can make progress concurrently. Returning an Effect from
|
|
35
|
-
* the callback lets the host suspend further rendering on backpressure
|
|
36
|
-
* (e.g. throttling redraws to the next animation frame).
|
|
37
|
-
*
|
|
38
|
-
* @param onState - callback invoked with each projected render state
|
|
39
|
-
* @param initial - the initial render state to fold from
|
|
40
|
-
* @returns an Effect that completes when the PubSub shuts down
|
|
41
|
-
* @public
|
|
42
|
-
*/
|
|
43
|
-
const forEachRenderState = (onState, initial = initialRenderState) => Effect.scoped(Effect.gen(function* () {
|
|
44
|
-
const channel = yield* RunEventChannel;
|
|
45
|
-
yield* Stream.fromPubSub(channel).pipe(Stream.scan(() => initial, reduceRenderState), Stream.runForEach(onState));
|
|
46
|
-
}));
|
|
47
|
-
/**
|
|
48
|
-
* Build an Effect `Stream` of accumulated states over the channel.
|
|
49
|
-
*
|
|
50
|
-
* Lower-level than {@link forEachRenderState} — useful when the host
|
|
51
|
-
* wants to compose with other stream operators (debouncing, throttling,
|
|
52
|
-
* tee-to-file) before running the terminal sink.
|
|
53
|
-
*
|
|
54
|
-
* @param initial - the initial render state to fold from
|
|
55
|
-
* @returns an Effect that resolves to a Stream of render states
|
|
56
|
-
* @public
|
|
57
|
-
*/
|
|
58
|
-
const renderStateStream = (initial = initialRenderState) => Effect.gen(function* () {
|
|
59
|
-
const channel = yield* RunEventChannel;
|
|
60
|
-
return Stream.fromPubSub(channel).pipe(Stream.scan(() => initial, reduceRenderState));
|
|
61
|
-
});
|
|
62
|
-
/**
|
|
63
|
-
* Convenience: subscribe and produce a low-level dequeue of raw
|
|
64
|
-
* `RunEvent` values. Mostly for tests and ad-hoc consumers; most
|
|
65
|
-
* application code should prefer {@link forEachRenderState} or
|
|
66
|
-
* {@link renderStateStream}.
|
|
67
|
-
*
|
|
68
|
-
* @returns an Effect that resolves to a dequeue of raw run events
|
|
69
|
-
* @public
|
|
70
|
-
*/
|
|
71
|
-
const subscribeRaw = () => Effect.gen(function* () {
|
|
72
|
-
const channel = yield* RunEventChannel;
|
|
73
|
-
return yield* PubSub.subscribe(channel);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
//#endregion
|
|
77
|
-
export { accumulateUntilFinished, forEachRenderState, renderStateStream, subscribeRaw };
|
package/pubsub/index.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { RunEventChannel, RunEventChannelLive } from "./Channel.js";
|
|
2
|
-
import { publish, publishAll } from "./Publisher.js";
|
|
3
|
-
import { accumulateUntilFinished, forEachRenderState, renderStateStream, subscribeRaw } from "./Subscriber.js";
|
|
4
|
-
|
|
5
|
-
export { RunEventChannel, RunEventChannelLive, accumulateUntilFinished, forEachRenderState, publish, publishAll, renderStateStream, subscribeRaw };
|