tubeless 0.2.12 → 0.2.13

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 (195) hide show
  1. package/dist/core/child-execution.d.ts +0 -23
  2. package/dist/core/child-execution.js +10 -12
  3. package/dist/core/child-execution.js.map +1 -1
  4. package/dist/core/child-progress.js +7 -2
  5. package/dist/core/child-progress.js.map +1 -1
  6. package/dist/core/iteration.d.ts +27 -0
  7. package/dist/core/iteration.js +111 -0
  8. package/dist/core/iteration.js.map +1 -0
  9. package/dist/core/lifecycle.d.ts +7 -5
  10. package/dist/core/lifecycle.js +36 -4
  11. package/dist/core/lifecycle.js.map +1 -1
  12. package/dist/core/pipeline-artifacts.d.ts +11 -0
  13. package/dist/core/pipeline-artifacts.js +2 -0
  14. package/dist/core/pipeline-artifacts.js.map +1 -0
  15. package/dist/core/pipeline-compiler.d.ts +1 -0
  16. package/dist/core/pipeline-compiler.js +1 -0
  17. package/dist/core/pipeline-compiler.js.map +1 -1
  18. package/dist/core/pipeline-definition-identity.d.ts +2 -2
  19. package/dist/core/pipeline-definition-identity.js +28 -5
  20. package/dist/core/pipeline-definition-identity.js.map +1 -1
  21. package/dist/core/pipeline-execute.d.ts +1 -6
  22. package/dist/core/pipeline-execute.js +28 -215
  23. package/dist/core/pipeline-execute.js.map +1 -1
  24. package/dist/core/pipeline-execution-error.d.ts +35 -0
  25. package/dist/core/pipeline-execution-error.js +195 -0
  26. package/dist/core/pipeline-execution-error.js.map +1 -0
  27. package/dist/core/pipeline-identity.d.ts +1 -0
  28. package/dist/core/pipeline-identity.js +1 -0
  29. package/dist/core/pipeline-identity.js.map +1 -1
  30. package/dist/core/pipeline-mermaid.js +4 -1
  31. package/dist/core/pipeline-mermaid.js.map +1 -1
  32. package/dist/core/pipeline-run-state.d.ts +4 -4
  33. package/dist/core/pipeline-run-state.js +10 -16
  34. package/dist/core/pipeline-run-state.js.map +1 -1
  35. package/dist/core/pipeline-step-executor.d.ts +2 -0
  36. package/dist/core/pipeline-step-executor.js +11 -3
  37. package/dist/core/pipeline-step-executor.js.map +1 -1
  38. package/dist/core/pipeline-steps.d.ts +20 -0
  39. package/dist/core/pipeline-steps.js +62 -0
  40. package/dist/core/pipeline-steps.js.map +1 -1
  41. package/dist/core/pipeline-types.d.ts +15 -2
  42. package/dist/core/pipeline-types.js.map +1 -1
  43. package/dist/core/pipeline.d.ts +4 -1
  44. package/dist/core/pipeline.js +18 -3
  45. package/dist/core/pipeline.js.map +1 -1
  46. package/dist/project/project-compiler.d.ts +3 -31
  47. package/dist/project/project-compiler.js +11 -180
  48. package/dist/project/project-compiler.js.map +1 -1
  49. package/dist/project/project-registry.d.ts +44 -0
  50. package/dist/project/project-registry.js +107 -0
  51. package/dist/project/project-registry.js.map +1 -0
  52. package/dist/project/project-step-graph.d.ts +9 -0
  53. package/dist/project/project-step-graph.js +99 -0
  54. package/dist/project/project-step-graph.js.map +1 -0
  55. package/dist/render/render.js +1 -1
  56. package/dist/render/render.js.map +1 -1
  57. package/dist/reporter/interactive-reporter.js +6 -3
  58. package/dist/reporter/interactive-reporter.js.map +1 -1
  59. package/dist/reporter/live-ticker-frame.d.ts +21 -0
  60. package/dist/reporter/live-ticker-frame.js +196 -0
  61. package/dist/reporter/live-ticker-frame.js.map +1 -0
  62. package/dist/reporter/live-ticker-protocol.d.ts +41 -0
  63. package/dist/reporter/live-ticker-protocol.js +59 -0
  64. package/dist/reporter/live-ticker-protocol.js.map +1 -0
  65. package/dist/reporter/live-ticker-worker.js +11 -25
  66. package/dist/reporter/live-ticker-worker.js.map +1 -1
  67. package/dist/reporter/live-ticker.d.ts +0 -15
  68. package/dist/reporter/live-ticker.js +11 -216
  69. package/dist/reporter/live-ticker.js.map +1 -1
  70. package/dist/reporter/reporter.js +7 -6
  71. package/dist/reporter/reporter.js.map +1 -1
  72. package/dist/run-store/definition-projection.d.ts +8 -0
  73. package/dist/run-store/definition-projection.js +89 -0
  74. package/dist/run-store/definition-projection.js.map +1 -0
  75. package/dist/run-store/run-projection.d.ts +15 -0
  76. package/dist/run-store/run-projection.js +203 -0
  77. package/dist/run-store/run-projection.js.map +1 -0
  78. package/dist/run-store/run-store-codec.d.ts +2 -0
  79. package/dist/run-store/run-store-codec.js +11 -0
  80. package/dist/run-store/run-store-codec.js.map +1 -1
  81. package/dist/run-store/run-store-event-decoder.js +3 -0
  82. package/dist/run-store/run-store-event-decoder.js.map +1 -1
  83. package/dist/run-store/run-store-reader.d.ts +7 -0
  84. package/dist/run-store/run-store-reader.js +31 -0
  85. package/dist/run-store/run-store-reader.js.map +1 -0
  86. package/dist/run-store/run-store-sqlite.js +23 -7
  87. package/dist/run-store/run-store-sqlite.js.map +1 -1
  88. package/dist/run-store/run-store.d.ts +16 -4
  89. package/dist/run-store/run-store.js +14 -263
  90. package/dist/run-store/run-store.js.map +1 -1
  91. package/dist/studio/run-store-ui-api.d.ts +13 -0
  92. package/dist/studio/run-store-ui-api.js +163 -0
  93. package/dist/studio/run-store-ui-api.js.map +1 -0
  94. package/dist/studio/run-store-ui-client-browser.js +2 -2
  95. package/dist/studio/run-store-ui-client-transport.js +28 -3
  96. package/dist/studio/run-store-ui-client-transport.js.map +1 -1
  97. package/dist/studio/run-store-ui-client.d.ts +2 -1
  98. package/dist/studio/run-store-ui-client.js +15 -9
  99. package/dist/studio/run-store-ui-client.js.map +1 -1
  100. package/dist/studio/run-store-ui-http.d.ts +11 -0
  101. package/dist/studio/run-store-ui-http.js +52 -0
  102. package/dist/studio/run-store-ui-http.js.map +1 -1
  103. package/dist/studio/run-store-ui-state.d.ts +1 -1
  104. package/dist/studio/run-store-ui-state.js +10 -28
  105. package/dist/studio/run-store-ui-state.js.map +1 -1
  106. package/dist/studio/run-store-ui.d.ts +5 -11
  107. package/dist/studio/run-store-ui.js +5 -203
  108. package/dist/studio/run-store-ui.js.map +1 -1
  109. package/dist/testing/testing.d.ts +18 -2
  110. package/dist/testing/testing.js +35 -2
  111. package/dist/testing/testing.js.map +1 -1
  112. package/dist/tracing/artifact-metadata.d.ts +28 -0
  113. package/dist/tracing/artifact-metadata.js +105 -0
  114. package/dist/tracing/artifact-metadata.js.map +1 -0
  115. package/dist/tracing/tracing-codec.d.ts +1 -1
  116. package/dist/tracing/tracing-codec.js +1 -1
  117. package/dist/tracing/tracing-codec.js.map +1 -1
  118. package/dist/tracing/tracing-constants.d.ts +1 -1
  119. package/dist/tracing/tracing-constants.js +1 -1
  120. package/dist/tracing/tracing-constants.js.map +1 -1
  121. package/dist/tracing/tracing-contracts.d.ts +3 -1
  122. package/dist/tracing/tracing-contracts.js.map +1 -1
  123. package/dist/tracing/tracing-internal.d.ts +2 -0
  124. package/dist/tracing/tracing-internal.js +36 -13
  125. package/dist/tracing/tracing-internal.js.map +1 -1
  126. package/dist/tracing/tracing-schema.d.ts +330 -49
  127. package/dist/tracing/tracing-schema.js +102 -10
  128. package/dist/tracing/tracing-schema.js.map +1 -1
  129. package/dist/workbench/workbench-command-execution.d.ts +6 -0
  130. package/dist/workbench/workbench-command-execution.js +48 -0
  131. package/dist/workbench/workbench-command-execution.js.map +1 -0
  132. package/dist/workbench/workbench-history.js +11 -18
  133. package/dist/workbench/workbench-history.js.map +1 -1
  134. package/dist/workbench/workbench-launch-session.d.ts +2 -2
  135. package/dist/workbench/workbench-launch-session.js.map +1 -1
  136. package/dist/workbench/workbench-run.d.ts +0 -4
  137. package/dist/workbench/workbench-run.js +3 -47
  138. package/dist/workbench/workbench-run.js.map +1 -1
  139. package/dist/workbench/workbench-studio-launcher.d.ts +27 -0
  140. package/dist/workbench/workbench-studio-launcher.js +95 -0
  141. package/dist/workbench/workbench-studio-launcher.js.map +1 -0
  142. package/dist/workbench/workbench-ui.js +10 -83
  143. package/dist/workbench/workbench-ui.js.map +1 -1
  144. package/docs/README.md +13 -7
  145. package/docs/agent-guide.md +69 -6
  146. package/docs/airflow.md +187 -0
  147. package/docs/api-reference.md +87 -76
  148. package/docs/api-report.json +17 -6
  149. package/docs/artifacts.md +173 -0
  150. package/docs/child-pipeline-composition.md +65 -2
  151. package/docs/comparison.md +20 -0
  152. package/docs/concepts.md +70 -2
  153. package/docs/dagster.md +161 -0
  154. package/docs/inngest.md +163 -0
  155. package/docs/llms.txt +30 -1
  156. package/docs/recipes.md +82 -33
  157. package/docs/remote-step-composition.md +6 -0
  158. package/docs/step-functions.md +190 -0
  159. package/docs/studio.md +31 -12
  160. package/docs/temporal.md +183 -0
  161. package/examples/airflow/contract.ts +46 -0
  162. package/examples/airflow/hosted.ts +70 -0
  163. package/examples/airflow/remote.ts +175 -0
  164. package/examples/airflow/tubeless_example.py +49 -0
  165. package/examples/airflow/worker.ts +24 -0
  166. package/examples/artifact-lineage.ts +70 -0
  167. package/examples/dagster/definitions.py +59 -0
  168. package/examples/dagster/hosted.ts +78 -0
  169. package/examples/dagster/pipeline.ts +62 -0
  170. package/examples/dagster/test_definitions.py +47 -0
  171. package/examples/dagster/tsconfig.build.json +10 -0
  172. package/examples/dagster/worker.ts +22 -0
  173. package/examples/inngest/client.ts +4 -0
  174. package/examples/inngest/functions.ts +65 -0
  175. package/examples/inngest/pipeline.ts +41 -0
  176. package/examples/inngest/send.ts +11 -0
  177. package/examples/inngest/server.ts +17 -0
  178. package/examples/inngest/tsconfig.build.json +10 -0
  179. package/examples/iteration.ts +52 -0
  180. package/examples/parameterized-steps.ts +96 -0
  181. package/examples/project/tubeless.project.ts +46 -0
  182. package/examples/step-functions/handler.ts +110 -0
  183. package/examples/step-functions/input.json +1 -0
  184. package/examples/step-functions/pipeline.ts +41 -0
  185. package/examples/step-functions/state-machine.asl.json +41 -0
  186. package/examples/step-functions/template.json +42 -0
  187. package/examples/step-output-overrides.ts +41 -0
  188. package/examples/temporal/activities.ts +94 -0
  189. package/examples/temporal/client.ts +19 -0
  190. package/examples/temporal/pipeline.ts +41 -0
  191. package/examples/temporal/tsconfig.build.json +10 -0
  192. package/examples/temporal/worker.ts +21 -0
  193. package/examples/temporal/workflows.ts +16 -0
  194. package/package.json +13 -4
  195. package/skills/tubeless/SKILL.md +30 -3
