@vitest-agent/ui 4.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -3
  2. package/dispatcher/cells/single-file-fail.js +1 -5
  3. package/dispatcher/cells/single-file-pass.js +1 -5
  4. package/dispatcher/cells/single-file-threshold.js +3 -8
  5. package/dispatcher/cells/single-project-fail.js +1 -5
  6. package/dispatcher/cells/single-project-pass.js +1 -5
  7. package/dispatcher/cells/single-project-threshold.js +4 -8
  8. package/dispatcher/cells/single-test-fail.js +1 -5
  9. package/dispatcher/cells/single-test-pass.js +1 -5
  10. package/dispatcher/cells/workspace-fail.js +1 -5
  11. package/dispatcher/cells/workspace-pass.js +1 -5
  12. package/dispatcher/cells/workspace-threshold.js +4 -8
  13. package/dispatcher/classify.js +6 -1
  14. package/dispatcher/dispatch.js +20 -25
  15. package/dispatcher/helpers.js +52 -3
  16. package/index.d.ts +148 -316
  17. package/index.js +5 -18
  18. package/{render-ink → ink}/CountColumns.js +2 -2
  19. package/{render-ink → ink}/CoverageBlock.js +2 -2
  20. package/{render-ink → ink}/FailureSection.js +2 -2
  21. package/{render-ink → ink}/FailuresSection.js +2 -2
  22. package/{render-ink → ink}/ModuleHeader.js +1 -1
  23. package/{render-ink → ink}/ProjectRow.js +1 -1
  24. package/{render-ink → ink}/StatusIcon.js +2 -2
  25. package/{render-ink → ink}/StreamApp.js +14 -5
  26. package/{render-ink → ink}/SuggestedActions.js +2 -2
  27. package/{render-ink → ink}/TagColumns.js +1 -1
  28. package/{render-ink → ink}/TestRow.js +1 -1
  29. package/{render-ink → ink}/TrendLine.js +2 -2
  30. package/ink/dispatch-ink.js +61 -0
  31. package/{dispatcher → ink}/ink-helpers.js +1 -1
  32. package/ink.d.ts +789 -0
  33. package/ink.js +15 -0
  34. package/package.json +12 -7
  35. package/reducer.js +4 -2
  36. package/render-agent.js +4 -1
  37. package/{render-ink/spinner.js → spinner.js} +1 -1
  38. package/synthesize.js +22 -7
  39. package/render-ink/index.js +0 -15
@@ -6,7 +6,7 @@ import { TagColumns } from "./TagColumns.js";
6
6
  import { Box, Text } from "ink";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
 
9
- //#region src/render-ink/ProjectRow.tsx
9
+ //#region src/ink/ProjectRow.tsx
10
10
  /**
11
11
  * Pick the glyph element for the project row using the spec's severity
12
12
  * precedence (`✗ > ⧖ > ⚠ > ↷ > ✓`). Skip-only projects (no passes, no
@@ -1,9 +1,9 @@
1
1
  import { statusGlyph, statusInkStyle } from "../theme.js";
2
- import { Text } from "ink";
3
2
  import { useGlyphs } from "@effected/cli/ui";
3
+ import { Text } from "ink";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
 
6
- //#region src/render-ink/StatusIcon.tsx
6
+ //#region src/ink/StatusIcon.tsx
7
7
  /**
8
8
  * Single-character status glyph for tests, modules, and the run itself.
9
9
  *
@@ -1,19 +1,20 @@
1
1
  import { classifyRunShape } from "../dispatcher/classify.js";
2
2
  import { VitestAgentTokens, inkStyle, statusGlyph, statusInkStyle } from "../theme.js";
3
3
  import { formatDisplayDuration } from "../format-duration.js";
4
+ import { spinnerFrame } from "../spinner.js";
4
5
  import { CountColumns, DURATION_CELL_WIDTH } from "./CountColumns.js";
5
6
  import { StatusIcon } from "./StatusIcon.js";
6
7
  import { TagColumns, tagUnion } from "./TagColumns.js";
7
8
  import { ProjectRow } from "./ProjectRow.js";
8
- import { spinnerFrame } from "./spinner.js";
9
9
  import { TestRow } from "./TestRow.js";
10
10
  import { TrendLine } from "./TrendLine.js";
11
- import { Box, Text } from "ink";
11
+ import { formatStrayOutputNote } from "@vitest-agent/sdk";
12
12
  import { Fmt } from "@effected/cli";
13
13
  import { useGlyphs } from "@effected/cli/ui";
14
+ import { Box, Text } from "ink";
14
15
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
16
 
16
- //#region src/render-ink/StreamApp.tsx
17
+ //#region src/ink/StreamApp.tsx
17
18
  const ANONYMOUS_PROJECT = "default";
18
19
  /** Maximum number of running rows displayed in the Live region. Beyond this,
19
20
  * excess running units collapse into a single "… and N more running" line. */
