tubeless 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/abort.d.ts +12 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +49 -0
- package/dist/abort.js.map +1 -0
- package/dist/batch.d.ts +22 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +73 -0
- package/dist/batch.js.map +1 -0
- package/dist/checkpoint.d.ts +33 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint.js +71 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/child-execution.d.ts +30 -0
- package/dist/child-execution.d.ts.map +1 -0
- package/dist/child-execution.js +270 -0
- package/dist/child-execution.js.map +1 -0
- package/dist/cli-command.d.ts +29 -0
- package/dist/cli-command.d.ts.map +1 -0
- package/dist/cli-command.js +314 -0
- package/dist/cli-command.js.map +1 -0
- package/dist/cli-parser.d.ts +28 -0
- package/dist/cli-parser.d.ts.map +1 -0
- package/dist/cli-parser.js +557 -0
- package/dist/cli-parser.js.map +1 -0
- package/dist/cli-pipeline-command.d.ts +84 -0
- package/dist/cli-pipeline-command.d.ts.map +1 -0
- package/dist/cli-pipeline-command.js +185 -0
- package/dist/cli-pipeline-command.js.map +1 -0
- package/dist/cli-types.d.ts +220 -0
- package/dist/cli-types.d.ts.map +1 -0
- package/dist/cli-types.js +19 -0
- package/dist/cli-types.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +8 -0
- package/dist/env.js.map +1 -0
- package/dist/file-utils.d.ts +4 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/file-utils.js +35 -0
- package/dist/file-utils.js.map +1 -0
- package/dist/interactive-reporter.d.ts +38 -0
- package/dist/interactive-reporter.d.ts.map +1 -0
- package/dist/interactive-reporter.js +308 -0
- package/dist/interactive-reporter.js.map +1 -0
- package/dist/lifecycle.d.ts +17 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +77 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/live-ticker.d.ts +21 -0
- package/dist/live-ticker.d.ts.map +1 -0
- package/dist/live-ticker.js +377 -0
- package/dist/live-ticker.js.map +1 -0
- package/dist/mapped-child-progress.d.ts +109 -0
- package/dist/mapped-child-progress.d.ts.map +1 -0
- package/dist/mapped-child-progress.js +133 -0
- package/dist/mapped-child-progress.js.map +1 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +5 -0
- package/dist/node.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/pipeline-command-marker.d.ts +5 -0
- package/dist/pipeline-command-marker.d.ts.map +1 -0
- package/dist/pipeline-command-marker.js +21 -0
- package/dist/pipeline-command-marker.js.map +1 -0
- package/dist/pipeline-diagnostics.d.ts +4 -0
- package/dist/pipeline-diagnostics.d.ts.map +1 -0
- package/dist/pipeline-diagnostics.js +17 -0
- package/dist/pipeline-diagnostics.js.map +1 -0
- package/dist/pipeline-module.d.ts +62 -0
- package/dist/pipeline-module.d.ts.map +1 -0
- package/dist/pipeline-module.js +157 -0
- package/dist/pipeline-module.js.map +1 -0
- package/dist/pipeline.d.ts +606 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +1444 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/progress.d.ts +4 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +8 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt-select.d.ts +81 -0
- package/dist/prompt-select.d.ts.map +1 -0
- package/dist/prompt-select.js +197 -0
- package/dist/prompt-select.js.map +1 -0
- package/dist/rate-limit.d.ts +7 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +23 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/render.d.ts +21 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +60 -0
- package/dist/render.js.map +1 -0
- package/dist/reporter-entry.d.ts +3 -0
- package/dist/reporter-entry.d.ts.map +1 -0
- package/dist/reporter-entry.js +3 -0
- package/dist/reporter-entry.js.map +1 -0
- package/dist/reporter.d.ts +50 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +167 -0
- package/dist/reporter.js.map +1 -0
- package/dist/retry.d.ts +28 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +59 -0
- package/dist/retry.js.map +1 -0
- package/dist/run-store-sqlite.d.ts +12 -0
- package/dist/run-store-sqlite.d.ts.map +1 -0
- package/dist/run-store-sqlite.js +187 -0
- package/dist/run-store-sqlite.js.map +1 -0
- package/dist/run-store-ui-http.d.ts +5 -0
- package/dist/run-store-ui-http.d.ts.map +1 -0
- package/dist/run-store-ui-http.js +19 -0
- package/dist/run-store-ui-http.js.map +1 -0
- package/dist/run-store-ui-page.d.ts +2 -0
- package/dist/run-store-ui-page.d.ts.map +1 -0
- package/dist/run-store-ui-page.js +759 -0
- package/dist/run-store-ui-page.js.map +1 -0
- package/dist/run-store-ui-protocol.d.ts +28 -0
- package/dist/run-store-ui-protocol.d.ts.map +1 -0
- package/dist/run-store-ui-protocol.js +84 -0
- package/dist/run-store-ui-protocol.js.map +1 -0
- package/dist/run-store-ui-state.d.ts +21 -0
- package/dist/run-store-ui-state.d.ts.map +1 -0
- package/dist/run-store-ui-state.js +65 -0
- package/dist/run-store-ui-state.js.map +1 -0
- package/dist/run-store-ui.d.ts +25 -0
- package/dist/run-store-ui.d.ts.map +1 -0
- package/dist/run-store-ui.js +217 -0
- package/dist/run-store-ui.js.map +1 -0
- package/dist/run-store.d.ts +109 -0
- package/dist/run-store.d.ts.map +1 -0
- package/dist/run-store.js +345 -0
- package/dist/run-store.js.map +1 -0
- package/dist/testing.d.ts +40 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +83 -0
- package/dist/testing.js.map +1 -0
- package/dist/tracing-internal.d.ts +21 -0
- package/dist/tracing-internal.d.ts.map +1 -0
- package/dist/tracing-internal.js +206 -0
- package/dist/tracing-internal.js.map +1 -0
- package/dist/tracing-json.d.ts +12 -0
- package/dist/tracing-json.d.ts.map +1 -0
- package/dist/tracing-json.js +8 -0
- package/dist/tracing-json.js.map +1 -0
- package/dist/tracing-otel.d.ts +36 -0
- package/dist/tracing-otel.d.ts.map +1 -0
- package/dist/tracing-otel.js +60 -0
- package/dist/tracing-otel.js.map +1 -0
- package/dist/tracing.d.ts +48 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +2 -0
- package/dist/tracing.js.map +1 -0
- package/dist/workbench-bin.d.ts +3 -0
- package/dist/workbench-bin.d.ts.map +1 -0
- package/dist/workbench-bin.js +8 -0
- package/dist/workbench-bin.js.map +1 -0
- package/dist/workbench-graph.d.ts +3 -0
- package/dist/workbench-graph.d.ts.map +1 -0
- package/dist/workbench-graph.js +64 -0
- package/dist/workbench-graph.js.map +1 -0
- package/dist/workbench-inspect.d.ts +3 -0
- package/dist/workbench-inspect.d.ts.map +1 -0
- package/dist/workbench-inspect.js +65 -0
- package/dist/workbench-inspect.js.map +1 -0
- package/dist/workbench-plan.d.ts +3 -0
- package/dist/workbench-plan.d.ts.map +1 -0
- package/dist/workbench-plan.js +72 -0
- package/dist/workbench-plan.js.map +1 -0
- package/dist/workbench-run.d.ts +13 -0
- package/dist/workbench-run.d.ts.map +1 -0
- package/dist/workbench-run.js +115 -0
- package/dist/workbench-run.js.map +1 -0
- package/dist/workbench-shared.d.ts +67 -0
- package/dist/workbench-shared.d.ts.map +1 -0
- package/dist/workbench-shared.js +163 -0
- package/dist/workbench-shared.js.map +1 -0
- package/dist/workbench-studio.d.ts +26 -0
- package/dist/workbench-studio.d.ts.map +1 -0
- package/dist/workbench-studio.js +57 -0
- package/dist/workbench-studio.js.map +1 -0
- package/dist/workbench-ui.d.ts +3 -0
- package/dist/workbench-ui.d.ts.map +1 -0
- package/dist/workbench-ui.js +262 -0
- package/dist/workbench-ui.js.map +1 -0
- package/dist/workbench.d.ts +5 -0
- package/dist/workbench.d.ts.map +1 -0
- package/dist/workbench.js +43 -0
- package/dist/workbench.js.map +1 -0
- package/docs/README.md +31 -0
- package/docs/agent-guide.md +168 -0
- package/docs/api-reference.md +269 -0
- package/docs/api-report.json +298 -0
- package/docs/child-pipeline-composition.md +185 -0
- package/docs/cli.md +118 -0
- package/docs/concepts.md +502 -0
- package/docs/getting-started.md +162 -0
- package/docs/llms.txt +62 -0
- package/docs/recipes.md +51 -0
- package/docs/studio.md +86 -0
- package/examples/best-effort.ts +42 -0
- package/examples/cancellation-and-testing.ts +45 -0
- package/examples/child-pipeline.ts +51 -0
- package/examples/cli-job.ts +86 -0
- package/examples/conditional-step.ts +41 -0
- package/examples/fan-out-progress.ts +53 -0
- package/examples/local-observability.ts +80 -0
- package/examples/publish-with-gates.ts +56 -0
- package/examples/rendering.ts +34 -0
- package/examples/resumable-enrichment.ts +75 -0
- package/examples/tracing.ts +35 -0
- package/examples/tsconfig.json +15 -0
- package/examples/typed-import.ts +54 -0
- package/examples/validated-boundaries.ts +75 -0
- package/package.json +156 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { throwIfAborted } from "./abort.js";
|
|
2
|
+
import { runConcurrent } from "./batch.js";
|
|
3
|
+
import { toMappedChildStepProgress, } from "./mapped-child-progress.js";
|
|
4
|
+
import { hasVisibleStepProgress } from "./progress.js";
|
|
5
|
+
import { createRunId, RUN_MODEL_VERSION, } from "./pipeline.js";
|
|
6
|
+
export class PipelineChildError extends Error {
|
|
7
|
+
cancelled;
|
|
8
|
+
constructor(message, cancelled = false, cause) {
|
|
9
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
10
|
+
this.cancelled = cancelled;
|
|
11
|
+
this.name = "PipelineChildError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function childTracingOptions(context, itemKey = context.trace?.itemKey) {
|
|
15
|
+
return context.tracing ? { ...context.tracing, itemKey } : undefined;
|
|
16
|
+
}
|
|
17
|
+
function duplicateValues(values) {
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const duplicates = new Set();
|
|
20
|
+
for (const value of values) {
|
|
21
|
+
if (seen.has(value))
|
|
22
|
+
duplicates.add(value);
|
|
23
|
+
seen.add(value);
|
|
24
|
+
}
|
|
25
|
+
return [...duplicates];
|
|
26
|
+
}
|
|
27
|
+
function childRunOptions(options, dryRun) {
|
|
28
|
+
return { ...options, dryRun };
|
|
29
|
+
}
|
|
30
|
+
function childRunControls(options) {
|
|
31
|
+
return {
|
|
32
|
+
continueOnError: options.continueOnError,
|
|
33
|
+
dryRun: options.dryRun,
|
|
34
|
+
stepIds: options.stepIds,
|
|
35
|
+
targets: options.targets,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function isConcurrencyFunction(concurrency) {
|
|
39
|
+
return typeof concurrency === "function";
|
|
40
|
+
}
|
|
41
|
+
function failedPlanRun(pipeline, options, context, errors) {
|
|
42
|
+
const now = context.now ?? Date.now;
|
|
43
|
+
const startedAtMs = now();
|
|
44
|
+
const result = {
|
|
45
|
+
pipelineId: pipeline.id,
|
|
46
|
+
dryRun: options.dryRun === true,
|
|
47
|
+
errors: [...errors],
|
|
48
|
+
finalized: false,
|
|
49
|
+
finishedAtMs: now(),
|
|
50
|
+
runId: context.runId ?? createRunId(pipeline.id),
|
|
51
|
+
startedAtMs,
|
|
52
|
+
status: "failed",
|
|
53
|
+
steps: [],
|
|
54
|
+
version: RUN_MODEL_VERSION,
|
|
55
|
+
};
|
|
56
|
+
if (context.parentRunId)
|
|
57
|
+
result.parentRunId = context.parentRunId;
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function firstChildFailure(result) {
|
|
61
|
+
const firstFailedStep = result.steps.find(({ status }) => status === "failed" || status === "cancelled");
|
|
62
|
+
const firstError = firstFailedStep && "error" in firstFailedStep ? firstFailedStep.error : result.errors[0];
|
|
63
|
+
return {
|
|
64
|
+
failureLocation: firstFailedStep?.id ?? firstError?.stepId ?? "unknown step",
|
|
65
|
+
message: firstError?.message ?? "unknown error",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function runChildPipeline(pipeline, options, context, hooks, dependencies, messagePrefix = "") {
|
|
69
|
+
const plan = pipeline.plan(childRunControls(options));
|
|
70
|
+
if (!plan.ok) {
|
|
71
|
+
const firstError = plan.errors[0];
|
|
72
|
+
const result = failedPlanRun(pipeline, options, context, plan.errors);
|
|
73
|
+
throw dependencies.createExecutionError(result, `${messagePrefix}could not start: ${firstError?.message ?? "invalid plan"}`);
|
|
74
|
+
}
|
|
75
|
+
const result = await pipeline.run(options, { ...context, hooks });
|
|
76
|
+
if (result.status !== "completed") {
|
|
77
|
+
const { failureLocation, message } = firstChildFailure(result);
|
|
78
|
+
throw dependencies.createExecutionError(result, `${messagePrefix}failed at ${failureLocation}: ${message}`);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
export function createSingleChildRunner(config, dependencies) {
|
|
83
|
+
return async (inputs, context) => {
|
|
84
|
+
const childOptions = childRunOptions(config.mapOptions(inputs, context), context.dryRun);
|
|
85
|
+
const baseChildContext = {
|
|
86
|
+
cwd: context.cwd,
|
|
87
|
+
log: context.log,
|
|
88
|
+
now: context.now,
|
|
89
|
+
parentRunId: context.runId,
|
|
90
|
+
signal: context.signal,
|
|
91
|
+
sleep: context.sleep,
|
|
92
|
+
tracing: childTracingOptions(context),
|
|
93
|
+
};
|
|
94
|
+
// Preview plan only for progress totals; invalid plans throw from runChildPipeline.
|
|
95
|
+
const childPlan = config.pipeline.plan(childRunControls(childOptions));
|
|
96
|
+
const selectedStepCount = childPlan.ok
|
|
97
|
+
? childPlan.steps.filter((step) => step.selected).length
|
|
98
|
+
: 0;
|
|
99
|
+
const terminalSteps = new Set();
|
|
100
|
+
const report = (step, message, terminal = false) => {
|
|
101
|
+
if (terminal)
|
|
102
|
+
terminalSteps.add(step.id);
|
|
103
|
+
context.reportProgress({
|
|
104
|
+
completed: terminalSteps.size,
|
|
105
|
+
total: Math.max(1, selectedStepCount),
|
|
106
|
+
message: `${config.pipeline.id}/${step.name ?? step.id}: ${message}`,
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const childHooks = {
|
|
110
|
+
onStepStart: ({ step }) => report(step, "started"),
|
|
111
|
+
onStepProgress: ({ progress, step }) => {
|
|
112
|
+
if (!hasVisibleStepProgress(progress))
|
|
113
|
+
return;
|
|
114
|
+
report(step, progress.message ?? `${progress.completed} completed`);
|
|
115
|
+
},
|
|
116
|
+
onStepComplete: ({ step }) => report(step, "complete", true),
|
|
117
|
+
onStepSkip: ({ reason, step }) => report(step, `skipped: ${reason}`, reason !== "filtered"),
|
|
118
|
+
onStepCancel: ({ error, step }) => report(step, `cancelled: ${error.message}`, true),
|
|
119
|
+
onStepFail: ({ error, step }) => report(step, `failed: ${error.message}`, true),
|
|
120
|
+
};
|
|
121
|
+
const childResult = await runChildPipeline(config.pipeline, childOptions, baseChildContext, childHooks, dependencies, `Child pipeline ${config.pipeline.id} `);
|
|
122
|
+
return config.mapResult
|
|
123
|
+
? config.mapResult(childResult.value, childResult, context)
|
|
124
|
+
: childResult.value;
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export function createMappedChildRunner(config, dependencies) {
|
|
128
|
+
return async (inputs, context) => {
|
|
129
|
+
const items = [...(await config.items(inputs, context))];
|
|
130
|
+
const keys = items.map((item, index) => config.key(item, index));
|
|
131
|
+
const duplicateKeys = duplicateValues(keys);
|
|
132
|
+
if (duplicateKeys.length > 0) {
|
|
133
|
+
throw new PipelineChildError(`Mapped child pipeline ${config.pipeline.id} received duplicate item keys: ${duplicateKeys.join(", ")}`);
|
|
134
|
+
}
|
|
135
|
+
const concurrency = Math.max(1, isConcurrencyFunction(config.concurrency)
|
|
136
|
+
? config.concurrency(inputs, context)
|
|
137
|
+
: (config.concurrency ?? 1));
|
|
138
|
+
const active = new Map();
|
|
139
|
+
const childTerminalSteps = new Map();
|
|
140
|
+
let finishedItems = 0;
|
|
141
|
+
let failedItems = 0;
|
|
142
|
+
let stepsPerItem = 0;
|
|
143
|
+
let plannedChildSteps = 0;
|
|
144
|
+
let plannedItems = 0;
|
|
145
|
+
let terminalChildSteps = 0;
|
|
146
|
+
const publishProgress = (spotlight) => {
|
|
147
|
+
const snapshot = {
|
|
148
|
+
active,
|
|
149
|
+
concurrency,
|
|
150
|
+
failedItems,
|
|
151
|
+
finishedItems,
|
|
152
|
+
itemCount: items.length,
|
|
153
|
+
plannedChildSteps,
|
|
154
|
+
plannedItems,
|
|
155
|
+
stepsPerItem,
|
|
156
|
+
terminalChildSteps,
|
|
157
|
+
spotlight,
|
|
158
|
+
};
|
|
159
|
+
context.reportProgress(toMappedChildStepProgress(snapshot, config.progress));
|
|
160
|
+
};
|
|
161
|
+
const markChildTerminal = (itemKey, stepId, label) => {
|
|
162
|
+
let seen = childTerminalSteps.get(itemKey);
|
|
163
|
+
if (!seen) {
|
|
164
|
+
seen = new Set();
|
|
165
|
+
childTerminalSteps.set(itemKey, seen);
|
|
166
|
+
}
|
|
167
|
+
if (!seen.has(stepId)) {
|
|
168
|
+
seen.add(stepId);
|
|
169
|
+
terminalChildSteps += 1;
|
|
170
|
+
}
|
|
171
|
+
active.set(itemKey, label);
|
|
172
|
+
publishProgress();
|
|
173
|
+
};
|
|
174
|
+
if (items.length === 0) {
|
|
175
|
+
publishProgress();
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
publishProgress();
|
|
179
|
+
const outcomes = await runConcurrent(items, { concurrency, signal: context.signal }, async (item, itemIndex) => {
|
|
180
|
+
const key = keys[itemIndex];
|
|
181
|
+
active.set(key, "starting");
|
|
182
|
+
publishProgress();
|
|
183
|
+
try {
|
|
184
|
+
throwIfAborted(context.signal, `Mapped child pipeline ${config.pipeline.id}`);
|
|
185
|
+
const childOptions = childRunOptions(config.mapOptions(item, itemIndex, inputs, context), context.dryRun);
|
|
186
|
+
// Preview plan for live fan-out progress; invalid plans throw from runChildPipeline.
|
|
187
|
+
const childPlan = config.pipeline.plan(childRunControls(childOptions));
|
|
188
|
+
if (childPlan.ok) {
|
|
189
|
+
const plannedSteps = childPlan.steps.filter((step) => step.selected).length;
|
|
190
|
+
plannedChildSteps += plannedSteps;
|
|
191
|
+
plannedItems += 1;
|
|
192
|
+
if (plannedSteps > stepsPerItem)
|
|
193
|
+
stepsPerItem = plannedSteps;
|
|
194
|
+
}
|
|
195
|
+
const childHooks = {
|
|
196
|
+
onStepStart: ({ step }) => {
|
|
197
|
+
active.set(key, step.name ?? step.id);
|
|
198
|
+
publishProgress();
|
|
199
|
+
},
|
|
200
|
+
onStepProgress: ({ progress, step }) => {
|
|
201
|
+
if (!hasVisibleStepProgress(progress))
|
|
202
|
+
return;
|
|
203
|
+
const detail = progress.message ??
|
|
204
|
+
(progress.total !== undefined
|
|
205
|
+
? `${progress.completed}/${progress.total}`
|
|
206
|
+
: `${progress.completed}`);
|
|
207
|
+
active.set(key, `${step.name ?? step.id}:${detail}`);
|
|
208
|
+
publishProgress();
|
|
209
|
+
},
|
|
210
|
+
onStepComplete: ({ step }) => markChildTerminal(key, step.id, `${step.name ?? step.id}:complete`),
|
|
211
|
+
onStepSkip: ({ reason, step }) => {
|
|
212
|
+
if (reason === "filtered")
|
|
213
|
+
return;
|
|
214
|
+
markChildTerminal(key, step.id, `${step.name ?? step.id}:skipped:${reason}`);
|
|
215
|
+
},
|
|
216
|
+
onStepCancel: ({ step }) => markChildTerminal(key, step.id, `${step.name ?? step.id}:cancelled`),
|
|
217
|
+
onStepFail: ({ step }) => markChildTerminal(key, step.id, `${step.name ?? step.id}:failed`),
|
|
218
|
+
};
|
|
219
|
+
const childResult = await runChildPipeline(config.pipeline, childOptions, {
|
|
220
|
+
cwd: context.cwd,
|
|
221
|
+
log: context.log,
|
|
222
|
+
now: context.now,
|
|
223
|
+
parentRunId: context.runId,
|
|
224
|
+
signal: context.signal,
|
|
225
|
+
sleep: context.sleep,
|
|
226
|
+
tracing: childTracingOptions(context, key),
|
|
227
|
+
}, childHooks, dependencies);
|
|
228
|
+
const seen = childTerminalSteps.get(key) ?? new Set();
|
|
229
|
+
if (childPlan.ok) {
|
|
230
|
+
for (const planStep of childPlan.steps) {
|
|
231
|
+
if (!planStep.selected || seen.has(planStep.id))
|
|
232
|
+
continue;
|
|
233
|
+
seen.add(planStep.id);
|
|
234
|
+
terminalChildSteps += 1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
childTerminalSteps.set(key, seen);
|
|
238
|
+
const value = config.mapResult
|
|
239
|
+
? config.mapResult(childResult.value, childResult, item, itemIndex, context)
|
|
240
|
+
: childResult.value;
|
|
241
|
+
active.delete(key);
|
|
242
|
+
finishedItems += 1;
|
|
243
|
+
publishProgress(`${key}: completed`);
|
|
244
|
+
return { key, ok: true, value };
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
248
|
+
active.delete(key);
|
|
249
|
+
failedItems += 1;
|
|
250
|
+
publishProgress(`${key}: failed`);
|
|
251
|
+
return { error: cause, key, ok: false };
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const failures = outcomes.filter((outcome) => !outcome.ok);
|
|
255
|
+
if (failures.length > 0) {
|
|
256
|
+
const details = failures.map(({ error, key }) => `${key}: ${error.message}`).join("; ");
|
|
257
|
+
const cancelled = failures.every(({ error }) => dependencies.isCancellation(error, context));
|
|
258
|
+
const primaryFailure = cancelled
|
|
259
|
+
? failures[0]
|
|
260
|
+
: (failures.find(({ error }) => !dependencies.isCancellation(error, context)) ??
|
|
261
|
+
failures[0]);
|
|
262
|
+
throw new PipelineChildError(`Mapped child pipeline ${config.pipeline.id} failed for ${failures.length} item(s): ${details}`, cancelled, primaryFailure?.error);
|
|
263
|
+
}
|
|
264
|
+
// SAFETY: when failures.length === 0 every outcome was produced by the
|
|
265
|
+
// success branch (return { key, ok: true, value }), so each outcome is
|
|
266
|
+
// necessarily `{ ok: true }`; the assertion narrows the union accordingly.
|
|
267
|
+
return outcomes.map((outcome) => outcome.value);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=child-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-execution.js","sourceRoot":"","sources":["../src/child-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CheckpointStore } from "./checkpoint.js";
|
|
2
|
+
import { type CliCommand, type CliCommandConfig, type CliContext, type CliParams, type CliParamsSchema } from "./cli-types.js";
|
|
3
|
+
export declare function resolveContext(overrides?: Partial<CliContext>): CliContext;
|
|
4
|
+
interface ManagedMainSignal {
|
|
5
|
+
context: CliContext;
|
|
6
|
+
wasInterrupted(): boolean;
|
|
7
|
+
cleanup(): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Give real CLI entrypoints graceful cancellation without making `run()` or
|
|
11
|
+
* `parse()` mutate process-global signal handlers. Embedded callers can pass
|
|
12
|
+
* their own signal through the context instead.
|
|
13
|
+
*/
|
|
14
|
+
export declare function manageMainSignal(context: CliContext): ManagedMainSignal;
|
|
15
|
+
/**
|
|
16
|
+
* An in-memory-only `CheckpointStore` seeded from `seed`: reads and `record()` behave
|
|
17
|
+
* exactly like a real store for the rest of this run, but `flush()`/`clear()` never touch
|
|
18
|
+
* disk. Every dry-run path hands `run` one of these instead of the real store — the
|
|
19
|
+
* managed-checkpoint contract is that a dry run never writes to the checkpoint file, no
|
|
20
|
+
* matter what `run` does with `context.checkpoint` (`record`/`flush`/`clear`, directly or
|
|
21
|
+
* via `withCheckpointedBatch`).
|
|
22
|
+
*/
|
|
23
|
+
export declare function inMemoryCheckpointView(seed: ReadonlyMap<string, unknown>): CheckpointStore;
|
|
24
|
+
export declare function createCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>, prepareContext?: (values: CliParams<TSchema>, context: CliContext) => CliContext, mainExits?: {
|
|
25
|
+
validation?: number;
|
|
26
|
+
}): CliCommand<TSchema, TResult>;
|
|
27
|
+
export declare function defineCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>): CliCommand<TSchema, TResult>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=cli-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-command.d.ts","sourceRoot":"","sources":["../src/cli-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAavE,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAC;AAGxB,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAS1E;AAED,UAAU,iBAAiB;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,cAAc,IAAI,OAAO,CAAC;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB;AAID;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,iBAAiB,CAmBvE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAa1F;AAED,wBAAgB,aAAa,CAAC,KAAK,CAAC,OAAO,SAAS,eAAe,EAAE,OAAO,GAAG,IAAI,EACjF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,EAC1C,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,KAAK,UAAU,EAChF,SAAS,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CA2Q9B;AA+CD,wBAAgB,aAAa,CAAC,KAAK,CAAC,OAAO,SAAS,eAAe,EAAE,OAAO,GAAG,IAAI,EACjF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,GACzC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAE9B"}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { openCheckpoint } from "./checkpoint.js";
|
|
3
|
+
import { assertNoDuplicateFlags, assertValidEnvironmentFallbacks, assertValidMultipleParams, assertValidPositionals, buildEffectiveSchema, commandDescriptor, renderHelp, resolveParam, tokenize, } from "./cli-parser.js";
|
|
4
|
+
import { CliHelpRequested, CliValidationError, } from "./cli-types.js";
|
|
5
|
+
import { isCliValidationError, isPipelineExecutionError, toExitCode } from "./workbench-shared.js";
|
|
6
|
+
export function resolveContext(overrides) {
|
|
7
|
+
return {
|
|
8
|
+
cwd: overrides?.cwd ?? process.cwd(),
|
|
9
|
+
env: overrides?.env ?? process.env,
|
|
10
|
+
log: overrides?.log ?? console,
|
|
11
|
+
pipelineContext: overrides?.pipelineContext,
|
|
12
|
+
signal: overrides?.signal,
|
|
13
|
+
checkpoint: overrides?.checkpoint,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const SIGINT_EXIT_CODE = 130;
|
|
17
|
+
/**
|
|
18
|
+
* Give real CLI entrypoints graceful cancellation without making `run()` or
|
|
19
|
+
* `parse()` mutate process-global signal handlers. Embedded callers can pass
|
|
20
|
+
* their own signal through the context instead.
|
|
21
|
+
*/
|
|
22
|
+
export function manageMainSignal(context) {
|
|
23
|
+
if (context.signal) {
|
|
24
|
+
return { context, wasInterrupted: () => false, cleanup: () => { } };
|
|
25
|
+
}
|
|
26
|
+
const controller = new AbortController();
|
|
27
|
+
let interrupted = false;
|
|
28
|
+
const onSigint = () => {
|
|
29
|
+
interrupted = true;
|
|
30
|
+
context.log.warn("SIGINT received; cancelling pipeline work.");
|
|
31
|
+
controller.abort();
|
|
32
|
+
};
|
|
33
|
+
process.once("SIGINT", onSigint);
|
|
34
|
+
return {
|
|
35
|
+
context: { ...context, signal: controller.signal },
|
|
36
|
+
wasInterrupted: () => interrupted,
|
|
37
|
+
cleanup: () => process.removeListener("SIGINT", onSigint),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* An in-memory-only `CheckpointStore` seeded from `seed`: reads and `record()` behave
|
|
42
|
+
* exactly like a real store for the rest of this run, but `flush()`/`clear()` never touch
|
|
43
|
+
* disk. Every dry-run path hands `run` one of these instead of the real store — the
|
|
44
|
+
* managed-checkpoint contract is that a dry run never writes to the checkpoint file, no
|
|
45
|
+
* matter what `run` does with `context.checkpoint` (`record`/`flush`/`clear`, directly or
|
|
46
|
+
* via `withCheckpointedBatch`).
|
|
47
|
+
*/
|
|
48
|
+
export function inMemoryCheckpointView(seed) {
|
|
49
|
+
const entries = new Map(seed);
|
|
50
|
+
return {
|
|
51
|
+
has: (key) => entries.has(key),
|
|
52
|
+
record: (key, meta) => {
|
|
53
|
+
entries.set(key, meta);
|
|
54
|
+
},
|
|
55
|
+
entries: () => entries,
|
|
56
|
+
flush: () => { },
|
|
57
|
+
clear: () => {
|
|
58
|
+
entries.clear();
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function createCommand(config, prepareContext, mainExits) {
|
|
63
|
+
const effectiveParams = buildEffectiveSchema(config.params, config.checkpoint);
|
|
64
|
+
assertNoDuplicateFlags(effectiveParams);
|
|
65
|
+
assertValidMultipleParams(effectiveParams);
|
|
66
|
+
assertValidEnvironmentFallbacks(effectiveParams);
|
|
67
|
+
const positionals = [...(config.positionals ?? [])];
|
|
68
|
+
assertValidPositionals(positionals, effectiveParams);
|
|
69
|
+
const descriptor = commandDescriptor(config, effectiveParams, positionals);
|
|
70
|
+
function parseWithContext(argv, context) {
|
|
71
|
+
const helpText = renderHelp(descriptor.name, descriptor.description, effectiveParams, positionals);
|
|
72
|
+
const tokenized = tokenize(argv, effectiveParams, positionals);
|
|
73
|
+
if (tokenized.help) {
|
|
74
|
+
return { kind: "help", helpText };
|
|
75
|
+
}
|
|
76
|
+
const errors = [...tokenized.errors];
|
|
77
|
+
const values = {};
|
|
78
|
+
for (const [key, param] of Object.entries(effectiveParams)) {
|
|
79
|
+
const argvValue = tokenized.values.get(key);
|
|
80
|
+
const envValue = argvValue === undefined && param.env ? context.env?.[param.env] : undefined;
|
|
81
|
+
values[key] = resolveParam(key, param, argvValue ?? envValue, context.cwd, errors, argvValue !== undefined ? "argv" : envValue !== undefined ? "env" : "default");
|
|
82
|
+
}
|
|
83
|
+
if (errors.length > 0) {
|
|
84
|
+
return { kind: "error", errors, helpText };
|
|
85
|
+
}
|
|
86
|
+
// SAFETY: `values` was populated by `resolveParam` for every key in `effectiveParams`,
|
|
87
|
+
// which is exactly the schema `TSchema` describes, so its runtime shape matches `CliParams<TSchema>`.
|
|
88
|
+
const typedValues = values;
|
|
89
|
+
const validationErrors = config.validate?.(typedValues, context) ?? [];
|
|
90
|
+
if (validationErrors.length > 0) {
|
|
91
|
+
return { kind: "error", errors: validationErrors, helpText };
|
|
92
|
+
}
|
|
93
|
+
return { kind: "values", values: typedValues };
|
|
94
|
+
}
|
|
95
|
+
function parse(argv = process.argv.slice(2), contextOverrides) {
|
|
96
|
+
return parseWithContext(argv, resolveContext(contextOverrides));
|
|
97
|
+
}
|
|
98
|
+
function parseStructuredWithContext(structuredValues, context) {
|
|
99
|
+
const helpText = renderHelp(descriptor.name, descriptor.description, effectiveParams, positionals);
|
|
100
|
+
const errors = [];
|
|
101
|
+
const values = {};
|
|
102
|
+
for (const key of Object.keys(structuredValues)) {
|
|
103
|
+
if (!Object.prototype.hasOwnProperty.call(effectiveParams, key)) {
|
|
104
|
+
errors.push(`Unknown parameter: ${key}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const [key, param] of Object.entries(effectiveParams)) {
|
|
108
|
+
const provided = structuredValues[key];
|
|
109
|
+
const raw = normalizeStructuredValue(key, param, provided, errors);
|
|
110
|
+
if (provided !== undefined && raw === undefined) {
|
|
111
|
+
values[key] = undefined;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const envValue = raw === undefined && param.env ? context.env?.[param.env] : undefined;
|
|
115
|
+
values[key] = resolveParam(key, param, raw ?? envValue, context.cwd, errors, raw !== undefined ? "argv" : envValue !== undefined ? "env" : "default");
|
|
116
|
+
}
|
|
117
|
+
if (errors.length > 0)
|
|
118
|
+
return { kind: "error", errors, helpText };
|
|
119
|
+
// SAFETY: `values` was populated by `resolveParam` for every key in `effectiveParams`,
|
|
120
|
+
// which is exactly the schema `TSchema` describes, so its runtime shape matches `CliParams<TSchema>`.
|
|
121
|
+
const typedValues = values;
|
|
122
|
+
const validationErrors = config.validate?.(typedValues, context) ?? [];
|
|
123
|
+
return validationErrors.length > 0
|
|
124
|
+
? { kind: "error", errors: validationErrors, helpText }
|
|
125
|
+
: { kind: "values", values: typedValues };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* No-op unless `config.checkpoint` is set. Respects a caller-provided `context.checkpoint`
|
|
129
|
+
* override (e.g. a stub in tests) instead of opening the real file. Otherwise opens (or
|
|
130
|
+
* clears, if not resuming) the checkpoint before `run` is called — never on the `--help`/
|
|
131
|
+
* error paths, since those return before this is reached.
|
|
132
|
+
*/
|
|
133
|
+
function attachCheckpoint(context, values) {
|
|
134
|
+
const checkpointConfig = config.checkpoint;
|
|
135
|
+
if (!checkpointConfig) {
|
|
136
|
+
return context;
|
|
137
|
+
}
|
|
138
|
+
const resolvedPath = path.isAbsolute(checkpointConfig.path)
|
|
139
|
+
? checkpointConfig.path
|
|
140
|
+
: path.join(context.cwd, checkpointConfig.path);
|
|
141
|
+
// A caller-provided context.checkpoint (e.g. a stub in tests) is used as the
|
|
142
|
+
// underlying store instead of opening the real file, but every rule below — fresh
|
|
143
|
+
// clearing, dry-run wrapping, resume detection/logging — still applies to it; only
|
|
144
|
+
// the "where does the store come from" step is skipped.
|
|
145
|
+
const store = context.checkpoint ?? openCheckpoint(resolvedPath);
|
|
146
|
+
const hadExisting = store.entries().size > 0;
|
|
147
|
+
if (values.resume) {
|
|
148
|
+
if (hadExisting) {
|
|
149
|
+
context.log.log(`Resuming from checkpoint: ${store.entries().size} item(s) already recorded.`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Without this, --resume against a missing/wrong-path/already-cleared checkpoint
|
|
153
|
+
// silently starts fresh — the exact failure mode that's dangerous for
|
|
154
|
+
// clearOnSuccess: false workflows, where "fresh" quietly means "reprocess
|
|
155
|
+
// everything already done".
|
|
156
|
+
context.log.warn(`--resume was passed, but no checkpoint was found at ${resolvedPath}; starting fresh.`);
|
|
157
|
+
}
|
|
158
|
+
// A dry run must never write to the checkpoint file, even while resuming — an
|
|
159
|
+
// in-memory view seeded with the real entries previews it accurately without risk.
|
|
160
|
+
return {
|
|
161
|
+
...context,
|
|
162
|
+
checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if (!hadExisting) {
|
|
166
|
+
return {
|
|
167
|
+
...context,
|
|
168
|
+
checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (values.dryRun) {
|
|
172
|
+
// Dry run must not touch the file — neither clearing it nor writing new progress —
|
|
173
|
+
// but the preview should still reflect what a real fresh run would see: an empty
|
|
174
|
+
// "done" set, not the stale entries a --resume invocation would use.
|
|
175
|
+
context.log.log("Dry run: leaving existing checkpoint untouched (would start fresh).");
|
|
176
|
+
return { ...context, checkpoint: inMemoryCheckpointView(new Map()) };
|
|
177
|
+
}
|
|
178
|
+
store.clear();
|
|
179
|
+
context.log.log("Starting fresh — cleared existing checkpoint.");
|
|
180
|
+
return { ...context, checkpoint: store };
|
|
181
|
+
}
|
|
182
|
+
/** No-op unless `config.checkpoint` is set, a store is attached, and the run wasn't a dry run. */
|
|
183
|
+
function finalizeCheckpoint(context, values) {
|
|
184
|
+
const checkpointConfig = config.checkpoint;
|
|
185
|
+
if (!checkpointConfig || !context.checkpoint || values.dryRun) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (checkpointConfig.clearOnSuccess === false) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
context.checkpoint.clear();
|
|
192
|
+
}
|
|
193
|
+
async function executeValues(values, context) {
|
|
194
|
+
const preparedContext = prepareContext?.(values, context) ?? context;
|
|
195
|
+
const runContext = attachCheckpoint(preparedContext, values);
|
|
196
|
+
const value = await config.run(values, runContext);
|
|
197
|
+
finalizeCheckpoint(runContext, values);
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
function parseValues(values, contextOverrides) {
|
|
201
|
+
const context = resolveContext(contextOverrides);
|
|
202
|
+
return parseStructuredWithContext(values, context);
|
|
203
|
+
}
|
|
204
|
+
async function execute(values, contextOverrides) {
|
|
205
|
+
return executeValues(values, resolveContext(contextOverrides));
|
|
206
|
+
}
|
|
207
|
+
async function run(argv = process.argv.slice(2), contextOverrides) {
|
|
208
|
+
const context = resolveContext(contextOverrides);
|
|
209
|
+
const result = parseWithContext(argv, context);
|
|
210
|
+
if (result.kind === "help")
|
|
211
|
+
throw new CliHelpRequested(result.helpText);
|
|
212
|
+
if (result.kind === "error")
|
|
213
|
+
throw new CliValidationError(result.errors, result.helpText);
|
|
214
|
+
return executeValues(result.values, context);
|
|
215
|
+
}
|
|
216
|
+
async function main(argv = process.argv.slice(2), contextOverrides) {
|
|
217
|
+
const context = resolveContext(contextOverrides);
|
|
218
|
+
let result;
|
|
219
|
+
try {
|
|
220
|
+
result = parseWithContext(argv, context);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
224
|
+
process.exitCode =
|
|
225
|
+
mainExits || isCliValidationError(error) || isPipelineExecutionError(error)
|
|
226
|
+
? toExitCode(error)
|
|
227
|
+
: 1;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (result.kind === "help") {
|
|
231
|
+
context.log.log(result.helpText);
|
|
232
|
+
process.exitCode = 0;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (result.kind === "error") {
|
|
236
|
+
for (const error of result.errors) {
|
|
237
|
+
context.log.error(`Error: ${error}`);
|
|
238
|
+
}
|
|
239
|
+
context.log.error("");
|
|
240
|
+
context.log.error(result.helpText);
|
|
241
|
+
process.exitCode = mainExits?.validation ?? 1;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const managedSignal = manageMainSignal(context);
|
|
245
|
+
try {
|
|
246
|
+
const preparedContext = prepareContext?.(result.values, managedSignal.context) ?? managedSignal.context;
|
|
247
|
+
const runContext = attachCheckpoint(preparedContext, result.values);
|
|
248
|
+
await config.run(result.values, runContext);
|
|
249
|
+
if (!managedSignal.wasInterrupted()) {
|
|
250
|
+
finalizeCheckpoint(runContext, result.values);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));
|
|
255
|
+
process.exitCode = managedSignal.wasInterrupted()
|
|
256
|
+
? SIGINT_EXIT_CODE
|
|
257
|
+
: mainExits || isCliValidationError(error) || isPipelineExecutionError(error)
|
|
258
|
+
? toExitCode(error)
|
|
259
|
+
: 1;
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
if (managedSignal.wasInterrupted()) {
|
|
263
|
+
process.exitCode = SIGINT_EXIT_CODE;
|
|
264
|
+
}
|
|
265
|
+
managedSignal.cleanup();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return { descriptor, execute, parse, parseValues, run, main };
|
|
269
|
+
}
|
|
270
|
+
function normalizeStructuredValue(key, param, value, errors) {
|
|
271
|
+
if (value === undefined)
|
|
272
|
+
return undefined;
|
|
273
|
+
const label = `--${param.flag ?? key}`;
|
|
274
|
+
if (param.type === "boolean") {
|
|
275
|
+
if (typeof value === "boolean")
|
|
276
|
+
return value;
|
|
277
|
+
errors.push(`${label} must be a boolean value.`);
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
if ((param.type === "number" || param.type === "string") && param.multiple === true) {
|
|
281
|
+
if (!Array.isArray(value)) {
|
|
282
|
+
errors.push(`${label} must be an array.`);
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
if (param.type === "number") {
|
|
286
|
+
if (!value.every((item) => typeof item === "number" && Number.isFinite(item))) {
|
|
287
|
+
errors.push(`${label} must contain only finite numbers.`);
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
return value.map(String);
|
|
291
|
+
}
|
|
292
|
+
if (!value.every((item) => typeof item === "string")) {
|
|
293
|
+
errors.push(`${label} must contain only strings.`);
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
return [...value];
|
|
297
|
+
}
|
|
298
|
+
if (param.type === "number") {
|
|
299
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
300
|
+
errors.push(`${label} must be a finite number.`);
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
return String(value);
|
|
304
|
+
}
|
|
305
|
+
if (typeof value !== "string") {
|
|
306
|
+
errors.push(`${label} must be a string value.`);
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
return value;
|
|
310
|
+
}
|
|
311
|
+
export function defineCommand(config) {
|
|
312
|
+
return createCommand(config);
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=cli-command.js.map
|