@@ -1,202 +1,12 @@
1
1
  import { writeSync } from "node:fs";
2
2
  import { isatty } from "node:tty";
3
3
  import { MessageChannel, receiveMessageOnPort, Worker } from "node:worker_threads";
4
- import { formatDurationMs } from "./reporter.js";
5
- export const SPINNER_TOKEN = "\u0001";
6
- const ELAPSED_TOKEN_START = "\u0002";
7
- const ELAPSED_TOKEN_END = "\u0003";
8
- export const SHIMMER_TOKEN_START = "\u0004";
9
- const SHIMMER_TOKEN_END = "\u0005";
10
- const ANSI = {
11
- clearDown: "\u001B[J",
12
- hideCursor: "\u001B[?25l",
13
- reset: "\u001B[0m",
14
- showCursor: "\u001B[?25h",
15
- };
16
- const SHIMMER_BAND_COLUMNS = 3;
17
- const SHIMMER_BRIGHT = "\u001B[0;1;36m";
18
- const SHIMMER_DIM = "\u001B[0;2;36m";
19
- const SHIMMER_FRAME_MS = 80;
4
+ import { currentSpinner, hasLiveAnimation, paintLiveLines, TICKER_ANSI, TickerFrame, } from "./live-ticker-frame.js";
5
+ import { TickerWorkerState, } from "./live-ticker-protocol.js";
20
6
  const OUTPUT_LOCK_TIMEOUT_MS = 50;