@@ -508,9 +509,17 @@ const StreamApp = ({ state, frameIndex, nowMs }) => {
508
509
  const projects = groupByProject(state).map((g) => buildProjectSummary(g.name, sumCounts(g.modules)));
509
510
  const shape = classifyRunShape(state, projects);
510
511
  const liveContent = liveRegion(state, shape, now, frame, glyphs);
511
- return /* @__PURE__ */ jsx(Box, {
512
+ const stray = state.strayOutput !== void 0 ? formatStrayOutputNote(state.strayOutput) : null;
513
+ return /* @__PURE__ */ jsxs(Box, {
512
514
  flexDirection: "column",
513
- children: liveContent
515
+ children: [liveContent, stray !== null ? /* @__PURE__ */ jsx(Box, {
516
+ flexDirection: "column",
517
+ marginTop: 1,
518
+ children: stray.map((line, i) => /* @__PURE__ */ jsx(Text, {
519
+ ...i === 0 ? statusInkStyle("warning") : {},
520
+ children: line
521
+ }, `stray:${i}`))
522
+ }) : null]
514
523
  });
515
524
  };
516
525
 
@@ -1,9 +1,9 @@
1
1
  import { inkStyle } from "../theme.js";
2
- import { Box, Text } from "ink";
3
2
  import { Token } from "@effected/cli";
3
+ import { Box, Text } from "ink";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
 
6
- //#region src/render-ink/SuggestedActions.tsx
6
+ //#region src/ink/SuggestedActions.tsx
7
7
  const SEVERITY_TOKEN = {
8
8
  info: Token.named("blue"),
9
9
  warn: "warning",
@@ -2,7 +2,7 @@ import { VitestAgentTokens, inkStyle } from "../theme.js";
2
2
  import { Text } from "ink";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
 
5
- //#region src/render-ink/TagColumns.tsx
5
+ //#region src/ink/TagColumns.tsx
6
6
  /**
7
7
  * Fixed-width tag-count columns for aggregate rows in the `stream` view.
8
8
  * Every row renders every tag in the view's union so the columns align
@@ -3,7 +3,7 @@ import { StatusIcon } from "./StatusIcon.js";
3
3
  import { Box, Text } from "ink";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
 
6
- //#region src/render-ink/TestRow.tsx
6
+ //#region src/ink/TestRow.tsx
7
7
  const testGlyph = (status) => status;
8
8
  /**
9
9
  * Renders one test row: status glyph, optional suite prefix, test name, and duration.
@@ -1,9 +1,9 @@
1
1
  import { VitestAgentTokens, inkStyle } from "../theme.js";
2
- import { Text } from "ink";
3
2
  import { Fmt } from "@effected/cli";
3
+ import { Text } from "ink";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
 
6
- //#region src/render-ink/TrendLine.tsx
6
+ //#region src/ink/TrendLine.tsx
7
7
  /** A regressing trend is a `warning`, not a failure (the kit's drift decision). */
8
8
  const TOKEN = {
9
9
  improving: "success",
@@ -0,0 +1,61 @@
1
+ import { dispatcherTable, scopedCoverageNoteFor, strayOutputNoteFor } from "../dispatcher/dispatch.js";
2
+ import { renderAgentStringAsInk } from "./ink-helpers.js";
3
+ import { Box, Text } from "ink";
4
+ import { createElement } from "react";
5
+
6
+ //#region src/ink/dispatch-ink.ts
7
+ /** The Ink half of a cell whose live view is its agent string, painted. */
8
+ const asInk = (agent) => (inputs, opts) => renderAgentStringAsInk(agent(inputs, opts));
9
+ const inkOf = (shape, outcome) => asInk(dispatcherTable[shape][outcome].agent);
10
+ /**
11
+ * The 4×3 Ink cell table, keyed by the same `(RunShape, RunOutcome)`
12
+ * matrix as the root entry's `dispatcherTable`. An `undefined` entry is a
13
+ * cell with no Ink half (`single-test × threshold-violation`).
14
+ *
15
+ * @public
16
+ */
17
+ const inkDispatcherTable = {
18
+ "single-test": {
19
+ "all-pass": inkOf("single-test", "all-pass"),
20
+ "some-fail": inkOf("single-test", "some-fail"),
21
+ "threshold-violation": void 0
22
+ },
23
+ "single-file": {
24
+ "all-pass": inkOf("single-file", "all-pass"),
25
+ "some-fail": inkOf("single-file", "some-fail"),
26
+ "threshold-violation": inkOf("single-file", "threshold-violation")
27
+ },
28
+ "single-project": {
29
+ "all-pass": inkOf("single-project", "all-pass"),
30
+ "some-fail": inkOf("single-project", "some-fail"),
31
+ "threshold-violation": inkOf("single-project", "threshold-violation")
32
+ },
33
+ workspace: {
34
+ "all-pass": inkOf("workspace", "all-pass"),
35
+ "some-fail": inkOf("workspace", "some-fail"),
36
+ "threshold-violation": inkOf("workspace", "threshold-violation")
37
+ }
38
+ };
39
+ /**
40
+ * Dispatch to the cell that matches `(inputs.shape, inputs.outcome)`
41
+ * and return its Ink-half React tree, followed by the scoped-coverage
42
+ * note on a partial run. Returns `null` when the matched cell has no Ink
43
+ * half — callers fall back to the root entry's `dispatch` string then.
44
+ *
45
+ * @param inputs - the classified dispatch inputs
46
+ * @param opts - cell rendering options
47
+ * @returns the Ink React element, or `null` when the cell has no Ink half
48
+ * @public
49
+ */
50
+ const dispatchInk = (inputs, opts) => {
51
+ const cell = inkDispatcherTable[inputs.shape][inputs.outcome];
52
+ if (cell === void 0) return null;
53
+ const element = cell(inputs, opts);
54
+ const note = scopedCoverageNoteFor(inputs);
55
+ const stray = strayOutputNoteFor(inputs);
56
+ if (note === null && stray === null) return element;
57
+ return createElement(Box, { flexDirection: "column" }, element, note !== null ? createElement(Text, null, note) : null, stray !== null ? createElement(Box, { marginTop: 1 }, createElement(Text, null, stray)) : null);
58
+ };
59
+
60
+ //#endregion
61
+ export { dispatchInk, inkDispatcherTable };
@@ -2,7 +2,7 @@ import { inkStyle, statusGlyph, statusInkStyle } from "../theme.js";
2
2
  import { Box, Text } from "ink";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
 
5
- //#region src/dispatcher/ink-helpers.tsx
5
+ //#region src/ink/ink-helpers.tsx
6
6
  /**
7
7
  * Render an agent-string output as a column of Ink Text rows, applying
8
8
  * color to the leading status glyph on each line.