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.
Files changed (118) hide show
  1. package/README.md +5 -5
  2. package/dist/cli/cli-command.d.ts +2 -2
  3. package/dist/cli/cli-command.js +28 -45
  4. package/dist/cli/cli-command.js.map +1 -1
  5. package/dist/cli/cli-pipeline-command.js +1 -1
  6. package/dist/cli/cli-pipeline-command.js.map +1 -1
  7. package/dist/core/child-execution.js +73 -5
  8. package/dist/core/child-execution.js.map +1 -1
  9. package/dist/core/child-progress.d.ts +6 -0
  10. package/dist/core/child-progress.js +48 -0
  11. package/dist/core/child-progress.js.map +1 -0
  12. package/dist/core/lifecycle.js +2 -0
  13. package/dist/core/lifecycle.js.map +1 -1
  14. package/dist/core/mapped-child-progress.d.ts +4 -2
  15. package/dist/core/mapped-child-progress.js.map +1 -1
  16. package/dist/core/pipeline-execute.d.ts +2 -0
  17. package/dist/core/pipeline-execute.js +132 -395
  18. package/dist/core/pipeline-execute.js.map +1 -1
  19. package/dist/core/pipeline-plan.js +96 -34
  20. package/dist/core/pipeline-plan.js.map +1 -1
  21. package/dist/core/pipeline-run-state.d.ts +49 -0
  22. package/dist/core/pipeline-run-state.js +284 -0
  23. package/dist/core/pipeline-run-state.js.map +1 -0
  24. package/dist/core/pipeline-step-executor.d.ts +20 -0
  25. package/dist/core/pipeline-step-executor.js +52 -0
  26. package/dist/core/pipeline-step-executor.js.map +1 -0
  27. package/dist/core/pipeline-steps.d.ts +3 -3
  28. package/dist/core/pipeline-steps.js +12 -23
  29. package/dist/core/pipeline-steps.js.map +1 -1
  30. package/dist/core/pipeline-types.d.ts +19 -3
  31. package/dist/core/pipeline-types.js.map +1 -1
  32. package/dist/core/pipeline-validation.d.ts +6 -0
  33. package/dist/core/pipeline-validation.js +41 -0
  34. package/dist/core/pipeline-validation.js.map +1 -0
  35. package/dist/render/render.js +2 -6
  36. package/dist/render/render.js.map +1 -1
  37. package/dist/reporter/interactive-reporter.d.ts +1 -0
  38. package/dist/reporter/interactive-reporter.js +50 -15
  39. package/dist/reporter/interactive-reporter.js.map +1 -1
  40. package/dist/reporter/live-ticker-worker.js +8 -42
  41. package/dist/reporter/live-ticker-worker.js.map +1 -1
  42. package/dist/reporter/live-ticker.d.ts +10 -0
  43. package/dist/reporter/live-ticker.js +50 -47
  44. package/dist/reporter/live-ticker.js.map +1 -1
  45. package/dist/run-store/run-store-ndjson.js +2 -289
  46. package/dist/run-store/run-store-ndjson.js.map +1 -1
  47. package/dist/run-store/run-store-sqlite.js +91 -42
  48. package/dist/run-store/run-store-sqlite.js.map +1 -1
  49. package/dist/run-store/run-store.d.ts +3 -2
  50. package/dist/run-store/run-store.js +40 -216
  51. package/dist/run-store/run-store.js.map +1 -1
  52. package/dist/studio/run-store-ui-client-controller.d.ts +9 -0
  53. package/dist/studio/run-store-ui-client-controller.js +479 -0
  54. package/dist/studio/run-store-ui-client-controller.js.map +1 -0
  55. package/dist/studio/run-store-ui-client-form.d.ts +9 -0
  56. package/dist/studio/run-store-ui-client-form.js +44 -0
  57. package/dist/studio/run-store-ui-client-form.js.map +1 -0
  58. package/dist/studio/run-store-ui-client-model.d.ts +40 -0
  59. package/dist/studio/run-store-ui-client-model.js +211 -0
  60. package/dist/studio/run-store-ui-client-model.js.map +1 -0
  61. package/dist/studio/run-store-ui-client-source.js +1 -1
  62. package/dist/studio/run-store-ui-client-transport.d.ts +25 -0
  63. package/dist/studio/run-store-ui-client-transport.js +322 -0
  64. package/dist/studio/run-store-ui-client-transport.js.map +1 -0
  65. package/dist/studio/run-store-ui-client-views.d.ts +24 -0
  66. package/dist/studio/run-store-ui-client-views.js +676 -0
  67. package/dist/studio/run-store-ui-client-views.js.map +1 -0
  68. package/dist/studio/run-store-ui-client.d.ts +2 -15
  69. package/dist/studio/run-store-ui-client.js +7 -1390
  70. package/dist/studio/run-store-ui-client.js.map +1 -1
  71. package/dist/studio/run-store-ui-page.d.ts +1 -1
  72. package/dist/studio/run-store-ui-page.js +1 -1
  73. package/dist/studio/run-store-ui-page.js.map +1 -1
  74. package/dist/studio/run-store-ui.js +44 -25
  75. package/dist/studio/run-store-ui.js.map +1 -1
  76. package/dist/tracing/tracing-codec.d.ts +6 -0
  77. package/dist/tracing/tracing-codec.js +829 -0
  78. package/dist/tracing/tracing-codec.js.map +1 -0
  79. package/dist/tracing/tracing-constants.d.ts +4 -0
  80. package/dist/tracing/tracing-constants.js +5 -0
  81. package/dist/tracing/tracing-constants.js.map +1 -0
  82. package/dist/tracing/tracing-internal.js +133 -72
  83. package/dist/tracing/tracing-internal.js.map +1 -1
  84. package/dist/tracing/tracing-otel.js +19 -3
  85. package/dist/tracing/tracing-otel.js.map +1 -1
  86. package/dist/tracing/tracing.d.ts +149 -10
  87. package/dist/tracing/tracing.js.map +1 -1
  88. package/dist/workbench/pipeline-module.d.ts +2 -12
  89. package/dist/workbench/pipeline-module.js +4 -11
  90. package/dist/workbench/pipeline-module.js.map +1 -1
  91. package/dist/workbench/workbench-history.js +8 -1
  92. package/dist/workbench/workbench-history.js.map +1 -1
  93. package/dist/workbench/workbench-project-loader.js +1 -1
  94. package/dist/workbench/workbench-project-loader.js.map +1 -1
  95. package/dist/workbench/workbench-ui.js +27 -7
  96. package/dist/workbench/workbench-ui.js.map +1 -1
  97. package/docs/README.md +21 -15
  98. package/docs/agent-guide.md +54 -33
  99. package/docs/agent-skills.md +59 -0
  100. package/docs/api-reference.md +28 -12
  101. package/docs/api-report.json +29 -13
  102. package/docs/child-pipeline-composition.md +142 -161
  103. package/docs/cli.md +103 -56
  104. package/docs/comparison.md +63 -62
  105. package/docs/concepts.md +210 -272
  106. package/docs/getting-started.md +59 -48
  107. package/docs/llms.txt +7 -4
  108. package/docs/recipes.md +23 -20
  109. package/docs/remote-step-composition.md +69 -74
  110. package/docs/studio.md +146 -71
  111. package/examples/catalog/pipelines/enrich.ts +2 -2
  112. package/examples/catalog/tubeless.project.ts +10 -2
  113. package/examples/fan-out-progress.ts +16 -2
  114. package/examples/host-embedding.ts +4 -5
  115. package/examples/remote-steps.ts +8 -5
  116. package/package.json +12 -10
  117. package/skills/tubeless/SKILL.md +83 -0
  118. 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://chetmancini.github.io/tubeless/">
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. The public line is `0.1.x`; expect API change before 1.0.
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 when to use each pattern.
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://chetmancini.github.io/tubeless/) ·
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 CliContext, type CliParams, type CliParamsSchema } from "./cli-types.js";
2
- export declare function createCommand<const TSchema extends CliParamsSchema, TResult = void>(config: CliCommandConfig<TSchema, TResult>, prepareContext?: (values: CliParams<TSchema>, context: CliContext) => CliContext, mainExits?: {
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>;
@@ -59,7 +59,7 @@ function inMemoryCheckpointView(seed) {
59
59
  },
60
60
  };
61
61
  }
