tubeless 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/abort.d.ts +12 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +49 -0
- package/dist/abort.js.map +1 -0
- package/dist/batch.d.ts +22 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +73 -0
- package/dist/batch.js.map +1 -0
- package/dist/checkpoint.d.ts +33 -0
- package/dist/checkpoint.d.ts.map +1 -0
- package/dist/checkpoint.js +71 -0
- package/dist/checkpoint.js.map +1 -0
- package/dist/child-execution.d.ts +30 -0
- package/dist/child-execution.d.ts.map +1 -0
- package/dist/child-execution.js +270 -0
- package/dist/child-execution.js.map +1 -0
- package/dist/cli-command.d.ts +29 -0
- package/dist/cli-command.d.ts.map +1 -0
- package/dist/cli-command.js +314 -0
- package/dist/cli-command.js.map +1 -0
- package/dist/cli-parser.d.ts +28 -0
- package/dist/cli-parser.d.ts.map +1 -0
- package/dist/cli-parser.js +557 -0
- package/dist/cli-parser.js.map +1 -0
- package/dist/cli-pipeline-command.d.ts +84 -0
- package/dist/cli-pipeline-command.d.ts.map +1 -0
- package/dist/cli-pipeline-command.js +185 -0
- package/dist/cli-pipeline-command.js.map +1 -0
- package/dist/cli-types.d.ts +220 -0
- package/dist/cli-types.d.ts.map +1 -0
- package/dist/cli-types.js +19 -0
- package/dist/cli-types.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/env.d.ts +2 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +8 -0
- package/dist/env.js.map +1 -0
- package/dist/file-utils.d.ts +4 -0
- package/dist/file-utils.d.ts.map +1 -0
- package/dist/file-utils.js +35 -0
- package/dist/file-utils.js.map +1 -0
- package/dist/interactive-reporter.d.ts +38 -0
- package/dist/interactive-reporter.d.ts.map +1 -0
- package/dist/interactive-reporter.js +308 -0
- package/dist/interactive-reporter.js.map +1 -0
- package/dist/lifecycle.d.ts +17 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +77 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/live-ticker.d.ts +21 -0
- package/dist/live-ticker.d.ts.map +1 -0
- package/dist/live-ticker.js +377 -0
- package/dist/live-ticker.js.map +1 -0
- package/dist/mapped-child-progress.d.ts +109 -0
- package/dist/mapped-child-progress.d.ts.map +1 -0
- package/dist/mapped-child-progress.js +133 -0
- package/dist/mapped-child-progress.js.map +1 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +5 -0
- package/dist/node.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +19 -0
- package/dist/paths.js.map +1 -0
- package/dist/pipeline-command-marker.d.ts +5 -0
- package/dist/pipeline-command-marker.d.ts.map +1 -0
- package/dist/pipeline-command-marker.js +21 -0
- package/dist/pipeline-command-marker.js.map +1 -0
- package/dist/pipeline-diagnostics.d.ts +4 -0
- package/dist/pipeline-diagnostics.d.ts.map +1 -0
- package/dist/pipeline-diagnostics.js +17 -0
- package/dist/pipeline-diagnostics.js.map +1 -0
- package/dist/pipeline-module.d.ts +62 -0
- package/dist/pipeline-module.d.ts.map +1 -0
- package/dist/pipeline-module.js +157 -0
- package/dist/pipeline-module.js.map +1 -0
- package/dist/pipeline.d.ts +606 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +1444 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/progress.d.ts +4 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +8 -0
- package/dist/progress.js.map +1 -0
- package/dist/prompt-select.d.ts +81 -0
- package/dist/prompt-select.d.ts.map +1 -0
- package/dist/prompt-select.js +197 -0
- package/dist/prompt-select.js.map +1 -0
- package/dist/rate-limit.d.ts +7 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +23 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/render.d.ts +21 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +60 -0
- package/dist/render.js.map +1 -0
- package/dist/reporter-entry.d.ts +3 -0
- package/dist/reporter-entry.d.ts.map +1 -0
- package/dist/reporter-entry.js +3 -0
- package/dist/reporter-entry.js.map +1 -0
- package/dist/reporter.d.ts +50 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +167 -0
- package/dist/reporter.js.map +1 -0
- package/dist/retry.d.ts +28 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +59 -0
- package/dist/retry.js.map +1 -0
- package/dist/run-store-sqlite.d.ts +12 -0
- package/dist/run-store-sqlite.d.ts.map +1 -0
- package/dist/run-store-sqlite.js +187 -0
- package/dist/run-store-sqlite.js.map +1 -0
- package/dist/run-store-ui-http.d.ts +5 -0
- package/dist/run-store-ui-http.d.ts.map +1 -0
- package/dist/run-store-ui-http.js +19 -0
- package/dist/run-store-ui-http.js.map +1 -0
- package/dist/run-store-ui-page.d.ts +2 -0
- package/dist/run-store-ui-page.d.ts.map +1 -0
- package/dist/run-store-ui-page.js +759 -0
- package/dist/run-store-ui-page.js.map +1 -0
- package/dist/run-store-ui-protocol.d.ts +28 -0
- package/dist/run-store-ui-protocol.d.ts.map +1 -0
- package/dist/run-store-ui-protocol.js +84 -0
- package/dist/run-store-ui-protocol.js.map +1 -0
- package/dist/run-store-ui-state.d.ts +21 -0
- package/dist/run-store-ui-state.d.ts.map +1 -0
- package/dist/run-store-ui-state.js +65 -0
- package/dist/run-store-ui-state.js.map +1 -0
- package/dist/run-store-ui.d.ts +25 -0
- package/dist/run-store-ui.d.ts.map +1 -0
- package/dist/run-store-ui.js +217 -0
- package/dist/run-store-ui.js.map +1 -0
- package/dist/run-store.d.ts +109 -0
- package/dist/run-store.d.ts.map +1 -0
- package/dist/run-store.js +345 -0
- package/dist/run-store.js.map +1 -0
- package/dist/testing.d.ts +40 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +83 -0
- package/dist/testing.js.map +1 -0
- package/dist/tracing-internal.d.ts +21 -0
- package/dist/tracing-internal.d.ts.map +1 -0
- package/dist/tracing-internal.js +206 -0
- package/dist/tracing-internal.js.map +1 -0
- package/dist/tracing-json.d.ts +12 -0
- package/dist/tracing-json.d.ts.map +1 -0
- package/dist/tracing-json.js +8 -0
- package/dist/tracing-json.js.map +1 -0
- package/dist/tracing-otel.d.ts +36 -0
- package/dist/tracing-otel.d.ts.map +1 -0
- package/dist/tracing-otel.js +60 -0
- package/dist/tracing-otel.js.map +1 -0
- package/dist/tracing.d.ts +48 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +2 -0
- package/dist/tracing.js.map +1 -0
- package/dist/workbench-bin.d.ts +3 -0
- package/dist/workbench-bin.d.ts.map +1 -0
- package/dist/workbench-bin.js +8 -0
- package/dist/workbench-bin.js.map +1 -0
- package/dist/workbench-graph.d.ts +3 -0
- package/dist/workbench-graph.d.ts.map +1 -0
- package/dist/workbench-graph.js +64 -0
- package/dist/workbench-graph.js.map +1 -0
- package/dist/workbench-inspect.d.ts +3 -0
- package/dist/workbench-inspect.d.ts.map +1 -0
- package/dist/workbench-inspect.js +65 -0
- package/dist/workbench-inspect.js.map +1 -0
- package/dist/workbench-plan.d.ts +3 -0
- package/dist/workbench-plan.d.ts.map +1 -0
- package/dist/workbench-plan.js +72 -0
- package/dist/workbench-plan.js.map +1 -0
- package/dist/workbench-run.d.ts +13 -0
- package/dist/workbench-run.d.ts.map +1 -0
- package/dist/workbench-run.js +115 -0
- package/dist/workbench-run.js.map +1 -0
- package/dist/workbench-shared.d.ts +67 -0
- package/dist/workbench-shared.d.ts.map +1 -0
- package/dist/workbench-shared.js +163 -0
- package/dist/workbench-shared.js.map +1 -0
- package/dist/workbench-studio.d.ts +26 -0
- package/dist/workbench-studio.d.ts.map +1 -0
- package/dist/workbench-studio.js +57 -0
- package/dist/workbench-studio.js.map +1 -0
- package/dist/workbench-ui.d.ts +3 -0
- package/dist/workbench-ui.d.ts.map +1 -0
- package/dist/workbench-ui.js +262 -0
- package/dist/workbench-ui.js.map +1 -0
- package/dist/workbench.d.ts +5 -0
- package/dist/workbench.d.ts.map +1 -0
- package/dist/workbench.js +43 -0
- package/dist/workbench.js.map +1 -0
- package/docs/README.md +31 -0
- package/docs/agent-guide.md +168 -0
- package/docs/api-reference.md +269 -0
- package/docs/api-report.json +298 -0
- package/docs/child-pipeline-composition.md +185 -0
- package/docs/cli.md +118 -0
- package/docs/concepts.md +502 -0
- package/docs/getting-started.md +162 -0
- package/docs/llms.txt +62 -0
- package/docs/recipes.md +51 -0
- package/docs/studio.md +86 -0
- package/examples/best-effort.ts +42 -0
- package/examples/cancellation-and-testing.ts +45 -0
- package/examples/child-pipeline.ts +51 -0
- package/examples/cli-job.ts +86 -0
- package/examples/conditional-step.ts +41 -0
- package/examples/fan-out-progress.ts +53 -0
- package/examples/local-observability.ts +80 -0
- package/examples/publish-with-gates.ts +56 -0
- package/examples/rendering.ts +34 -0
- package/examples/resumable-enrichment.ts +75 -0
- package/examples/tracing.ts +35 -0
- package/examples/tsconfig.json +15 -0
- package/examples/typed-import.ts +54 -0
- package/examples/validated-boundaries.ts +75 -0
- package/package.json +156 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Child-pipeline composition
|
|
2
|
+
|
|
3
|
+
## What ships
|
|
4
|
+
|
|
5
|
+
Compose a child pipeline as one typed parent step with
|
|
6
|
+
`createSteps<TOptions>().fromPipeline(...)`. Overloads cover identity and
|
|
7
|
+
mapped results. Child lifecycle hooks stay isolated, and child work reports
|
|
8
|
+
through parent-step progress without changing the pipeline run loop or
|
|
9
|
+
reporter contracts.
|
|
10
|
+
|
|
11
|
+
Map a runtime item list onto the same child pipeline with
|
|
12
|
+
`createSteps<TOptions>().forEachPipeline(...)`. Item keys are stable,
|
|
13
|
+
concurrency is bounded, and results keep input order even when children
|
|
14
|
+
finish out of order. All running children settle before an aggregate failure
|
|
15
|
+
is returned, so the parent cannot finalize while child side effects are still
|
|
16
|
+
in flight.
|
|
17
|
+
|
|
18
|
+
Opaque parent steps pass outputs through typed dependencies, skip side
|
|
19
|
+
effects in dry-run, and convert domain validation errors into failed parent
|
|
20
|
+
steps.
|
|
21
|
+
|
|
22
|
+
## Why not call the child from an ordinary step
|
|
23
|
+
|
|
24
|
+
Invoking a child pipeline from an ordinary parent step and passing the parent
|
|
25
|
+
`PipelineStepContext` gives the child the parent's runtime seams, but it also
|
|
26
|
+
gives the child the parent's raw hooks and parent-only `reportProgress`
|
|
27
|
+
callback.
|
|
28
|
+
|
|
29
|
+
The resulting lifecycle stream is flat. A direct nested run emits the child pipeline, step, finalize, and completion events between the parent wrapper step's start and completion events. Most events have no pipeline path or run identity. The interactive reporter also owns one plan, one step map, and one result. A child start replaces its visible plan, and a child completion disposes the reporter before the parent completes.
|
|
30
|
+
|
|
31
|
+
The package needs a composition contract that preserves typing and runtime behavior without exposing two pipeline frames through hooks designed for one pipeline.
|
|
32
|
+
|
|
33
|
+
## Goals
|
|
34
|
+
|
|
35
|
+
- Model a child pipeline as one typed step in the parent DAG.
|
|
36
|
+
- Infer parent dependency inputs, parent options, child options, the child result, and any mapped result.
|
|
37
|
+
- Preserve cancellation, logging, timing, working-directory, dry-run, progress, and failure behavior.
|
|
38
|
+
- Keep raw child lifecycle hooks inside the adapter while reporting useful progress through the opaque parent step.
|
|
39
|
+
- Keep the first slice bounded: one opaque child, or a mapped set of the same child.
|
|
40
|
+
|
|
41
|
+
## Supported: policy skip on opaque steps
|
|
42
|
+
|
|
43
|
+
Policy skip (`step.skippable` / `StepSkipDecision`) is part of the shipped API and
|
|
44
|
+
applies to ordinary steps and to `fromPipeline` adapters (the opaque parent
|
|
45
|
+
step is a normal step under the hood):
|
|
46
|
+
|
|
47
|
+
- Return a non-empty string or `{ reason, value? }` from `skip` to skip without
|
|
48
|
+
calling `run` (or without running the child). Reporters show a yellow skip
|
|
49
|
+
whose terminal report has `status: "skipped"` and `reason: "policy"`.
|
|
50
|
+
- Policy skips unlock required dependents. A bare string (or `{ reason }`
|
|
51
|
+
without `value`) publishes `undefined` as the step output.
|
|
52
|
+
- Any step that declares `skip` is typed so dependents see `TOut | undefined`
|
|
53
|
+
(including `PipelineResultOf<Child> | undefined` for `fromPipeline` without
|
|
54
|
+
`mapResult`). Prefer `{ reason, value }` on every skip path when dependents
|
|
55
|
+
need a real output. With `mapResult`, skip `value` is the parent-facing
|
|
56
|
+
mapped `TOut` — policy skip does not call `mapResult`.
|
|
57
|
+
|
|
58
|
+
A `fromPipeline.skippable` step can policy-skip optional work and publish a
|
|
59
|
+
concrete disabled result via `{ reason, value }`.
|
|
60
|
+
|
|
61
|
+
`forEachPipeline` does not accept `skip` today; gate mapped fan-out with an
|
|
62
|
+
upstream step or filter `items` instead.
|
|
63
|
+
|
|
64
|
+
## Non-goals
|
|
65
|
+
|
|
66
|
+
- Flatten child steps into the parent plan.
|
|
67
|
+
- Add hierarchical or versioned external lifecycle events.
|
|
68
|
+
- Support namespaced selection such as `parent.child-step`.
|
|
69
|
+
- Add parallel DAG execution, remote checkpoints, or subcommands.
|
|
70
|
+
- Injected runner overrides (substituting a child pipeline implementation at
|
|
71
|
+
test time via parent options) — separate from policy skip.
|
|
72
|
+
|
|
73
|
+
## Why this shape
|
|
74
|
+
|
|
75
|
+
| Model | Typing | Planning | Hooks and reporting | Selective execution | Failure | Dry run | Cost |
|
|
76
|
+
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
77
|
+
| Continue manual shared-context calls | Each wrapper can map options and return a typed value, but each wrapper repeats the contract and structural context passing makes unsafe fields easy to forward. | The parent sees only the wrapper step; the child creates a separate plan at runtime. | Raw child events enter the parent's flat hook stream. The current interactive reporter replaces the parent frame and disposes on child completion. | Parent selection can select the wrapper. Child selection depends on ad hoc mapped `stepIds`. | `runOrThrow` can fail the wrapper, but consistent child-identifying messages and progress require repeated wrapper code. | Each wrapper must remember parent/child dry-run precedence and per-step policy. | Low per call, with continuing duplication and reporter breakage. |
|
|
78
|
+
| Flatten the child DAG into the parent DAG | The API must translate child option and dependency types into a parent definition without losing inference. | Child ids need stable namespacing, and runtime option mapping can change which child plan is valid. | A flat plan fits current hooks only after defining pipeline identity, paths, and collision rules. | Namespaced filters need semantics for parent dependencies, child dependencies, and finalization. | The parent must define how child failures, partial outputs, and child finalization affect the flattened DAG. | The parent must reconcile its dry-run rules with every flattened child step. | High. It requires event identity and selection semantics before the first useful slice. |
|
|
79
|
+
| Opaque typed child-step adapter | A parent-scoped factory can infer dependency inputs and parent options while a typed child pipeline constrains mapped options and results. | The parent plan contains one stable step. The adapter validates the child plan immediately before running it. | Parent hooks see the opaque step only. An internal bridge translates child terminal events into parent-step progress. | Selecting the opaque parent step runs the child according to mapped child options. Nested selection is deferred. | An unusable child result throws a parent-step error that retains the child pipeline and failing step identity. | Framework-owned parent `dryRun` overrides the mapper, then the child applies its own per-step rules. | Medium. It uses existing pipeline and hook primitives without changing the external event model. |
|
|
80
|
+
|
|
81
|
+
Shared raw hooks are rejected because they already corrupt the interactive reporter's single frame and cannot distinguish nested runs. Immediate flattening is rejected because it needs stable identity, selection, dependency, failure, and finalization rules that the current event and plan models don't provide. The opaque adapter addresses the existing composition case without deciding those broader contracts.
|
|
82
|
+
|
|
83
|
+
## Contract
|
|
84
|
+
|
|
85
|
+
The parent DAG contains one ordinary step. That step maps its typed parent inputs and context into typed child options, validates the child plan, runs the child with an isolated internal hook bridge, and returns either the child result or a mapped parent result.
|
|
86
|
+
|
|
87
|
+
The bridge owns child lifecycle events. Parent and custom hooks receive only the parent pipeline and opaque parent-step events. The bridge reports terminal child-step counts through the parent step's `reportProgress`, so existing reporters keep one live frame.
|
|
88
|
+
|
|
89
|
+
## API
|
|
90
|
+
|
|
91
|
+
The parent-scoped step factory owns the adapter:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const seedIndexStage = step.fromPipeline("seed-index", {
|
|
95
|
+
pipeline: IndexSeedPipeline,
|
|
96
|
+
dependsOn: [seedCatalogStage],
|
|
97
|
+
description: "Seed a precomputed search index",
|
|
98
|
+
mapOptions: (_inputs, context) => ({
|
|
99
|
+
indexDir: context.options.indexDir,
|
|
100
|
+
syncSchema: false,
|
|
101
|
+
}),
|
|
102
|
+
mapResult: () => ({ ran: true, stageId: "seed-index" }),
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`StepFactory.fromPipeline` and `StepFactory.fromPipeline.skippable` infer the
|
|
107
|
+
child result when `mapResult` is absent, and infer the mapped result when it
|
|
108
|
+
is present.
|
|
109
|
+
|
|
110
|
+
For runtime-selected sets (any domain — shards, files, jobs, catalog rows):
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const processShards = step.forEachPipeline("process-shards", {
|
|
114
|
+
pipeline: ShardPipeline,
|
|
115
|
+
dependsOn: [resolveShards],
|
|
116
|
+
items: ({ "resolve-shards": shards }) => shards,
|
|
117
|
+
key: (shard) => shard.id,
|
|
118
|
+
concurrency: (_inputs, context) => context.options.concurrency,
|
|
119
|
+
// Optional presentation only. Defaults to the noun "items".
|
|
120
|
+
progress: { itemNoun: "shards" },
|
|
121
|
+
mapOptions: (shard, _index, _inputs, context) => ({
|
|
122
|
+
shardPath: shard.path,
|
|
123
|
+
outputRoot: context.options.outputRoot,
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The parent sees one opaque `process-shards` step. Progress is domain-neutral by
|
|
129
|
+
default: a one-line item/concurrency summary plus structured `details` rows for
|
|
130
|
+
each in-flight child (`id` + `label`). Interactive reporters render those as
|
|
131
|
+
indented lines under the parent step so high concurrency stays readable. The
|
|
132
|
+
progress bar advances on terminal child steps so long fan-out work does not look
|
|
133
|
+
hung at 0%. Override `progress.itemNoun` or `progress.formatMessage` for domain
|
|
134
|
+
labels without changing scheduling. Duplicate keys fail before any child starts.
|
|
135
|
+
Parent dry-run overrides the mapped child run object's `dryRun` value.
|
|
136
|
+
|
|
137
|
+
## Semantics matrix
|
|
138
|
+
|
|
139
|
+
| Concern | Contract |
|
|
140
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
141
|
+
| Parent plan | The child is one opaque parent step. Its `nestedPipeline` metadata identifies the child pipeline, declared child step ids, and single/fan-out mode; child steps are not added to `PipelinePlan.steps` and runtime selection is not predicted. |
|
|
142
|
+
| Option mapping | `mapOptions(inputs, parentContext)` returns the child's complete run object: domain fields plus any child-specific controls. The adapter applies parent `dryRun` last so framework semantics win. |
|
|
143
|
+
| Other run controls | The adapter does not automatically propagate parent `stepIds`, `targets`, or `continueOnError`. `mapOptions` may choose child-specific values; child `targets` are limited to that child's declared public goals. Mapping parent selection would usually be invalid because parent and child ids occupy different namespaces. Mapping `continueOnError` lets independent child work finish but does not make a failed child usable by the parent. |
|
|
144
|
+
| Runtime context | The adapter forwards `cwd`, `log`, `now`, `sleep`, and `signal` field by field. It does not forward parent hooks or the parent-only `reportProgress` field. |
|
|
145
|
+
| Hook isolation | Parent and custom hooks see only the parent pipeline and opaque parent step. Raw child lifecycle events go only to an internal bridge. |
|
|
146
|
+
| Progress | Single-child `fromPipeline` bridges terminal child steps into the opaque step (`completed` / plan step count, messages prefixed with `childPipelineId/childStepId`). Mapped `forEachPipeline` reports domain-neutral fan-out progress via `toMappedChildStepProgress`: `completed` counts terminal child steps across items, `total` is `items × stepsPerItem`, `message` is a one-line summary, and `details` lists each in-flight item for multi-line reporters. Presentation is optional (`progress.itemNoun` / `progress.formatMessage` / `progress.detailLimit`); neither path creates another live reporter frame. |
|
|
147
|
+
| Result | The default output is the typed child result. `mapResult` may transform it into a domain-specific parent-step output. A child result is usable only when its status is `"completed"`; best-effort child results must be handled through an explicit ordinary step that calls `run()` and inspects the structured result. |
|
|
148
|
+
| Failure | An unusable child result fails the opaque parent step. Its error names the child pipeline and the first failing child step and message, with `code: "TUBELESS_CHILD_FAILED"`, `phase: "execution"`, and `kind: "child"`; its JSON-safe cause chain retains the actionable child failure. When mapped children contain both cancellation and genuine failure, failure takes precedence; the aggregate is cancelled only when every unsuccessful child was cancelled. |
|
|
149
|
+
| Cancellation | The child receives the exact parent `AbortSignal`. An already-aborted or later-aborted signal stops the child and transitions the parent step to `cancelled`. |
|
|
150
|
+
| Dry run | The child receives `dryRun: parentContext.dryRun` and applies its own per-step policy. Child steps with `dryRun: "skip"` are skipped; ordinary child steps run normally. |
|
|
151
|
+
| Selective execution | Selecting or targeting the opaque parent step runs the child according to its mapped controls. Parent selection is never forwarded into the child's ID namespace. |
|
|
152
|
+
| Checkpoints | The adapter adds no checkpoint behavior. The child receives mapped options and the normal runtime context. |
|
|
153
|
+
|
|
154
|
+
## Guarantees
|
|
155
|
+
|
|
156
|
+
Call sites infer required and optional dependency inputs, parent domain
|
|
157
|
+
options, required child options, the default child result, and a transformed
|
|
158
|
+
`mapResult` output without explicit generic arguments. Missing required child
|
|
159
|
+
options fail at compile time.
|
|
160
|
+
|
|
161
|
+
The parent plan contains only the opaque stage. The child receives the
|
|
162
|
+
parent's working directory, logger, clock, sleep function, and abort signal.
|
|
163
|
+
Parent hooks see no raw child lifecycle events. The internal bridge converts
|
|
164
|
+
the child's canonical step statuses into monotonic progress on the opaque
|
|
165
|
+
parent step.
|
|
166
|
+
|
|
167
|
+
Parent dry-run precedence prevents a child side-effecting step from running.
|
|
168
|
+
An unusable child result fails one opaque parent step and names the child
|
|
169
|
+
pipeline, step, and error, including when `continueOnError` produced a
|
|
170
|
+
best-effort final value. Later cancellation interrupts in-flight child work.
|
|
171
|
+
An invalid child plan fails before the child starts.
|
|
172
|
+
|
|
173
|
+
`fromPipeline` identity (no `mapResult`) uses overloads so the parent-facing
|
|
174
|
+
output stays the child result.
|
|
175
|
+
|
|
176
|
+
## Out of scope
|
|
177
|
+
|
|
178
|
+
Policy skip plus `TOut | undefined` typing cover skip-without-run for opaque
|
|
179
|
+
`fromPipeline` steps. Runner substitution and any richer skipped-output shape
|
|
180
|
+
beyond policy skip are not supported.
|
|
181
|
+
|
|
182
|
+
Hierarchical or versioned external events, flattened or namespaced child
|
|
183
|
+
selection, and parallel DAG scheduling remain out of scope. Mapped children
|
|
184
|
+
provide bounded parallelism inside one opaque parent step; they do not make
|
|
185
|
+
the pipeline DAG executor parallel.
|
package/docs/cli.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# CLI
|
|
2
|
+
|
|
3
|
+
The `tubeless` binary inspects, plans, graphs, and runs exported pipeline
|
|
4
|
+
modules. It requires Bun 1.3.14 or later (`#!/usr/bin/env bun`). Bun loads
|
|
5
|
+
TypeScript pipeline files directly. `npx tubeless` is not supported.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
bunx tubeless --help
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Library imports stay dependency-free compiled JavaScript. The CLI is the Bun
|
|
12
|
+
workbench around those same exports.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
| Command | Accepts | Does |
|
|
17
|
+
| ------------------ | -------------------------------- | ----------------------------------------------------------------------------- |
|
|
18
|
+
| `tubeless inspect` | A pipeline export | Prints identity (`id`, targets, exact steps) plus the default structural plan |
|
|
19
|
+
| `tubeless plan` | A pipeline or command export | Previews selection without executing or requiring domain options |
|
|
20
|
+
| `tubeless graph` | A pipeline export | Writes Mermaid flowchart source |
|
|
21
|
+
| `tubeless run` | A `definePipelineCommand` export | Executes the command's own validated CLI contract |
|
|
22
|
+
| `tubeless ui` | An optional studio catalog | Serves the local run studio; see [studio](./studio.md) |
|
|
23
|
+
|
|
24
|
+
The workbench discovers a single matching export automatically. Pass
|
|
25
|
+
`--export Name` when the file exports more than one. `plan` prefers a marked
|
|
26
|
+
command when a module exports both a pipeline and a command.
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
bunx tubeless inspect ./pipelines/import-pipeline.ts
|
|
30
|
+
bunx tubeless plan ./pipelines/import-pipeline.ts --target normalize --explain
|
|
31
|
+
bunx tubeless graph ./pipelines/import-pipeline.ts --markdown
|
|
32
|
+
bunx tubeless run ./scripts/import.ts -- --source rows.txt --target normalize
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Workbench flags stay before `--`. Application flags belong after it.
|
|
36
|
+
`tubeless run` never executes a raw pipeline or guesses domain options.
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
tubeless run --export ImportCommand ./scripts/import.ts -- --source rows.txt --target normalize
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For command help:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
tubeless run ./scripts/import.ts -- --help
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Inspect
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
tubeless inspect [options] <pipeline-file>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- `-e, --export <name>` selects a pipeline export
|
|
55
|
+
- `--json` emits identity and the default plan as JSON
|
|
56
|
+
|
|
57
|
+
## Plan
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
tubeless plan [options] <pipeline-or-command-file>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `-e, --export <name>` selects a pipeline or command export
|
|
64
|
+
- `-t, --target <id>` selects a declared target and its prerequisites (repeatable)
|
|
65
|
+
- `-s, --step <id>` selects exact internal steps (repeatable)
|
|
66
|
+
- `--dry-run` shows each step's dry-run disposition
|
|
67
|
+
- `--explain` includes target/dependency selection provenance
|
|
68
|
+
- `--json` emits the structured plan
|
|
69
|
+
|
|
70
|
+
Do not simulate planning with a `--plan` flag on the command itself. Use
|
|
71
|
+
`command.plan()` or `tubeless plan`. `--target` and `--step` cannot be combined.
|
|
72
|
+
|
|
73
|
+
## Graph
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
tubeless graph [options] <pipeline-file>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- `-e, --export <name>` selects a pipeline export
|
|
80
|
+
- `-d, --direction <value>` is `BT`, `LR`, `RL`, `TB`, or `TD` (default `TD`)
|
|
81
|
+
- `--descriptions` includes step descriptions in node labels
|
|
82
|
+
- `--markdown` wraps the result in a fenced Mermaid block
|
|
83
|
+
|
|
84
|
+
The same graph is available in process as `pipeline.toMermaid()`.
|
|
85
|
+
|
|
86
|
+
## Run
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
tubeless run [options] <command-file> [-- <command-args...>]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- `-e, --export <name>` selects a command export
|
|
93
|
+
- `--store <path>` appends run events to a local SQLite database
|
|
94
|
+
|
|
95
|
+
`run` accepts only a `definePipelineCommand` export. That export owns parsing,
|
|
96
|
+
validation, option mapping, reporting, and the result summary. Omit `mapOptions`
|
|
97
|
+
when validated flags already satisfy same-name pipeline options; keep it when
|
|
98
|
+
names, types, defaults, or derived values differ.
|
|
99
|
+
|
|
100
|
+
A first script is [`cli-job.ts`](../examples/cli-job.ts). Local history with
|
|
101
|
+
`--store` is covered in [the studio](./studio.md).
|
|
102
|
+
|
|
103
|
+
## Exit codes
|
|
104
|
+
|
|
105
|
+
| Code | Meaning |
|
|
106
|
+
| ---- | ------------ |
|
|
107
|
+
| `0` | Success |
|
|
108
|
+
| `1` | Usage |
|
|
109
|
+
| `2` | Load |
|
|
110
|
+
| `3` | Definition |
|
|
111
|
+
| `4` | Validation |
|
|
112
|
+
| `5` | Planning |
|
|
113
|
+
| `6` | Execution |
|
|
114
|
+
| `7` | Cancellation |
|
|
115
|
+
|
|
116
|
+
These values are also exported as `TUBELESS_WORKBENCH_EXIT_CODE` from
|
|
117
|
+
`tubeless/cli`. SIGINT is forwarded through the command context. Help (`--help`
|
|
118
|
+
or a command's own help) exits `0`.
|