21
- const ANSI_STYLE = /\u001B\[[0-9;]*m/g;
22
- const ANSI_STYLE_PREFIX = /^\u001B\[[0-9;]*m/;
23
- const COMBINING_MARK = /\p{Mark}/u;
24
- const EMOJI = /\p{Extended_Pictographic}/u;
25
- const SPINNERS = {
26
- ascii: ["-", "\\", "|", "/"],
27
- unicode: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
28
- };
29
- function characterWidth(character) {
30
- if (COMBINING_MARK.test(character) || character === "\u200D")
31
- return 0;
32
- if (EMOJI.test(character))
33
- return 2;
34
- const codePoint = character.codePointAt(0) ?? 0;
35
- return codePoint >= 0x1100 &&
36
- (codePoint <= 0x115f ||
37
- codePoint === 0x2329 ||
38
- codePoint === 0x232a ||
39
- (codePoint >= 0x2e80 && codePoint <= 0xa4cf) ||
40
- (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
41
- (codePoint >= 0xf900 && codePoint <= 0xfaff) ||
42
- (codePoint >= 0xfe10 && codePoint <= 0xfe6f) ||
43
- (codePoint >= 0xff00 && codePoint <= 0xff60) ||
44
- (codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
45
- (codePoint >= 0x20000 && codePoint <= 0x3fffd))
46
- ? 2
47
- : 1;
48
- }
49
- function visibleWidth(value) {
50
- return [...value].reduce((width, character) => width + characterWidth(character), 0);
51
- }
52
- function fitLine(value, columns, unicode) {
53
- if (!columns || columns <= 1)
54
- return value;
55
- const maxWidth = columns - 1;
56
- const plain = value.replace(ANSI_STYLE, "");
57
- if (visibleWidth(plain) <= maxWidth)
58
- return value;
59
- const ellipsis = unicode ? "…" : ".".repeat(Math.min(3, maxWidth));
60
- const targetWidth = Math.max(0, maxWidth - visibleWidth(ellipsis));
61
- let width = 0;
62
- let truncated = "";
63
- let index = 0;
64
- let hasStyle = false;
65
- while (index < value.length) {
66
- const style = value.slice(index).match(ANSI_STYLE_PREFIX)?.[0];
67
- if (style) {
68
- truncated += style;
69
- index += style.length;
70
- hasStyle = true;
71
- continue;
72
- }
73
- const character = String.fromCodePoint(value.codePointAt(index) ?? 0);
74
- const nextWidth = width + characterWidth(character);
75
- if (nextWidth > targetWidth)
76
- break;
77
- truncated += character;
78
- width = nextWidth;
79
- index += character.length;
80
- }
81
- return `${truncated}${hasStyle ? ANSI.reset : ""}${ellipsis}`;
82
- }
83
- export function elapsedToken(startedAtMs) {
84
- return `${ELAPSED_TOKEN_START}${startedAtMs}${ELAPSED_TOKEN_END}`;
85
- }
86
- export function shimmerToken(value) {
87
- return `${SHIMMER_TOKEN_START}${value}${SHIMMER_TOKEN_END}`;
88
- }
89
- function paintShimmerText(text, nowMs) {
90
- const characters = [...text];
91
- if (characters.length === 0)
92
- return text;
93
- const widths = characters.map(characterWidth);
94
- const totalWidth = visibleWidth(text);
95
- const period = Math.max(1, totalWidth + SHIMMER_BAND_COLUMNS);
96
- const head = Math.floor(nowMs / SHIMMER_FRAME_MS) % period;
97
- const bandStart = head - SHIMMER_BAND_COLUMNS + 1;
98
- let column = 0;
99
- let output = ANSI.reset;
100
- let last;
101
- for (const [index, character] of characters.entries()) {
102
- const width = widths[index] ?? 0;
103
- const inBand = width === 0 ? last === "bright" : column <= head && column + width - 1 >= bandStart;
104
- const style = inBand ? "bright" : "dim";
105
- if (style !== last) {
106
- output += style === "bright" ? SHIMMER_BRIGHT : SHIMMER_DIM;
107
- last = style;
108
- }
109
- output += character;
110
- column += width;
111
- }
112
- return `${output}${ANSI.reset}`;
113
- }
114
- function replaceLiveTokens(line, spinner, nowMs, color) {
115
- return line
116
- .replaceAll(SPINNER_TOKEN, spinner)
117
- .replace(new RegExp(`${ELAPSED_TOKEN_START}(\\d+)${ELAPSED_TOKEN_END}`, "g"), (_match, start) => formatDurationMs(Math.max(0, nowMs - Number(start))))
118
- .replace(new RegExp(`${SHIMMER_TOKEN_START}(.*?)${SHIMMER_TOKEN_END}`, "g"), (_match, text) => (color ? paintShimmerText(text, nowMs) : text));
119
- }
120
- export function paintLiveLines(lines, spinner, nowMs, columns, color = false, unicode = true, logPane) {
121
- const painted = lines.map((line) => replaceLiveTokens(line, spinner, nowMs, color));
122
- if (!logPane || !columns || columns < 120) {
123
- return painted.map((line) => fitLine(line, columns, unicode));
124
- }
125
- const paneWidth = Math.min(60, Math.floor(columns * 0.4));
126
- const leftWidth = columns - paneWidth - 3;
127
- const horizontal = unicode ? "─" : "-";
128
- const vertical = unicode ? "│" : "|";
129
- const pad = (line, width) => {
130
- const fitted = fitLine(line, width + 1, unicode);
131
- return fitted + " ".repeat(Math.max(0, width - visibleWidth(fitted.replace(ANSI_STYLE, ""))));
132
- };
133
- const pane = [
134
- `${unicode ? "╭" : "+"}${horizontal} Logs ${horizontal.repeat(paneWidth - 9)}${unicode ? "╮" : "+"}`,
135
- ...logPane.map((line) => `${vertical} ${pad(line, paneWidth - 4)} ${vertical}`),
136
- `${unicode ? "╰" : "+"}${horizontal.repeat(paneWidth - 2)}${unicode ? "╯" : "+"}`,
137
- ];
138
- return Array.from({ length: Math.max(painted.length, pane.length) }, (_, index) => pane[index] === undefined
139
- ? fitLine(painted[index] ?? "", leftWidth + 1, unicode)
140
- : `${pad(painted[index] ?? "", leftWidth)} ${pane[index]}`);
141
- }
142
- export class TickerFrame {
143
- write;
144
- paintedLines;
145
- cursorHidden;
146
- constructor(write, paintedLines = []) {
147
- this.write = write;
148
- this.paintedLines = paintedLines;
149
- this.cursorHidden = paintedLines.length > 0;
150
- }
151
- showCursor() {
152
- if (!this.cursorHidden)
153
- return;
154
- this.write(ANSI.showCursor);
155
- this.cursorHidden = false;
156
- }
157
- clear(columns) {
158
- if (this.paintedLines.length === 0)
159
- return;
160
- // Resizing can reflow each previously painted line across several rows.
161
- // Count those rows at the current width before moving back to the frame start.
162
- let rows = this.paintedLines.length;
163
- if (columns !== undefined && columns > 0) {
164
- rows = 0;
165
- for (const line of this.paintedLines) {
166
- rows += 1;
167
- let column = 0;
168
- for (const character of line.replace(ANSI_STYLE, "")) {
169
- const width = characterWidth(character);
170
- if (column + width > columns) {
171
- rows += 1;
172
- column = 0;
173
- }
174
- column += width;
175
- }
176
- }
177
- }
178
- this.write(`\u001B[${rows}F${ANSI.clearDown}`);
179
- this.paintedLines = [];
180
- }
181
- redraw(lines, columns) {
182
- if (!this.cursorHidden) {
183
- this.write(ANSI.hideCursor);
184
- this.cursorHidden = true;
185
- }
186
- this.clear(columns);
187
- if (lines.length === 0)
188
- return;
189
- this.write(`${lines.join("\n")}\n`);
190
- this.paintedLines = lines;
191
- }
192
- }
193
7
  function resolveColumns(options) {
194
8
  return options.getColumns?.() ?? options.columns;
195
9
  }
196
- export function currentSpinner(unicode, refreshIntervalMs) {
197
- const frames = unicode ? SPINNERS.unicode : SPINNERS.ascii;
198
- return frames[Math.floor(Date.now() / refreshIntervalMs) % frames.length] ?? frames[0];
199
- }
200
10
  function createInlineTicker(options, adoptedPaintedLines = []) {
201
11
  let disposed = false;
202
12
  let lines = [];
@@ -209,8 +19,7 @@ function createInlineTicker(options, adoptedPaintedLines = []) {
209
19
  frame.redraw(paintLiveLines(lines, currentSpinner(options.unicode, options.refreshIntervalMs), Date.now(), columns, options.color === true, options.unicode, logPane), columns);
210
20
  };
211
21
  const timer = setInterval(() => {
212
- if (disposed ||
213
- !lines.some((line) => line.includes(SPINNER_TOKEN) || line.includes(SHIMMER_TOKEN_START))) {
22
+ if (disposed || !hasLiveAnimation(lines)) {
214
23
  return;
215
24
  }
216
25
  redraw();
@@ -258,9 +67,7 @@ function fileWorkerExecArgv(argv = process.execArgv) {
258
67
  return next;
259
68
  }
260
69
  function createWorkerTicker(options) {
261
- // [0] stopped, [1] accepted logs, [2] inline owns output, [3] output lock
262
- const stateBuffer = new SharedArrayBuffer(16);
263
- const state = new Int32Array(stateBuffer);
70
+ const state = new TickerWorkerState();
264
71
  const { port1: framePort, port2: workerFramePort } = new MessageChannel();
265
72
  let worker;
266
73
  try {
@@ -273,7 +80,7 @@ function createWorkerTicker(options) {
273
80
  fd: options.fd,
274
81
  framePort: workerFramePort,
275
82
  refreshIntervalMs: options.refreshIntervalMs,
276
- stateBuffer,
83
+ stateBuffer: state.buffer,
277
84
  unicode: options.unicode,
278
85
  },
279
86
  });
@@ -297,10 +104,10 @@ function createWorkerTicker(options) {
297
104
  const restoreCursor = () => {
298
105
  try {
299
106
  if (isatty(options.fd)) {
300
- writeSync(options.fd, ANSI.showCursor);
107
+ writeSync(options.fd, TICKER_ANSI.showCursor);
301
108
  }
302
109
  else {
303
- options.write(ANSI.showCursor);
110
+ options.write(TICKER_ANSI.showCursor);
304
111
  }
305
112
  }
306
113
  catch {
@@ -308,7 +115,7 @@ function createWorkerTicker(options) {
308
115
  }
309
116
  };
310
117
  const dropAcknowledgedLogs = () => {
311
- const accepted = Atomics.load(state, 1);
118
+ const accepted = state.acceptedLogs;
312
119
  pendingLogs.splice(0, accepted - acknowledgedLogs);
313
120
  acknowledgedLogs = accepted;
314
121
  };
@@ -319,19 +126,8 @@ function createWorkerTicker(options) {
319
126
  pendingLogs.length = 0;
320
127
  ticker.setLines([...lines], logPane);
321
128
  };
322
- const claimOutput = () => {
323
- Atomics.store(state, 2, 1);
324
- const deadline = Date.now() + OUTPUT_LOCK_TIMEOUT_MS;
325
- while (Atomics.compareExchange(state, 3, 0, 1) !== 0) {
326
- const remainingMs = deadline - Date.now();
327
- if (remainingMs <= 0)
328
- return false;
329
- Atomics.wait(state, 3, 1, remainingMs);
330
- }
331
- return true;
332
- };
333
129
  const createFallback = () => {
334
- if (!claimOutput())
130
+ if (!state.claimOutput(OUTPUT_LOCK_TIMEOUT_MS))
335
131
  return undefined;
336
132
  // dispose() blocks the event loop. Drain snapshots synchronously after taking
337
133
  // the output lock so adoption includes the worker's last completed paint.
@@ -347,8 +143,7 @@ function createWorkerTicker(options) {
347
143
  const failToInline = () => {
348
144
  if (disposed || inlineFallback)
349
145
  return;
350
- // The exit event guarantees that no worker write still owns this lock.
351
- Atomics.store(state, 3, 0);
146
+ state.releaseOutputAfterWorkerExit();
352
147
  inlineFallback = createFallback();
353
148
  };
354
149
  worker.on("error", () => void worker.terminate());
@@ -407,7 +202,7 @@ function createWorkerTicker(options) {
407
202
  logPane,
408
203
  type: "stop",
409
204
  });
410
- workerStopped = Atomics.wait(state, 0, 0, 500) !== "timed-out";
205
+ workerStopped = state.waitForStop(500);
411
206
  }
412
207
  catch {
413
208
  // The worker is unavailable; render its retained state below.
@@ -1 +1 @@
1
- {"version":3,"file":"live-ticker.js","sourceRoot":"","sources":["../../src/reporter/live-ticker.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeSync } from \"node:fs\";\nimport { isatty } from \"node:tty\";\nimport { MessageChannel, receiveMessageOnPort, Worker } from \"node:worker_threads\";\nimport { formatDurationMs } from \"./reporter.js\";\n\nexport const SPINNER_TOKEN = \"\\u0001\";\nconst ELAPSED_TOKEN_START = \"\\u0002\";\nconst ELAPSED_TOKEN_END = \"\\u0003\";\nexport const SHIMMER_TOKEN_START = \"\\u0004\";\nconst SHIMMER_TOKEN_END = \"\\u0005\";\n\nconst ANSI = {\n clearDown: \"\\u001B[J\",\n hideCursor: \"\\u001B[?25l\",\n reset: \"\\u001B[0m\",\n showCursor: \"\\u001B[?25h\",\n} as const;\n\nconst SHIMMER_BAND_COLUMNS = 3;\nconst SHIMMER_BRIGHT = \"\\u001B[0;1;36m\";\nconst SHIMMER_DIM = \"\\u001B[0;2;36m\";\nconst SHIMMER_FRAME_MS = 80;\nconst OUTPUT_LOCK_TIMEOUT_MS = 50;\n\nconst ANSI_STYLE = /\\u001B\\[[0-9;]*m/g;\nconst ANSI_STYLE_PREFIX = /^\\u001B\\[[0-9;]*m/;\nconst COMBINING_MARK = /\\p{Mark}/u;\nconst EMOJI = /\\p{Extended_Pictographic}/u;\n\nconst SPINNERS = {\n ascii: [\"-\", \"\\\\\", \"|\", \"/\"],\n unicode: [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"],\n} as const;\n\nfunction characterWidth(character: string): number {\n if (COMBINING_MARK.test(character) || character === \"\\u200D\") return 0;\n if (EMOJI.test(character)) return 2;\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint >= 0x1100 &&\n (codePoint <= 0x115f ||\n codePoint === 0x2329 ||\n codePoint === 0x232a ||\n (codePoint >= 0x2e80 && codePoint <= 0xa4cf) ||\n (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||\n (codePoint >= 0xf900 && codePoint <= 0xfaff) ||\n (codePoint >= 0xfe10 && codePoint <= 0xfe6f) ||\n (codePoint >= 0xff00 && codePoint <= 0xff60) ||\n (codePoint >= 0xffe0 && codePoint <= 0xffe6) ||\n (codePoint >= 0x20000 && codePoint <= 0x3fffd))\n ? 2\n : 1;\n}\n\nfunction visibleWidth(value: string): number {\n return [...value].reduce((width, character) => width + characterWidth(character), 0);\n}\n\nfunction fitLine(value: string, columns: number | undefined, unicode: boolean): string {\n if (!columns || columns <= 1) return value;\n const maxWidth = columns - 1;\n const plain = value.replace(ANSI_STYLE, \"\");\n if (visibleWidth(plain) <= maxWidth) return value;\n const ellipsis = unicode ? \"…\" : \".\".repeat(Math.min(3, maxWidth));\n const targetWidth = Math.max(0, maxWidth - visibleWidth(ellipsis));\n let width = 0;\n let truncated = \"\";\n let index = 0;\n let hasStyle = false;\n while (index < value.length) {\n const style = value.slice(index).match(ANSI_STYLE_PREFIX)?.[0];\n if (style) {\n truncated += style;\n index += style.length;\n hasStyle = true;\n continue;\n }\n const character = String.fromCodePoint(value.codePointAt(index) ?? 0);\n const nextWidth = width + characterWidth(character);\n if (nextWidth > targetWidth) break;\n truncated += character;\n width = nextWidth;\n index += character.length;\n }\n return `${truncated}${hasStyle ? ANSI.reset : \"\"}${ellipsis}`;\n}\n\nexport function elapsedToken(startedAtMs: number): string {\n return `${ELAPSED_TOKEN_START}${startedAtMs}${ELAPSED_TOKEN_END}`;\n}\n\nexport function shimmerToken(value: string): string {\n return `${SHIMMER_TOKEN_START}${value}${SHIMMER_TOKEN_END}`;\n}\n\nfunction paintShimmerText(text: string, nowMs: number): string {\n const characters = [...text];\n if (characters.length === 0) return text;\n const widths = characters.map(characterWidth);\n const totalWidth = visibleWidth(text);\n const period = Math.max(1, totalWidth + SHIMMER_BAND_COLUMNS);\n const head = Math.floor(nowMs / SHIMMER_FRAME_MS) % period;\n const bandStart = head - SHIMMER_BAND_COLUMNS + 1;\n let column = 0;\n let output = ANSI.reset;\n let last: \"bright\" | \"dim\" | undefined;\n for (const [index, character] of characters.entries()) {\n const width = widths[index] ?? 0;\n const inBand =\n width === 0 ? last === \"bright\" : column <= head && column + width - 1 >= bandStart;\n const style = inBand ? \"bright\" : \"dim\";\n if (style !== last) {\n output += style === \"bright\" ? SHIMMER_BRIGHT : SHIMMER_DIM;\n last = style;\n }\n output += character;\n column += width;\n }\n return `${output}${ANSI.reset}`;\n}\n\nfunction replaceLiveTokens(line: string, spinner: string, nowMs: number, color: boolean): string {\n return line\n .replaceAll(SPINNER_TOKEN, spinner)\n .replace(\n new RegExp(`${ELAPSED_TOKEN_START}(\\\\d+)${ELAPSED_TOKEN_END}`, \"g\"),\n (_match, start: string) => formatDurationMs(Math.max(0, nowMs - Number(start)))\n )\n .replace(\n new RegExp(`${SHIMMER_TOKEN_START}(.*?)${SHIMMER_TOKEN_END}`, \"g\"),\n (_match, text: string) => (color ? paintShimmerText(text, nowMs) : text)\n );\n}\n\nexport function paintLiveLines(\n lines: readonly string[],\n spinner: string,\n nowMs: number,\n columns?: number,\n color = false,\n unicode = true,\n logPane?: readonly string[]\n): string[] {\n const painted = lines.map((line) => replaceLiveTokens(line, spinner, nowMs, color));\n if (!logPane || !columns || columns < 120) {\n return painted.map((line) => fitLine(line, columns, unicode));\n }\n const paneWidth = Math.min(60, Math.floor(columns * 0.4));\n const leftWidth = columns - paneWidth - 3;\n const horizontal = unicode ? \"─\" : \"-\";\n const vertical = unicode ? \"│\" : \"|\";\n const pad = (line: string, width: number): string => {\n const fitted = fitLine(line, width + 1, unicode);\n return fitted + \" \".repeat(Math.max(0, width - visibleWidth(fitted.replace(ANSI_STYLE, \"\"))));\n };\n const pane = [\n `${unicode ? \"╭\" : \"+\"}${horizontal} Logs ${horizontal.repeat(paneWidth - 9)}${unicode ? \"╮\" : \"+\"}`,\n ...logPane.map((line) => `${vertical} ${pad(line, paneWidth - 4)} ${vertical}`),\n `${unicode ? \"╰\" : \"+\"}${horizontal.repeat(paneWidth - 2)}${unicode ? \"╯\" : \"+\"}`,\n ];\n return Array.from({ length: Math.max(painted.length, pane.length) }, (_, index) =>\n pane[index] === undefined\n ? fitLine(painted[index] ?? \"\", leftWidth + 1, unicode)\n : `${pad(painted[index] ?? \"\", leftWidth)} ${pane[index]}`\n );\n}\n\nexport interface LiveTicker {\n setLines(lines: readonly string[], logPane?: readonly string[]): void;\n writeLog(text: string): void;\n dispose(): void;\n}\n\nexport interface LiveTickerOptions {\n columns?: number;\n getColumns?(): number | undefined;\n fd?: number;\n refreshIntervalMs: number;\n unicode: boolean;\n color?: boolean;\n write(chunk: string): void;\n workerUrl?: URL;\n}\n\ntype TickerWorkerMessage =\n | { columns?: number; lines: string[]; logPane?: readonly string[]; type: \"lines\" }\n | { columns?: number; text: string; type: \"log\" }\n | { columns?: number; lines: string[]; logPane?: readonly string[]; type: \"stop\" };\n\nexport class TickerFrame {\n private cursorHidden: boolean;\n\n constructor(\n private readonly write: (chunk: string) => void,\n private paintedLines: readonly string[] = []\n ) {\n this.cursorHidden = paintedLines.length > 0;\n }\n\n showCursor(): void {\n if (!this.cursorHidden) return;\n this.write(ANSI.showCursor);\n this.cursorHidden = false;\n }\n\n clear(columns?: number): void {\n if (this.paintedLines.length === 0) return;\n // Resizing can reflow each previously painted line across several rows.\n // Count those rows at the current width before moving back to the frame start.\n let rows = this.paintedLines.length;\n if (columns !== undefined && columns > 0) {\n rows = 0;\n for (const line of this.paintedLines) {\n rows += 1;\n let column = 0;\n for (const character of line.replace(ANSI_STYLE, \"\")) {\n const width = characterWidth(character);\n if (column + width > columns) {\n rows += 1;\n column = 0;\n }\n column += width;\n }\n }\n }\n this.write(`\\u001B[${rows}F${ANSI.clearDown}`);\n this.paintedLines = [];\n }\n\n redraw(lines: readonly string[], columns?: number): void {\n if (!this.cursorHidden) {\n this.write(ANSI.hideCursor);\n this.cursorHidden = true;\n }\n this.clear(columns);\n if (lines.length === 0) return;\n this.write(`${lines.join(\"\\n\")}\\n`);\n this.paintedLines = lines;\n }\n}\n\nfunction resolveColumns(options: LiveTickerOptions): number | undefined {\n return options.getColumns?.() ?? options.columns;\n}\n\nexport function currentSpinner(unicode: boolean, refreshIntervalMs: number): string {\n const frames = unicode ? SPINNERS.unicode : SPINNERS.ascii;\n return frames[Math.floor(Date.now() / refreshIntervalMs) % frames.length] ?? frames[0]!;\n}\n\nfunction createInlineTicker(\n options: LiveTickerOptions,\n adoptedPaintedLines: readonly string[] = []\n): LiveTicker {\n let disposed = false;\n let lines: readonly string[] = [];\n let logPane: readonly string[] | undefined;\n const frame = new TickerFrame((chunk) => options.write(chunk), adoptedPaintedLines);\n const redraw = (): void => {\n if (disposed) return;\n const columns = resolveColumns(options);\n frame.redraw(\n paintLiveLines(\n lines,\n currentSpinner(options.unicode, options.refreshIntervalMs),\n Date.now(),\n columns,\n options.color === true,\n options.unicode,\n logPane\n ),\n columns\n );\n };\n\n const timer = setInterval(() => {\n if (\n disposed ||\n !lines.some((line) => line.includes(SPINNER_TOKEN) || line.includes(SHIMMER_TOKEN_START))\n ) {\n return;\n }\n redraw();\n }, options.refreshIntervalMs);\n timer.unref();\n\n return {\n setLines(nextLines, nextLogPane) {\n lines = nextLines;\n logPane = nextLogPane;\n redraw();\n },\n writeLog(text) {\n if (disposed) {\n options.write(text);\n return;\n }\n frame.clear(resolveColumns(options));\n options.write(text);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n clearInterval(timer);\n frame.showCursor();\n },\n };\n}\n\nfunction resolveLiveTickerWorkerUrl(): URL {\n return import.meta.url.endsWith(\".ts\")\n ? new URL(\"../../dist/reporter/live-ticker-worker.js\", import.meta.url)\n : new URL(\"./live-ticker-worker.js\", import.meta.url);\n}\n\nfunction fileWorkerExecArgv(argv: readonly string[] = process.execArgv): string[] {\n const next: string[] = [];\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n if (arg === \"--input-type\") {\n index += 1;\n } else if (!arg.startsWith(\"--input-type=\")) {\n next.push(arg);\n }\n }\n return next;\n}\n\nfunction createWorkerTicker(options: LiveTickerOptions & { fd: number }): LiveTicker {\n // [0] stopped, [1] accepted logs, [2] inline owns output, [3] output lock\n const stateBuffer = new SharedArrayBuffer(16);\n const state = new Int32Array(stateBuffer);\n const { port1: framePort, port2: workerFramePort } = new MessageChannel();\n let worker: Worker;\n try {\n worker = new Worker(options.workerUrl ?? resolveLiveTickerWorkerUrl(), {\n execArgv: fileWorkerExecArgv(),\n transferList: [workerFramePort],\n workerData: {\n color: options.color === true,\n columns: resolveColumns(options),\n fd: options.fd,\n framePort: workerFramePort,\n refreshIntervalMs: options.refreshIntervalMs,\n stateBuffer,\n unicode: options.unicode,\n },\n });\n } catch (error) {\n framePort.close();\n workerFramePort.close();\n throw error;\n }\n let paintedLines: readonly string[] = [];\n framePort.on(\"message\", (nextLines: string[]) => {\n paintedLines = nextLines;\n });\n framePort.unref();\n let disposed = false;\n let inlineFallback: LiveTicker | undefined;\n let lines: readonly string[] = [];\n let logPane: readonly string[] | undefined;\n const pendingLogs: string[] = [];\n let acknowledgedLogs = 0;\n\n const restoreCursor = (): void => {\n try {\n if (isatty(options.fd)) {\n writeSync(options.fd, ANSI.showCursor);\n } else {\n options.write(ANSI.showCursor);\n }\n } catch {\n // The output may remain unavailable; cursor restore is best-effort.\n }\n };\n\n const dropAcknowledgedLogs = (): void => {\n const accepted = Atomics.load(state, 1);\n pendingLogs.splice(0, accepted - acknowledgedLogs);\n acknowledgedLogs = accepted;\n };\n\n const replayThrough = (ticker: LiveTicker): void => {\n dropAcknowledgedLogs();\n for (const text of pendingLogs) ticker.writeLog(text);\n pendingLogs.length = 0;\n ticker.setLines([...lines], logPane);\n };\n\n const claimOutput = (): boolean => {\n Atomics.store(state, 2, 1);\n const deadline = Date.now() + OUTPUT_LOCK_TIMEOUT_MS;\n while (Atomics.compareExchange(state, 3, 0, 1) !== 0) {\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) return false;\n Atomics.wait(state, 3, 1, remainingMs);\n }\n return true;\n };\n\n const createFallback = (): LiveTicker | undefined => {\n if (!claimOutput()) return undefined;\n // dispose() blocks the event loop. Drain snapshots synchronously after taking\n // the output lock so adoption includes the worker's last completed paint.\n let snapshot;\n while ((snapshot = receiveMessageOnPort(framePort)) !== undefined) {\n paintedLines = snapshot.message as string[];\n }\n framePort.close();\n const ticker = createInlineTicker(options, paintedLines);\n replayThrough(ticker);\n return ticker;\n };\n\n const failToInline = (): void => {\n if (disposed || inlineFallback) return;\n // The exit event guarantees that no worker write still owns this lock.\n Atomics.store(state, 3, 0);\n inlineFallback = createFallback();\n };\n\n worker.on(\"error\", () => void worker.terminate());\n worker.on(\"exit\", () => failToInline());\n worker.unref();\n\n return {\n setLines(nextLines, nextLogPane) {\n if (disposed) return;\n lines = nextLines;\n logPane = nextLogPane;\n if (inlineFallback) {\n inlineFallback.setLines(nextLines, nextLogPane);\n return;\n }\n worker.postMessage({\n columns: resolveColumns(options),\n lines: [...nextLines],\n logPane,\n type: \"lines\",\n } satisfies TickerWorkerMessage);\n },\n writeLog(text) {\n if (inlineFallback) {\n inlineFallback.writeLog(text);\n return;\n }\n if (disposed) {\n options.write(text);\n return;\n }\n dropAcknowledgedLogs();\n pendingLogs.push(text);\n worker.postMessage({\n columns: resolveColumns(options),\n text,\n type: \"log\",\n } satisfies TickerWorkerMessage);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n if (inlineFallback) {\n inlineFallback.dispose();\n void worker.terminate();\n return;\n }\n let restoreCursorAfterTerminate = false;\n try {\n let workerStopped = false;\n try {\n worker.postMessage({\n columns: resolveColumns(options),\n lines: [...lines],\n logPane,\n type: \"stop\",\n } satisfies TickerWorkerMessage);\n workerStopped = Atomics.wait(state, 0, 0, 500) !== \"timed-out\";\n } catch {\n // The worker is unavailable; render its retained state below.\n }\n if (!workerStopped) {\n const ticker = createFallback();\n if (ticker) {\n ticker.dispose();\n } else {\n restoreCursorAfterTerminate = true;\n }\n }\n } finally {\n framePort.close();\n const terminated = worker.terminate();\n if (restoreCursorAfterTerminate) {\n restoreCursor();\n void terminated.then(restoreCursor);\n }\n }\n },\n };\n}\n\nfunction outputFd(fd: number | undefined): fd is number {\n return fd !== undefined && Number.isInteger(fd) && fd >= 0;\n}\n\nexport function createLiveTicker(options: LiveTickerOptions): LiveTicker {\n if (outputFd(options.fd)) {\n try {\n return createWorkerTicker({ ...options, fd: options.fd });\n } catch {\n // Some embeddings do not provide worker threads.\n }\n }\n return createInlineTicker(options);\n}\n"]}
1
+ {"version":3,"file":"live-ticker.js","sourceRoot":"","sources":["../../src/reporter/live-ticker.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeSync } from \"node:fs\";\nimport { isatty } from \"node:tty\";\nimport { MessageChannel, receiveMessageOnPort, Worker } from \"node:worker_threads\";\nimport {\n currentSpinner,\n hasLiveAnimation,\n paintLiveLines,\n TICKER_ANSI,\n TickerFrame,\n} from \"./live-ticker-frame.js\";\nimport {\n TickerWorkerState,\n type LiveTickerWorkerData,\n type TickerWorkerMessage,\n} from \"./live-ticker-protocol.js\";\n\nconst OUTPUT_LOCK_TIMEOUT_MS = 50;\n\nexport interface LiveTicker {\n setLines(lines: readonly string[], logPane?: readonly string[]): void;\n writeLog(text: string): void;\n dispose(): void;\n}\n\nexport interface LiveTickerOptions {\n columns?: number;\n getColumns?(): number | undefined;\n fd?: number;\n refreshIntervalMs: number;\n unicode: boolean;\n color?: boolean;\n write(chunk: string): void;\n workerUrl?: URL;\n}\n\nfunction resolveColumns(options: LiveTickerOptions): number | undefined {\n return options.getColumns?.() ?? options.columns;\n}\n\nfunction createInlineTicker(\n options: LiveTickerOptions,\n adoptedPaintedLines: readonly string[] = []\n): LiveTicker {\n let disposed = false;\n let lines: readonly string[] = [];\n let logPane: readonly string[] | undefined;\n const frame = new TickerFrame((chunk) => options.write(chunk), adoptedPaintedLines);\n const redraw = (): void => {\n if (disposed) return;\n const columns = resolveColumns(options);\n frame.redraw(\n paintLiveLines(\n lines,\n currentSpinner(options.unicode, options.refreshIntervalMs),\n Date.now(),\n columns,\n options.color === true,\n options.unicode,\n logPane\n ),\n columns\n );\n };\n\n const timer = setInterval(() => {\n if (disposed || !hasLiveAnimation(lines)) {\n return;\n }\n redraw();\n }, options.refreshIntervalMs);\n timer.unref();\n\n return {\n setLines(nextLines, nextLogPane) {\n lines = nextLines;\n logPane = nextLogPane;\n redraw();\n },\n writeLog(text) {\n if (disposed) {\n options.write(text);\n return;\n }\n frame.clear(resolveColumns(options));\n options.write(text);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n clearInterval(timer);\n frame.showCursor();\n },\n };\n}\n\nfunction resolveLiveTickerWorkerUrl(): URL {\n return import.meta.url.endsWith(\".ts\")\n ? new URL(\"../../dist/reporter/live-ticker-worker.js\", import.meta.url)\n : new URL(\"./live-ticker-worker.js\", import.meta.url);\n}\n\nfunction fileWorkerExecArgv(argv: readonly string[] = process.execArgv): string[] {\n const next: string[] = [];\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n if (arg === \"--input-type\") {\n index += 1;\n } else if (!arg.startsWith(\"--input-type=\")) {\n next.push(arg);\n }\n }\n return next;\n}\n\nfunction createWorkerTicker(options: LiveTickerOptions & { fd: number }): LiveTicker {\n const state = new TickerWorkerState();\n const { port1: framePort, port2: workerFramePort } = new MessageChannel();\n let worker: Worker;\n try {\n worker = new Worker(options.workerUrl ?? resolveLiveTickerWorkerUrl(), {\n execArgv: fileWorkerExecArgv(),\n transferList: [workerFramePort],\n workerData: {\n color: options.color === true,\n columns: resolveColumns(options),\n fd: options.fd,\n framePort: workerFramePort,\n refreshIntervalMs: options.refreshIntervalMs,\n stateBuffer: state.buffer,\n unicode: options.unicode,\n } satisfies LiveTickerWorkerData,\n });\n } catch (error) {\n framePort.close();\n workerFramePort.close();\n throw error;\n }\n let paintedLines: readonly string[] = [];\n framePort.on(\"message\", (nextLines: string[]) => {\n paintedLines = nextLines;\n });\n framePort.unref();\n let disposed = false;\n let inlineFallback: LiveTicker | undefined;\n let lines: readonly string[] = [];\n let logPane: readonly string[] | undefined;\n const pendingLogs: string[] = [];\n let acknowledgedLogs = 0;\n\n const restoreCursor = (): void => {\n try {\n if (isatty(options.fd)) {\n writeSync(options.fd, TICKER_ANSI.showCursor);\n } else {\n options.write(TICKER_ANSI.showCursor);\n }\n } catch {\n // The output may remain unavailable; cursor restore is best-effort.\n }\n };\n\n const dropAcknowledgedLogs = (): void => {\n const accepted = state.acceptedLogs;\n pendingLogs.splice(0, accepted - acknowledgedLogs);\n acknowledgedLogs = accepted;\n };\n\n const replayThrough = (ticker: LiveTicker): void => {\n dropAcknowledgedLogs();\n for (const text of pendingLogs) ticker.writeLog(text);\n pendingLogs.length = 0;\n ticker.setLines([...lines], logPane);\n };\n\n const createFallback = (): LiveTicker | undefined => {\n if (!state.claimOutput(OUTPUT_LOCK_TIMEOUT_MS)) return undefined;\n // dispose() blocks the event loop. Drain snapshots synchronously after taking\n // the output lock so adoption includes the worker's last completed paint.\n let snapshot;\n while ((snapshot = receiveMessageOnPort(framePort)) !== undefined) {\n paintedLines = snapshot.message as string[];\n }\n framePort.close();\n const ticker = createInlineTicker(options, paintedLines);\n replayThrough(ticker);\n return ticker;\n };\n\n const failToInline = (): void => {\n if (disposed || inlineFallback) return;\n state.releaseOutputAfterWorkerExit();\n inlineFallback = createFallback();\n };\n\n worker.on(\"error\", () => void worker.terminate());\n worker.on(\"exit\", () => failToInline());\n worker.unref();\n\n return {\n setLines(nextLines, nextLogPane) {\n if (disposed) return;\n lines = nextLines;\n logPane = nextLogPane;\n if (inlineFallback) {\n inlineFallback.setLines(nextLines, nextLogPane);\n return;\n }\n worker.postMessage({\n columns: resolveColumns(options),\n lines: [...nextLines],\n logPane,\n type: \"lines\",\n } satisfies TickerWorkerMessage);\n },\n writeLog(text) {\n if (inlineFallback) {\n inlineFallback.writeLog(text);\n return;\n }\n if (disposed) {\n options.write(text);\n return;\n }\n dropAcknowledgedLogs();\n pendingLogs.push(text);\n worker.postMessage({\n columns: resolveColumns(options),\n text,\n type: \"log\",\n } satisfies TickerWorkerMessage);\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n if (inlineFallback) {\n inlineFallback.dispose();\n void worker.terminate();\n return;\n }\n let restoreCursorAfterTerminate = false;\n try {\n let workerStopped = false;\n try {\n worker.postMessage({\n columns: resolveColumns(options),\n lines: [...lines],\n logPane,\n type: \"stop\",\n } satisfies TickerWorkerMessage);\n workerStopped = state.waitForStop(500);\n } catch {\n // The worker is unavailable; render its retained state below.\n }\n if (!workerStopped) {\n const ticker = createFallback();\n if (ticker) {\n ticker.dispose();\n } else {\n restoreCursorAfterTerminate = true;\n }\n }\n } finally {\n framePort.close();\n const terminated = worker.terminate();\n if (restoreCursorAfterTerminate) {\n restoreCursor();\n void terminated.then(restoreCursor);\n }\n }\n },\n };\n}\n\nfunction outputFd(fd: number | undefined): fd is number {\n return fd !== undefined && Number.isInteger(fd) && fd >= 0;\n}\n\nexport function createLiveTicker(options: LiveTickerOptions): LiveTicker {\n if (outputFd(options.fd)) {\n try {\n return createWorkerTicker({ ...options, fd: options.fd });\n } catch {\n // Some embeddings do not provide worker threads.\n }\n }\n return createInlineTicker(options);\n}\n"]}
@@ -89,7 +89,8 @@ export function createRunReporter(options) {
89
89
  const lastProgressMessage = new Map();
90
90
  const progressLogIntervalMs = 750;
91
91
  const ellipsis = unicodeEnabled ? "…" : "...";
92
- const displayName = (step) => safeTerminalText(step.name ?? step.id);
92
+ const displayName = (step) => safeTerminalText(step.name ?? step.id) +
93
+ (step.outputSource === "override" ? " (overridden)" : "");
93
94
  const clearProgress = (stepId) => {
94
95
  lastProgressLogAt.delete(stepId);
95
96
  lastProgressMessage.delete(stepId);
@@ -100,11 +101,11 @@ export function createRunReporter(options) {
100
101
  return;
101
102
  log.log(styled.pipeline(`Pipeline ${safeTerminalText(plan.pipelineId)}: starting (${plan.steps.length} steps, dryRun=${plan.dryRun})`));
102
103
  },
103
- onStepStart: ({ step }) => {
104
+ onStepStart: ({ step, outputSource }) => {
104
105
  const description = step.description
105
106
  ? ` - ${styled.description(safeTerminalText(step.description))}`
106
107
  : "";
107
- log.log(` ${styled.start(symbols.start)} ${displayName(step)}${description}`);
108
+ log.log(` ${styled.start(symbols.start)} ${displayName({ ...step, outputSource })}${description}`);
108
109
  },
109
110
  onStepProgress: ({ progress, step }) => {
110
111
  // Ignore empty/non-visible progress snapshots (no message, total, or work count).
@@ -141,15 +142,15 @@ export function createRunReporter(options) {
141
142
  const detail = safeTerminalText(event.dependencyId
142
143
  ? `${event.reason}: ${event.dependencyId}`
143
144
  : (event.message ?? event.reason));
144
- log.log(` ${styled.skip(symbols.skip)} ${displayName(event.step)} ${styled.duration(`(${detail})`)}`);
145
+ log.log(` ${styled.skip(symbols.skip)} ${displayName(event)} ${styled.duration(`(${detail})`)}`);
145
146
  },
146
147
  onStepCancel: (event) => {
147
148
  clearProgress(event.id);
148
- log.warn(` ${styled.skip(symbols.skip)} ${displayName(event.step)}: cancelled: ${safeTerminalText(event.error.message)}`);
149
+ log.warn(` ${styled.skip(symbols.skip)} ${displayName(event)}: cancelled: ${safeTerminalText(event.error.message)}`);
149
150
  },
150
151
  onStepFail: (event) => {
151
152
  clearProgress(event.id);
152
- log.error(` ${styled.fail(symbols.fail)} ${displayName(event.step)}: ${safeTerminalText(event.error.message)}`);
153
+ log.error(` ${styled.fail(symbols.fail)} ${displayName(event)}: ${safeTerminalText(event.error.message)}`);
153
154
  },
154
155
  onFinalizeStart: () => {
155
156
  log.log(` ${styled.start(symbols.start)} finalize`);
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/reporter/reporter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PipelineHooks, PipelineLogger } from \"../core/pipeline.js\";\nimport { hasVisibleStepProgress } from \"../core/progress.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\n/** Policy for ANSI color in terminal reporter output. */\nexport type ReporterColorMode = \"always\" | \"auto\" | \"never\";\n/** Symbol set used for step lifecycle markers in reporter output. */\nexport type ReporterSymbolMode = \"ascii\" | \"auto\" | \"emoji\" | \"unicode\";\n\n/** Detected or caller-overridden terminal rendering capabilities. */\nexport interface ReporterTerminalCapabilities {\n color: boolean;\n isTTY: boolean;\n unicode: boolean;\n}\n\n/** Presentation settings shared by plain and interactive pipeline reporters. */\nexport interface RunReporterConfig {\n /** Defaults to auto: color only when the output supports it. */\n color?: ReporterColorMode;\n /** Defaults to auto: Unicode in capable terminals, ASCII elsewhere. */\n symbols?: ReporterSymbolMode;\n /** Override detected capabilities, primarily for custom streams and tests. */\n terminal?: Partial<ReporterTerminalCapabilities>;\n /** Log the pipeline start summary. Defaults to true. */\n logPlan?: boolean;\n /** Log the final pipeline summary. Defaults to true. */\n logSummary?: boolean;\n}\n\nexport interface RunReporterOptions extends RunReporterConfig {\n log: PipelineLogger;\n}\n\nexport interface ReporterSymbols {\n complete: string;\n fail: string;\n pending: string;\n skip: string;\n start: string;\n}\n\nconst SYMBOLS = {\n ascii: { complete: \"ok\", fail: \"fail\", pending: \".\", skip: \"-\", start: \"->\" },\n // Distinct from pending (○): skipped work uses a yellow dash, not a green check.\n unicode: { complete: \"✓\", fail: \"✗\", pending: \"○\", skip: \"–\", start: \"→\" },\n emoji: { complete: \"✅\", fail: \"❌\", pending: \"▫️\", skip: \"⏭️\", start: \"⏳\" },\n} satisfies Record<Exclude<ReporterSymbolMode, \"auto\">, ReporterSymbols>;\n\nconst ANSI = {\n boldCyan: \"\\u001B[1;36m\",\n cyan: \"\\u001B[36m\",\n dim: \"\\u001B[2m\",\n green: \"\\u001B[32m\",\n red: \"\\u001B[31m\",\n reset: \"\\u001B[0m\",\n yellow: \"\\u001B[33m\",\n} as const;\n\nfunction detectTerminalCapabilities(\n overrides: Partial<ReporterTerminalCapabilities> = {}\n): ReporterTerminalCapabilities {\n const isTTY = overrides.isTTY ?? process.stdout.isTTY === true;\n const termIsDumb = process.env.TERM === \"dumb\";\n const forceColor = process.env.FORCE_COLOR;\n const autoColor =\n forceColor !== undefined\n ? forceColor !== \"0\"\n : process.env.NO_COLOR === undefined && isTTY && !termIsDumb;\n return {\n isTTY,\n color: overrides.color ?? autoColor,\n unicode: overrides.unicode ?? (isTTY && !termIsDumb),\n };\n}\n\nfunction resolveColorEnabled(\n mode: ReporterColorMode,\n capabilities: ReporterTerminalCapabilities\n): boolean {\n if (mode === \"always\") return true;\n if (mode === \"never\") return false;\n return capabilities.color;\n}\n\nfunction resolveSymbols(\n mode: ReporterSymbolMode,\n capabilities: ReporterTerminalCapabilities\n): ReporterSymbols {\n return SYMBOLS[mode === \"auto\" ? (capabilities.unicode ? \"unicode\" : \"ascii\") : mode];\n}\n\nfunction paint(enabled: boolean, code: string, value: string): string {\n return enabled ? `${code}${value}${ANSI.reset}` : value;\n}\n\nexport function formatDurationMs(durationMs: number): string {\n const ms = Math.max(0, Math.round(durationMs));\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) {\n const seconds = Math.round(ms / 100) / 10;\n if (seconds < 60) {\n return Number.isInteger(seconds) ? `${seconds}s` : `${seconds.toFixed(1)}s`;\n }\n }\n const totalSeconds = Math.round(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return seconds === 0 ? `${minutes}m` : `${minutes}m${seconds}s`;\n}\n\nexport interface ReporterTheme {\n capabilities: ReporterTerminalCapabilities;\n colorEnabled: boolean;\n styled: {\n complete(value: string): string;\n description(value: string): string;\n duration(value: string): string;\n fail(value: string): string;\n pipeline(value: string): string;\n skip(value: string): string;\n start(value: string): string;\n };\n symbols: ReporterSymbols;\n unicodeEnabled: boolean;\n}\n\nexport function createReporterTheme(config: RunReporterConfig = {}): ReporterTheme {\n const capabilities = detectTerminalCapabilities(config.terminal);\n const colorEnabled = resolveColorEnabled(config.color ?? \"auto\", capabilities);\n const symbolMode = config.symbols ?? \"auto\";\n const symbols = resolveSymbols(symbolMode, capabilities);\n const unicodeEnabled = symbolMode === \"auto\" ? capabilities.unicode : symbolMode !== \"ascii\";\n return {\n capabilities,\n colorEnabled,\n symbols,\n unicodeEnabled,\n styled: {\n complete: (value) => paint(colorEnabled, ANSI.green, value),\n description: (value) => paint(colorEnabled, ANSI.dim, value),\n duration: (value) => paint(colorEnabled, ANSI.dim, value),\n fail: (value) => paint(colorEnabled, ANSI.red, value),\n pipeline: (value) => paint(colorEnabled, ANSI.boldCyan, value),\n skip: (value) => paint(colorEnabled, ANSI.yellow, value),\n start: (value) => paint(colorEnabled, ANSI.cyan, value),\n },\n };\n}\n\n/** Create concise, append-only lifecycle logging for a pipeline run. */\nexport function createRunReporter<TResult = unknown>(\n options: RunReporterOptions\n): PipelineHooks<TResult> {\n const { log } = options;\n const logPlan = options.logPlan !== false;\n const logSummary = options.logSummary !== false;\n const { styled, symbols, unicodeEnabled } = createReporterTheme(options);\n // Throttle progress lines so concurrent mapped children stay readable.\n const lastProgressLogAt = new Map<string, number>();\n const lastProgressMessage = new Map<string, string>();\n const progressLogIntervalMs = 750;\n const ellipsis = unicodeEnabled ? \"…\" : \"...\";\n const displayName = (step: { id: string; name?: string }): string =>\n safeTerminalText(step.name ?? step.id);\n const clearProgress = (stepId: string): void => {\n lastProgressLogAt.delete(stepId);\n lastProgressMessage.delete(stepId);\n };\n\n return {\n onPipelineStart: (plan) => {\n if (!logPlan) return;\n log.log(\n styled.pipeline(\n `Pipeline ${safeTerminalText(plan.pipelineId)}: starting (${plan.steps.length} steps, dryRun=${plan.dryRun})`\n )\n );\n },\n onStepStart: ({ step }) => {\n const description = step.description\n ? ` - ${styled.description(safeTerminalText(step.description))}`\n : \"\";\n log.log(` ${styled.start(symbols.start)} ${displayName(step)}${description}`);\n },\n onStepProgress: ({ progress, step }) => {\n // Ignore empty/non-visible progress snapshots (no message, total, or work count).\n if (!hasVisibleStepProgress(progress)) return;\n\n const total =\n progress.total !== undefined && Number.isFinite(progress.total)\n ? String(progress.total)\n : \"?\";\n const message = progress.message ? ` ${safeTerminalText(progress.message)}` : \"\";\n const line = `${progress.completed}/${total}${message}`;\n const now = Date.now();\n const previousAt = lastProgressLogAt.get(step.id) ?? Number.NEGATIVE_INFINITY;\n const previousLine = lastProgressMessage.get(step.id);\n const isCompletion =\n progress.total !== undefined &&\n Number.isFinite(progress.total) &&\n progress.completed >= progress.total;\n if (!isCompletion && line === previousLine && now - previousAt < progressLogIntervalMs) {\n return;\n }\n if (!isCompletion && now - previousAt < progressLogIntervalMs && previousLine !== undefined) {\n return;\n }\n lastProgressLogAt.set(step.id, now);\n lastProgressMessage.set(step.id, line);\n log.log(` ${styled.description(ellipsis)} ${displayName(step)} ${styled.description(line)}`);\n },\n onStepComplete: (event) => {\n clearProgress(event.id);\n const durationMs = event.finishedAtMs - event.startedAtMs;\n log.log(\n ` ${styled.complete(symbols.complete)} ${displayName(event)} ${styled.duration(`(${formatDurationMs(durationMs)})`)}`\n );\n },\n onStepSkip: (event) => {\n clearProgress(event.id);\n const detail = safeTerminalText(\n event.dependencyId\n ? `${event.reason}: ${event.dependencyId}`\n : (event.message ?? event.reason)\n );\n log.log(\n ` ${styled.skip(symbols.skip)} ${displayName(event.step)} ${styled.duration(`(${detail})`)}`\n );\n },\n onStepCancel: (event) => {\n clearProgress(event.id);\n log.warn(\n ` ${styled.skip(symbols.skip)} ${displayName(event.step)}: cancelled: ${safeTerminalText(event.error.message)}`\n );\n },\n onStepFail: (event) => {\n clearProgress(event.id);\n log.error(\n ` ${styled.fail(symbols.fail)} ${displayName(event.step)}: ${safeTerminalText(event.error.message)}`\n );\n },\n onFinalizeStart: () => {\n log.log(` ${styled.start(symbols.start)} finalize`);\n },\n onFinalizeComplete: ({ durationMs }) => {\n log.log(\n ` ${styled.complete(symbols.complete)} finalize ${styled.duration(`(${formatDurationMs(durationMs)})`)}`\n );\n },\n onFinalizeError: ({ error }) => {\n log.error(` ${styled.fail(symbols.fail)} finalize: ${safeTerminalText(error.message)}`);\n },\n onPipelineComplete: (result) => {\n if (!logSummary) return;\n const durationMs = result.finishedAtMs - result.startedAtMs;\n const message = `Pipeline ${safeTerminalText(result.pipelineId)}: done in ${formatDurationMs(durationMs)} (status=${result.status}, steps=${result.steps.length}, errors=${result.errors.length})`;\n if (result.status === \"completed\") {\n log.log(styled.complete(message));\n } else {\n log.error(styled.fail(message));\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/reporter/reporter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PipelineHooks, PipelineLogger } from \"../core/pipeline.js\";\nimport { hasVisibleStepProgress } from \"../core/progress.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\n/** Policy for ANSI color in terminal reporter output. */\nexport type ReporterColorMode = \"always\" | \"auto\" | \"never\";\n/** Symbol set used for step lifecycle markers in reporter output. */\nexport type ReporterSymbolMode = \"ascii\" | \"auto\" | \"emoji\" | \"unicode\";\n\n/** Detected or caller-overridden terminal rendering capabilities. */\nexport interface ReporterTerminalCapabilities {\n color: boolean;\n isTTY: boolean;\n unicode: boolean;\n}\n\n/** Presentation settings shared by plain and interactive pipeline reporters. */\nexport interface RunReporterConfig {\n /** Defaults to auto: color only when the output supports it. */\n color?: ReporterColorMode;\n /** Defaults to auto: Unicode in capable terminals, ASCII elsewhere. */\n symbols?: ReporterSymbolMode;\n /** Override detected capabilities, primarily for custom streams and tests. */\n terminal?: Partial<ReporterTerminalCapabilities>;\n /** Log the pipeline start summary. Defaults to true. */\n logPlan?: boolean;\n /** Log the final pipeline summary. Defaults to true. */\n logSummary?: boolean;\n}\n\nexport interface RunReporterOptions extends RunReporterConfig {\n log: PipelineLogger;\n}\n\nexport interface ReporterSymbols {\n complete: string;\n fail: string;\n pending: string;\n skip: string;\n start: string;\n}\n\nconst SYMBOLS = {\n ascii: { complete: \"ok\", fail: \"fail\", pending: \".\", skip: \"-\", start: \"->\" },\n // Distinct from pending (○): skipped work uses a yellow dash, not a green check.\n unicode: { complete: \"✓\", fail: \"✗\", pending: \"○\", skip: \"–\", start: \"→\" },\n emoji: { complete: \"✅\", fail: \"❌\", pending: \"▫️\", skip: \"⏭️\", start: \"⏳\" },\n} satisfies Record<Exclude<ReporterSymbolMode, \"auto\">, ReporterSymbols>;\n\nconst ANSI = {\n boldCyan: \"\\u001B[1;36m\",\n cyan: \"\\u001B[36m\",\n dim: \"\\u001B[2m\",\n green: \"\\u001B[32m\",\n red: \"\\u001B[31m\",\n reset: \"\\u001B[0m\",\n yellow: \"\\u001B[33m\",\n} as const;\n\nfunction detectTerminalCapabilities(\n overrides: Partial<ReporterTerminalCapabilities> = {}\n): ReporterTerminalCapabilities {\n const isTTY = overrides.isTTY ?? process.stdout.isTTY === true;\n const termIsDumb = process.env.TERM === \"dumb\";\n const forceColor = process.env.FORCE_COLOR;\n const autoColor =\n forceColor !== undefined\n ? forceColor !== \"0\"\n : process.env.NO_COLOR === undefined && isTTY && !termIsDumb;\n return {\n isTTY,\n color: overrides.color ?? autoColor,\n unicode: overrides.unicode ?? (isTTY && !termIsDumb),\n };\n}\n\nfunction resolveColorEnabled(\n mode: ReporterColorMode,\n capabilities: ReporterTerminalCapabilities\n): boolean {\n if (mode === \"always\") return true;\n if (mode === \"never\") return false;\n return capabilities.color;\n}\n\nfunction resolveSymbols(\n mode: ReporterSymbolMode,\n capabilities: ReporterTerminalCapabilities\n): ReporterSymbols {\n return SYMBOLS[mode === \"auto\" ? (capabilities.unicode ? \"unicode\" : \"ascii\") : mode];\n}\n\nfunction paint(enabled: boolean, code: string, value: string): string {\n return enabled ? `${code}${value}${ANSI.reset}` : value;\n}\n\nexport function formatDurationMs(durationMs: number): string {\n const ms = Math.max(0, Math.round(durationMs));\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) {\n const seconds = Math.round(ms / 100) / 10;\n if (seconds < 60) {\n return Number.isInteger(seconds) ? `${seconds}s` : `${seconds.toFixed(1)}s`;\n }\n }\n const totalSeconds = Math.round(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return seconds === 0 ? `${minutes}m` : `${minutes}m${seconds}s`;\n}\n\nexport interface ReporterTheme {\n capabilities: ReporterTerminalCapabilities;\n colorEnabled: boolean;\n styled: {\n complete(value: string): string;\n description(value: string): string;\n duration(value: string): string;\n fail(value: string): string;\n pipeline(value: string): string;\n skip(value: string): string;\n start(value: string): string;\n };\n symbols: ReporterSymbols;\n unicodeEnabled: boolean;\n}\n\nexport function createReporterTheme(config: RunReporterConfig = {}): ReporterTheme {\n const capabilities = detectTerminalCapabilities(config.terminal);\n const colorEnabled = resolveColorEnabled(config.color ?? \"auto\", capabilities);\n const symbolMode = config.symbols ?? \"auto\";\n const symbols = resolveSymbols(symbolMode, capabilities);\n const unicodeEnabled = symbolMode === \"auto\" ? capabilities.unicode : symbolMode !== \"ascii\";\n return {\n capabilities,\n colorEnabled,\n symbols,\n unicodeEnabled,\n styled: {\n complete: (value) => paint(colorEnabled, ANSI.green, value),\n description: (value) => paint(colorEnabled, ANSI.dim, value),\n duration: (value) => paint(colorEnabled, ANSI.dim, value),\n fail: (value) => paint(colorEnabled, ANSI.red, value),\n pipeline: (value) => paint(colorEnabled, ANSI.boldCyan, value),\n skip: (value) => paint(colorEnabled, ANSI.yellow, value),\n start: (value) => paint(colorEnabled, ANSI.cyan, value),\n },\n };\n}\n\n/** Create concise, append-only lifecycle logging for a pipeline run. */\nexport function createRunReporter<TResult = unknown>(\n options: RunReporterOptions\n): PipelineHooks<TResult> {\n const { log } = options;\n const logPlan = options.logPlan !== false;\n const logSummary = options.logSummary !== false;\n const { styled, symbols, unicodeEnabled } = createReporterTheme(options);\n // Throttle progress lines so concurrent mapped children stay readable.\n const lastProgressLogAt = new Map<string, number>();\n const lastProgressMessage = new Map<string, string>();\n const progressLogIntervalMs = 750;\n const ellipsis = unicodeEnabled ? \"…\" : \"...\";\n const displayName = (step: { id: string; name?: string; outputSource?: \"override\" }): string =>\n safeTerminalText(step.name ?? step.id) +\n (step.outputSource === \"override\" ? \" (overridden)\" : \"\");\n const clearProgress = (stepId: string): void => {\n lastProgressLogAt.delete(stepId);\n lastProgressMessage.delete(stepId);\n };\n\n return {\n onPipelineStart: (plan) => {\n if (!logPlan) return;\n log.log(\n styled.pipeline(\n `Pipeline ${safeTerminalText(plan.pipelineId)}: starting (${plan.steps.length} steps, dryRun=${plan.dryRun})`\n )\n );\n },\n onStepStart: ({ step, outputSource }) => {\n const description = step.description\n ? ` - ${styled.description(safeTerminalText(step.description))}`\n : \"\";\n log.log(\n ` ${styled.start(symbols.start)} ${displayName({ ...step, outputSource })}${description}`\n );\n },\n onStepProgress: ({ progress, step }) => {\n // Ignore empty/non-visible progress snapshots (no message, total, or work count).\n if (!hasVisibleStepProgress(progress)) return;\n\n const total =\n progress.total !== undefined && Number.isFinite(progress.total)\n ? String(progress.total)\n : \"?\";\n const message = progress.message ? ` ${safeTerminalText(progress.message)}` : \"\";\n const line = `${progress.completed}/${total}${message}`;\n const now = Date.now();\n const previousAt = lastProgressLogAt.get(step.id) ?? Number.NEGATIVE_INFINITY;\n const previousLine = lastProgressMessage.get(step.id);\n const isCompletion =\n progress.total !== undefined &&\n Number.isFinite(progress.total) &&\n progress.completed >= progress.total;\n if (!isCompletion && line === previousLine && now - previousAt < progressLogIntervalMs) {\n return;\n }\n if (!isCompletion && now - previousAt < progressLogIntervalMs && previousLine !== undefined) {\n return;\n }\n lastProgressLogAt.set(step.id, now);\n lastProgressMessage.set(step.id, line);\n log.log(` ${styled.description(ellipsis)} ${displayName(step)} ${styled.description(line)}`);\n },\n onStepComplete: (event) => {\n clearProgress(event.id);\n const durationMs = event.finishedAtMs - event.startedAtMs;\n log.log(\n ` ${styled.complete(symbols.complete)} ${displayName(event)} ${styled.duration(`(${formatDurationMs(durationMs)})`)}`\n );\n },\n onStepSkip: (event) => {\n clearProgress(event.id);\n const detail = safeTerminalText(\n event.dependencyId\n ? `${event.reason}: ${event.dependencyId}`\n : (event.message ?? event.reason)\n );\n log.log(\n ` ${styled.skip(symbols.skip)} ${displayName(event)} ${styled.duration(`(${detail})`)}`\n );\n },\n onStepCancel: (event) => {\n clearProgress(event.id);\n log.warn(\n ` ${styled.skip(symbols.skip)} ${displayName(event)}: cancelled: ${safeTerminalText(event.error.message)}`\n );\n },\n onStepFail: (event) => {\n clearProgress(event.id);\n log.error(\n ` ${styled.fail(symbols.fail)} ${displayName(event)}: ${safeTerminalText(event.error.message)}`\n );\n },\n onFinalizeStart: () => {\n log.log(` ${styled.start(symbols.start)} finalize`);\n },\n onFinalizeComplete: ({ durationMs }) => {\n log.log(\n ` ${styled.complete(symbols.complete)} finalize ${styled.duration(`(${formatDurationMs(durationMs)})`)}`\n );\n },\n onFinalizeError: ({ error }) => {\n log.error(` ${styled.fail(symbols.fail)} finalize: ${safeTerminalText(error.message)}`);\n },\n onPipelineComplete: (result) => {\n if (!logSummary) return;\n const durationMs = result.finishedAtMs - result.startedAtMs;\n const message = `Pipeline ${safeTerminalText(result.pipelineId)}: done in ${formatDurationMs(durationMs)} (status=${result.status}, steps=${result.steps.length}, errors=${result.errors.length})`;\n if (result.status === \"completed\") {\n log.log(styled.complete(message));\n } else {\n log.error(styled.fail(message));\n }\n },\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { StoredPipelineDefinition, StoredPipelineEvent, StoredPipelineRun } from "./run-store.js";
2
+ /** Own observed definition replacement independently of run execution state. */
3
+ export declare class DefinitionProjection {
4
+ #private;
5
+ constructor(event: StoredPipelineEvent);
6
+ append(event: StoredPipelineEvent): void;
7
+ snapshot(pipelineRuns: readonly StoredPipelineRun[]): StoredPipelineDefinition;
8
+ }
@@ -0,0 +1,89 @@
1
+ function definitionStep(event) {
2
+ const step = {
3
+ dependencies: [...event.payload.dependencies],
4
+ dryRun: event.payload.dryRun,
5
+ id: event.stepId,
6
+ optionalDependencies: [...event.payload.optionalDependencies],
7
+ runtimeSkipPossible: event.payload.runtimeSkipPossible,
8
+ skipAfterFailureOf: [...event.payload.skipAfterFailureOf],
9
+ };
10
+ const description = event.payload.description;
11
+ if (description)
12
+ step.description = description;
13
+ const name = event.payload.name;
14
+ if (name)
15
+ step.name = name;
16
+ if (event.payload.nestedPipeline) {
17
+ step.nestedPipeline = {
18
+ ...event.payload.nestedPipeline,
19
+ stepIds: [...event.payload.nestedPipeline.stepIds],
20
+ };
21
+ }
22
+ if (event.payload.remote)
23
+ step.remote = { ...event.payload.remote };
24
+ return step;
25
+ }
26
+ /** Own observed definition replacement independently of run execution state. */
27
+ export class DefinitionProjection {
28
+ #snapshot;
29
+ #definitionRun;
30
+ #firstSeenAtMs;
31
+ #lastSeenAtMs;
32
+ #latestSteps = new Map();
33
+ #runStarts = new Map();
34
+ #targetIds = [];
35
+ constructor(event) {
36
+ this.#firstSeenAtMs = event.timestampMs;
37
+ this.#lastSeenAtMs = event.timestampMs;
38
+ this.append(event);
39
+ }
40
+ append(event) {
41
+ this.#firstSeenAtMs = Math.min(this.#firstSeenAtMs, event.timestampMs);
42
+ this.#lastSeenAtMs = Math.max(this.#lastSeenAtMs, event.timestampMs);
43
+ if (event.name === "pipeline.started") {
44
+ if (event.payload.definitionSnapshot)
45
+ this.#snapshot = structuredClone(event.payload.definitionSnapshot);
46
+ this.#runStarts.set(event.runId, {
47
+ atMs: event.timestampMs,
48
+ eventId: event.id,
49
+ targetIds: [...event.payload.targetIds],
50
+ });
51
+ }
52
+ if (event.name !== "step.planned" || !event.stepId)
53
+ return;
54
+ const start = this.#runStarts.get(event.runId);
55
+ if (!start)
56
+ return;
57
+ const current = this.#definitionRun;
58
+ if (!current ||
59
+ start.atMs > current.startedAtMs ||
60
+ (start.atMs === current.startedAtMs && start.eventId > current.startedEventId)) {
61
+ this.#definitionRun = {
62
+ id: event.runId,
63
+ startedAtMs: start.atMs,
64
+ startedEventId: start.eventId,
65
+ };
66
+ this.#latestSteps.clear();
67
+ this.#targetIds = start.targetIds;
68
+ }
69
+ if (event.runId === this.#definitionRun?.id) {
70
+ this.#latestSteps.set(event.stepId, definitionStep(event));
71
+ }
72
+ }
73
+ snapshot(pipelineRuns) {
74
+ const identity = pipelineRuns[0].definitionIdentity;
75
+ const snapshot = this.#snapshot;
76
+ return {
77
+ activeRuns: pipelineRuns.filter(({ status }) => status === "running").length,
78
+ firstSeenAtMs: this.#firstSeenAtMs,
79
+ lastSeenAtMs: this.#lastSeenAtMs,
80
+ pipelineId: pipelineRuns[0].pipelineId,
81
+ ...(identity ? { identity: { ...identity } } : {}),
82
+ ...(snapshot ? { snapshot: structuredClone(snapshot) } : {}),
83
+ runCount: pipelineRuns.length,
84
+ steps: [...this.#latestSteps.values()].map((step) => structuredClone(step)),
85
+ targetIds: [...(snapshot?.targetIds ?? this.#targetIds)],
86
+ };
87
+ }
88
+ }
89
+ //# sourceMappingURL=definition-projection.js.map