@withone/cli 1.21.0 → 1.23.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/package.json
CHANGED
|
@@ -95,6 +95,21 @@ process.stdout.write(JSON.stringify(items.filter(i => i.active)));
|
|
|
95
95
|
|
|
96
96
|
The module runs as a child `node` process: the flow context `$` is piped to stdin as JSON, and stdout is parsed as JSON and used as the step's output. Modules have full Node APIs available (unlike inline `code.source`, which is sandboxed). Use `code.module` for anything non-trivial; keep `code.source` for one-liners.
|
|
97
97
|
|
|
98
|
+
#### Inline `code.source` sandbox
|
|
99
|
+
|
|
100
|
+
Inline `code.source` runs inside an async function with a restricted `require`. Only the following Node built-ins are importable:
|
|
101
|
+
|
|
102
|
+
- `node:buffer`
|
|
103
|
+
- `node:crypto`
|
|
104
|
+
- `node:url`
|
|
105
|
+
- `node:path`
|
|
106
|
+
|
|
107
|
+
Everything else — `fs`, `http`, `https`, `net`, `child_process`, `process`, `os`, `cluster`, `dgram`, `tls`, `vm`, `worker_threads` — is **blocked** and will throw `Module "<name>" is blocked in code steps`. The runtime also does not expose `process`, `__dirname`, `__filename`, `setTimeout`, or `fetch`.
|
|
108
|
+
|
|
109
|
+
If you need any of those (filesystem reads, network calls, timers, etc.), use a `code.module` step instead — modules run as a real child `node` process and have the full Node API surface.
|
|
110
|
+
|
|
111
|
+
When an inline `code.source` step throws at runtime, the error message reports the user-relative line and column plus the offending line of source — e.g. `Code step "blowup" failed at line 3:34\n const c = $.steps.mk.output.data.score;\n Cannot read properties of null (reading 'score')`. No need to bisect the step manually.
|
|
112
|
+
|
|
98
113
|
Whatever JSON a module writes to stdout becomes both `$.steps.<id>.output` and `$.steps.<id>.response` (aliases). Downstream steps can reference either.
|
|
99
114
|
|
|
100
115
|
### Migrating a legacy single-file flow
|
|
@@ -130,6 +145,8 @@ Two rules: (1) prepend the stdin-read line, (2) replace `return X` with `process
|
|
|
130
145
|
one --agent flow validate <key>
|
|
131
146
|
```
|
|
132
147
|
|
|
148
|
+
`flow validate` parses every inline `code.source` and runs `node --check` on every `code.module` file, so syntax errors (brace/paren mismatches, duplicate `let`, etc.) surface here instead of after upstream steps have already run. It also extracts `$.steps.X` and `$.input.X` references from inside `code.source` and `transform.expression` and reports any reference to an undefined step/input or to a step declared **after** the current one (forward references resolve to `undefined` at runtime — silent data loss). The same checks run automatically at the start of `flow execute` so a broken step in position 15 fails the run immediately rather than 15 minutes in.
|
|
149
|
+
|
|
133
150
|
### Step 6: Execute
|
|
134
151
|
|
|
135
152
|
```bash
|
|
@@ -187,6 +204,16 @@ Connection inputs with a `connection` field auto-resolve if the user has exactly
|
|
|
187
204
|
|
|
188
205
|
A pure `$.xxx` value resolves to the raw type. A string containing `{{$.xxx}}` does string interpolation.
|
|
189
206
|
|
|
207
|
+
**Passing objects and arrays:** `{{ }}` interpolation always produces a string — if the resolved value is an object or array it will be JSON-stringified and the engine will log a warning. To pass an object/array as a native value to the next step, use a **direct selector without `{{ }}`**:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
// ✗ Wrong — becomes a JSON string, triggers a runtime warning
|
|
211
|
+
"files": "{{$.steps.extract.output.allFiles}}"
|
|
212
|
+
|
|
213
|
+
// ✓ Right — passes the array as an array
|
|
214
|
+
"files": "$.steps.extract.output.allFiles"
|
|
215
|
+
```
|
|
216
|
+
|
|
190
217
|
### Selectors vs expressions
|
|
191
218
|
|
|
192
219
|
Selectors in data fields (`data`, `queryParams`, `pathVars`, `connectionKey`) are **dot-path lookups only** — they do not support JavaScript operators like `||` or `&&`. For default values, use the `default` field on the input definition:
|
|
@@ -343,6 +370,14 @@ After a parallel step, access each substep's output by its `id`: `$.steps.fetchE
|
|
|
343
370
|
}
|
|
344
371
|
```
|
|
345
372
|
|
|
373
|
+
A sub-flow step exposes the sub-flow's **step results map** at both `.output` and `.response` (they are aliases — pick whichever reads better). Access a specific sub-step's data with:
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
$.steps.<parent>.output.<subStepId>.output.<field>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
e.g. if sub-flow `enrich-customer` has a step `load` that returns `{ TEAM: "acme" }`, the caller reads it as `$.steps.enrich.output.load.output.TEAM`. There is no longer any `.response.<subStepId>` vs `.output.<subStepId>` ambiguity.
|
|
380
|
+
|
|
346
381
|
### `paginate` — Auto-collect paginated results
|
|
347
382
|
|
|
348
383
|
```json
|
|
@@ -369,6 +404,26 @@ After a parallel step, access each substep's output by its `id`: `$.steps.fetchE
|
|
|
369
404
|
}
|
|
370
405
|
```
|
|
371
406
|
|
|
407
|
+
**Safe interpolation.** Plain `{{$.input.x}}` does string substitution and is **unsafe** for bash — values containing quotes, `$`, backticks, `&`, etc. will break the command (or worse). Use the `q` helper to POSIX-shell-quote the value:
|
|
408
|
+
|
|
409
|
+
```json
|
|
410
|
+
{ "command": "echo {{q $.input.companyName}} | tr '[:upper:]' '[:lower:]'" }
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
`{{q $.input.companyName}}` resolves `O'Reilly Media & Co` to `'O'\''Reilly Media & Co'` — a single argv token bash will parse cleanly. Use `{{q ...}}` for **every** interpolation of user-controlled data into a bash command.
|
|
414
|
+
|
|
415
|
+
Alternatively, pass values as environment variables (also shell-safe) and reference them with `$VAR`:
|
|
416
|
+
|
|
417
|
+
```json
|
|
418
|
+
{
|
|
419
|
+
"type": "bash",
|
|
420
|
+
"bash": {
|
|
421
|
+
"env": { "COMPANY": "$.input.companyName" },
|
|
422
|
+
"command": "echo \"$COMPANY\" | tr '[:upper:]' '[:lower:]'"
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
372
427
|
## Error Handling
|
|
373
428
|
|
|
374
429
|
```json
|
|
@@ -377,6 +432,30 @@ After a parallel step, access each substep's output by its `id`: `$.steps.fetchE
|
|
|
377
432
|
|
|
378
433
|
Strategies: `fail` (default), `continue`, `retry`, `fallback`.
|
|
379
434
|
|
|
435
|
+
**Retry backoff.** By default each retry waits exactly `retryDelayMs`. For rate-limited APIs add `"backoff": "exponential"` (or `"exponential-jitter"`) and an optional `"maxDelayMs"` cap (defaults to 30000):
|
|
436
|
+
|
|
437
|
+
```json
|
|
438
|
+
{
|
|
439
|
+
"onError": {
|
|
440
|
+
"strategy": "retry",
|
|
441
|
+
"retries": 4,
|
|
442
|
+
"retryDelayMs": 1000,
|
|
443
|
+
"backoff": "exponential-jitter",
|
|
444
|
+
"maxDelayMs": 10000
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`exponential` waits `retryDelayMs * 2^(retryIndex)` (1s, 2s, 4s, 8s…) capped at `maxDelayMs`. `exponential-jitter` multiplies each wait by a random factor in [0.5, 1.0) so concurrent retries spread out.
|
|
450
|
+
|
|
451
|
+
**Inspecting retry outcomes.** Every retried step exposes how it ended on its `StepResult`:
|
|
452
|
+
|
|
453
|
+
- `$.steps.<id>.status` — `"success"` or `"failed"`
|
|
454
|
+
- `$.steps.<id>.retries` — number of retries actually performed (0 if first attempt succeeded)
|
|
455
|
+
- `$.steps.<id>.error` — last error message (only set when `status === "failed"` under `continue`/`fallback` strategies)
|
|
456
|
+
|
|
457
|
+
A successful-after-retry step also emits a `step:retry-success` event with the retry count, so you can distinguish a clean first-attempt success from a recovered one in logs.
|
|
458
|
+
|
|
380
459
|
Conditional execution: `"if": "$.steps.find.response.data.length > 0"`
|
|
381
460
|
|
|
382
461
|
## AI-Augmented Patterns
|