62
- export function createCommand(config, prepareContext, mainExits) {
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 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];
70
+ function resolveValues(readValue, context, errors, helpText) {
77
71
  const values = {};
78
72
  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");
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
- if (validationErrors.length > 0) {
91
- return { kind: "error", errors: validationErrors, helpText };
92
- }
93
- return { kind: "values", values: typedValues };
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
- 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 };
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
- /** No-op unless `config.checkpoint` is set, a store is attached, and the run wasn't a dry run. */
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 preparedContext = prepareContext?.(values, context) ?? context;
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 preparedContext = prepareContext?.(result.values, managedSignal.context) ?? managedSignal.context;
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":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAwB,MAAM,uBAAuB,CAAC;AAC7E,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,QAAQ,GAET,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,GAOnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3F,SAAS,cAAc,CAAC,SAA+B;IACrD,OAAO;QACL,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;QACpC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG;QAClC,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,OAAO;QAC9B,eAAe,EAAE,SAAS,EAAE,eAAe;QAC3C,MAAM,EAAE,SAAS,EAAE,MAAM;QACzB,UAAU,EAAE,SAAS,EAAE,UAAU;KAClC,CAAC;AACJ,CAAC;AAQD,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,OAAmB;IAC3C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IACrE,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,WAAW,GAAG,IAAI,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC/D,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEjC,OAAO;QACL,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;QAClD,cAAc,EAAE,GAAG,EAAE,CAAC,WAAW;QACjC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,sBAAsB,CAAC,IAAkC;IAChE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO;QACL,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;YACpB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO;QACtB,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;QACf,KAAK,EAAE,GAAG,EAAE;YACV,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAA0C,EAC1C,SAAmC;IAEnC,MAAM,eAAe,GAAG,oBAAoB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/E,sBAAsB,CAAC,eAAe,CAAC,CAAC;IACxC,yBAAyB,CAAC,eAAe,CAAC,CAAC;IAC3C,+BAA+B,CAAC,eAAe,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC;IACpD,sBAAsB,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;IAE3E,SAAS,aAAa,CACpB,SAG4C,EAC5C,OAAmB,EACnB,MAAgB,EAChB,QAAgB;QAEhB,MAAM,MAAM,GAAuC,EAAE,CAAC;QACtD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;YACjC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAClC,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU;gBAAE,SAAS;YACzC,MAAM,QAAQ,GAAG,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvF,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CACxB,GAAG,EACH,KAAK,EACL,GAAG,IAAI,QAAQ,EACf,OAAO,CAAC,GAAG,EACX,MAAM,EACN,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CACxE,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QAClE,yFAAyF;QACzF,MAAM,WAAW,GAAG,MAA4B,CAAC;QACjD,MAAM,gBAAgB,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;QACvE,OAAO,gBAAgB,CAAC,MAAM,GAAG,CAAC;YAChC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE;YACvD,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC9C,CAAC;IAED,SAAS,gBAAgB,CAAC,IAAuB,EAAE,OAAmB;QACpE,MAAM,QAAQ,GAAG,UAAU,CACzB,UAAU,CAAC,IAAI,EACf,UAAU,CAAC,WAAW,EACtB,eAAe,EACf,WAAW,CACZ,CAAC;QACF,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;QAC/D,IAAI,SAAS,CAAC,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACtD,OAAO,aAAa,CAClB,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAClC,OAAO,EACP,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,EACrB,QAAQ,CACT,CAAC;IACJ,CAAC;IAED,SAAS,KAAK,CACZ,IAAI,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAC/C,gBAAsC;QAEtC,OAAO,gBAAgB,CAAC,IAAI,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,SAAS,0BAA0B,CACjC,gBAAyC,EACzC,OAAmB;QAEnB,MAAM,QAAQ,GAAG,UAAU,CACzB,UAAU,CAAC,IAAI,EACf,UAAU,CAAC,WAAW,EACtB,eAAe,EACf,WAAW,CACZ,CAAC;QACF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,EAAE,CAAC;gBAChE,MAAM,CAAC,IAAI,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,OAAO,aAAa,CAClB,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,wBAAwB,CAAC,GAAG,EAAE,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,EACnF,OAAO,EACP,MAAM,EACN,QAAQ,CACT,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,SAAS,gBAAgB,CAAC,OAAmB,EAAE,MAA0B;QACvE,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC;QAC3C,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC;YACzD,CAAC,CAAC,gBAAgB,CAAC,IAAI;YACvB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAClD,6EAA6E;QAC7E,kFAAkF;QAClF,mFAAmF;QACnF,wDAAwD;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,IAAI,cAAc,CAAC,YAAY,CAAC,CAAC;QACjE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC;QAE7C,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,GAAG,CACb,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,4BAA4B,CAC9E,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,iFAAiF;gBACjF,sEAAsE;gBACtE,0EAA0E;gBAC1E,4BAA4B;gBAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CACd,uDAAuD,YAAY,mBAAmB,CACvF,CAAC;YACJ,CAAC;YACD,8EAA8E;YAC9E,mFAAmF;YACnF,OAAO;gBACL,GAAG,OAAO;gBACV,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK;aAC5E,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO;gBACL,GAAG,OAAO;gBACV,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK;aAC5E,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,mFAAmF;YACnF,iFAAiF;YACjF,qEAAqE;YACrE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;YACvF,OAAO,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,sBAAsB,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC;QACvE,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QACjE,OAAO,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACH,SAAS,kBAAkB,CAAC,OAAmB,EAAE,MAA0B;QACzE,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC;QAC3C,IAAI,CAAC,gBAAgB,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YACzF,OAAO;QACT,CAAC;QACD,IAAI,gBAAgB,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QACD,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,UAAU,aAAa,CAAC,MAA0B,EAAE,OAAmB;QAC1E,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACnD,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,SAAS,WAAW,CAClB,MAA+B,EAC/B,gBAAsC;QAEtC,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjD,OAAO,0BAA0B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,UAAU,OAAO,CACpB,MAA0B,EAC1B,gBAAsC;QAEtC,OAAO,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,KAAK,UAAU,GAAG,CAChB,IAAI,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAC/C,gBAAsC;QAEtC,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;YAAE,MAAM,IAAI,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxE,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;YAAE,MAAM,IAAI,kBAAkB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1F,OAAO,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,UAAU,IAAI,CACjB,IAAI,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAC/C,gBAAsC;QAEtC,MAAM,OAAO,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjD,IAAI,MAA+B,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3F,OAAO,CAAC,QAAQ;gBACd,SAAS,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,wBAAwB,CAAC,KAAK,CAAC;oBACzE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC;oBACnB,CAAC,CAAC,CAAC,CAAC;YACR,OAAO;QACT,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACjC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC5B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnC,OAAO,CAAC,QAAQ,GAAG,SAAS,EAAE,UAAU,IAAI,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QACD,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,gBAAgB,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC1E,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC5C,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC;gBACpC,kBAAkB,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3F,OAAO,CAAC,QAAQ,GAAG,aAAa,CAAC,cAAc,EAAE;gBAC/C,CAAC,CAAC,gBAAgB;gBAClB,CAAC,CAAC,SAAS,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,wBAAwB,CAAC,KAAK,CAAC;oBAC3E,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC;oBACnB,CAAC,CAAC,CAAC,CAAC;QACV,CAAC;gBAAS,CAAC;YACT,IAAI,aAAa,CAAC,cAAc,EAAE,EAAE,CAAC;gBACnC,OAAO,CAAC,QAAQ,GAAG,gBAAgB,CAAC;YACtC,CAAC;YACD,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAChE,CAAC;AAED,SAAS,wBAAwB,CAC/B,GAAW,EACX,KAA8B,EAC9B,KAAc,EACd,MAAgB;IAEhB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;IACvC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAO,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,2BAA2B,CAAC,CAAC;QACjD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QACpF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;YAC1C,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC9E,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,oCAAoC,CAAC,CAAC;gBAC1D,OAAO,SAAS,CAAC;YACnB,CAAC;YACD,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,6BAA6B,CAAC,CAAC;YACnD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IACpB,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,2BAA2B,CAAC,CAAC;YACjD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,0BAA0B,CAAC,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,MAA0C;IAE1C,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC","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, undefined, {
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: context.runId ?? createRunId(pipeline.id),
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
- context.reportProgress(toMappedChildStepProgress(snapshot, config.progress));
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