tubeless 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/cli/cli-command.d.ts +2 -2
- package/dist/cli/cli-command.js +28 -45
- package/dist/cli/cli-command.js.map +1 -1
- package/dist/cli/cli-pipeline-command.js +1 -1
- package/dist/cli/cli-pipeline-command.js.map +1 -1
- package/dist/core/child-execution.js +73 -5
- package/dist/core/child-execution.js.map +1 -1
- package/dist/core/child-progress.d.ts +6 -0
- package/dist/core/child-progress.js +48 -0
- package/dist/core/child-progress.js.map +1 -0
- package/dist/core/lifecycle.js +2 -0
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/mapped-child-progress.d.ts +4 -2
- package/dist/core/mapped-child-progress.js.map +1 -1
- package/dist/core/pipeline-execute.d.ts +2 -0
- package/dist/core/pipeline-execute.js +132 -395
- package/dist/core/pipeline-execute.js.map +1 -1
- package/dist/core/pipeline-plan.js +96 -34
- package/dist/core/pipeline-plan.js.map +1 -1
- package/dist/core/pipeline-run-state.d.ts +49 -0
- package/dist/core/pipeline-run-state.js +284 -0
- package/dist/core/pipeline-run-state.js.map +1 -0
- package/dist/core/pipeline-step-executor.d.ts +20 -0
- package/dist/core/pipeline-step-executor.js +52 -0
- package/dist/core/pipeline-step-executor.js.map +1 -0
- package/dist/core/pipeline-steps.d.ts +3 -3
- package/dist/core/pipeline-steps.js +12 -23
- package/dist/core/pipeline-steps.js.map +1 -1
- package/dist/core/pipeline-types.d.ts +19 -3
- package/dist/core/pipeline-types.js.map +1 -1
- package/dist/core/pipeline-validation.d.ts +6 -0
- package/dist/core/pipeline-validation.js +41 -0
- package/dist/core/pipeline-validation.js.map +1 -0
- package/dist/render/render.js +2 -6
- package/dist/render/render.js.map +1 -1
- package/dist/reporter/interactive-reporter.d.ts +1 -0
- package/dist/reporter/interactive-reporter.js +50 -15
- package/dist/reporter/interactive-reporter.js.map +1 -1
- package/dist/reporter/live-ticker-worker.js +8 -42
- package/dist/reporter/live-ticker-worker.js.map +1 -1
- package/dist/reporter/live-ticker.d.ts +10 -0
- package/dist/reporter/live-ticker.js +50 -47
- package/dist/reporter/live-ticker.js.map +1 -1
- package/dist/run-store/run-store-ndjson.js +2 -289
- package/dist/run-store/run-store-ndjson.js.map +1 -1
- package/dist/run-store/run-store-sqlite.js +91 -42
- package/dist/run-store/run-store-sqlite.js.map +1 -1
- package/dist/run-store/run-store.d.ts +3 -2
- package/dist/run-store/run-store.js +40 -216
- package/dist/run-store/run-store.js.map +1 -1
- package/dist/studio/run-store-ui-client-controller.d.ts +9 -0
- package/dist/studio/run-store-ui-client-controller.js +479 -0
- package/dist/studio/run-store-ui-client-controller.js.map +1 -0
- package/dist/studio/run-store-ui-client-form.d.ts +9 -0
- package/dist/studio/run-store-ui-client-form.js +44 -0
- package/dist/studio/run-store-ui-client-form.js.map +1 -0
- package/dist/studio/run-store-ui-client-model.d.ts +40 -0
- package/dist/studio/run-store-ui-client-model.js +211 -0
- package/dist/studio/run-store-ui-client-model.js.map +1 -0
- package/dist/studio/run-store-ui-client-source.js +1 -1
- package/dist/studio/run-store-ui-client-transport.d.ts +25 -0
- package/dist/studio/run-store-ui-client-transport.js +322 -0
- package/dist/studio/run-store-ui-client-transport.js.map +1 -0
- package/dist/studio/run-store-ui-client-views.d.ts +24 -0
- package/dist/studio/run-store-ui-client-views.js +676 -0
- package/dist/studio/run-store-ui-client-views.js.map +1 -0
- package/dist/studio/run-store-ui-client.d.ts +2 -15
- package/dist/studio/run-store-ui-client.js +7 -1390
- package/dist/studio/run-store-ui-client.js.map +1 -1
- package/dist/studio/run-store-ui-page.d.ts +1 -1
- package/dist/studio/run-store-ui-page.js +1 -1
- package/dist/studio/run-store-ui-page.js.map +1 -1
- package/dist/studio/run-store-ui.js +44 -25
- package/dist/studio/run-store-ui.js.map +1 -1
- package/dist/tracing/tracing-codec.d.ts +6 -0
- package/dist/tracing/tracing-codec.js +829 -0
- package/dist/tracing/tracing-codec.js.map +1 -0
- package/dist/tracing/tracing-constants.d.ts +4 -0
- package/dist/tracing/tracing-constants.js +5 -0
- package/dist/tracing/tracing-constants.js.map +1 -0
- package/dist/tracing/tracing-internal.js +133 -72
- package/dist/tracing/tracing-internal.js.map +1 -1
- package/dist/tracing/tracing-otel.js +19 -3
- package/dist/tracing/tracing-otel.js.map +1 -1
- package/dist/tracing/tracing.d.ts +149 -10
- package/dist/tracing/tracing.js.map +1 -1
- package/dist/workbench/pipeline-module.d.ts +2 -12
- package/dist/workbench/pipeline-module.js +4 -11
- package/dist/workbench/pipeline-module.js.map +1 -1
- package/dist/workbench/workbench-history.js +8 -1
- package/dist/workbench/workbench-history.js.map +1 -1
- package/dist/workbench/workbench-project-loader.js +1 -1
- package/dist/workbench/workbench-project-loader.js.map +1 -1
- package/dist/workbench/workbench-ui.js +27 -7
- package/dist/workbench/workbench-ui.js.map +1 -1
- package/docs/README.md +21 -15
- package/docs/agent-guide.md +54 -33
- package/docs/agent-skills.md +59 -0
- package/docs/api-reference.md +28 -12
- package/docs/api-report.json +29 -13
- package/docs/child-pipeline-composition.md +142 -161
- package/docs/cli.md +103 -56
- package/docs/comparison.md +63 -62
- package/docs/concepts.md +210 -272
- package/docs/getting-started.md +59 -48
- package/docs/llms.txt +7 -4
- package/docs/recipes.md +23 -20
- package/docs/remote-step-composition.md +69 -74
- package/docs/studio.md +146 -71
- package/examples/catalog/pipelines/enrich.ts +2 -2
- package/examples/catalog/tubeless.project.ts +10 -2
- package/examples/fan-out-progress.ts +16 -2
- package/examples/host-embedding.ts +4 -5
- package/examples/remote-steps.ts +8 -5
- package/package.json +12 -10
- package/skills/tubeless/SKILL.md +83 -0
- package/skills/tubeless-make-pipeline/SKILL.md +126 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<a href="https://
|
|
2
|
+
<a href="https://tubeless.io/">
|
|
3
3
|
<img src="docs/assets/logo.svg" width="72" height="72" alt="Tubeless">
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
Typed, observable data pipelines you import from TypeScript or run from a Bun
|
|
17
17
|
CLI. It is a library, not a hosted workflow engine or a Make/npm-scripts
|
|
18
|
-
replacement.
|
|
18
|
+
replacement. Tubeless is pre-1.0; its public API may change.
|
|
19
19
|
|
|
20
20
|
```sh
|
|
21
21
|
npm install tubeless
|
|
@@ -99,15 +99,15 @@ go after `--`. `history` lists recorded
|
|
|
99
99
|
| Export lifecycle telemetry | [Structured tracing](./examples/tracing.ts) |
|
|
100
100
|
| Persist and inspect local runs | [Local observability](./examples/local-observability.ts) |
|
|
101
101
|
|
|
102
|
-
The [recipe index](./docs/recipes.md) explains
|
|
102
|
+
Install the [agent skill pack](./docs/agent-skills.md) with `npx skills add chetmancini/tubeless` to convert existing code using `tubeless-make-pipeline`. The [recipe index](./docs/recipes.md) explains each pattern.
|
|
103
103
|
|
|
104
104
|
## Docs
|
|
105
105
|
|
|
106
|
-
[Website](https://
|
|
106
|
+
[Website](https://tubeless.io/) ·
|
|
107
107
|
[Getting started](./docs/getting-started.md) · [CLI](./docs/cli.md) ·
|
|
108
108
|
[Studio](./docs/studio.md) · [Concepts](./docs/concepts.md) ·
|
|
109
109
|
[Comparison](./docs/comparison.md) · [API](./docs/api-reference.md) ·
|
|
110
|
-
[Agents](./docs/agent-guide.md)
|
|
110
|
+
[Agents](./docs/agent-guide.md) · [Studio OpenAPI](https://tubeless.io/openapi.json)
|
|
111
111
|
|
|
112
112
|
## Contributing
|
|
113
113
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type CliCommand, type CliCommandConfig, type
|
|
2
|
-
export declare function createCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>,
|
|
1
|
+
import { type CliCommand, type CliCommandConfig, type CliParamsSchema } from "./cli-types.js";
|
|
2
|
+
export declare function createCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>, mainExits?: {
|
|
3
3
|
validation?: number;
|
|
4
4
|
}): CliCommand<TSchema, TResult>;
|
|
5
5
|
export declare function defineCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>): CliCommand<TSchema, TResult>;
|
package/dist/cli/cli-command.js
CHANGED
|
@@ -59,7 +59,7 @@ function inMemoryCheckpointView(seed) {
|
|
|
59
59
|
},
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
export function createCommand(config,
|
|
62
|
+
export function createCommand(config, mainExits) {
|
|
63
63
|
const effectiveParams = buildEffectiveSchema(config.params, config.checkpoint);
|
|
64
64
|
assertNoDuplicateFlags(effectiveParams);
|
|
65
65
|
assertValidMultipleParams(effectiveParams);
|
|
@@ -67,30 +67,31 @@ export function createCommand(config, prepareContext, mainExits) {
|
|
|
67
67
|
const positionals = [...(config.positionals ?? [])];
|
|
68
68
|
assertValidPositionals(positionals, effectiveParams);
|
|
69
69
|
const descriptor = commandDescriptor(config, effectiveParams, positionals);
|
|
70
|
-
function
|
|
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];
|
|
70
|
+
function resolveValues(readValue, context, errors, helpText) {
|
|
77
71
|
const values = {};
|
|
78
72
|
for (const [key, param] of Object.entries(effectiveParams)) {
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
73
|
+
const errorCount = errors.length;
|
|
74
|
+
const raw = readValue(key, param);
|
|
75
|
+
if (errors.length > errorCount)
|
|
76
|
+
continue;
|
|
77
|
+
const envValue = raw === undefined && param.env ? context.env?.[param.env] : undefined;
|
|
78
|
+
values[key] = resolveParam(key, param, raw ?? envValue, context.cwd, errors, raw !== undefined ? "argv" : envValue !== undefined ? "env" : "default");
|
|
82
79
|
}
|
|
83
|
-
if (errors.length > 0)
|
|
80
|
+
if (errors.length > 0)
|
|
84
81
|
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>`.
|
|
82
|
+
// SAFETY: resolveParam populated every effective schema key and all input checks passed.
|
|
88
83
|
const typedValues = values;
|
|
89
84
|
const validationErrors = config.validate?.(typedValues, context) ?? [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
return validationErrors.length > 0
|
|
86
|
+
? { kind: "error", errors: validationErrors, helpText }
|
|
87
|
+
: { kind: "values", values: typedValues };
|
|
88
|
+
}
|
|
89
|
+
function parseWithContext(argv, context) {
|
|
90
|
+
const helpText = renderHelp(descriptor.name, descriptor.description, effectiveParams, positionals);
|
|
91
|
+
const tokenized = tokenize(argv, effectiveParams, positionals);
|
|
92
|
+
if (tokenized.help)
|
|
93
|
+
return { kind: "help", helpText };
|
|
94
|
+
return resolveValues((key) => tokenized.values.get(key), context, [...tokenized.errors], helpText);
|
|
94
95
|
}
|
|
95
96
|
function parse(argv = process.argv.slice(2), contextOverrides) {
|
|
96
97
|
return parseWithContext(argv, resolveContext(contextOverrides));
|
|
@@ -98,31 +99,12 @@ export function createCommand(config, prepareContext, mainExits) {
|
|
|
98
99
|
function parseStructuredWithContext(structuredValues, context) {
|
|
99
100
|
const helpText = renderHelp(descriptor.name, descriptor.description, effectiveParams, positionals);
|
|
100
101
|
const errors = [];
|
|
101
|
-
const values = {};
|
|
102
102
|
for (const key of Object.keys(structuredValues)) {
|
|
103
103
|
if (!Object.prototype.hasOwnProperty.call(effectiveParams, key)) {
|
|
104
104
|
errors.push(`Unknown parameter: ${key}`);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
|
|
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 };
|
|
107
|
+
return resolveValues((key, param) => normalizeStructuredValue(key, param, structuredValues[key], errors), context, errors, helpText);
|
|
126
108
|
}
|
|
127
109
|
/**
|
|
128
110
|
* No-op unless `config.checkpoint` is set. Respects a caller-provided `context.checkpoint`
|
|
@@ -179,10 +161,13 @@ export function createCommand(config, prepareContext, mainExits) {
|
|
|
179
161
|
context.log.log("Starting fresh — cleared existing checkpoint.");
|
|
180
162
|
return { ...context, checkpoint: store };
|
|
181
163
|
}
|
|
182
|
-
/**
|
|
164
|
+
/**
|
|
165
|
+
* No-op unless `config.checkpoint` is set, a store is attached, and the run completed
|
|
166
|
+
* without a dry run or caller cancellation.
|
|
167
|
+
*/
|
|
183
168
|
function finalizeCheckpoint(context, values) {
|
|
184
169
|
const checkpointConfig = config.checkpoint;
|
|
185
|
-
if (!checkpointConfig || !context.checkpoint || values.dryRun) {
|
|
170
|
+
if (!checkpointConfig || !context.checkpoint || values.dryRun || context.signal?.aborted) {
|
|
186
171
|
return;
|
|
187
172
|
}
|
|
188
173
|
if (checkpointConfig.clearOnSuccess === false) {
|
|
@@ -191,8 +176,7 @@ export function createCommand(config, prepareContext, mainExits) {
|
|
|
191
176
|
context.checkpoint.clear();
|
|
192
177
|
}
|
|
193
178
|
async function executeValues(values, context) {
|
|
194
|
-
const
|
|
195
|
-
const runContext = attachCheckpoint(preparedContext, values);
|
|
179
|
+
const runContext = attachCheckpoint(context, values);
|
|
196
180
|
const value = await config.run(values, runContext);
|
|
197
181
|
finalizeCheckpoint(runContext, values);
|
|
198
182
|
return value;
|
|
@@ -243,8 +227,7 @@ export function createCommand(config, prepareContext, mainExits) {
|
|
|
243
227
|
}
|
|
244
228
|
const managedSignal = manageMainSignal(context);
|
|
245
229
|
try {
|
|
246
|
-
const
|
|
247
|
-
const runContext = attachCheckpoint(preparedContext, result.values);
|
|
230
|
+
const runContext = attachCheckpoint(managedSignal.context, result.values);
|
|
248
231
|
await config.run(result.values, runContext);
|
|
249
232
|
if (!managedSignal.wasInterrupted()) {
|
|
250
233
|
finalizeCheckpoint(runContext, result.values);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-command.js","sourceRoot":"","sources":["../../src/cli/cli-command.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from \"path\";\nimport { openCheckpoint, type CheckpointStore } from \"../node/checkpoint.js\";\nimport {\n assertNoDuplicateFlags,\n assertValidEnvironmentFallbacks,\n assertValidMultipleParams,\n assertValidPositionals,\n buildEffectiveSchema,\n commandDescriptor,\n renderHelp,\n resolveParam,\n tokenize,\n type ResolvedParamValue,\n} from \"./cli-parser.js\";\nimport {\n CliHelpRequested,\n CliValidationError,\n type CliCommand,\n type CliCommandConfig,\n type CliContext,\n type CliParams,\n type CliParamsSchema,\n type CliParseResult,\n} from \"./cli-types.js\";\nimport { isCliValidationError, isPipelineExecutionError, toExitCode } from \"./cli-exit.js\";\n\nfunction resolveContext(overrides?: Partial<CliContext>): CliContext {\n return {\n cwd: overrides?.cwd ?? process.cwd(),\n env: overrides?.env ?? process.env,\n log: overrides?.log ?? console,\n pipelineContext: overrides?.pipelineContext,\n signal: overrides?.signal,\n checkpoint: overrides?.checkpoint,\n };\n}\n\ninterface ManagedMainSignal {\n context: CliContext;\n wasInterrupted(): boolean;\n cleanup(): void;\n}\n\nconst SIGINT_EXIT_CODE = 130;\n\n/**\n * Give real CLI entrypoints graceful cancellation without making `run()` or\n * `parse()` mutate process-global signal handlers. Embedded callers can pass\n * their own signal through the context instead.\n */\nfunction manageMainSignal(context: CliContext): ManagedMainSignal {\n if (context.signal) {\n return { context, wasInterrupted: () => false, cleanup: () => {} };\n }\n\n const controller = new AbortController();\n let interrupted = false;\n const onSigint = (): void => {\n interrupted = true;\n context.log.warn(\"SIGINT received; cancelling pipeline work.\");\n controller.abort();\n };\n process.once(\"SIGINT\", onSigint);\n\n return {\n context: { ...context, signal: controller.signal },\n wasInterrupted: () => interrupted,\n cleanup: () => process.removeListener(\"SIGINT\", onSigint),\n };\n}\n\n/**\n * An in-memory-only `CheckpointStore` seeded from `seed`: reads and `record()` behave\n * exactly like a real store for the rest of this run, but `flush()`/`clear()` never touch\n * disk. Every dry-run path hands `run` one of these instead of the real store — the\n * managed-checkpoint contract is that a dry run never writes to the checkpoint file, no\n * matter what `run` does with `context.checkpoint` (`record`/`flush`/`clear`, directly or\n * via `withCheckpointedBatch`).\n */\nfunction inMemoryCheckpointView(seed: ReadonlyMap<string, unknown>): CheckpointStore {\n const entries = new Map(seed);\n return {\n has: (key) => entries.has(key),\n record: (key, meta) => {\n entries.set(key, meta);\n },\n entries: () => entries,\n flush: () => {},\n clear: () => {\n entries.clear();\n },\n };\n}\n\nexport function createCommand<const TSchema extends CliParamsSchema, TResult = void>(\n config: CliCommandConfig<TSchema, TResult>,\n prepareContext?: (values: CliParams<TSchema>, context: CliContext) => CliContext,\n mainExits?: { validation?: number }\n): CliCommand<TSchema, TResult> {\n const effectiveParams = buildEffectiveSchema(config.params, config.checkpoint);\n assertNoDuplicateFlags(effectiveParams);\n assertValidMultipleParams(effectiveParams);\n assertValidEnvironmentFallbacks(effectiveParams);\n const positionals = [...(config.positionals ?? [])];\n assertValidPositionals(positionals, effectiveParams);\n const descriptor = commandDescriptor(config, effectiveParams, positionals);\n\n function parseWithContext(argv: readonly string[], context: CliContext): CliParseResult<TSchema> {\n const helpText = renderHelp(\n descriptor.name,\n descriptor.description,\n effectiveParams,\n positionals\n );\n\n const tokenized = tokenize(argv, effectiveParams, positionals);\n if (tokenized.help) {\n return { kind: \"help\", helpText };\n }\n\n const errors = [...tokenized.errors];\n const values: Record<string, ResolvedParamValue> = {};\n for (const [key, param] of Object.entries(effectiveParams)) {\n const argvValue = tokenized.values.get(key);\n const envValue = argvValue === undefined && param.env ? context.env?.[param.env] : undefined;\n values[key] = resolveParam(\n key,\n param,\n argvValue ?? envValue,\n context.cwd,\n errors,\n argvValue !== undefined ? \"argv\" : envValue !== undefined ? \"env\" : \"default\"\n );\n }\n\n if (errors.length > 0) {\n return { kind: \"error\", errors, helpText };\n }\n\n // SAFETY: `values` was populated by `resolveParam` for every key in `effectiveParams`,\n // which is exactly the schema `TSchema` describes, so its runtime shape matches `CliParams<TSchema>`.\n const typedValues = values as CliParams<TSchema>;\n const validationErrors = config.validate?.(typedValues, context) ?? [];\n if (validationErrors.length > 0) {\n return { kind: \"error\", errors: validationErrors, helpText };\n }\n\n return { kind: \"values\", values: typedValues };\n }\n\n function parse(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): CliParseResult<TSchema> {\n return parseWithContext(argv, resolveContext(contextOverrides));\n }\n\n function parseStructuredWithContext(\n structuredValues: Record<string, unknown>,\n context: CliContext\n ): CliParseResult<TSchema> {\n const helpText = renderHelp(\n descriptor.name,\n descriptor.description,\n effectiveParams,\n positionals\n );\n const errors: string[] = [];\n const values: Record<string, ResolvedParamValue> = {};\n for (const key of Object.keys(structuredValues)) {\n if (!Object.prototype.hasOwnProperty.call(effectiveParams, key)) {\n errors.push(`Unknown parameter: ${key}`);\n }\n }\n for (const [key, param] of Object.entries(effectiveParams)) {\n const provided = structuredValues[key];\n const raw = normalizeStructuredValue(key, param, provided, errors);\n if (provided !== undefined && raw === undefined) {\n values[key] = undefined;\n continue;\n }\n const envValue = raw === undefined && param.env ? context.env?.[param.env] : undefined;\n values[key] = resolveParam(\n key,\n param,\n raw ?? envValue,\n context.cwd,\n errors,\n raw !== undefined ? \"argv\" : envValue !== undefined ? \"env\" : \"default\"\n );\n }\n if (errors.length > 0) return { kind: \"error\", errors, helpText };\n // SAFETY: `values` was populated by `resolveParam` for every key in `effectiveParams`,\n // which is exactly the schema `TSchema` describes, so its runtime shape matches `CliParams<TSchema>`.\n const typedValues = values as CliParams<TSchema>;\n const validationErrors = config.validate?.(typedValues, context) ?? [];\n return validationErrors.length > 0\n ? { kind: \"error\", errors: validationErrors, helpText }\n : { kind: \"values\", values: typedValues };\n }\n\n /**\n * No-op unless `config.checkpoint` is set. Respects a caller-provided `context.checkpoint`\n * override (e.g. a stub in tests) instead of opening the real file. Otherwise opens (or\n * clears, if not resuming) the checkpoint before `run` is called — never on the `--help`/\n * error paths, since those return before this is reached.\n */\n function attachCheckpoint(context: CliContext, values: CliParams<TSchema>): CliContext {\n const checkpointConfig = config.checkpoint;\n if (!checkpointConfig) {\n return context;\n }\n const resolvedPath = path.isAbsolute(checkpointConfig.path)\n ? checkpointConfig.path\n : path.join(context.cwd, checkpointConfig.path);\n // A caller-provided context.checkpoint (e.g. a stub in tests) is used as the\n // underlying store instead of opening the real file, but every rule below — fresh\n // clearing, dry-run wrapping, resume detection/logging — still applies to it; only\n // the \"where does the store come from\" step is skipped.\n const store = context.checkpoint ?? openCheckpoint(resolvedPath);\n const hadExisting = store.entries().size > 0;\n\n if (values.resume) {\n if (hadExisting) {\n context.log.log(\n `Resuming from checkpoint: ${store.entries().size} item(s) already recorded.`\n );\n } else {\n // Without this, --resume against a missing/wrong-path/already-cleared checkpoint\n // silently starts fresh — the exact failure mode that's dangerous for\n // clearOnSuccess: false workflows, where \"fresh\" quietly means \"reprocess\n // everything already done\".\n context.log.warn(\n `--resume was passed, but no checkpoint was found at ${resolvedPath}; starting fresh.`\n );\n }\n // A dry run must never write to the checkpoint file, even while resuming — an\n // in-memory view seeded with the real entries previews it accurately without risk.\n return {\n ...context,\n checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,\n };\n }\n\n if (!hadExisting) {\n return {\n ...context,\n checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,\n };\n }\n\n if (values.dryRun) {\n // Dry run must not touch the file — neither clearing it nor writing new progress —\n // but the preview should still reflect what a real fresh run would see: an empty\n // \"done\" set, not the stale entries a --resume invocation would use.\n context.log.log(\"Dry run: leaving existing checkpoint untouched (would start fresh).\");\n return { ...context, checkpoint: inMemoryCheckpointView(new Map()) };\n }\n\n store.clear();\n context.log.log(\"Starting fresh — cleared existing checkpoint.\");\n return { ...context, checkpoint: store };\n }\n\n /** No-op unless `config.checkpoint` is set, a store is attached, and the run wasn't a dry run. */\n function finalizeCheckpoint(context: CliContext, values: CliParams<TSchema>): void {\n const checkpointConfig = config.checkpoint;\n if (!checkpointConfig || !context.checkpoint || values.dryRun) {\n return;\n }\n if (checkpointConfig.clearOnSuccess === false) {\n return;\n }\n context.checkpoint.clear();\n }\n\n async function executeValues(values: CliParams<TSchema>, context: CliContext): Promise<TResult> {\n const preparedContext = prepareContext?.(values, context) ?? context;\n const runContext = attachCheckpoint(preparedContext, values);\n const value = await config.run(values, runContext);\n finalizeCheckpoint(runContext, values);\n return value;\n }\n\n function parseValues(\n values: Record<string, unknown>,\n contextOverrides?: Partial<CliContext>\n ): CliParseResult<TSchema> {\n const context = resolveContext(contextOverrides);\n return parseStructuredWithContext(values, context);\n }\n\n async function execute(\n values: CliParams<TSchema>,\n contextOverrides?: Partial<CliContext>\n ): Promise<TResult> {\n return executeValues(values, resolveContext(contextOverrides));\n }\n\n async function run(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): Promise<TResult> {\n const context = resolveContext(contextOverrides);\n const result = parseWithContext(argv, context);\n if (result.kind === \"help\") throw new CliHelpRequested(result.helpText);\n if (result.kind === \"error\") throw new CliValidationError(result.errors, result.helpText);\n return executeValues(result.values, context);\n }\n\n async function main(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): Promise<void> {\n const context = resolveContext(contextOverrides);\n let result: CliParseResult<TSchema>;\n try {\n result = parseWithContext(argv, context);\n } catch (error) {\n context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.exitCode =\n mainExits || isCliValidationError(error) || isPipelineExecutionError(error)\n ? toExitCode(error)\n : 1;\n return;\n }\n if (result.kind === \"help\") {\n context.log.log(result.helpText);\n process.exitCode = 0;\n return;\n }\n if (result.kind === \"error\") {\n for (const error of result.errors) {\n context.log.error(`Error: ${error}`);\n }\n context.log.error(\"\");\n context.log.error(result.helpText);\n process.exitCode = mainExits?.validation ?? 1;\n return;\n }\n const managedSignal = manageMainSignal(context);\n try {\n const preparedContext =\n prepareContext?.(result.values, managedSignal.context) ?? managedSignal.context;\n const runContext = attachCheckpoint(preparedContext, result.values);\n await config.run(result.values, runContext);\n if (!managedSignal.wasInterrupted()) {\n finalizeCheckpoint(runContext, result.values);\n }\n } catch (error) {\n context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.exitCode = managedSignal.wasInterrupted()\n ? SIGINT_EXIT_CODE\n : mainExits || isCliValidationError(error) || isPipelineExecutionError(error)\n ? toExitCode(error)\n : 1;\n } finally {\n if (managedSignal.wasInterrupted()) {\n process.exitCode = SIGINT_EXIT_CODE;\n }\n managedSignal.cleanup();\n }\n }\n\n return { descriptor, execute, parse, parseValues, run, main };\n}\n\nfunction normalizeStructuredValue(\n key: string,\n param: CliParamsSchema[string],\n value: unknown,\n errors: string[]\n): string | boolean | string[] | undefined {\n if (value === undefined) return undefined;\n const label = `--${param.flag ?? key}`;\n if (param.type === \"boolean\") {\n if (typeof value === \"boolean\") return value;\n errors.push(`${label} must be a boolean value.`);\n return undefined;\n }\n if ((param.type === \"number\" || param.type === \"string\") && param.multiple === true) {\n if (!Array.isArray(value)) {\n errors.push(`${label} must be an array.`);\n return undefined;\n }\n if (param.type === \"number\") {\n if (!value.every((item) => typeof item === \"number\" && Number.isFinite(item))) {\n errors.push(`${label} must contain only finite numbers.`);\n return undefined;\n }\n return value.map(String);\n }\n if (!value.every((item) => typeof item === \"string\")) {\n errors.push(`${label} must contain only strings.`);\n return undefined;\n }\n return [...value];\n }\n if (param.type === \"number\") {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n errors.push(`${label} must be a finite number.`);\n return undefined;\n }\n return String(value);\n }\n if (typeof value !== \"string\") {\n errors.push(`${label} must be a string value.`);\n return undefined;\n }\n return value;\n}\n\nexport function defineCommand<const TSchema extends CliParamsSchema, TResult = void>(\n config: CliCommandConfig<TSchema, TResult>\n): CliCommand<TSchema, TResult> {\n return createCommand(config);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cli-command.js","sourceRoot":"","sources":["../../src/cli/cli-command.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from \"path\";\nimport { openCheckpoint, type CheckpointStore } from \"../node/checkpoint.js\";\nimport {\n assertNoDuplicateFlags,\n assertValidEnvironmentFallbacks,\n assertValidMultipleParams,\n assertValidPositionals,\n buildEffectiveSchema,\n commandDescriptor,\n renderHelp,\n resolveParam,\n tokenize,\n type ResolvedParamValue,\n} from \"./cli-parser.js\";\nimport {\n CliHelpRequested,\n CliValidationError,\n type CliCommand,\n type CliCommandConfig,\n type CliContext,\n type CliParams,\n type CliParamsSchema,\n type CliParseResult,\n} from \"./cli-types.js\";\nimport { isCliValidationError, isPipelineExecutionError, toExitCode } from \"./cli-exit.js\";\n\nfunction resolveContext(overrides?: Partial<CliContext>): CliContext {\n return {\n cwd: overrides?.cwd ?? process.cwd(),\n env: overrides?.env ?? process.env,\n log: overrides?.log ?? console,\n pipelineContext: overrides?.pipelineContext,\n signal: overrides?.signal,\n checkpoint: overrides?.checkpoint,\n };\n}\n\ninterface ManagedMainSignal {\n context: CliContext;\n wasInterrupted(): boolean;\n cleanup(): void;\n}\n\nconst SIGINT_EXIT_CODE = 130;\n\n/**\n * Give real CLI entrypoints graceful cancellation without making `run()` or\n * `parse()` mutate process-global signal handlers. Embedded callers can pass\n * their own signal through the context instead.\n */\nfunction manageMainSignal(context: CliContext): ManagedMainSignal {\n if (context.signal) {\n return { context, wasInterrupted: () => false, cleanup: () => {} };\n }\n\n const controller = new AbortController();\n let interrupted = false;\n const onSigint = (): void => {\n interrupted = true;\n context.log.warn(\"SIGINT received; cancelling pipeline work.\");\n controller.abort();\n };\n process.once(\"SIGINT\", onSigint);\n\n return {\n context: { ...context, signal: controller.signal },\n wasInterrupted: () => interrupted,\n cleanup: () => process.removeListener(\"SIGINT\", onSigint),\n };\n}\n\n/**\n * An in-memory-only `CheckpointStore` seeded from `seed`: reads and `record()` behave\n * exactly like a real store for the rest of this run, but `flush()`/`clear()` never touch\n * disk. Every dry-run path hands `run` one of these instead of the real store — the\n * managed-checkpoint contract is that a dry run never writes to the checkpoint file, no\n * matter what `run` does with `context.checkpoint` (`record`/`flush`/`clear`, directly or\n * via `withCheckpointedBatch`).\n */\nfunction inMemoryCheckpointView(seed: ReadonlyMap<string, unknown>): CheckpointStore {\n const entries = new Map(seed);\n return {\n has: (key) => entries.has(key),\n record: (key, meta) => {\n entries.set(key, meta);\n },\n entries: () => entries,\n flush: () => {},\n clear: () => {\n entries.clear();\n },\n };\n}\n\nexport function createCommand<const TSchema extends CliParamsSchema, TResult = void>(\n config: CliCommandConfig<TSchema, TResult>,\n mainExits?: { validation?: number }\n): CliCommand<TSchema, TResult> {\n const effectiveParams = buildEffectiveSchema(config.params, config.checkpoint);\n assertNoDuplicateFlags(effectiveParams);\n assertValidMultipleParams(effectiveParams);\n assertValidEnvironmentFallbacks(effectiveParams);\n const positionals = [...(config.positionals ?? [])];\n assertValidPositionals(positionals, effectiveParams);\n const descriptor = commandDescriptor(config, effectiveParams, positionals);\n\n function resolveValues(\n readValue: (\n key: string,\n param: CliParamsSchema[string]\n ) => string | boolean | string[] | undefined,\n context: CliContext,\n errors: string[],\n helpText: string\n ): CliParseResult<TSchema> {\n const values: Record<string, ResolvedParamValue> = {};\n for (const [key, param] of Object.entries(effectiveParams)) {\n const errorCount = errors.length;\n const raw = readValue(key, param);\n if (errors.length > errorCount) continue;\n const envValue = raw === undefined && param.env ? context.env?.[param.env] : undefined;\n values[key] = resolveParam(\n key,\n param,\n raw ?? envValue,\n context.cwd,\n errors,\n raw !== undefined ? \"argv\" : envValue !== undefined ? \"env\" : \"default\"\n );\n }\n if (errors.length > 0) return { kind: \"error\", errors, helpText };\n // SAFETY: resolveParam populated every effective schema key and all input checks passed.\n const typedValues = values as CliParams<TSchema>;\n const validationErrors = config.validate?.(typedValues, context) ?? [];\n return validationErrors.length > 0\n ? { kind: \"error\", errors: validationErrors, helpText }\n : { kind: \"values\", values: typedValues };\n }\n\n function parseWithContext(argv: readonly string[], context: CliContext): CliParseResult<TSchema> {\n const helpText = renderHelp(\n descriptor.name,\n descriptor.description,\n effectiveParams,\n positionals\n );\n const tokenized = tokenize(argv, effectiveParams, positionals);\n if (tokenized.help) return { kind: \"help\", helpText };\n return resolveValues(\n (key) => tokenized.values.get(key),\n context,\n [...tokenized.errors],\n helpText\n );\n }\n\n function parse(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): CliParseResult<TSchema> {\n return parseWithContext(argv, resolveContext(contextOverrides));\n }\n\n function parseStructuredWithContext(\n structuredValues: Record<string, unknown>,\n context: CliContext\n ): CliParseResult<TSchema> {\n const helpText = renderHelp(\n descriptor.name,\n descriptor.description,\n effectiveParams,\n positionals\n );\n const errors: string[] = [];\n for (const key of Object.keys(structuredValues)) {\n if (!Object.prototype.hasOwnProperty.call(effectiveParams, key)) {\n errors.push(`Unknown parameter: ${key}`);\n }\n }\n return resolveValues(\n (key, param) => normalizeStructuredValue(key, param, structuredValues[key], errors),\n context,\n errors,\n helpText\n );\n }\n\n /**\n * No-op unless `config.checkpoint` is set. Respects a caller-provided `context.checkpoint`\n * override (e.g. a stub in tests) instead of opening the real file. Otherwise opens (or\n * clears, if not resuming) the checkpoint before `run` is called — never on the `--help`/\n * error paths, since those return before this is reached.\n */\n function attachCheckpoint(context: CliContext, values: CliParams<TSchema>): CliContext {\n const checkpointConfig = config.checkpoint;\n if (!checkpointConfig) {\n return context;\n }\n const resolvedPath = path.isAbsolute(checkpointConfig.path)\n ? checkpointConfig.path\n : path.join(context.cwd, checkpointConfig.path);\n // A caller-provided context.checkpoint (e.g. a stub in tests) is used as the\n // underlying store instead of opening the real file, but every rule below — fresh\n // clearing, dry-run wrapping, resume detection/logging — still applies to it; only\n // the \"where does the store come from\" step is skipped.\n const store = context.checkpoint ?? openCheckpoint(resolvedPath);\n const hadExisting = store.entries().size > 0;\n\n if (values.resume) {\n if (hadExisting) {\n context.log.log(\n `Resuming from checkpoint: ${store.entries().size} item(s) already recorded.`\n );\n } else {\n // Without this, --resume against a missing/wrong-path/already-cleared checkpoint\n // silently starts fresh — the exact failure mode that's dangerous for\n // clearOnSuccess: false workflows, where \"fresh\" quietly means \"reprocess\n // everything already done\".\n context.log.warn(\n `--resume was passed, but no checkpoint was found at ${resolvedPath}; starting fresh.`\n );\n }\n // A dry run must never write to the checkpoint file, even while resuming — an\n // in-memory view seeded with the real entries previews it accurately without risk.\n return {\n ...context,\n checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,\n };\n }\n\n if (!hadExisting) {\n return {\n ...context,\n checkpoint: values.dryRun ? inMemoryCheckpointView(store.entries()) : store,\n };\n }\n\n if (values.dryRun) {\n // Dry run must not touch the file — neither clearing it nor writing new progress —\n // but the preview should still reflect what a real fresh run would see: an empty\n // \"done\" set, not the stale entries a --resume invocation would use.\n context.log.log(\"Dry run: leaving existing checkpoint untouched (would start fresh).\");\n return { ...context, checkpoint: inMemoryCheckpointView(new Map()) };\n }\n\n store.clear();\n context.log.log(\"Starting fresh — cleared existing checkpoint.\");\n return { ...context, checkpoint: store };\n }\n\n /**\n * No-op unless `config.checkpoint` is set, a store is attached, and the run completed\n * without a dry run or caller cancellation.\n */\n function finalizeCheckpoint(context: CliContext, values: CliParams<TSchema>): void {\n const checkpointConfig = config.checkpoint;\n if (!checkpointConfig || !context.checkpoint || values.dryRun || context.signal?.aborted) {\n return;\n }\n if (checkpointConfig.clearOnSuccess === false) {\n return;\n }\n context.checkpoint.clear();\n }\n\n async function executeValues(values: CliParams<TSchema>, context: CliContext): Promise<TResult> {\n const runContext = attachCheckpoint(context, values);\n const value = await config.run(values, runContext);\n finalizeCheckpoint(runContext, values);\n return value;\n }\n\n function parseValues(\n values: Record<string, unknown>,\n contextOverrides?: Partial<CliContext>\n ): CliParseResult<TSchema> {\n const context = resolveContext(contextOverrides);\n return parseStructuredWithContext(values, context);\n }\n\n async function execute(\n values: CliParams<TSchema>,\n contextOverrides?: Partial<CliContext>\n ): Promise<TResult> {\n return executeValues(values, resolveContext(contextOverrides));\n }\n\n async function run(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): Promise<TResult> {\n const context = resolveContext(contextOverrides);\n const result = parseWithContext(argv, context);\n if (result.kind === \"help\") throw new CliHelpRequested(result.helpText);\n if (result.kind === \"error\") throw new CliValidationError(result.errors, result.helpText);\n return executeValues(result.values, context);\n }\n\n async function main(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): Promise<void> {\n const context = resolveContext(contextOverrides);\n let result: CliParseResult<TSchema>;\n try {\n result = parseWithContext(argv, context);\n } catch (error) {\n context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.exitCode =\n mainExits || isCliValidationError(error) || isPipelineExecutionError(error)\n ? toExitCode(error)\n : 1;\n return;\n }\n if (result.kind === \"help\") {\n context.log.log(result.helpText);\n process.exitCode = 0;\n return;\n }\n if (result.kind === \"error\") {\n for (const error of result.errors) {\n context.log.error(`Error: ${error}`);\n }\n context.log.error(\"\");\n context.log.error(result.helpText);\n process.exitCode = mainExits?.validation ?? 1;\n return;\n }\n const managedSignal = manageMainSignal(context);\n try {\n const runContext = attachCheckpoint(managedSignal.context, result.values);\n await config.run(result.values, runContext);\n if (!managedSignal.wasInterrupted()) {\n finalizeCheckpoint(runContext, result.values);\n }\n } catch (error) {\n context.log.error(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.exitCode = managedSignal.wasInterrupted()\n ? SIGINT_EXIT_CODE\n : mainExits || isCliValidationError(error) || isPipelineExecutionError(error)\n ? toExitCode(error)\n : 1;\n } finally {\n if (managedSignal.wasInterrupted()) {\n process.exitCode = SIGINT_EXIT_CODE;\n }\n managedSignal.cleanup();\n }\n }\n\n return { descriptor, execute, parse, parseValues, run, main };\n}\n\nfunction normalizeStructuredValue(\n key: string,\n param: CliParamsSchema[string],\n value: unknown,\n errors: string[]\n): string | boolean | string[] | undefined {\n if (value === undefined) return undefined;\n const label = `--${param.flag ?? key}`;\n if (param.type === \"boolean\") {\n if (typeof value === \"boolean\") return value;\n errors.push(`${label} must be a boolean value.`);\n return undefined;\n }\n if ((param.type === \"number\" || param.type === \"string\") && param.multiple === true) {\n if (!Array.isArray(value)) {\n errors.push(`${label} must be an array.`);\n return undefined;\n }\n if (param.type === \"number\") {\n if (!value.every((item) => typeof item === \"number\" && Number.isFinite(item))) {\n errors.push(`${label} must contain only finite numbers.`);\n return undefined;\n }\n return value.map(String);\n }\n if (!value.every((item) => typeof item === \"string\")) {\n errors.push(`${label} must contain only strings.`);\n return undefined;\n }\n return [...value];\n }\n if (param.type === \"number\") {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n errors.push(`${label} must be a finite number.`);\n return undefined;\n }\n return String(value);\n }\n if (typeof value !== \"string\") {\n errors.push(`${label} must be a string value.`);\n return undefined;\n }\n return value;\n}\n\nexport function defineCommand<const TSchema extends CliParamsSchema, TResult = void>(\n config: CliCommandConfig<TSchema, TResult>\n): CliCommand<TSchema, TResult> {\n return createCommand(config);\n}\n"]}
|
|
@@ -153,7 +153,7 @@ export function definePipelineCommand(pipeline, config) {
|
|
|
153
153
|
return result;
|
|
154
154
|
},
|
|
155
155
|
};
|
|
156
|
-
const command = createCommand(commandConfig,
|
|
156
|
+
const command = createCommand(commandConfig, {
|
|
157
157
|
validation: TUBELESS_WORKBENCH_EXIT_CODE.validation,
|
|
158
158
|
});
|
|
159
159
|
function parse(argv = process.argv.slice(2), contextOverrides) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-pipeline-command.js","sourceRoot":"","sources":["../../src/cli/cli-pipeline-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCommand } from \"./cli-command.js\";\nimport { flagName } from \"./cli-parser.js\";\nimport type {\n CliBooleanParam,\n CliCheckpointConfig,\n CliCommandConfig,\n CliCommandDescriptor,\n CliContext,\n CliParams,\n CliParamsSchema,\n CliStringParam,\n} from \"./cli-types.js\";\nimport { markPipelineCommand } from \"./pipeline-command-marker.js\";\nimport {\n type Pipeline,\n type PipelineHooks,\n type PipelineMermaidOptions,\n type PipelinePlan,\n type PipelineRunControls,\n} from \"../core/pipeline.js\";\nimport { createPipelineReporter, type PipelineReporterConfig } from \"../reporter/reporter-entry.js\";\nimport { TUBELESS_WORKBENCH_EXIT_CODE } from \"./cli-exit.js\";\n\nexport type PipelineCliBuiltins = {\n stepIds: CliStringParam & { multiple: true };\n targets: CliStringParam & { multiple: true };\n continueOnError: CliBooleanParam;\n};\n\nexport type PipelineCliValues<TSchema extends CliParamsSchema> = CliParams<TSchema> & {\n stepIds: readonly string[];\n targets: readonly string[];\n continueOnError: boolean;\n};\n\nexport type PipelineCliParseResult<TSchema extends CliParamsSchema> =\n | { kind: \"values\"; values: PipelineCliValues<TSchema> }\n | { kind: \"help\"; helpText: string }\n | { kind: \"error\"; errors: readonly string[]; helpText: string };\n\nexport interface PipelineCommand<TSchema extends CliParamsSchema, TResult> {\n readonly descriptor: CliCommandDescriptor;\n /** Stable identity of the wrapped pipeline. */\n readonly id: string;\n /** Stable definition-order step ids for discovery surfaces such as CLI help. */\n readonly stepIds: readonly string[];\n /** Stable declared goal ids that support dependency-aware target execution. */\n readonly targetIds: readonly string[];\n /** Plan without parsing or requiring domain parameters. */\n plan(controls?: PipelineRunControls): PipelinePlan;\n /** Generate a static Mermaid flowchart without running or planning the pipeline. */\n toMermaid(options?: PipelineMermaidOptions): string;\n parse(argv?: readonly string[], context?: Partial<CliContext>): PipelineCliParseResult<TSchema>;\n /** Validate structured form values without tokenizing argv. */\n parseValues(\n values: Record<string, unknown>,\n context?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema>;\n /** Execute already validated form values. */\n execute(values: PipelineCliValues<TSchema>, context?: Partial<CliContext>): Promise<TResult>;\n run(argv?: readonly string[], context?: Partial<CliContext>): Promise<TResult>;\n main(argv?: readonly string[], context?: Partial<CliContext>): Promise<void>;\n}\n\nexport interface PipelineCommandHookContext<TSchema extends CliParamsSchema> {\n context: CliContext;\n values: PipelineCliValues<TSchema>;\n}\n\nexport type PipelineCommandHookSets<TResult> =\n | PipelineHooks<TResult>\n | readonly PipelineHooks<TResult>[];\n\nexport type PipelineCommandHookConfig<TResult, TSchema extends CliParamsSchema> =\n | PipelineCommandHookSets<TResult>\n | ((input: PipelineCommandHookContext<TSchema>) => PipelineCommandHookSets<TResult> | undefined);\n\ntype PipelineCommandMapOptions<TOptions extends object, TSchema extends CliParamsSchema> = (\n values: PipelineCliValues<TSchema>,\n context: CliContext\n) => TOptions | Promise<TOptions>;\n\ntype DefaultPipelineCommandOptions<TSchema extends CliParamsSchema> = Omit<\n PipelineCliValues<TSchema>,\n \"continueOnError\" | \"dryRun\" | \"resume\" | \"stepIds\" | \"targets\"\n>;\n\ntype CanDefaultPipelineCommandOptions<TOptions extends object, TSchema extends CliParamsSchema> =\n DefaultPipelineCommandOptions<TSchema> extends TOptions\n ? Exclude<keyof TSchema, keyof TOptions> extends never\n ? true\n : false\n : false;\n\ninterface DefinePipelineCommandConfigBase<TResult, TSchema extends CliParamsSchema> {\n /** Defaults to pipeline.id. */\n name?: string;\n description?: string;\n /** Extra flags beyond the command and pipeline built-ins. */\n params?: TSchema;\n /** Extra parameter keys accepted in positional order. */\n positionals?: readonly (keyof TSchema & string)[];\n checkpoint?: CliCheckpointConfig;\n /** Additional lifecycle hooks, or a factory resolved from parsed values and CLI context. */\n hooks?: PipelineCommandHookConfig<TResult, TSchema>;\n /** Configure plain/interactive reporting, or disable it. Defaults to automatic mode. */\n reporter?: false | PipelineReporterConfig;\n /** Print domain-specific result lines after a successful run. */\n summarize?(\n result: TResult,\n values: PipelineCliValues<TSchema>,\n context: CliContext\n ): readonly string[] | void;\n validate?(values: PipelineCliValues<TSchema>, context: CliContext): string[] | void;\n}\n\n/** Configuration for a typed pipeline command. Mapping is optional only for compatible flags. */\nexport type DefinePipelineCommandConfig<\n TOptions extends object,\n TResult,\n TSchema extends CliParamsSchema,\n> = DefinePipelineCommandConfigBase<TResult, TSchema> &\n (CanDefaultPipelineCommandOptions<TOptions, TSchema> extends true\n ? {\n /** Override the default same-name flag-to-option mapping. */\n mapOptions?: PipelineCommandMapOptions<TOptions, TSchema>;\n }\n : {\n /** Required when parsed flags do not already satisfy the pipeline's domain options. */\n mapOptions: PipelineCommandMapOptions<TOptions, TSchema>;\n });\n\nconst PIPELINE_COMMAND_KEYS = new Set([\"continueOnError\", \"stepIds\", \"targets\"]);\nconst PIPELINE_COMMAND_FLAGS = new Set([\"continue-on-error\", \"step\", \"target\"]);\n\nfunction assertNoPipelineCommandConflicts(params: CliParamsSchema): void {\n for (const [key, param] of Object.entries(params)) {\n if (PIPELINE_COMMAND_KEYS.has(key)) {\n throw new Error(\n `\"${key}\" is a reserved parameter provided automatically by pipeline commands; remove it from params.`\n );\n }\n const flag = flagName(key, param);\n if (PIPELINE_COMMAND_FLAGS.has(flag)) {\n throw new Error(\n `--${flag} is a reserved flag provided automatically by pipeline commands; remove \"${key}\" from params or give it a different flag name.`\n );\n }\n }\n}\n\nfunction normalizePipelineCliValues<TSchema extends CliParamsSchema>(\n values: CliParams<PipelineCliBuiltins & TSchema>\n): PipelineCliValues<TSchema> {\n // SAFETY: `PipelineCliValues<TSchema>` is `CliParams<TSchema>` plus the builtin\n // `stepIds`/`targets`/`continueOnError` keys, all of which `CliParams<PipelineCliBuiltins & TSchema>`\n // already provides, so the runtime shape matches the target type.\n const pipelineValues = values as PipelineCliValues<TSchema>;\n const { continueOnError, stepIds, targets } = pipelineValues;\n return {\n ...pipelineValues,\n continueOnError,\n stepIds,\n targets: targets ?? [],\n };\n}\n\nfunction pipelineRunControlsFromCliValues(values: {\n continueOnError: boolean;\n dryRun: boolean;\n stepIds: readonly string[];\n targets: readonly string[];\n}): PipelineRunControls {\n const controls: PipelineRunControls = {\n dryRun: values.dryRun,\n continueOnError: values.continueOnError,\n };\n if (values.stepIds.length > 0) controls.stepIds = values.stepIds;\n if (values.targets.length > 0) controls.targets = values.targets;\n return controls;\n}\n\nfunction normalizePipelineHookSets<TResult>(\n hooks: PipelineCommandHookSets<TResult> | undefined\n): PipelineHooks<TResult>[] {\n if (!hooks) return [];\n // SAFETY: a non-array `PipelineCommandHookSets` is always a single `PipelineHooks`.\n return Array.isArray(hooks) ? [...hooks] : [hooks as PipelineHooks<TResult>];\n}\n\nfunction isHookConfigFunction<TResult, TSchema extends CliParamsSchema>(\n config: PipelineCommandHookConfig<TResult, TSchema> | undefined\n): config is (\n input: PipelineCommandHookContext<TSchema>\n) => PipelineCommandHookSets<TResult> | undefined {\n return typeof config === \"function\";\n}\n\nfunction defaultPipelineCommandOptions<TSchema extends CliParamsSchema>(\n values: PipelineCliValues<TSchema>\n): DefaultPipelineCommandOptions<TSchema> {\n const {\n continueOnError: _continueOnError,\n dryRun: _dryRun,\n resume: _resume,\n stepIds: _stepIds,\n targets: _targets,\n ...domainValues\n } = values;\n return domainValues;\n}\n\n/** Turn a typed pipeline into a command with selection, plan, and reporting defaults. */\nexport function definePipelineCommand<\n TOptions extends object,\n TResult,\n const TSchema extends CliParamsSchema = {},\n>(\n pipeline: Pipeline<TOptions, TResult>,\n config: DefinePipelineCommandConfig<NoInfer<TOptions>, TResult, TSchema>\n): PipelineCommand<TSchema, TResult> {\n // SAFETY: `config.params` is declared as `TSchema`; the empty-object fallback is only\n // reached when the caller omits `params`, which is exactly the `{}` schema case.\n const userParams = config.params ?? ({} as TSchema);\n assertNoPipelineCommandConflicts(userParams);\n\n const targetFlagEnabled = pipeline.targetIds.length > 0;\n const bridgeParams: CliParamsSchema = {\n stepIds: {\n type: \"string\",\n multiple: true,\n flag: \"step\",\n group: \"execution\",\n exclusive: true,\n choices: pipeline.stepIds,\n description: `Run exactly this step. Steps: ${pipeline.stepIds.join(\", \")}`,\n },\n continueOnError: {\n type: \"boolean\",\n group: \"execution\",\n description: \"Continue independent work after a step fails.\",\n },\n };\n if (targetFlagEnabled) {\n bridgeParams.targets = {\n type: \"string\",\n multiple: true,\n flag: \"target\",\n group: \"execution\",\n exclusive: true,\n choices: pipeline.targetIds,\n description: `Run this declared target and its prerequisites. Targets: ${pipeline.targetIds.join(\", \")}`,\n };\n }\n\n // SAFETY: `bridgeParams` supplies the `PipelineCliBuiltins` keys and `userParams` is\n // `TSchema`, so the merged object satisfies `PipelineCliBuiltins & TSchema`.\n const params = { ...bridgeParams, ...userParams } as PipelineCliBuiltins & TSchema;\n\n const commandConfig = {\n name: config.name ?? pipeline.id,\n description: config.description,\n params,\n positionals: config.positionals,\n checkpoint: config.checkpoint,\n validate: (values, context) => {\n const pipelineValues = normalizePipelineCliValues<TSchema>(values);\n const errors = config.validate?.(pipelineValues, context) ?? [];\n if (pipelineValues.stepIds.length > 0 && pipelineValues.targets.length > 0) {\n return [\"--step and --target cannot be used together.\", ...errors];\n }\n return errors.length > 0 ? errors : undefined;\n },\n run: async (values, cliContext) => {\n const pipelineValues = normalizePipelineCliValues<TSchema>(values);\n let mapped: TOptions;\n if (config.mapOptions) {\n mapped = await config.mapOptions(pipelineValues, cliContext);\n } else {\n // SAFETY: `defaultPipelineCommandOptions` returns exactly the domain options the\n // `CanDefaultPipelineCommandOptions` constraint guarantees map to `TOptions`.\n mapped = defaultPipelineCommandOptions(pipelineValues) as TOptions;\n }\n const controls = pipelineRunControlsFromCliValues({\n dryRun: values.dryRun,\n continueOnError: pipelineValues.continueOnError,\n stepIds: pipelineValues.stepIds,\n targets: targetFlagEnabled ? pipelineValues.targets : [],\n });\n\n const reporter =\n config.reporter === false\n ? undefined\n : createPipelineReporter<TResult>({ log: cliContext.log, ...(config.reporter ?? {}) });\n const runtimeContext = reporter ? { ...cliContext, log: reporter.log } : cliContext;\n let result: TResult;\n try {\n const configuredHooks = isHookConfigFunction(config.hooks)\n ? config.hooks({ context: runtimeContext, values: pipelineValues })\n : config.hooks;\n const hooks: PipelineHooks<TResult>[] = [\n ...normalizePipelineHookSets(cliContext.pipelineContext?.hooks),\n ...(reporter ? [reporter.hooks] : []),\n ...normalizePipelineHookSets(configuredHooks),\n ];\n\n result = await pipeline.runOrThrow(mapped, controls, {\n ...cliContext.pipelineContext,\n cwd: runtimeContext.cwd,\n log: runtimeContext.log,\n hooks: hooks.length > 0 ? hooks : undefined,\n signal: runtimeContext.signal,\n });\n } finally {\n reporter?.dispose();\n }\n for (const line of config.summarize?.(result, pipelineValues, cliContext) ?? []) {\n cliContext.log.log(line);\n }\n return result;\n },\n } satisfies CliCommandConfig<PipelineCliBuiltins & TSchema, TResult>;\n\n const command = createCommand(commandConfig, undefined, {\n validation: TUBELESS_WORKBENCH_EXIT_CODE.validation,\n });\n\n function parse(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema> {\n const result = command.parse(argv, contextOverrides);\n return result.kind === \"values\"\n ? { kind: \"values\", values: normalizePipelineCliValues<TSchema>(result.values) }\n : result;\n }\n\n function plan(controls: PipelineRunControls = {}): PipelinePlan {\n return pipeline.plan(controls);\n }\n\n function parseValues(\n values: Record<string, unknown>,\n contextOverrides?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema> {\n const result = command.parseValues(values, contextOverrides);\n return result.kind === \"values\"\n ? { kind: \"values\", values: normalizePipelineCliValues<TSchema>(result.values) }\n : result;\n }\n\n return markPipelineCommand({\n descriptor: command.descriptor,\n id: pipeline.id,\n stepIds: pipeline.stepIds,\n targetIds: pipeline.targetIds,\n execute: (values, contextOverrides) =>\n // SAFETY: `execute` receives `PipelineCliValues<TSchema>` from the public interface,\n // which is a subtype of `CliParams<PipelineCliBuiltins & TSchema>`.\n command.execute(values as CliParams<PipelineCliBuiltins & TSchema>, contextOverrides),\n parse,\n parseValues,\n plan,\n toMermaid: (options) => pipeline.toMermaid(options),\n run: command.run,\n main: command.main,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cli-pipeline-command.js","sourceRoot":"","sources":["../../src/cli/cli-pipeline-command.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCommand } from \"./cli-command.js\";\nimport { flagName } from \"./cli-parser.js\";\nimport type {\n CliBooleanParam,\n CliCheckpointConfig,\n CliCommandConfig,\n CliCommandDescriptor,\n CliContext,\n CliParams,\n CliParamsSchema,\n CliStringParam,\n} from \"./cli-types.js\";\nimport { markPipelineCommand } from \"./pipeline-command-marker.js\";\nimport {\n type Pipeline,\n type PipelineHooks,\n type PipelineMermaidOptions,\n type PipelinePlan,\n type PipelineRunControls,\n} from \"../core/pipeline.js\";\nimport { createPipelineReporter, type PipelineReporterConfig } from \"../reporter/reporter-entry.js\";\nimport { TUBELESS_WORKBENCH_EXIT_CODE } from \"./cli-exit.js\";\n\nexport type PipelineCliBuiltins = {\n stepIds: CliStringParam & { multiple: true };\n targets: CliStringParam & { multiple: true };\n continueOnError: CliBooleanParam;\n};\n\nexport type PipelineCliValues<TSchema extends CliParamsSchema> = CliParams<TSchema> & {\n stepIds: readonly string[];\n targets: readonly string[];\n continueOnError: boolean;\n};\n\nexport type PipelineCliParseResult<TSchema extends CliParamsSchema> =\n | { kind: \"values\"; values: PipelineCliValues<TSchema> }\n | { kind: \"help\"; helpText: string }\n | { kind: \"error\"; errors: readonly string[]; helpText: string };\n\nexport interface PipelineCommand<TSchema extends CliParamsSchema, TResult> {\n readonly descriptor: CliCommandDescriptor;\n /** Stable identity of the wrapped pipeline. */\n readonly id: string;\n /** Stable definition-order step ids for discovery surfaces such as CLI help. */\n readonly stepIds: readonly string[];\n /** Stable declared goal ids that support dependency-aware target execution. */\n readonly targetIds: readonly string[];\n /** Plan without parsing or requiring domain parameters. */\n plan(controls?: PipelineRunControls): PipelinePlan;\n /** Generate a static Mermaid flowchart without running or planning the pipeline. */\n toMermaid(options?: PipelineMermaidOptions): string;\n parse(argv?: readonly string[], context?: Partial<CliContext>): PipelineCliParseResult<TSchema>;\n /** Validate structured form values without tokenizing argv. */\n parseValues(\n values: Record<string, unknown>,\n context?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema>;\n /** Execute already validated form values. */\n execute(values: PipelineCliValues<TSchema>, context?: Partial<CliContext>): Promise<TResult>;\n run(argv?: readonly string[], context?: Partial<CliContext>): Promise<TResult>;\n main(argv?: readonly string[], context?: Partial<CliContext>): Promise<void>;\n}\n\nexport interface PipelineCommandHookContext<TSchema extends CliParamsSchema> {\n context: CliContext;\n values: PipelineCliValues<TSchema>;\n}\n\nexport type PipelineCommandHookSets<TResult> =\n | PipelineHooks<TResult>\n | readonly PipelineHooks<TResult>[];\n\nexport type PipelineCommandHookConfig<TResult, TSchema extends CliParamsSchema> =\n | PipelineCommandHookSets<TResult>\n | ((input: PipelineCommandHookContext<TSchema>) => PipelineCommandHookSets<TResult> | undefined);\n\ntype PipelineCommandMapOptions<TOptions extends object, TSchema extends CliParamsSchema> = (\n values: PipelineCliValues<TSchema>,\n context: CliContext\n) => TOptions | Promise<TOptions>;\n\ntype DefaultPipelineCommandOptions<TSchema extends CliParamsSchema> = Omit<\n PipelineCliValues<TSchema>,\n \"continueOnError\" | \"dryRun\" | \"resume\" | \"stepIds\" | \"targets\"\n>;\n\ntype CanDefaultPipelineCommandOptions<TOptions extends object, TSchema extends CliParamsSchema> =\n DefaultPipelineCommandOptions<TSchema> extends TOptions\n ? Exclude<keyof TSchema, keyof TOptions> extends never\n ? true\n : false\n : false;\n\ninterface DefinePipelineCommandConfigBase<TResult, TSchema extends CliParamsSchema> {\n /** Defaults to pipeline.id. */\n name?: string;\n description?: string;\n /** Extra flags beyond the command and pipeline built-ins. */\n params?: TSchema;\n /** Extra parameter keys accepted in positional order. */\n positionals?: readonly (keyof TSchema & string)[];\n checkpoint?: CliCheckpointConfig;\n /** Additional lifecycle hooks, or a factory resolved from parsed values and CLI context. */\n hooks?: PipelineCommandHookConfig<TResult, TSchema>;\n /** Configure plain/interactive reporting, or disable it. Defaults to automatic mode. */\n reporter?: false | PipelineReporterConfig;\n /** Print domain-specific result lines after a successful run. */\n summarize?(\n result: TResult,\n values: PipelineCliValues<TSchema>,\n context: CliContext\n ): readonly string[] | void;\n validate?(values: PipelineCliValues<TSchema>, context: CliContext): string[] | void;\n}\n\n/** Configuration for a typed pipeline command. Mapping is optional only for compatible flags. */\nexport type DefinePipelineCommandConfig<\n TOptions extends object,\n TResult,\n TSchema extends CliParamsSchema,\n> = DefinePipelineCommandConfigBase<TResult, TSchema> &\n (CanDefaultPipelineCommandOptions<TOptions, TSchema> extends true\n ? {\n /** Override the default same-name flag-to-option mapping. */\n mapOptions?: PipelineCommandMapOptions<TOptions, TSchema>;\n }\n : {\n /** Required when parsed flags do not already satisfy the pipeline's domain options. */\n mapOptions: PipelineCommandMapOptions<TOptions, TSchema>;\n });\n\nconst PIPELINE_COMMAND_KEYS = new Set([\"continueOnError\", \"stepIds\", \"targets\"]);\nconst PIPELINE_COMMAND_FLAGS = new Set([\"continue-on-error\", \"step\", \"target\"]);\n\nfunction assertNoPipelineCommandConflicts(params: CliParamsSchema): void {\n for (const [key, param] of Object.entries(params)) {\n if (PIPELINE_COMMAND_KEYS.has(key)) {\n throw new Error(\n `\"${key}\" is a reserved parameter provided automatically by pipeline commands; remove it from params.`\n );\n }\n const flag = flagName(key, param);\n if (PIPELINE_COMMAND_FLAGS.has(flag)) {\n throw new Error(\n `--${flag} is a reserved flag provided automatically by pipeline commands; remove \"${key}\" from params or give it a different flag name.`\n );\n }\n }\n}\n\nfunction normalizePipelineCliValues<TSchema extends CliParamsSchema>(\n values: CliParams<PipelineCliBuiltins & TSchema>\n): PipelineCliValues<TSchema> {\n // SAFETY: `PipelineCliValues<TSchema>` is `CliParams<TSchema>` plus the builtin\n // `stepIds`/`targets`/`continueOnError` keys, all of which `CliParams<PipelineCliBuiltins & TSchema>`\n // already provides, so the runtime shape matches the target type.\n const pipelineValues = values as PipelineCliValues<TSchema>;\n const { continueOnError, stepIds, targets } = pipelineValues;\n return {\n ...pipelineValues,\n continueOnError,\n stepIds,\n targets: targets ?? [],\n };\n}\n\nfunction pipelineRunControlsFromCliValues(values: {\n continueOnError: boolean;\n dryRun: boolean;\n stepIds: readonly string[];\n targets: readonly string[];\n}): PipelineRunControls {\n const controls: PipelineRunControls = {\n dryRun: values.dryRun,\n continueOnError: values.continueOnError,\n };\n if (values.stepIds.length > 0) controls.stepIds = values.stepIds;\n if (values.targets.length > 0) controls.targets = values.targets;\n return controls;\n}\n\nfunction normalizePipelineHookSets<TResult>(\n hooks: PipelineCommandHookSets<TResult> | undefined\n): PipelineHooks<TResult>[] {\n if (!hooks) return [];\n // SAFETY: a non-array `PipelineCommandHookSets` is always a single `PipelineHooks`.\n return Array.isArray(hooks) ? [...hooks] : [hooks as PipelineHooks<TResult>];\n}\n\nfunction isHookConfigFunction<TResult, TSchema extends CliParamsSchema>(\n config: PipelineCommandHookConfig<TResult, TSchema> | undefined\n): config is (\n input: PipelineCommandHookContext<TSchema>\n) => PipelineCommandHookSets<TResult> | undefined {\n return typeof config === \"function\";\n}\n\nfunction defaultPipelineCommandOptions<TSchema extends CliParamsSchema>(\n values: PipelineCliValues<TSchema>\n): DefaultPipelineCommandOptions<TSchema> {\n const {\n continueOnError: _continueOnError,\n dryRun: _dryRun,\n resume: _resume,\n stepIds: _stepIds,\n targets: _targets,\n ...domainValues\n } = values;\n return domainValues;\n}\n\n/** Turn a typed pipeline into a command with selection, plan, and reporting defaults. */\nexport function definePipelineCommand<\n TOptions extends object,\n TResult,\n const TSchema extends CliParamsSchema = {},\n>(\n pipeline: Pipeline<TOptions, TResult>,\n config: DefinePipelineCommandConfig<NoInfer<TOptions>, TResult, TSchema>\n): PipelineCommand<TSchema, TResult> {\n // SAFETY: `config.params` is declared as `TSchema`; the empty-object fallback is only\n // reached when the caller omits `params`, which is exactly the `{}` schema case.\n const userParams = config.params ?? ({} as TSchema);\n assertNoPipelineCommandConflicts(userParams);\n\n const targetFlagEnabled = pipeline.targetIds.length > 0;\n const bridgeParams: CliParamsSchema = {\n stepIds: {\n type: \"string\",\n multiple: true,\n flag: \"step\",\n group: \"execution\",\n exclusive: true,\n choices: pipeline.stepIds,\n description: `Run exactly this step. Steps: ${pipeline.stepIds.join(\", \")}`,\n },\n continueOnError: {\n type: \"boolean\",\n group: \"execution\",\n description: \"Continue independent work after a step fails.\",\n },\n };\n if (targetFlagEnabled) {\n bridgeParams.targets = {\n type: \"string\",\n multiple: true,\n flag: \"target\",\n group: \"execution\",\n exclusive: true,\n choices: pipeline.targetIds,\n description: `Run this declared target and its prerequisites. Targets: ${pipeline.targetIds.join(\", \")}`,\n };\n }\n\n // SAFETY: `bridgeParams` supplies the `PipelineCliBuiltins` keys and `userParams` is\n // `TSchema`, so the merged object satisfies `PipelineCliBuiltins & TSchema`.\n const params = { ...bridgeParams, ...userParams } as PipelineCliBuiltins & TSchema;\n\n const commandConfig = {\n name: config.name ?? pipeline.id,\n description: config.description,\n params,\n positionals: config.positionals,\n checkpoint: config.checkpoint,\n validate: (values, context) => {\n const pipelineValues = normalizePipelineCliValues<TSchema>(values);\n const errors = config.validate?.(pipelineValues, context) ?? [];\n if (pipelineValues.stepIds.length > 0 && pipelineValues.targets.length > 0) {\n return [\"--step and --target cannot be used together.\", ...errors];\n }\n return errors.length > 0 ? errors : undefined;\n },\n run: async (values, cliContext) => {\n const pipelineValues = normalizePipelineCliValues<TSchema>(values);\n let mapped: TOptions;\n if (config.mapOptions) {\n mapped = await config.mapOptions(pipelineValues, cliContext);\n } else {\n // SAFETY: `defaultPipelineCommandOptions` returns exactly the domain options the\n // `CanDefaultPipelineCommandOptions` constraint guarantees map to `TOptions`.\n mapped = defaultPipelineCommandOptions(pipelineValues) as TOptions;\n }\n const controls = pipelineRunControlsFromCliValues({\n dryRun: values.dryRun,\n continueOnError: pipelineValues.continueOnError,\n stepIds: pipelineValues.stepIds,\n targets: targetFlagEnabled ? pipelineValues.targets : [],\n });\n\n const reporter =\n config.reporter === false\n ? undefined\n : createPipelineReporter<TResult>({ log: cliContext.log, ...(config.reporter ?? {}) });\n const runtimeContext = reporter ? { ...cliContext, log: reporter.log } : cliContext;\n let result: TResult;\n try {\n const configuredHooks = isHookConfigFunction(config.hooks)\n ? config.hooks({ context: runtimeContext, values: pipelineValues })\n : config.hooks;\n const hooks: PipelineHooks<TResult>[] = [\n ...normalizePipelineHookSets(cliContext.pipelineContext?.hooks),\n ...(reporter ? [reporter.hooks] : []),\n ...normalizePipelineHookSets(configuredHooks),\n ];\n\n result = await pipeline.runOrThrow(mapped, controls, {\n ...cliContext.pipelineContext,\n cwd: runtimeContext.cwd,\n log: runtimeContext.log,\n hooks: hooks.length > 0 ? hooks : undefined,\n signal: runtimeContext.signal,\n });\n } finally {\n reporter?.dispose();\n }\n for (const line of config.summarize?.(result, pipelineValues, cliContext) ?? []) {\n cliContext.log.log(line);\n }\n return result;\n },\n } satisfies CliCommandConfig<PipelineCliBuiltins & TSchema, TResult>;\n\n const command = createCommand(commandConfig, {\n validation: TUBELESS_WORKBENCH_EXIT_CODE.validation,\n });\n\n function parse(\n argv: readonly string[] = process.argv.slice(2),\n contextOverrides?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema> {\n const result = command.parse(argv, contextOverrides);\n return result.kind === \"values\"\n ? { kind: \"values\", values: normalizePipelineCliValues<TSchema>(result.values) }\n : result;\n }\n\n function plan(controls: PipelineRunControls = {}): PipelinePlan {\n return pipeline.plan(controls);\n }\n\n function parseValues(\n values: Record<string, unknown>,\n contextOverrides?: Partial<CliContext>\n ): PipelineCliParseResult<TSchema> {\n const result = command.parseValues(values, contextOverrides);\n return result.kind === \"values\"\n ? { kind: \"values\", values: normalizePipelineCliValues<TSchema>(result.values) }\n : result;\n }\n\n return markPipelineCommand({\n descriptor: command.descriptor,\n id: pipeline.id,\n stepIds: pipeline.stepIds,\n targetIds: pipeline.targetIds,\n execute: (values, contextOverrides) =>\n // SAFETY: `execute` receives `PipelineCliValues<TSchema>` from the public interface,\n // which is a subtype of `CliParams<PipelineCliBuiltins & TSchema>`.\n command.execute(values as CliParams<PipelineCliBuiltins & TSchema>, contextOverrides),\n parse,\n parseValues,\n plan,\n toMermaid: (options) => pipeline.toMermaid(options),\n run: command.run,\n main: command.main,\n });\n}\n"]}
|
|
@@ -5,6 +5,7 @@ import { toMappedChildStepProgress, } from "./mapped-child-progress.js";
|
|
|
5
5
|
import { createRunId, RUN_MODEL_VERSION } from "./pipeline-ids.js";
|
|
6
6
|
import { duplicateValues } from "../utilities/collections.js";
|
|
7
7
|
import { EXECUTE_COMPILED_RUN, isCompiledPipeline } from "./pipeline-plan.js";
|
|
8
|
+
import { createChildProgress } from "./child-progress.js";
|
|
8
9
|
import { hasVisibleStepProgress } from "./progress.js";
|
|
9
10
|
export class PipelineChildError extends Error {
|
|
10
11
|
cancelled;
|
|
@@ -16,6 +17,7 @@ export class PipelineChildError extends Error {
|
|
|
16
17
|
this.name = "PipelineChildError";
|
|
17
18
|
}
|
|
18
19
|
}
|
|
20
|
+
const LIVE_FAN_OUT_GROUP_LIMIT = 32;
|
|
19
21
|
function compiledChildExecute(pipeline) {
|
|
20
22
|
if (!isCompiledPipeline(pipeline))
|
|
21
23
|
return undefined;
|
|
@@ -38,6 +40,8 @@ function publicChildRuntime(context) {
|
|
|
38
40
|
now: context.now ?? Date.now,
|
|
39
41
|
sleep: context.sleep ?? (async () => undefined),
|
|
40
42
|
};
|
|
43
|
+
if (context.correlationId !== undefined)
|
|
44
|
+
runtime.correlationId = context.correlationId;
|
|
41
45
|
if (context.hooks)
|
|
42
46
|
runtime.hooks = context.hooks;
|
|
43
47
|
if (context.parentRunId)
|
|
@@ -59,12 +63,15 @@ async function failedPublicChildPlanRun(pipeline, plan, controls, context) {
|
|
|
59
63
|
errors: [...plan.errors],
|
|
60
64
|
finalized: false,
|
|
61
65
|
finishedAtMs: runtime.now(),
|
|
62
|
-
runId:
|
|
66
|
+
runId: createRunId(pipeline.id),
|
|
63
67
|
startedAtMs,
|
|
64
68
|
status: "failed",
|
|
65
69
|
steps: [],
|
|
66
70
|
version: RUN_MODEL_VERSION,
|
|
67
71
|
};
|
|
72
|
+
const correlationId = context.correlationId ?? context.runId;
|
|
73
|
+
if (correlationId !== undefined)
|
|
74
|
+
result.correlationId = correlationId;
|
|
68
75
|
if (context.parentRunId)
|
|
69
76
|
result.parentRunId = context.parentRunId;
|
|
70
77
|
await emitRejectedPlanLifecycle(pipeline.id, pipeline.targetIds, plan, runtime, result);
|
|
@@ -175,10 +182,15 @@ async function runChildPipeline(pipeline, domainOptions, controls, context, hook
|
|
|
175
182
|
}
|
|
176
183
|
return result;
|
|
177
184
|
}
|
|
185
|
+
function hasProgressObserver(context) {
|
|
186
|
+
const hooks = Array.isArray(context.hooks) ? context.hooks : [context.hooks];
|
|
187
|
+
return (Boolean(context.tracing) || hooks.some((hook) => hook?.onStepProgress || hook?.onStepStatus));
|
|
188
|
+
}
|
|
178
189
|
export function createSingleChildRunner(config, dependencies) {
|
|
179
190
|
return async (inputs, context) => {
|
|
180
191
|
const { controls, domainOptions } = childRunBags(config.mapOptions(inputs, context), context.dryRun);
|
|
181
192
|
const baseChildContext = {
|
|
193
|
+
correlationId: context.correlationId,
|
|
182
194
|
cwd: context.cwd,
|
|
183
195
|
log: context.log,
|
|
184
196
|
now: context.now,
|
|
@@ -192,17 +204,22 @@ export function createSingleChildRunner(config, dependencies) {
|
|
|
192
204
|
const selectedStepCount = childPlan.ok
|
|
193
205
|
? childPlan.steps.filter((step) => step.selected).length
|
|
194
206
|
: 0;
|
|
207
|
+
const childProgress = hasProgressObserver(context) ? createChildProgress(childPlan) : undefined;
|
|
195
208
|
const terminalSteps = new Set();
|
|
196
209
|
const report = (step, message, terminal = false) => {
|
|
210
|
+
if (!childProgress)
|
|
211
|
+
return;
|
|
197
212
|
if (terminal)
|
|
198
213
|
terminalSteps.add(step.id);
|
|
199
214
|
context.reportProgress({
|
|
215
|
+
details: childProgress.details(),
|
|
200
216
|
completed: terminalSteps.size,
|
|
201
217
|
total: Math.max(1, selectedStepCount),
|
|
202
218
|
message: `${config.pipeline.id}/${step.name ?? step.id}: ${message}`,
|
|
203
219
|
});
|
|
204
220
|
};
|
|
205
221
|
const childHooks = {
|
|
222
|
+
onStepStatus: childProgress?.update,
|
|
206
223
|
onStepStart: ({ step }) => report(step, "started"),
|
|
207
224
|
onStepProgress: ({ progress, step }) => {
|
|
208
225
|
if (!hasVisibleStepProgress(progress))
|
|
@@ -214,7 +231,7 @@ export function createSingleChildRunner(config, dependencies) {
|
|
|
214
231
|
onStepCancel: ({ error, step }) => report(step, `cancelled: ${error.message}`, true),
|
|
215
232
|
onStepFail: ({ error, step }) => report(step, `failed: ${error.message}`, true),
|
|
216
233
|
};
|
|
217
|
-
const childResult = await runChildPipeline(config.pipeline, domainOptions, controls, baseChildContext, childHooks, dependencies, `Child pipeline ${config.pipeline.id} `, childPlan);
|
|
234
|
+
const childResult = await runChildPipeline(config.pipeline, domainOptions, controls, baseChildContext, childProgress ? childHooks : {}, dependencies, `Child pipeline ${config.pipeline.id} `, childPlan);
|
|
218
235
|
return config.mapResult
|
|
219
236
|
? config.mapResult(childResult.value, childResult, context)
|
|
220
237
|
: childResult.value;
|
|
@@ -232,6 +249,11 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
232
249
|
? config.concurrency(inputs, context)
|
|
233
250
|
: (config.concurrency ?? 1));
|
|
234
251
|
const active = new Map();
|
|
252
|
+
const failedKeys = new Set();
|
|
253
|
+
const itemIndexes = new Map(keys.map((key, index) => [key, index]));
|
|
254
|
+
const observesProgress = hasProgressObserver(context);
|
|
255
|
+
const itemRows = new Map(keys.map((id) => [id, { id, status: "pending" }]));
|
|
256
|
+
const itemProgress = new Map();
|
|
235
257
|
const childTerminalSteps = new Map();
|
|
236
258
|
let finishedItems = 0;
|
|
237
259
|
let failedItems = 0;
|
|
@@ -239,7 +261,9 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
239
261
|
let plannedChildSteps = 0;
|
|
240
262
|
let plannedItems = 0;
|
|
241
263
|
let terminalChildSteps = 0;
|
|
242
|
-
const publishProgress = (spotlight) => {
|
|
264
|
+
const publishProgress = (spotlight, final = false) => {
|
|
265
|
+
if (!observesProgress)
|
|
266
|
+
return;
|
|
243
267
|
const snapshot = {
|
|
244
268
|
active,
|
|
245
269
|
concurrency,
|
|
@@ -252,7 +276,35 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
252
276
|
terminalChildSteps,
|
|
253
277
|
spotlight,
|
|
254
278
|
};
|
|
255
|
-
|
|
279
|
+
// Materialize a bounded live window; expand the default final snapshot once.
|
|
280
|
+
// Active and failed sets avoid scanning or sorting the full fan-out per event.
|
|
281
|
+
const limit = Math.max(0, Math.floor(config.progress?.detailLimit ?? LIVE_FAN_OUT_GROUP_LIMIT)) || 0;
|
|
282
|
+
let visibleKeys;
|
|
283
|
+
if (final && config.progress?.detailLimit === undefined) {
|
|
284
|
+
visibleKeys = keys;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
const visible = new Set();
|
|
288
|
+
for (const candidates of [active.keys(), failedKeys.keys(), keys.values()]) {
|
|
289
|
+
for (const key of candidates) {
|
|
290
|
+
if (visible.size >= limit)
|
|
291
|
+
break;
|
|
292
|
+
visible.add(key);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
visibleKeys = [...visible].sort((left, right) => itemIndexes.get(left) - itemIndexes.get(right));
|
|
296
|
+
}
|
|
297
|
+
const details = visibleKeys.flatMap((key) => [
|
|
298
|
+
{ ...itemRows.get(key) },
|
|
299
|
+
...(itemProgress.get(key)?.details() ?? []).map((detail) => ({
|
|
300
|
+
...detail,
|
|
301
|
+
depth: (detail.depth ?? 0) + 1,
|
|
302
|
+
})),
|
|
303
|
+
]);
|
|
304
|
+
if (visibleKeys.length < keys.length) {
|
|
305
|
+
details.push({ id: `+${keys.length - visibleKeys.length} more`, status: "pending" });
|
|
306
|
+
}
|
|
307
|
+
context.reportProgress({ ...toMappedChildStepProgress(snapshot, config.progress), details });
|
|
256
308
|
};
|
|
257
309
|
const markChildTerminal = (itemKey, stepId, label) => {
|
|
258
310
|
let seen = childTerminalSteps.get(itemKey);
|
|
@@ -275,6 +327,7 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
275
327
|
const settled = await runConcurrentSettled(items, { concurrency, signal: context.signal }, async (item, itemIndex) => {
|
|
276
328
|
const key = keys[itemIndex];
|
|
277
329
|
active.set(key, "starting");
|
|
330
|
+
itemRows.set(key, { id: key, status: "running" });
|
|
278
331
|
publishProgress();
|
|
279
332
|
try {
|
|
280
333
|
throwIfAborted(context.signal, `Mapped child pipeline ${config.pipeline.id}`);
|
|
@@ -288,7 +341,11 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
288
341
|
if (plannedSteps > stepsPerItem)
|
|
289
342
|
stepsPerItem = plannedSteps;
|
|
290
343
|
}
|
|
344
|
+
const childProgress = observesProgress ? createChildProgress(childPlan) : undefined;
|
|
345
|
+
if (childProgress)
|
|
346
|
+
itemProgress.set(key, childProgress);
|
|
291
347
|
const childHooks = {
|
|
348
|
+
onStepStatus: childProgress?.update,
|
|
292
349
|
onStepStart: ({ step }) => {
|
|
293
350
|
active.set(key, step.name ?? step.id);
|
|
294
351
|
publishProgress();
|
|
@@ -313,6 +370,7 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
313
370
|
onStepFail: ({ step }) => markChildTerminal(key, step.id, `${step.name ?? step.id}:failed`),
|
|
314
371
|
};
|
|
315
372
|
const childResult = await runChildPipeline(config.pipeline, domainOptions, controls, {
|
|
373
|
+
correlationId: context.correlationId,
|
|
316
374
|
cwd: context.cwd,
|
|
317
375
|
log: context.log,
|
|
318
376
|
now: context.now,
|
|
@@ -320,7 +378,7 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
320
378
|
signal: context.signal,
|
|
321
379
|
sleep: context.sleep,
|
|
322
380
|
tracing: childTracingOptions(context, key),
|
|
323
|
-
}, childHooks, dependencies, "", childPlan);
|
|
381
|
+
}, observesProgress ? childHooks : {}, dependencies, "", childPlan);
|
|
324
382
|
const seen = childTerminalSteps.get(key) ?? new Set();
|
|
325
383
|
if (childPlan.ok) {
|
|
326
384
|
for (const planStep of childPlan.steps) {
|
|
@@ -335,6 +393,7 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
335
393
|
? config.mapResult(childResult.value, childResult, item, itemIndex, context)
|
|
336
394
|
: childResult.value;
|
|
337
395
|
active.delete(key);
|
|
396
|
+
itemRows.set(key, { id: key, status: "completed" });
|
|
338
397
|
finishedItems += 1;
|
|
339
398
|
publishProgress(`${key}: completed`);
|
|
340
399
|
return { key, ok: true, value };
|
|
@@ -342,11 +401,20 @@ export function createMappedChildRunner(config, dependencies) {
|
|
|
342
401
|
catch (error) {
|
|
343
402
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
344
403
|
active.delete(key);
|
|
404
|
+
itemRows.set(key, {
|
|
405
|
+
id: key,
|
|
406
|
+
status: dependencies.isCancellation(cause, context) ? "cancelled" : "failed",
|
|
407
|
+
label: cause.message,
|
|
408
|
+
});
|
|
409
|
+
failedKeys.add(key);
|
|
345
410
|
failedItems += 1;
|
|
346
411
|
publishProgress(`${key}: failed`);
|
|
347
412
|
return { error: cause, key, index: itemIndex, ok: false };
|
|
348
413
|
}
|
|
349
414
|
});
|
|
415
|
+
if (config.progress?.detailLimit === undefined && keys.length > LIVE_FAN_OUT_GROUP_LIMIT) {
|
|
416
|
+
publishProgress(undefined, true);
|
|
417
|
+
}
|
|
350
418
|
const outcomes = settled.results.filter((outcome) => outcome !== undefined);
|
|
351
419
|
const schedulerFailure = settled.failure === undefined
|
|
352
420
|
? undefined
|