@probelabs/visor 0.1.124 → 0.1.126
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/dist/config.d.ts.map +1 -1
- package/dist/docs/DEPLOYMENT.md +117 -11
- package/dist/docs/GITHUB_CHECKS.md +18 -4
- package/dist/docs/NPM_USAGE.md +112 -39
- package/dist/docs/action-reference.md +63 -9
- package/dist/docs/advanced-ai.md +58 -51
- package/dist/docs/ai-configuration.md +99 -11
- package/dist/docs/ai-custom-tools-usage.md +70 -33
- package/dist/docs/ai-custom-tools.md +50 -27
- package/dist/docs/architecture.md +1232 -0
- package/dist/docs/bot-transports-rfc.md +13 -3
- package/dist/docs/ci-cli-mode.md +116 -8
- package/dist/docs/claude-code.md +111 -41
- package/dist/docs/command-provider.md +37 -15
- package/dist/docs/commands.md +252 -6
- package/dist/docs/configuration.md +138 -4
- package/dist/docs/contributing.md +737 -0
- package/dist/docs/custom-tools.md +39 -8
- package/dist/docs/dashboards/README.md +33 -19
- package/dist/docs/debug-visualizer-progress.md +14 -13
- package/dist/docs/debug-visualizer-rfc.md +14 -13
- package/dist/docs/debug-visualizer.md +30 -5
- package/dist/docs/debugging.md +73 -8
- package/dist/docs/default-output-schema.md +24 -20
- package/dist/docs/dependencies.md +75 -21
- package/dist/docs/dev-playbook.md +85 -9
- package/dist/docs/engine-pause-resume-rfc.md +11 -11
- package/dist/docs/engine-state-machine-plan.md +10 -3
- package/dist/docs/event-driven-github-integration-rfc.md +20 -11
- package/dist/docs/event-triggers.md +95 -6
- package/dist/docs/execution-statistics-rfc.md +16 -4
- package/dist/docs/fact-validator-gap-analysis.md +12 -1
- package/dist/docs/fact-validator-implementation-plan.md +19 -11
- package/dist/docs/fail-if.md +116 -11
- package/dist/docs/failure-conditions-implementation.md +40 -6
- package/dist/docs/failure-conditions-schema.md +243 -87
- package/dist/docs/failure-routing-rfc.md +43 -18
- package/dist/docs/failure-routing.md +80 -23
- package/dist/docs/faq.md +836 -0
- package/dist/docs/foreach-dependency-propagation.md +32 -15
- package/dist/docs/github-ops.md +6 -5
- package/dist/docs/glossary.md +322 -0
- package/dist/docs/goto-forward-run-plan.md +23 -10
- package/dist/docs/guides/criticality-modes.md +15 -13
- package/dist/docs/guides/fault-management-and-contracts.md +8 -5
- package/dist/docs/guides/workflow-style-guide.md +17 -8
- package/dist/docs/http.md +102 -3
- package/dist/docs/human-input-provider.md +20 -36
- package/dist/docs/index.md +206 -0
- package/dist/docs/lifecycle-hooks.md +322 -2
- package/dist/docs/limits.md +20 -5
- package/dist/docs/liquid-templates.md +86 -14
- package/dist/docs/loop-routing-refactor.md +4 -2
- package/dist/docs/mcp-provider.md +53 -19
- package/dist/docs/mcp.md +27 -1
- package/dist/docs/memory.md +7 -2
- package/dist/docs/migration.md +596 -0
- package/dist/docs/observability.md +227 -6
- package/dist/docs/output-formats.md +388 -9
- package/dist/docs/output-history.md +36 -6
- package/dist/docs/performance.md +510 -4
- package/dist/docs/pluggable.md +95 -4
- package/dist/docs/proposals/snapshot-scope-execution.md +6 -5
- package/dist/docs/providers/git-checkout.md +16 -14
- package/dist/docs/providers/noop.md +696 -0
- package/dist/docs/recipes.md +8 -9
- package/dist/docs/rfc/git-checkout-step.md +3 -1
- package/dist/docs/rfc/on_init-hook.md +18 -5
- package/dist/docs/rfc/workspace-isolation.md +16 -0
- package/dist/docs/roadmap/criticality-implementation-tasks.md +27 -27
- package/dist/docs/router-patterns.md +155 -43
- package/dist/docs/schema-templates.md +51 -15
- package/dist/docs/script.md +162 -13
- package/dist/docs/sdk.md +46 -12
- package/dist/docs/security.md +464 -5
- package/dist/docs/slack-integration.md +481 -0
- package/dist/docs/tag-filtering.md +60 -20
- package/dist/docs/telemetry-setup.md +157 -46
- package/dist/docs/test-framework-rfc.md +37 -36
- package/dist/docs/testing/assertions.md +92 -4
- package/dist/docs/testing/ci.md +56 -7
- package/dist/docs/testing/cli.md +57 -15
- package/dist/docs/testing/cookbook.md +53 -20
- package/dist/docs/testing/dsl-reference.md +110 -9
- package/dist/docs/testing/fixtures-and-mocks.md +28 -3
- package/dist/docs/testing/flows.md +59 -4
- package/dist/docs/testing/getting-started.md +14 -13
- package/dist/docs/testing/troubleshooting.md +39 -2
- package/dist/docs/timeouts.md +174 -18
- package/dist/docs/troubleshooting.md +176 -6
- package/dist/docs/workflow-creation-guide.md +101 -3
- package/dist/docs/workflows.md +138 -41
- package/dist/examples/README.md +169 -4
- package/dist/examples/ai-custom-tools-simple.yaml +2 -3
- package/dist/examples/cron-webhook-config.yaml +15 -0
- package/dist/examples/forEach-example.yaml +6 -0
- package/dist/examples/git-checkout-basic.yaml +4 -0
- package/dist/examples/git-checkout-compare.yaml +6 -0
- package/dist/examples/git-checkout-cross-repo.yaml +7 -0
- package/dist/examples/http-integration-config.yaml +30 -0
- package/dist/examples/https-server-config.yaml +15 -0
- package/dist/examples/mcp-provider-example.yaml +10 -10
- package/dist/examples/transform-example.yaml +3 -0
- package/dist/examples/webhook-pipeline-config.yaml +18 -0
- package/dist/examples/workflows/workflow-composition-example.yaml +4 -0
- package/dist/frontends/slack-frontend.d.ts +2 -0
- package/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +11 -7
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +11 -7
- package/dist/index.js +3127 -974
- package/dist/output/traces/{run-2026-01-28T16-15-24-569Z.ndjson → run-2026-01-31T16-37-22-321Z.ndjson} +84 -84
- package/dist/output/traces/{run-2026-01-28T16-16-09-757Z.ndjson → run-2026-01-31T16-38-06-031Z.ndjson} +1013 -1013
- package/dist/providers/ai-check-provider.d.ts +9 -2
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/mcp-custom-sse-server.d.ts +17 -1
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-tool-executor.d.ts +68 -0
- package/dist/providers/workflow-tool-executor.d.ts.map +1 -0
- package/dist/sdk/{check-provider-registry-AQ3JETBG.mjs → check-provider-registry-3KI5RKXT.mjs} +6 -5
- package/dist/sdk/check-provider-registry-IYILYY35.mjs +28 -0
- package/dist/sdk/chunk-2CPMMNIX.mjs +1459 -0
- package/dist/sdk/chunk-2CPMMNIX.mjs.map +1 -0
- package/dist/sdk/chunk-5LI6T4O3.mjs +3600 -0
- package/dist/sdk/chunk-5LI6T4O3.mjs.map +1 -0
- package/dist/sdk/{chunk-YLQ4UN62.mjs → chunk-A4PGHURG.mjs} +6838 -6257
- package/dist/sdk/chunk-A4PGHURG.mjs.map +1 -0
- package/dist/sdk/chunk-EXFGO4FX.mjs +147 -0
- package/dist/sdk/chunk-EXFGO4FX.mjs.map +1 -0
- package/dist/sdk/chunk-PJ7K5UFC.mjs +17732 -0
- package/dist/sdk/chunk-PJ7K5UFC.mjs.map +1 -0
- package/dist/sdk/{chunk-BHZ4CKUS.mjs → chunk-PXFIALUH.mjs} +77 -8
- package/dist/sdk/chunk-PXFIALUH.mjs.map +1 -0
- package/dist/sdk/{chunk-PVITVJ6J.mjs → chunk-RTKJXNZS.mjs} +32 -9
- package/dist/sdk/chunk-RTKJXNZS.mjs.map +1 -0
- package/dist/sdk/chunk-VW2GBXQT.mjs +606 -0
- package/dist/sdk/chunk-VW2GBXQT.mjs.map +1 -0
- package/dist/sdk/{config-RQQPMLRD.mjs → config-5AUYQFHE.mjs} +2 -2
- package/dist/sdk/config-6CUVEH7H.mjs +16 -0
- package/dist/sdk/config-6CUVEH7H.mjs.map +1 -0
- package/dist/sdk/{github-frontend-6Q4BISZX.mjs → github-frontend-BZ4N3BFZ.mjs} +7 -3
- package/dist/sdk/github-frontend-BZ4N3BFZ.mjs.map +1 -0
- package/dist/sdk/host-4MT3EW2I.mjs +52 -0
- package/dist/sdk/{host-P5NQICP7.mjs → host-NYWXLIFC.mjs} +2 -2
- package/dist/sdk/host-NYWXLIFC.mjs.map +1 -0
- package/dist/sdk/{routing-DEY2AIXM.mjs → routing-6R42GXUO.mjs} +2 -2
- package/dist/sdk/routing-6R42GXUO.mjs.map +1 -0
- package/dist/sdk/routing-7FXPULTO.mjs +24 -0
- package/dist/sdk/routing-7FXPULTO.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +3 -1
- package/dist/sdk/sdk.d.ts +3 -1
- package/dist/sdk/sdk.js +12163 -11204
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +14 -10
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk/slack-frontend-JUT3TYVC.mjs +821 -0
- package/dist/sdk/slack-frontend-JUT3TYVC.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-H3CUOLUD.mjs +28 -0
- package/dist/sdk/workflow-check-provider-H3CUOLUD.mjs.map +1 -0
- package/dist/sdk/workflow-check-provider-YUNNF4KC.mjs +28 -0
- package/dist/sdk/workflow-check-provider-YUNNF4KC.mjs.map +1 -0
- package/dist/sdk/workflow-registry-KFWSDSLM.mjs +12 -0
- package/dist/sdk/workflow-registry-KFWSDSLM.mjs.map +1 -0
- package/dist/slack/socket-runner.d.ts +2 -0
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/state-machine/context/workflow-inputs.d.ts +20 -0
- package/dist/state-machine/context/workflow-inputs.d.ts.map +1 -0
- package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
- package/dist/state-machine/dispatch/foreach-processor.d.ts.map +1 -1
- package/dist/state-machine/dispatch/stats-manager.d.ts.map +1 -1
- package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
- package/dist/state-machine/states/routing.d.ts +2 -1
- package/dist/state-machine/states/routing.d.ts.map +1 -1
- package/dist/traces/{run-2026-01-28T16-15-24-569Z.ndjson → run-2026-01-31T16-37-22-321Z.ndjson} +84 -84
- package/dist/traces/{run-2026-01-28T16-16-09-757Z.ndjson → run-2026-01-31T16-38-06-031Z.ndjson} +1013 -1013
- package/dist/types/config.d.ts +3 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/human-id.d.ts +12 -0
- package/dist/utils/human-id.d.ts.map +1 -0
- package/dist/utils/worktree-manager.d.ts +3 -0
- package/dist/utils/worktree-manager.d.ts.map +1 -1
- package/dist/workflow-executor.d.ts.map +1 -1
- package/dist/workflow-registry.d.ts +1 -0
- package/dist/workflow-registry.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/sdk/chunk-BHZ4CKUS.mjs.map +0 -1
- package/dist/sdk/chunk-PVITVJ6J.mjs.map +0 -1
- package/dist/sdk/chunk-YLQ4UN62.mjs.map +0 -1
- package/dist/sdk/github-frontend-6Q4BISZX.mjs.map +0 -1
- /package/dist/sdk/{check-provider-registry-AQ3JETBG.mjs.map → check-provider-registry-3KI5RKXT.mjs.map} +0 -0
- /package/dist/sdk/{config-RQQPMLRD.mjs.map → check-provider-registry-IYILYY35.mjs.map} +0 -0
- /package/dist/sdk/{routing-DEY2AIXM.mjs.map → config-5AUYQFHE.mjs.map} +0 -0
- /package/dist/sdk/{host-P5NQICP7.mjs.map → host-4MT3EW2I.mjs.map} +0 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# Lifecycle Hooks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Visor provides four lifecycle hooks that allow you to control step execution at different phases:
|
|
4
|
+
|
|
5
|
+
| Hook | When it Runs | Use Case |
|
|
6
|
+
|------|--------------|----------|
|
|
7
|
+
| `on_init` | **Before** step execution | Preprocessing, data fetching, context enrichment |
|
|
8
|
+
| `on_success` | **After** step succeeds | Post-processing, notifications, routing to next step |
|
|
9
|
+
| `on_fail` | **After** step fails | Error handling, retries, remediation |
|
|
10
|
+
| `on_finish` | **After all** forEach iterations complete | Aggregation, validation across all items |
|
|
4
11
|
|
|
5
12
|
## `on_init` Hook
|
|
6
13
|
|
|
@@ -245,9 +252,322 @@ See the `examples/` directory for comprehensive examples:
|
|
|
245
252
|
4. **Use `run_js` for conditionals**: Avoid fetching unnecessary data
|
|
246
253
|
5. **Handle failures gracefully**: Consider what happens if preprocessing fails
|
|
247
254
|
|
|
248
|
-
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## `on_success` Hook
|
|
258
|
+
|
|
259
|
+
The `on_success` hook runs **after** a step completes successfully. It allows you to:
|
|
260
|
+
- Run post-processing steps
|
|
261
|
+
- Trigger notifications or downstream actions
|
|
262
|
+
- Jump back to a previous step for re-evaluation (routing)
|
|
263
|
+
|
|
264
|
+
### Basic Usage
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
steps:
|
|
268
|
+
build:
|
|
269
|
+
type: command
|
|
270
|
+
exec: npm run build
|
|
271
|
+
on_success:
|
|
272
|
+
run: [notify, deploy]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Configuration Options
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
on_success:
|
|
279
|
+
# Run additional steps after success
|
|
280
|
+
run: [step1, step2]
|
|
281
|
+
|
|
282
|
+
# Optional: jump back to an ancestor step
|
|
283
|
+
goto: previous-step
|
|
284
|
+
|
|
285
|
+
# Optional: simulate a different event during goto
|
|
286
|
+
goto_event: pr_updated
|
|
287
|
+
|
|
288
|
+
# Dynamic step selection (JS expression returning string[])
|
|
289
|
+
run_js: |
|
|
290
|
+
return outputs['build'].hasWarnings ? ['review-warnings'] : [];
|
|
291
|
+
|
|
292
|
+
# Dynamic routing (JS expression returning step id or null)
|
|
293
|
+
goto_js: |
|
|
294
|
+
// Re-run once using history length as attempt counter
|
|
295
|
+
return outputs.history['build'].length === 1 ? 'setup' : null;
|
|
296
|
+
|
|
297
|
+
# Declarative transitions (evaluated in order, first match wins)
|
|
298
|
+
transitions:
|
|
299
|
+
- when: "outputs['build'].score >= 90"
|
|
300
|
+
to: publish
|
|
301
|
+
- when: "outputs['build'].score >= 70"
|
|
302
|
+
to: review
|
|
303
|
+
- when: "true"
|
|
304
|
+
to: null # No routing
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Example: Conditional Post-Processing
|
|
308
|
+
|
|
309
|
+
```yaml
|
|
310
|
+
steps:
|
|
311
|
+
analyze:
|
|
312
|
+
type: ai
|
|
313
|
+
prompt: Analyze code quality
|
|
314
|
+
on_success:
|
|
315
|
+
run_js: |
|
|
316
|
+
const result = outputs['analyze'];
|
|
317
|
+
if (result.issues?.length > 0) {
|
|
318
|
+
return ['create-report', 'notify-team'];
|
|
319
|
+
}
|
|
320
|
+
return ['mark-approved'];
|
|
321
|
+
|
|
322
|
+
create-report:
|
|
323
|
+
type: command
|
|
324
|
+
exec: generate-report.sh
|
|
325
|
+
on: []
|
|
326
|
+
|
|
327
|
+
notify-team:
|
|
328
|
+
type: http
|
|
329
|
+
url: https://slack.webhook.url
|
|
330
|
+
on: []
|
|
331
|
+
|
|
332
|
+
mark-approved:
|
|
333
|
+
type: command
|
|
334
|
+
exec: gh pr review --approve
|
|
335
|
+
on: []
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## `on_fail` Hook
|
|
341
|
+
|
|
342
|
+
The `on_fail` hook runs **after** a step fails. It provides mechanisms for:
|
|
343
|
+
- Automatic retries with backoff
|
|
344
|
+
- Running remediation steps before retry
|
|
345
|
+
- Jumping back to an ancestor step for re-execution
|
|
346
|
+
|
|
347
|
+
### Basic Usage
|
|
348
|
+
|
|
349
|
+
```yaml
|
|
350
|
+
steps:
|
|
351
|
+
deploy:
|
|
352
|
+
type: command
|
|
353
|
+
exec: ./deploy.sh
|
|
354
|
+
on_fail:
|
|
355
|
+
retry:
|
|
356
|
+
max: 3
|
|
357
|
+
backoff:
|
|
358
|
+
mode: exponential
|
|
359
|
+
delay_ms: 1000
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Configuration Options
|
|
363
|
+
|
|
364
|
+
```yaml
|
|
365
|
+
on_fail:
|
|
366
|
+
# Retry configuration
|
|
367
|
+
retry:
|
|
368
|
+
max: 3 # Maximum retry attempts
|
|
369
|
+
backoff:
|
|
370
|
+
mode: fixed | exponential # Backoff strategy
|
|
371
|
+
delay_ms: 1000 # Initial delay
|
|
372
|
+
|
|
373
|
+
# Run remediation steps before retry
|
|
374
|
+
run: [cleanup, reset-state]
|
|
375
|
+
|
|
376
|
+
# Jump back to ancestor step
|
|
377
|
+
goto: setup
|
|
378
|
+
|
|
379
|
+
# Simulate different event during goto
|
|
380
|
+
goto_event: pr_updated
|
|
381
|
+
|
|
382
|
+
# Dynamic remediation (JS returning string[])
|
|
383
|
+
run_js: |
|
|
384
|
+
if (output.error?.includes('lock')) {
|
|
385
|
+
return ['clear-locks'];
|
|
386
|
+
}
|
|
387
|
+
return [];
|
|
388
|
+
|
|
389
|
+
# Dynamic routing (JS returning step id or null)
|
|
390
|
+
goto_js: |
|
|
391
|
+
return attempt < 2 ? 'install-deps' : null;
|
|
392
|
+
|
|
393
|
+
# Declarative transitions
|
|
394
|
+
transitions:
|
|
395
|
+
- when: "output.error?.includes('timeout')"
|
|
396
|
+
to: null # Don't route, just retry
|
|
397
|
+
- when: "output.error?.includes('auth')"
|
|
398
|
+
to: refresh-auth
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Example: Remediation with Retry
|
|
402
|
+
|
|
403
|
+
```yaml
|
|
404
|
+
steps:
|
|
405
|
+
install:
|
|
406
|
+
type: command
|
|
407
|
+
exec: npm ci
|
|
408
|
+
|
|
409
|
+
test:
|
|
410
|
+
type: command
|
|
411
|
+
depends_on: [install]
|
|
412
|
+
exec: npm test
|
|
413
|
+
on_fail:
|
|
414
|
+
run: [clean-cache]
|
|
415
|
+
retry:
|
|
416
|
+
max: 2
|
|
417
|
+
backoff:
|
|
418
|
+
mode: fixed
|
|
419
|
+
delay_ms: 500
|
|
420
|
+
|
|
421
|
+
clean-cache:
|
|
422
|
+
type: command
|
|
423
|
+
exec: rm -rf node_modules/.cache
|
|
424
|
+
on: [] # Helper step only
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## `on_finish` Hook
|
|
430
|
+
|
|
431
|
+
The `on_finish` hook runs **once** after a `forEach` step completes **all** iterations and all dependent checks. This is ideal for:
|
|
432
|
+
- Aggregating results from all forEach iterations
|
|
433
|
+
- Making routing decisions based on collective outcomes
|
|
434
|
+
- Validation across all processed items
|
|
435
|
+
|
|
436
|
+
**Note:** `on_finish` only applies to steps with `forEach: true`.
|
|
437
|
+
|
|
438
|
+
### When It Triggers
|
|
439
|
+
|
|
440
|
+
1. The forEach step produces an array of items
|
|
441
|
+
2. All dependent steps execute for each item
|
|
442
|
+
3. After ALL iterations complete, `on_finish` triggers once
|
|
443
|
+
|
|
444
|
+
### Basic Usage
|
|
445
|
+
|
|
446
|
+
```yaml
|
|
447
|
+
steps:
|
|
448
|
+
process-files:
|
|
449
|
+
type: command
|
|
450
|
+
exec: "echo '[\"/a.ts\", \"/b.ts\", \"/c.ts\"]'"
|
|
451
|
+
forEach: true
|
|
452
|
+
on_finish:
|
|
453
|
+
run: [summarize-results]
|
|
454
|
+
goto_js: |
|
|
455
|
+
const results = outputs.history['validate-file'];
|
|
456
|
+
const allValid = results.every(r => r.valid);
|
|
457
|
+
return allValid ? null : 'process-files'; # Retry if any failed
|
|
458
|
+
|
|
459
|
+
validate-file:
|
|
460
|
+
type: ai
|
|
461
|
+
depends_on: [process-files]
|
|
462
|
+
prompt: Validate {{ outputs['process-files'] }}
|
|
463
|
+
|
|
464
|
+
summarize-results:
|
|
465
|
+
type: script
|
|
466
|
+
content: |
|
|
467
|
+
const results = outputs.history['validate-file'];
|
|
468
|
+
return {
|
|
469
|
+
total: results.length,
|
|
470
|
+
passed: results.filter(r => r.valid).length
|
|
471
|
+
};
|
|
472
|
+
on: []
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Available Context
|
|
476
|
+
|
|
477
|
+
The `on_finish` context is richer than other hooks:
|
|
478
|
+
|
|
479
|
+
```javascript
|
|
480
|
+
{
|
|
481
|
+
step: { id: 'process-files', tags: [...] },
|
|
482
|
+
attempt: 1, // Current attempt number
|
|
483
|
+
loop: 0, // Current loop in routing
|
|
484
|
+
outputs: {
|
|
485
|
+
'process-files': [...], // Array of forEach items
|
|
486
|
+
'validate-file': [...], // ALL dependent results
|
|
487
|
+
history: { ... } // Alias for outputs_history
|
|
488
|
+
},
|
|
489
|
+
outputs_history: {
|
|
490
|
+
'process-files': [[...], ...],
|
|
491
|
+
'validate-file': [[...], ...],
|
|
492
|
+
},
|
|
493
|
+
outputs_raw: {
|
|
494
|
+
'process-files': [...], // Aggregate/parent values
|
|
495
|
+
},
|
|
496
|
+
forEach: {
|
|
497
|
+
items: 3, // Number of items
|
|
498
|
+
last_wave_size: 3,
|
|
499
|
+
last_items: [...],
|
|
500
|
+
is_parent: true
|
|
501
|
+
},
|
|
502
|
+
memory: { get, set, has, getAll, increment, clear },
|
|
503
|
+
pr: { number, title, author, branch, base },
|
|
504
|
+
files: [...],
|
|
505
|
+
env: { ... },
|
|
506
|
+
event: { name: '...' }
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Example: Validation with Retry
|
|
511
|
+
|
|
512
|
+
```yaml
|
|
513
|
+
steps:
|
|
514
|
+
extract-facts:
|
|
515
|
+
type: ai
|
|
516
|
+
forEach: true
|
|
517
|
+
transform_js: JSON.parse(output).facts
|
|
518
|
+
on_finish:
|
|
519
|
+
run: [aggregate-validations]
|
|
520
|
+
goto_js: |
|
|
521
|
+
const allValid = memory.get('all_valid', 'validation');
|
|
522
|
+
const attempt = memory.get('attempt', 'validation') || 0;
|
|
523
|
+
|
|
524
|
+
if (allValid || attempt >= 2) {
|
|
525
|
+
return null; // Success or max attempts
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
memory.increment('attempt', 1, 'validation');
|
|
529
|
+
return 'generate-response'; # Retry from ancestor
|
|
530
|
+
|
|
531
|
+
validate-fact:
|
|
532
|
+
type: ai
|
|
533
|
+
depends_on: [extract-facts]
|
|
534
|
+
prompt: Validate this fact...
|
|
535
|
+
|
|
536
|
+
aggregate-validations:
|
|
537
|
+
type: script
|
|
538
|
+
content: |
|
|
539
|
+
const results = outputs.history['validate-fact'];
|
|
540
|
+
const allValid = results.every(r => r.is_valid);
|
|
541
|
+
memory.set('all_valid', allValid, 'validation');
|
|
542
|
+
return { total: results.length, valid: results.filter(r => r.is_valid).length };
|
|
543
|
+
on: []
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## Loop Protection & Safety
|
|
549
|
+
|
|
550
|
+
All routing hooks (`on_success`, `on_fail`, `on_finish`) are subject to loop protection:
|
|
551
|
+
|
|
552
|
+
```yaml
|
|
553
|
+
routing:
|
|
554
|
+
max_loops: 10 # Per-scope cap on routing transitions
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
- **Retry counters**: Each step tracks attempt count independently
|
|
558
|
+
- **Loop budget**: Total routing transitions (goto + run) are capped per scope
|
|
559
|
+
- **forEach isolation**: Each item has its own loop/attempt counters
|
|
560
|
+
|
|
561
|
+
For hard caps on step executions, see [Execution Limits](./limits.md).
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## See Also
|
|
249
566
|
|
|
567
|
+
- [Failure Routing](./failure-routing.md) - Complete guide to on_success, on_fail, on_finish
|
|
250
568
|
- [Custom Tools](./custom-tools.md) - Define reusable MCP tools
|
|
251
569
|
- [Workflows](./workflows.md) - Create reusable workflows
|
|
252
570
|
- [Liquid Templates](./liquid-templates.md) - Template syntax for dynamic values
|
|
571
|
+
- [Output History](./output-history.md) - Accessing historical outputs in routing
|
|
572
|
+
- [Execution Limits](./limits.md) - Configuring execution caps
|
|
253
573
|
- [RFC: on_init Hook](./rfc/on_init-hook.md) - Design proposal and rationale
|
package/dist/docs/limits.md
CHANGED
|
@@ -9,13 +9,14 @@ This feature protects workflows from accidental infinite loops by capping how ma
|
|
|
9
9
|
|
|
10
10
|
### Configuration
|
|
11
11
|
|
|
12
|
-
Global (
|
|
12
|
+
Global limits (defaults shown):
|
|
13
13
|
|
|
14
14
|
```yaml
|
|
15
15
|
version: "1.0"
|
|
16
16
|
|
|
17
17
|
limits:
|
|
18
|
-
max_runs_per_check: 50
|
|
18
|
+
max_runs_per_check: 50 # Applies to every step unless overridden
|
|
19
|
+
max_workflow_depth: 3 # Maximum nesting depth for nested workflows
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
Per-step override:
|
|
@@ -47,9 +48,23 @@ steps:
|
|
|
47
48
|
|
|
48
49
|
### How this differs from `routing.max_loops`
|
|
49
50
|
|
|
50
|
-
- `routing.max_loops` caps routing transitions (e.g., goto/retry waves) per scope.
|
|
51
|
-
- `limits.max_runs_per_check` caps actual step executions per step (also per scope for `forEach`).
|
|
52
|
-
-
|
|
51
|
+
- `routing.max_loops` caps routing transitions (e.g., goto/retry waves) per scope. Default: 10.
|
|
52
|
+
- `limits.max_runs_per_check` caps actual step executions per step (also per scope for `forEach`). Default: 50.
|
|
53
|
+
- `limits.max_workflow_depth` caps nested workflow invocations. Default: 3.
|
|
54
|
+
- Both execution and routing guard rails can be used together: set a modest routing budget (e.g., 5-10) and leave the execution cap at the default (50) or tailor per step.
|
|
55
|
+
|
|
56
|
+
### Workflow Depth Limit
|
|
57
|
+
|
|
58
|
+
The `max_workflow_depth` setting prevents infinite recursion when workflows call other workflows:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
limits:
|
|
62
|
+
max_workflow_depth: 3 # Maximum nesting depth (default: 3)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When the depth limit is exceeded, the workflow provider throws an error. This protects against:
|
|
66
|
+
- Accidentally creating recursive workflow chains
|
|
67
|
+
- Runaway nested workflow invocations
|
|
53
68
|
|
|
54
69
|
### Recommendations
|
|
55
70
|
|
|
@@ -103,6 +103,20 @@ The `json` filter serializes objects to JSON strings, useful for debugging or pa
|
|
|
103
103
|
# Debug output object
|
|
104
104
|
{{ outputs | json }}
|
|
105
105
|
|
|
106
|
+
# Debug specific check output
|
|
107
|
+
{{ outputs.security | json }}
|
|
108
|
+
|
|
109
|
+
# Pass to command safely
|
|
110
|
+
echo '{{ pr | json }}' | jq .
|
|
111
|
+
|
|
112
|
+
# Create JSON payload
|
|
113
|
+
{
|
|
114
|
+
"title": {{ pr.title | json }},
|
|
115
|
+
"files": {{ files | json }},
|
|
116
|
+
"outputs": {{ outputs | json }}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
106
120
|
### Author Permission Filters
|
|
107
121
|
|
|
108
122
|
> **📖 For complete documentation, see [Author Permissions Guide](./author-permissions.md)**
|
|
@@ -165,20 +179,6 @@ Ticket key: {{ outputs['fetch-tickets'].tickets[0].key }}
|
|
|
165
179
|
|
|
166
180
|
If the underlying value is plain text, it behaves as a normal string.
|
|
167
181
|
|
|
168
|
-
# Debug specific check output
|
|
169
|
-
{{ outputs.security | json }}
|
|
170
|
-
|
|
171
|
-
# Pass to command safely
|
|
172
|
-
echo '{{ pr | json }}' | jq .
|
|
173
|
-
|
|
174
|
-
# Create JSON payload
|
|
175
|
-
{
|
|
176
|
-
"title": {{ pr.title | json }},
|
|
177
|
-
"files": {{ files | json }},
|
|
178
|
-
"outputs": {{ outputs | json }}
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
182
|
### String Filters
|
|
183
183
|
|
|
184
184
|
```liquid
|
|
@@ -198,6 +198,78 @@ echo '{{ pr | json }}' | jq .
|
|
|
198
198
|
{{ files | map: "filename" }} # Array of filenames
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
+
### Encoding Filters
|
|
202
|
+
|
|
203
|
+
```liquid
|
|
204
|
+
# Base64 encoding/decoding
|
|
205
|
+
{{ "user:password" | base64 }} # Encode to base64
|
|
206
|
+
{{ encoded_value | base64_decode }} # Decode from base64
|
|
207
|
+
|
|
208
|
+
# JSON escaping (for use inside JSON string values)
|
|
209
|
+
"jql": "{{ myValue | json_escape }}"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Shell Escaping Filters
|
|
213
|
+
|
|
214
|
+
For safely passing values to shell commands:
|
|
215
|
+
|
|
216
|
+
```liquid
|
|
217
|
+
# Single-quote escaping (recommended, POSIX-compliant)
|
|
218
|
+
{{ value | shell_escape }} # "hello'world" becomes "'hello'\''world'"
|
|
219
|
+
{{ value | escape_shell }} # Alias for shell_escape
|
|
220
|
+
|
|
221
|
+
# Double-quote escaping (less safe, use when needed)
|
|
222
|
+
{{ value | shell_escape_double }} # Escapes $, `, \, ", and !
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Utility Filters
|
|
226
|
+
|
|
227
|
+
```liquid
|
|
228
|
+
# Safe nested access using dot-path
|
|
229
|
+
{{ obj | get: 'a.b.c' }} # Access nested property safely
|
|
230
|
+
|
|
231
|
+
# Check if value is non-empty
|
|
232
|
+
{% if items | not_empty %} # True for non-empty arrays/strings/objects
|
|
233
|
+
Has items
|
|
234
|
+
{% endif %}
|
|
235
|
+
|
|
236
|
+
# Pick first non-empty value
|
|
237
|
+
{{ a | coalesce: b, c }} # Returns first non-empty value
|
|
238
|
+
|
|
239
|
+
# Expression-based array filtering (Shopify-style)
|
|
240
|
+
{{ items | where_exp: 'i', 'i.is_valid == true' }}
|
|
241
|
+
|
|
242
|
+
# String manipulation
|
|
243
|
+
{{ value | unescape_newlines }} # Convert "\n" to actual newlines
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Label Sanitization Filters
|
|
247
|
+
|
|
248
|
+
For safely formatting labels (only allows `[A-Za-z0-9:/\- ]`):
|
|
249
|
+
|
|
250
|
+
```liquid
|
|
251
|
+
{{ label | safe_label }} # Sanitize a single label
|
|
252
|
+
{{ labels | safe_label_list }} # Sanitize an array of labels
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Memory Store Filters
|
|
256
|
+
|
|
257
|
+
Access the persistent memory store from templates:
|
|
258
|
+
|
|
259
|
+
```liquid
|
|
260
|
+
# Get a value from memory
|
|
261
|
+
{{ "my-key" | memory_get }}
|
|
262
|
+
{{ "my-key" | memory_get: "namespace" }}
|
|
263
|
+
|
|
264
|
+
# Check if a key exists
|
|
265
|
+
{% if "my-key" | memory_has %}
|
|
266
|
+
Key exists in memory
|
|
267
|
+
{% endif %}
|
|
268
|
+
|
|
269
|
+
# List all keys in a namespace
|
|
270
|
+
{{ "namespace" | memory_list }}
|
|
271
|
+
```
|
|
272
|
+
|
|
201
273
|
### Chat History Helper
|
|
202
274
|
|
|
203
275
|
The `chat_history` filter turns one or more check histories into a linear, timestamp‑sorted chat transcript. This is especially useful for human‑input + AI chat flows (Slack, CLI, etc.).
|
|
@@ -25,14 +25,16 @@ The previous behavior de‑duplicated a step when re‑routed in the same event,
|
|
|
25
25
|
- Skip static `on_success.goto` chains when the target produced fatal issues (including `fail_if`).
|
|
26
26
|
- For `origin='on_fail'`, schedule only direct dependents of the failed target; skip dependents when any direct dep has fatal issues.
|
|
27
27
|
|
|
28
|
-
4) One‑shot opt‑in
|
|
29
|
-
- `tags: [one_shot]`
|
|
28
|
+
4) One‑shot opt‑in (NOT YET IMPLEMENTED)
|
|
29
|
+
- `tags: [one_shot]` would prevent a terminal step (e.g., `finish`) from running more than once per grouped run.
|
|
30
|
+
- Status: Planned but not yet implemented in codebase.
|
|
30
31
|
|
|
31
32
|
5) Test‑visible history
|
|
32
33
|
- `executeChecks` now attaches `reviewSummary.history` with a safe snapshot of per‑step outputs history for deterministic testing (no I/O).
|
|
33
34
|
|
|
34
35
|
6) Task‑refinement agent (manual‑only)
|
|
35
36
|
- `defaults/task-refinement.yaml` uses `ask` → `refine` loop with `fail_if` and `on_fail/on_success` only; no `repeatable`, no `goto_js`, no `schedule`.
|
|
37
|
+
- The `finish` step uses an `if` guard to prevent re-execution (workaround for unimplemented `one_shot` tag).
|
|
36
38
|
- Embedded tests: one‑pass and multi‑turn pass locally.
|
|
37
39
|
|
|
38
40
|
## Removed
|