tubeless 0.2.11 → 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.
- package/dist/core/child-execution.d.ts +1 -24
- package/dist/core/child-execution.js +11 -13
- package/dist/core/child-execution.js.map +1 -1
- package/dist/core/child-progress.js +7 -2
- package/dist/core/child-progress.js.map +1 -1
- package/dist/core/iteration.d.ts +27 -0
- package/dist/core/iteration.js +111 -0
- package/dist/core/iteration.js.map +1 -0
- package/dist/core/lifecycle.d.ts +7 -5
- package/dist/core/lifecycle.js +36 -4
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/pipeline-artifacts.d.ts +11 -0
- package/dist/core/pipeline-artifacts.js +2 -0
- package/dist/core/pipeline-artifacts.js.map +1 -0
- package/dist/core/pipeline-compiler.d.ts +1 -0
- package/dist/core/pipeline-compiler.js +1 -0
- package/dist/core/pipeline-compiler.js.map +1 -1
- package/dist/core/pipeline-definition-identity.d.ts +2 -2
- package/dist/core/pipeline-definition-identity.js +28 -5
- package/dist/core/pipeline-definition-identity.js.map +1 -1
- package/dist/core/pipeline-execute.d.ts +1 -6
- package/dist/core/pipeline-execute.js +28 -215
- package/dist/core/pipeline-execute.js.map +1 -1
- package/dist/core/pipeline-execution-error.d.ts +35 -0
- package/dist/core/pipeline-execution-error.js +195 -0
- package/dist/core/pipeline-execution-error.js.map +1 -0
- package/dist/core/pipeline-identity.d.ts +1 -0
- package/dist/core/pipeline-identity.js +1 -0
- package/dist/core/pipeline-identity.js.map +1 -1
- package/dist/core/pipeline-mermaid.js +4 -1
- package/dist/core/pipeline-mermaid.js.map +1 -1
- package/dist/core/pipeline-run-state.d.ts +4 -4
- package/dist/core/pipeline-run-state.js +10 -16
- package/dist/core/pipeline-run-state.js.map +1 -1
- package/dist/core/pipeline-step-executor.d.ts +2 -0
- package/dist/core/pipeline-step-executor.js +11 -3
- package/dist/core/pipeline-step-executor.js.map +1 -1
- package/dist/core/pipeline-steps.d.ts +24 -1
- package/dist/core/pipeline-steps.js +62 -0
- package/dist/core/pipeline-steps.js.map +1 -1
- package/dist/core/pipeline-types.d.ts +28 -3
- package/dist/core/pipeline-types.js.map +1 -1
- package/dist/core/pipeline.d.ts +4 -1
- package/dist/core/pipeline.js +22 -4
- package/dist/core/pipeline.js.map +1 -1
- package/dist/project/project-compiler.d.ts +3 -31
- package/dist/project/project-compiler.js +11 -180
- package/dist/project/project-compiler.js.map +1 -1
- package/dist/project/project-registry.d.ts +44 -0
- package/dist/project/project-registry.js +107 -0
- package/dist/project/project-registry.js.map +1 -0
- package/dist/project/project-step-graph.d.ts +9 -0
- package/dist/project/project-step-graph.js +99 -0
- package/dist/project/project-step-graph.js.map +1 -0
- package/dist/render/render.js +1 -1
- package/dist/render/render.js.map +1 -1
- package/dist/reporter/interactive-reporter.js +6 -3
- package/dist/reporter/interactive-reporter.js.map +1 -1
- package/dist/reporter/live-ticker-frame.d.ts +21 -0
- package/dist/reporter/live-ticker-frame.js +196 -0
- package/dist/reporter/live-ticker-frame.js.map +1 -0
- package/dist/reporter/live-ticker-protocol.d.ts +41 -0
- package/dist/reporter/live-ticker-protocol.js +59 -0
- package/dist/reporter/live-ticker-protocol.js.map +1 -0
- package/dist/reporter/live-ticker-worker.js +11 -25
- package/dist/reporter/live-ticker-worker.js.map +1 -1
- package/dist/reporter/live-ticker.d.ts +0 -15
- package/dist/reporter/live-ticker.js +11 -216
- package/dist/reporter/live-ticker.js.map +1 -1
- package/dist/reporter/reporter.js +7 -6
- package/dist/reporter/reporter.js.map +1 -1
- package/dist/run-store/definition-projection.d.ts +8 -0
- package/dist/run-store/definition-projection.js +89 -0
- package/dist/run-store/definition-projection.js.map +1 -0
- package/dist/run-store/run-projection.d.ts +15 -0
- package/dist/run-store/run-projection.js +203 -0
- package/dist/run-store/run-projection.js.map +1 -0
- package/dist/run-store/run-store-codec.d.ts +2 -0
- package/dist/run-store/run-store-codec.js +11 -0
- package/dist/run-store/run-store-codec.js.map +1 -1
- package/dist/run-store/run-store-event-decoder.js +3 -0
- package/dist/run-store/run-store-event-decoder.js.map +1 -1
- package/dist/run-store/run-store-reader.d.ts +7 -0
- package/dist/run-store/run-store-reader.js +31 -0
- package/dist/run-store/run-store-reader.js.map +1 -0
- package/dist/run-store/run-store-sqlite.js +23 -7
- package/dist/run-store/run-store-sqlite.js.map +1 -1
- package/dist/run-store/run-store.d.ts +16 -4
- package/dist/run-store/run-store.js +14 -263
- package/dist/run-store/run-store.js.map +1 -1
- package/dist/studio/run-store-ui-api.d.ts +13 -0
- package/dist/studio/run-store-ui-api.js +163 -0
- package/dist/studio/run-store-ui-api.js.map +1 -0
- package/dist/studio/run-store-ui-client-browser.js +2 -2
- package/dist/studio/run-store-ui-client-transport.js +28 -3
- package/dist/studio/run-store-ui-client-transport.js.map +1 -1
- package/dist/studio/run-store-ui-client.d.ts +2 -1
- package/dist/studio/run-store-ui-client.js +15 -9
- package/dist/studio/run-store-ui-client.js.map +1 -1
- package/dist/studio/run-store-ui-http.d.ts +11 -0
- package/dist/studio/run-store-ui-http.js +52 -0
- package/dist/studio/run-store-ui-http.js.map +1 -1
- package/dist/studio/run-store-ui-state.d.ts +1 -1
- package/dist/studio/run-store-ui-state.js +10 -28
- package/dist/studio/run-store-ui-state.js.map +1 -1
- package/dist/studio/run-store-ui.d.ts +5 -11
- package/dist/studio/run-store-ui.js +5 -203
- package/dist/studio/run-store-ui.js.map +1 -1
- package/dist/testing/testing.d.ts +18 -2
- package/dist/testing/testing.js +35 -2
- package/dist/testing/testing.js.map +1 -1
- package/dist/tracing/artifact-metadata.d.ts +28 -0
- package/dist/tracing/artifact-metadata.js +105 -0
- package/dist/tracing/artifact-metadata.js.map +1 -0
- package/dist/tracing/tracing-codec.d.ts +1 -1
- package/dist/tracing/tracing-codec.js +1 -1
- package/dist/tracing/tracing-codec.js.map +1 -1
- package/dist/tracing/tracing-constants.d.ts +1 -1
- package/dist/tracing/tracing-constants.js +1 -1
- package/dist/tracing/tracing-constants.js.map +1 -1
- package/dist/tracing/tracing-contracts.d.ts +3 -1
- package/dist/tracing/tracing-contracts.js.map +1 -1
- package/dist/tracing/tracing-internal.d.ts +2 -0
- package/dist/tracing/tracing-internal.js +36 -13
- package/dist/tracing/tracing-internal.js.map +1 -1
- package/dist/tracing/tracing-schema.d.ts +330 -49
- package/dist/tracing/tracing-schema.js +102 -10
- package/dist/tracing/tracing-schema.js.map +1 -1
- package/dist/workbench/workbench-command-execution.d.ts +6 -0
- package/dist/workbench/workbench-command-execution.js +48 -0
- package/dist/workbench/workbench-command-execution.js.map +1 -0
- package/dist/workbench/workbench-history.js +11 -18
- package/dist/workbench/workbench-history.js.map +1 -1
- package/dist/workbench/workbench-launch-session.d.ts +2 -2
- package/dist/workbench/workbench-launch-session.js.map +1 -1
- package/dist/workbench/workbench-run.d.ts +0 -4
- package/dist/workbench/workbench-run.js +3 -47
- package/dist/workbench/workbench-run.js.map +1 -1
- package/dist/workbench/workbench-studio-launcher.d.ts +27 -0
- package/dist/workbench/workbench-studio-launcher.js +95 -0
- package/dist/workbench/workbench-studio-launcher.js.map +1 -0
- package/dist/workbench/workbench-ui.js +10 -83
- package/dist/workbench/workbench-ui.js.map +1 -1
- package/docs/README.md +13 -7
- package/docs/agent-guide.md +75 -6
- package/docs/airflow.md +187 -0
- package/docs/api-reference.md +87 -76
- package/docs/api-report.json +17 -6
- package/docs/artifacts.md +173 -0
- package/docs/child-pipeline-composition.md +87 -8
- package/docs/comparison.md +20 -0
- package/docs/concepts.md +79 -2
- package/docs/dagster.md +161 -0
- package/docs/inngest.md +163 -0
- package/docs/llms.txt +30 -1
- package/docs/recipes.md +82 -32
- package/docs/remote-step-composition.md +6 -0
- package/docs/step-functions.md +190 -0
- package/docs/studio.md +31 -12
- package/docs/temporal.md +183 -0
- package/examples/airflow/contract.ts +46 -0
- package/examples/airflow/hosted.ts +70 -0
- package/examples/airflow/remote.ts +175 -0
- package/examples/airflow/tubeless_example.py +49 -0
- package/examples/airflow/worker.ts +24 -0
- package/examples/artifact-lineage.ts +70 -0
- package/examples/dagster/definitions.py +59 -0
- package/examples/dagster/hosted.ts +78 -0
- package/examples/dagster/pipeline.ts +62 -0
- package/examples/dagster/test_definitions.py +47 -0
- package/examples/dagster/tsconfig.build.json +10 -0
- package/examples/dagster/worker.ts +22 -0
- package/examples/inherited-inputs.ts +28 -0
- package/examples/inngest/client.ts +4 -0
- package/examples/inngest/functions.ts +65 -0
- package/examples/inngest/pipeline.ts +41 -0
- package/examples/inngest/send.ts +11 -0
- package/examples/inngest/server.ts +17 -0
- package/examples/inngest/tsconfig.build.json +10 -0
- package/examples/iteration.ts +52 -0
- package/examples/parameterized-steps.ts +96 -0
- package/examples/project/tubeless.project.ts +50 -0
- package/examples/step-functions/handler.ts +110 -0
- package/examples/step-functions/input.json +1 -0
- package/examples/step-functions/pipeline.ts +41 -0
- package/examples/step-functions/state-machine.asl.json +41 -0
- package/examples/step-functions/template.json +42 -0
- package/examples/step-output-overrides.ts +41 -0
- package/examples/temporal/activities.ts +94 -0
- package/examples/temporal/client.ts +19 -0
- package/examples/temporal/pipeline.ts +41 -0
- package/examples/temporal/tsconfig.build.json +10 -0
- package/examples/temporal/worker.ts +21 -0
- package/examples/temporal/workflows.ts +16 -0
- package/package.json +13 -4
- package/skills/tubeless/SKILL.md +37 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-ticker-frame.js","sourceRoot":"","sources":["../../src/reporter/live-ticker-frame.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatDurationMs } from \"./reporter.js\";\n\nexport const SPINNER_TOKEN = \"\\u0001\";\nconst ELAPSED_TOKEN_START = \"\\u0002\";\nconst ELAPSED_TOKEN_END = \"\\u0003\";\nconst SHIMMER_TOKEN_START = \"\\u0004\";\nconst SHIMMER_TOKEN_END = \"\\u0005\";\n\nexport const TICKER_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;\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 ? TICKER_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 = TICKER_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}${TICKER_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 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(TICKER_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${TICKER_ANSI.clearDown}`);\n this.paintedLines = [];\n }\n\n redraw(lines: readonly string[], columns?: number): void {\n if (!this.cursorHidden) {\n this.write(TICKER_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\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\nexport function hasLiveAnimation(lines: readonly string[]): boolean {\n return lines.some((line) => line.includes(SPINNER_TOKEN) || line.includes(SHIMMER_TOKEN_START));\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MessagePort } from "node:worker_threads";
|
|
2
|
+
export interface LiveTickerWorkerData {
|
|
3
|
+
color: boolean;
|
|
4
|
+
columns?: number;
|
|
5
|
+
fd: number;
|
|
6
|
+
framePort: MessagePort;
|
|
7
|
+
refreshIntervalMs: number;
|
|
8
|
+
stateBuffer: SharedArrayBuffer;
|
|
9
|
+
unicode: boolean;
|
|
10
|
+
}
|
|
11
|
+
export type TickerWorkerMessage = {
|
|
12
|
+
columns?: number;
|
|
13
|
+
lines: string[];
|
|
14
|
+
logPane?: readonly string[];
|
|
15
|
+
type: "lines";
|
|
16
|
+
} | {
|
|
17
|
+
columns?: number;
|
|
18
|
+
text: string;
|
|
19
|
+
type: "log";
|
|
20
|
+
} | {
|
|
21
|
+
columns?: number;
|
|
22
|
+
lines: string[];
|
|
23
|
+
logPane?: readonly string[];
|
|
24
|
+
type: "stop";
|
|
25
|
+
};
|
|
26
|
+
/** Shared output ownership and acknowledgements, viewed from either thread. */
|
|
27
|
+
export declare class TickerWorkerState {
|
|
28
|
+
#private;
|
|
29
|
+
readonly buffer: SharedArrayBuffer;
|
|
30
|
+
constructor(buffer?: SharedArrayBuffer);
|
|
31
|
+
get acceptedLogs(): number;
|
|
32
|
+
acknowledgeLog(): void;
|
|
33
|
+
get inlineRequested(): boolean;
|
|
34
|
+
markStopped(): void;
|
|
35
|
+
waitForStop(timeoutMs: number): boolean;
|
|
36
|
+
withWorkerOutput(write: () => void): void;
|
|
37
|
+
/** Revoke worker writes, then acquire exclusive output ownership within the deadline. */
|
|
38
|
+
claimOutput(timeoutMs: number): boolean;
|
|
39
|
+
/** Only an exit event guarantees that an abandoned lock no longer protects a write. */
|
|
40
|
+
releaseOutputAfterWorkerExit(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const STOPPED = 0;
|
|
2
|
+
const ACCEPTED_LOGS = 1;
|
|
3
|
+
const INLINE_REQUESTED = 2;
|
|
4
|
+
const OUTPUT_LOCK = 3;
|
|
5
|
+
/** Shared output ownership and acknowledgements, viewed from either thread. */
|
|
6
|
+
export class TickerWorkerState {
|
|
7
|
+
buffer;
|
|
8
|
+
#state;
|
|
9
|
+
constructor(buffer = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT)) {
|
|
10
|
+
this.buffer = buffer;
|
|
11
|
+
this.#state = new Int32Array(buffer);
|
|
12
|
+
}
|
|
13
|
+
get acceptedLogs() {
|
|
14
|
+
return Atomics.load(this.#state, ACCEPTED_LOGS);
|
|
15
|
+
}
|
|
16
|
+
acknowledgeLog() {
|
|
17
|
+
Atomics.add(this.#state, ACCEPTED_LOGS, 1);
|
|
18
|
+
}
|
|
19
|
+
get inlineRequested() {
|
|
20
|
+
return Atomics.load(this.#state, INLINE_REQUESTED) === 1;
|
|
21
|
+
}
|
|
22
|
+
markStopped() {
|
|
23
|
+
Atomics.store(this.#state, STOPPED, 1);
|
|
24
|
+
Atomics.notify(this.#state, STOPPED);
|
|
25
|
+
}
|
|
26
|
+
waitForStop(timeoutMs) {
|
|
27
|
+
return Atomics.wait(this.#state, STOPPED, 0, timeoutMs) !== "timed-out";
|
|
28
|
+
}
|
|
29
|
+
withWorkerOutput(write) {
|
|
30
|
+
while (Atomics.compareExchange(this.#state, OUTPUT_LOCK, 0, 1) !== 0) {
|
|
31
|
+
Atomics.wait(this.#state, OUTPUT_LOCK, 1);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
if (!this.inlineRequested)
|
|
35
|
+
write();
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
Atomics.store(this.#state, OUTPUT_LOCK, 0);
|
|
39
|
+
Atomics.notify(this.#state, OUTPUT_LOCK);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Revoke worker writes, then acquire exclusive output ownership within the deadline. */
|
|
43
|
+
claimOutput(timeoutMs) {
|
|
44
|
+
Atomics.store(this.#state, INLINE_REQUESTED, 1);
|
|
45
|
+
const deadline = Date.now() + timeoutMs;
|
|
46
|
+
while (Atomics.compareExchange(this.#state, OUTPUT_LOCK, 0, 1) !== 0) {
|
|
47
|
+
const remainingMs = deadline - Date.now();
|
|
48
|
+
if (remainingMs <= 0)
|
|
49
|
+
return false;
|
|
50
|
+
Atomics.wait(this.#state, OUTPUT_LOCK, 1, remainingMs);
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/** Only an exit event guarantees that an abandoned lock no longer protects a write. */
|
|
55
|
+
releaseOutputAfterWorkerExit() {
|
|
56
|
+
Atomics.store(this.#state, OUTPUT_LOCK, 0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=live-ticker-protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"live-ticker-protocol.js","sourceRoot":"","sources":["../../src/reporter/live-ticker-protocol.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,GAAG,CAAC,CAAC;AAClB,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,+EAA+E;AAC/E,MAAM,OAAO,iBAAiB;IAGP,MAAM;IAFlB,MAAM,CAAa;IAE5B,YAAqB,MAAM,GAAG,IAAI,iBAAiB,CAAC,CAAC,GAAG,UAAU,CAAC,iBAAiB,CAAC;sBAAhE,MAAM;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAClD,CAAC;IAED,cAAc;QACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,eAAe;QACjB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,WAAW;QACT,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,KAAK,WAAW,CAAC;IAC1E,CAAC;IAED,gBAAgB,CAAC,KAAiB;QAChC,OAAO,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;QAC5C,CAAC;QACD,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,eAAe;gBAAE,KAAK,EAAE,CAAC;QACrC,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;YAC3C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,yFAAyF;IACzF,WAAW,CAAC,SAAiB;QAC3B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACrE,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1C,IAAI,WAAW,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uFAAuF;IACvF,4BAA4B;QAC1B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF","sourcesContent":["import type { MessagePort } from \"node:worker_threads\";\n\nexport interface LiveTickerWorkerData {\n color: boolean;\n columns?: number;\n fd: number;\n framePort: MessagePort;\n refreshIntervalMs: number;\n stateBuffer: SharedArrayBuffer;\n unicode: boolean;\n}\n\nexport type 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\nconst STOPPED = 0;\nconst ACCEPTED_LOGS = 1;\nconst INLINE_REQUESTED = 2;\nconst OUTPUT_LOCK = 3;\n\n/** Shared output ownership and acknowledgements, viewed from either thread. */\nexport class TickerWorkerState {\n readonly #state: Int32Array;\n\n constructor(readonly buffer = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT)) {\n this.#state = new Int32Array(buffer);\n }\n\n get acceptedLogs(): number {\n return Atomics.load(this.#state, ACCEPTED_LOGS);\n }\n\n acknowledgeLog(): void {\n Atomics.add(this.#state, ACCEPTED_LOGS, 1);\n }\n\n get inlineRequested(): boolean {\n return Atomics.load(this.#state, INLINE_REQUESTED) === 1;\n }\n\n markStopped(): void {\n Atomics.store(this.#state, STOPPED, 1);\n Atomics.notify(this.#state, STOPPED);\n }\n\n waitForStop(timeoutMs: number): boolean {\n return Atomics.wait(this.#state, STOPPED, 0, timeoutMs) !== \"timed-out\";\n }\n\n withWorkerOutput(write: () => void): void {\n while (Atomics.compareExchange(this.#state, OUTPUT_LOCK, 0, 1) !== 0) {\n Atomics.wait(this.#state, OUTPUT_LOCK, 1);\n }\n try {\n if (!this.inlineRequested) write();\n } finally {\n Atomics.store(this.#state, OUTPUT_LOCK, 0);\n Atomics.notify(this.#state, OUTPUT_LOCK);\n }\n }\n\n /** Revoke worker writes, then acquire exclusive output ownership within the deadline. */\n claimOutput(timeoutMs: number): boolean {\n Atomics.store(this.#state, INLINE_REQUESTED, 1);\n const deadline = Date.now() + timeoutMs;\n while (Atomics.compareExchange(this.#state, OUTPUT_LOCK, 0, 1) !== 0) {\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) return false;\n Atomics.wait(this.#state, OUTPUT_LOCK, 1, remainingMs);\n }\n return true;\n }\n\n /** Only an exit event guarantees that an abandoned lock no longer protects a write. */\n releaseOutputAfterWorkerExit(): void {\n Atomics.store(this.#state, OUTPUT_LOCK, 0);\n }\n}\n"]}
|
|
@@ -1,61 +1,48 @@
|
|
|
1
1
|
import { writeSync } from "node:fs";
|
|
2
2
|
import { parentPort, workerData } from "node:worker_threads";
|
|
3
|
-
import { currentSpinner, paintLiveLines,
|
|
3
|
+
import { currentSpinner, paintLiveLines, hasLiveAnimation, TickerFrame, } from "./live-ticker-frame.js";
|
|
4
|
+
import { TickerWorkerState, } from "./live-ticker-protocol.js";
|
|
4
5
|
const port = parentPort;
|
|
5
6
|
if (port === null)
|
|
6
7
|
throw new Error("live-ticker-worker must run in a worker thread");
|
|
7
8
|
// SAFETY: createWorkerTicker owns the workerData shape.
|
|
8
9
|
const data = workerData;
|
|
9
|
-
|
|
10
|
-
const state = new Int32Array(data.stateBuffer);
|
|
10
|
+
const state = new TickerWorkerState(data.stateBuffer);
|
|
11
11
|
const frame = new TickerFrame((chunk) => writeSync(data.fd, chunk));
|
|
12
12
|
let columns = data.columns;
|
|
13
13
|
let lines = [];
|
|
14
14
|
let logPane;
|
|
15
|
-
function withOutputLock(write) {
|
|
16
|
-
while (Atomics.compareExchange(state, 3, 0, 1) !== 0) {
|
|
17
|
-
Atomics.wait(state, 3, 1);
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
if (Atomics.load(state, 2) === 0)
|
|
21
|
-
write();
|
|
22
|
-
}
|
|
23
|
-
finally {
|
|
24
|
-
Atomics.store(state, 3, 0);
|
|
25
|
-
Atomics.notify(state, 3);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
15
|
function paintFrame() {
|
|
29
16
|
const painted = paintLiveLines(lines, currentSpinner(data.unicode, data.refreshIntervalMs), Date.now(), columns, data.color, data.unicode, logPane);
|
|
30
17
|
frame.redraw(painted, columns);
|
|
31
18
|
data.framePort.postMessage(painted);
|
|
32
19
|
}
|
|
33
20
|
function redraw() {
|
|
34
|
-
|
|
21
|
+
state.withWorkerOutput(paintFrame);
|
|
35
22
|
}
|
|
36
23
|
const timer = setInterval(() => {
|
|
37
|
-
if (
|
|
24
|
+
if (state.inlineRequested) {
|
|
38
25
|
clearInterval(timer);
|
|
39
26
|
port.close();
|
|
40
27
|
return;
|
|
41
28
|
}
|
|
42
|
-
if (lines
|
|
29
|
+
if (hasLiveAnimation(lines)) {
|
|
43
30
|
redraw();
|
|
44
31
|
}
|
|
45
32
|
}, data.refreshIntervalMs);
|
|
46
33
|
port.on("message", (message) => {
|
|
47
|
-
if (
|
|
34
|
+
if (state.inlineRequested) {
|
|
48
35
|
clearInterval(timer);
|
|
49
36
|
port.close();
|
|
50
37
|
return;
|
|
51
38
|
}
|
|
52
39
|
columns = message.columns ?? columns;
|
|
53
40
|
if (message.type === "log") {
|
|
54
|
-
|
|
41
|
+
state.withWorkerOutput(() => {
|
|
55
42
|
frame.clear(columns);
|
|
56
43
|
data.framePort.postMessage([]);
|
|
57
44
|
writeSync(data.fd, message.text);
|
|
58
|
-
|
|
45
|
+
state.acknowledgeLog();
|
|
59
46
|
});
|
|
60
47
|
return;
|
|
61
48
|
}
|
|
@@ -67,12 +54,11 @@ port.on("message", (message) => {
|
|
|
67
54
|
}
|
|
68
55
|
clearInterval(timer);
|
|
69
56
|
try {
|
|
70
|
-
|
|
57
|
+
state.withWorkerOutput(() => {
|
|
71
58
|
paintFrame();
|
|
72
59
|
frame.showCursor();
|
|
73
60
|
});
|
|
74
|
-
|
|
75
|
-
Atomics.notify(state, 0);
|
|
61
|
+
state.markStopped();
|
|
76
62
|
}
|
|
77
63
|
finally {
|
|
78
64
|
port.close();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-ticker-worker.js","sourceRoot":"","sources":["../../src/reporter/live-ticker-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"live-ticker-worker.js","sourceRoot":"","sources":["../../src/reporter/live-ticker-worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeSync } from \"node:fs\";\nimport { parentPort, workerData } from \"node:worker_threads\";\nimport {\n currentSpinner,\n paintLiveLines,\n hasLiveAnimation,\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 port = parentPort;\nif (port === null) throw new Error(\"live-ticker-worker must run in a worker thread\");\n\n// SAFETY: createWorkerTicker owns the workerData shape.\nconst data = workerData as LiveTickerWorkerData;\nconst state = new TickerWorkerState(data.stateBuffer);\nconst frame = new TickerFrame((chunk) => writeSync(data.fd, chunk));\nlet columns = data.columns;\nlet lines: string[] = [];\nlet logPane: readonly string[] | undefined;\n\nfunction paintFrame(): void {\n const painted = paintLiveLines(\n lines,\n currentSpinner(data.unicode, data.refreshIntervalMs),\n Date.now(),\n columns,\n data.color,\n data.unicode,\n logPane\n );\n frame.redraw(painted, columns);\n data.framePort.postMessage(painted);\n}\n\nfunction redraw(): void {\n state.withWorkerOutput(paintFrame);\n}\n\nconst timer = setInterval(() => {\n if (state.inlineRequested) {\n clearInterval(timer);\n port.close();\n return;\n }\n if (hasLiveAnimation(lines)) {\n redraw();\n }\n}, data.refreshIntervalMs);\n\nport.on(\"message\", (message: TickerWorkerMessage) => {\n if (state.inlineRequested) {\n clearInterval(timer);\n port.close();\n return;\n }\n columns = message.columns ?? columns;\n if (message.type === \"log\") {\n state.withWorkerOutput(() => {\n frame.clear(columns);\n data.framePort.postMessage([]);\n writeSync(data.fd, message.text);\n state.acknowledgeLog();\n });\n return;\n }\n lines = message.lines;\n logPane = message.logPane;\n if (message.type === \"lines\") {\n redraw();\n return;\n }\n clearInterval(timer);\n try {\n state.withWorkerOutput(() => {\n paintFrame();\n frame.showCursor();\n });\n state.markStopped();\n } finally {\n port.close();\n }\n});\n"]}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export declare const SPINNER_TOKEN = "\u0001";
|
|
2
|
-
export declare const SHIMMER_TOKEN_START = "\u0004";
|
|
3
|
-
export declare function elapsedToken(startedAtMs: number): string;
|
|
4
|
-
export declare function shimmerToken(value: string): string;
|
|
5
|
-
export declare function paintLiveLines(lines: readonly string[], spinner: string, nowMs: number, columns?: number, color?: boolean, unicode?: boolean, logPane?: readonly string[]): string[];
|
|
6
1
|
export interface LiveTicker {
|
|
7
2
|
setLines(lines: readonly string[], logPane?: readonly string[]): void;
|
|
8
3
|
writeLog(text: string): void;
|
|
@@ -18,14 +13,4 @@ export interface LiveTickerOptions {
|
|
|
18
13
|
write(chunk: string): void;
|
|
19
14
|
workerUrl?: URL;
|
|
20
15
|
}
|
|
21
|
-
export declare class TickerFrame {
|
|
22
|
-
private readonly write;
|
|
23
|
-
private paintedLines;
|
|
24
|
-
private cursorHidden;
|
|
25
|
-
constructor(write: (chunk: string) => void, paintedLines?: readonly string[]);
|
|
26
|
-
showCursor(): void;
|
|
27
|
-
clear(columns?: number): void;
|
|
28
|
-
redraw(lines: readonly string[], columns?: number): void;
|
|
29
|
-
}
|
|
30
|
-
export declare function currentSpinner(unicode: boolean, refreshIntervalMs: number): string;
|
|
31
16
|
export declare function createLiveTicker(options: LiveTickerOptions): LiveTicker;
|
|
@@ -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 {
|
|
5
|
-
|
|
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
|
-
|
|
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,
|
|
107
|
+
writeSync(options.fd, TICKER_ANSI.showCursor);
|
|
301
108
|
}
|
|
302
109
|
else {
|
|
303
|
-
options.write(
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
205
|
+
workerStopped = state.waitForStop(500);
|
|
411
206
|
}
|
|
412
207
|
catch {
|
|
413
208
|
// The worker is unavailable; render its retained state below.
|