@relayflows/sdk 2.0.8 → 2.0.10
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/adapters/base.d.ts +46 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +15 -0
- package/dist/adapters/base.js.map +1 -0
- package/dist/adapters/claude.d.ts +5 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +44 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +5 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +45 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/index.d.ts +14 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +29 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/wrapper.d.ts +12 -0
- package/dist/adapters/wrapper.d.ts.map +1 -0
- package/dist/adapters/wrapper.js +31 -0
- package/dist/adapters/wrapper.js.map +1 -0
- package/dist/agent-relay-transport.d.ts +84 -0
- package/dist/agent-relay-transport.d.ts.map +1 -0
- package/dist/agent-relay-transport.js +134 -0
- package/dist/agent-relay-transport.js.map +1 -0
- package/dist/authored-budget.d.ts +13 -0
- package/dist/authored-budget.d.ts.map +1 -0
- package/dist/authored-budget.js +78 -0
- package/dist/authored-budget.js.map +1 -0
- package/dist/authored-flow-error.d.ts +1 -1
- package/dist/authored-flow-error.d.ts.map +1 -1
- package/dist/authored-flow-error.js.map +1 -1
- package/dist/authored-flow-executor.d.ts +13 -7
- package/dist/authored-flow-executor.d.ts.map +1 -1
- package/dist/authored-flow-executor.js +115 -194
- package/dist/authored-flow-executor.js.map +1 -1
- package/dist/authored-flow-loader.d.ts +10 -1
- package/dist/authored-flow-loader.d.ts.map +1 -1
- package/dist/authored-flow-loader.js +56 -3
- package/dist/authored-flow-loader.js.map +1 -1
- package/dist/authored-flow-operation.d.ts +9 -1
- package/dist/authored-flow-operation.d.ts.map +1 -1
- package/dist/authored-flow-operation.js +35 -4
- package/dist/authored-flow-operation.js.map +1 -1
- package/dist/authored-helper-effect.d.ts +12 -0
- package/dist/authored-helper-effect.d.ts.map +1 -0
- package/dist/authored-helper-effect.js +144 -0
- package/dist/authored-helper-effect.js.map +1 -0
- package/dist/authored-mcp.d.ts +17 -0
- package/dist/authored-mcp.d.ts.map +1 -0
- package/dist/authored-mcp.js +171 -0
- package/dist/authored-mcp.js.map +1 -0
- package/dist/authored-memory.d.ts +7 -0
- package/dist/authored-memory.d.ts.map +1 -0
- package/dist/authored-memory.js +60 -0
- package/dist/authored-memory.js.map +1 -0
- package/dist/authored-plugin-effect.d.ts +16 -0
- package/dist/authored-plugin-effect.d.ts.map +1 -0
- package/dist/authored-plugin-effect.js +163 -0
- package/dist/authored-plugin-effect.js.map +1 -0
- package/dist/authored-step-output.d.ts +23 -0
- package/dist/authored-step-output.d.ts.map +1 -0
- package/dist/authored-step-output.js +67 -0
- package/dist/authored-step-output.js.map +1 -0
- package/dist/authored-worker-step.d.ts +15 -0
- package/dist/authored-worker-step.d.ts.map +1 -0
- package/dist/authored-worker-step.js +136 -0
- package/dist/authored-worker-step.js.map +1 -0
- package/dist/budget-preflight.d.ts +5 -0
- package/dist/budget-preflight.d.ts.map +1 -0
- package/dist/budget-preflight.js +33 -0
- package/dist/budget-preflight.js.map +1 -0
- package/dist/budget.d.ts +14 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +52 -0
- package/dist/budget.js.map +1 -0
- package/dist/bundle-transport.d.ts +18 -0
- package/dist/bundle-transport.d.ts.map +1 -0
- package/dist/bundle-transport.js +111 -0
- package/dist/bundle-transport.js.map +1 -0
- package/dist/bundle-typescript.d.ts +8 -0
- package/dist/bundle-typescript.d.ts.map +1 -0
- package/dist/bundle-typescript.js +108 -0
- package/dist/bundle-typescript.js.map +1 -0
- package/dist/bundle.d.ts +25 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +199 -0
- package/dist/bundle.js.map +1 -0
- package/dist/child-stop.d.ts +59 -0
- package/dist/child-stop.d.ts.map +1 -0
- package/dist/child-stop.js +94 -0
- package/dist/child-stop.js.map +1 -0
- package/dist/cli/add.d.ts +6 -0
- package/dist/cli/add.d.ts.map +1 -0
- package/dist/cli/add.js +47 -0
- package/dist/cli/add.js.map +1 -0
- package/dist/cli/build.d.ts +13 -0
- package/dist/cli/build.d.ts.map +1 -0
- package/dist/cli/build.js +224 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/bundle-preflight.d.ts +5 -0
- package/dist/cli/bundle-preflight.d.ts.map +1 -0
- package/dist/cli/bundle-preflight.js +28 -0
- package/dist/cli/bundle-preflight.js.map +1 -0
- package/dist/cli/check-helper-body.d.ts +4 -0
- package/dist/cli/check-helper-body.d.ts.map +1 -0
- package/dist/cli/check-helper-body.js +15 -0
- package/dist/cli/check-helper-body.js.map +1 -0
- package/dist/cli/check-triggers.d.ts +14 -0
- package/dist/cli/check-triggers.d.ts.map +1 -0
- package/dist/cli/check-triggers.js +37 -0
- package/dist/cli/check-triggers.js.map +1 -0
- package/dist/cli/check-typescript.d.ts +20 -0
- package/dist/cli/check-typescript.d.ts.map +1 -0
- package/dist/cli/check-typescript.js +54 -0
- package/dist/cli/check-typescript.js.map +1 -0
- package/dist/cli/check.d.ts +36 -3
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +122 -11
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/cloud-run.d.ts +8 -0
- package/dist/cli/cloud-run.d.ts.map +1 -0
- package/dist/cli/cloud-run.js +50 -0
- package/dist/cli/cloud-run.js.map +1 -0
- package/dist/cli/deploy.d.ts +9 -0
- package/dist/cli/deploy.d.ts.map +1 -0
- package/dist/cli/deploy.js +58 -0
- package/dist/cli/deploy.js.map +1 -0
- package/dist/cli/deterministic-failure.d.ts +5 -0
- package/dist/cli/deterministic-failure.d.ts.map +1 -0
- package/dist/cli/deterministic-failure.js +66 -0
- package/dist/cli/deterministic-failure.js.map +1 -0
- package/dist/cli/direct-run.d.ts.map +1 -1
- package/dist/cli/direct-run.js +83 -7
- package/dist/cli/direct-run.js.map +1 -1
- package/dist/cli/hn-monitor.d.ts.map +1 -1
- package/dist/cli/hn-monitor.js +2 -1
- package/dist/cli/hn-monitor.js.map +1 -1
- package/dist/cli/replay.d.ts +12 -0
- package/dist/cli/replay.d.ts.map +1 -0
- package/dist/cli/replay.js +82 -0
- package/dist/cli/replay.js.map +1 -0
- package/dist/cli/reuse.d.ts +8 -0
- package/dist/cli/reuse.d.ts.map +1 -0
- package/dist/cli/reuse.js +25 -0
- package/dist/cli/reuse.js.map +1 -0
- package/dist/cli/run-digest.d.ts +4 -0
- package/dist/cli/run-digest.d.ts.map +1 -0
- package/dist/cli/run-digest.js +24 -0
- package/dist/cli/run-digest.js.map +1 -0
- package/dist/cli/run.d.ts +16 -5
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +99 -17
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/serve-webhook.d.ts +40 -0
- package/dist/cli/serve-webhook.d.ts.map +1 -0
- package/dist/cli/serve-webhook.js +233 -0
- package/dist/cli/serve-webhook.js.map +1 -0
- package/dist/cli/tick-runner.d.ts.map +1 -1
- package/dist/cli/tick-runner.js +2 -1
- package/dist/cli/tick-runner.js.map +1 -1
- package/dist/cli-adapter.d.ts +8 -14
- package/dist/cli-adapter.d.ts.map +1 -1
- package/dist/cli-adapter.js +19 -64
- package/dist/cli-adapter.js.map +1 -1
- package/dist/cli-watch.d.ts +13 -0
- package/dist/cli-watch.d.ts.map +1 -0
- package/dist/cli-watch.js +185 -0
- package/dist/cli-watch.js.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +387 -14
- package/dist/cli.js.map +1 -1
- package/dist/cloud-http.d.ts +22 -0
- package/dist/cloud-http.d.ts.map +1 -0
- package/dist/cloud-http.js +84 -0
- package/dist/cloud-http.js.map +1 -0
- package/dist/cloud-run.d.ts +38 -0
- package/dist/cloud-run.d.ts.map +1 -0
- package/dist/cloud-run.js +112 -0
- package/dist/cloud-run.js.map +1 -0
- package/dist/compile.d.ts +21 -3
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +97 -23
- package/dist/compile.js.map +1 -1
- package/dist/create-flow.d.ts +17 -0
- package/dist/create-flow.d.ts.map +1 -0
- package/dist/create-flow.js +72 -0
- package/dist/create-flow.js.map +1 -0
- package/dist/daemon-connection.d.ts +14 -0
- package/dist/daemon-connection.d.ts.map +1 -1
- package/dist/daemon-connection.js +33 -1
- package/dist/daemon-connection.js.map +1 -1
- package/dist/demo-hn-monitor.js +2 -1
- package/dist/demo-hn-monitor.js.map +1 -1
- package/dist/effect-channel.d.ts +30 -0
- package/dist/effect-channel.d.ts.map +1 -0
- package/dist/effect-channel.js +71 -0
- package/dist/effect-channel.js.map +1 -0
- package/dist/failure-kinds.d.ts +14 -3
- package/dist/failure-kinds.d.ts.map +1 -1
- package/dist/failure-kinds.js +27 -0
- package/dist/failure-kinds.js.map +1 -1
- package/dist/gate-contract.d.ts.map +1 -1
- package/dist/gate-contract.js +9 -0
- package/dist/gate-contract.js.map +1 -1
- package/dist/helper-preflight.d.ts +18 -0
- package/dist/helper-preflight.d.ts.map +1 -0
- package/dist/helper-preflight.js +32 -0
- package/dist/helper-preflight.js.map +1 -0
- package/dist/helper-storage.d.ts +5 -0
- package/dist/helper-storage.d.ts.map +1 -0
- package/dist/helper-storage.js +31 -0
- package/dist/helper-storage.js.map +1 -0
- package/dist/helper-writeback.d.ts +12 -0
- package/dist/helper-writeback.d.ts.map +1 -0
- package/dist/helper-writeback.js +95 -0
- package/dist/helper-writeback.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/input-binding.d.ts +4 -0
- package/dist/input-binding.d.ts.map +1 -0
- package/dist/input-binding.js +78 -0
- package/dist/input-binding.js.map +1 -0
- package/dist/journal-client.d.ts +12 -4
- package/dist/journal-client.d.ts.map +1 -1
- package/dist/journal-client.js +17 -6
- package/dist/journal-client.js.map +1 -1
- package/dist/journal-offset.d.ts +3 -0
- package/dist/journal-offset.d.ts.map +1 -0
- package/dist/journal-offset.js +69 -0
- package/dist/journal-offset.js.map +1 -0
- package/dist/journal-reader.d.ts +30 -0
- package/dist/journal-reader.d.ts.map +1 -0
- package/dist/journal-reader.js +156 -0
- package/dist/journal-reader.js.map +1 -0
- package/dist/json-schema.d.ts +2 -0
- package/dist/json-schema.d.ts.map +1 -1
- package/dist/json-schema.js +38 -22
- package/dist/json-schema.js.map +1 -1
- package/dist/llm-worker.d.ts +16 -0
- package/dist/llm-worker.d.ts.map +1 -0
- package/dist/llm-worker.js +79 -0
- package/dist/llm-worker.js.map +1 -0
- package/dist/local-agent.d.ts +8 -0
- package/dist/local-agent.d.ts.map +1 -0
- package/dist/local-agent.js +25 -0
- package/dist/local-agent.js.map +1 -0
- package/dist/mcp-client.d.ts +15 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +104 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/mcp-config.d.ts +4 -0
- package/dist/mcp-config.d.ts.map +1 -0
- package/dist/mcp-config.js +61 -0
- package/dist/mcp-config.js.map +1 -0
- package/dist/mcp-stdio.d.ts +24 -0
- package/dist/mcp-stdio.d.ts.map +1 -0
- package/dist/mcp-stdio.js +89 -0
- package/dist/mcp-stdio.js.map +1 -0
- package/dist/model-pricing.d.ts +22 -0
- package/dist/model-pricing.d.ts.map +1 -0
- package/dist/model-pricing.js +30 -0
- package/dist/model-pricing.js.map +1 -0
- package/dist/mount-registry.d.ts +9 -0
- package/dist/mount-registry.d.ts.map +1 -0
- package/dist/mount-registry.js +47 -0
- package/dist/mount-registry.js.map +1 -0
- package/dist/named-gate-lowering.d.ts +9 -0
- package/dist/named-gate-lowering.d.ts.map +1 -0
- package/dist/named-gate-lowering.js +152 -0
- package/dist/named-gate-lowering.js.map +1 -0
- package/dist/named-gates.d.ts +10 -0
- package/dist/named-gates.d.ts.map +1 -0
- package/dist/named-gates.js +69 -0
- package/dist/named-gates.js.map +1 -0
- package/dist/observer-link.d.ts +129 -0
- package/dist/observer-link.d.ts.map +1 -0
- package/dist/observer-link.js +274 -0
- package/dist/observer-link.js.map +1 -0
- package/dist/plugin-loader.d.ts +13 -0
- package/dist/plugin-loader.d.ts.map +1 -0
- package/dist/plugin-loader.js +110 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/plugin-manifest.d.ts +27 -0
- package/dist/plugin-manifest.d.ts.map +1 -0
- package/dist/plugin-manifest.js +89 -0
- package/dist/plugin-manifest.js.map +1 -0
- package/dist/preflight.d.ts +26 -2
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +175 -1
- package/dist/preflight.js.map +1 -1
- package/dist/progress.d.ts +14 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +39 -0
- package/dist/progress.js.map +1 -0
- package/dist/protocol.d.ts +11 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/pty-sidechannel.d.ts +14 -0
- package/dist/pty-sidechannel.d.ts.map +1 -0
- package/dist/pty-sidechannel.js +103 -0
- package/dist/pty-sidechannel.js.map +1 -0
- package/dist/scope-compiler.d.ts +52 -0
- package/dist/scope-compiler.d.ts.map +1 -0
- package/dist/scope-compiler.js +62 -0
- package/dist/scope-compiler.js.map +1 -0
- package/dist/slack-preflight.d.ts +6 -0
- package/dist/slack-preflight.d.ts.map +1 -0
- package/dist/slack-preflight.js +28 -0
- package/dist/slack-preflight.js.map +1 -0
- package/dist/slack-writeback.d.ts +40 -0
- package/dist/slack-writeback.d.ts.map +1 -0
- package/dist/slack-writeback.js +60 -0
- package/dist/slack-writeback.js.map +1 -0
- package/dist/spec.d.ts +134 -4
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/step-dependencies.d.ts.map +1 -1
- package/dist/step-dependencies.js +2 -1
- package/dist/step-dependencies.js.map +1 -1
- package/dist/step-fields.d.ts +4 -4
- package/dist/step-fields.d.ts.map +1 -1
- package/dist/step-fields.js +5 -2
- package/dist/step-fields.js.map +1 -1
- package/dist/trigger-executor.d.ts +7 -0
- package/dist/trigger-executor.d.ts.map +1 -0
- package/dist/trigger-executor.js +35 -0
- package/dist/trigger-executor.js.map +1 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +53 -6
- package/dist/validate.js.map +1 -1
- package/dist/webhook-rate-limit.d.ts +29 -0
- package/dist/webhook-rate-limit.d.ts.map +1 -0
- package/dist/webhook-rate-limit.js +38 -0
- package/dist/webhook-rate-limit.js.map +1 -0
- package/dist/webhook-signature.d.ts +22 -0
- package/dist/webhook-signature.d.ts.map +1 -0
- package/dist/webhook-signature.js +53 -0
- package/dist/webhook-signature.js.map +1 -0
- package/dist/worker-cli.d.ts +13 -1
- package/dist/worker-cli.d.ts.map +1 -1
- package/dist/worker-cli.js +133 -12
- package/dist/worker-cli.js.map +1 -1
- package/dist/worker-input.d.ts +4 -0
- package/dist/worker-input.d.ts.map +1 -0
- package/dist/worker-input.js +14 -0
- package/dist/worker-input.js.map +1 -0
- package/dist/worker-lease.d.ts +5 -0
- package/dist/worker-lease.d.ts.map +1 -0
- package/dist/worker-lease.js +80 -0
- package/dist/worker-lease.js.map +1 -0
- package/dist/worker-spend.d.ts +19 -0
- package/dist/worker-spend.d.ts.map +1 -0
- package/dist/worker-spend.js +22 -0
- package/dist/worker-spend.js.map +1 -0
- package/dist/worker-usage.d.ts +7 -0
- package/dist/worker-usage.d.ts.map +1 -0
- package/dist/worker-usage.js +54 -0
- package/dist/worker-usage.js.map +1 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +22 -8
- package/dist/worker.js.map +1 -1
- package/dist/wrapper-session.d.ts +1 -1
- package/dist/wrapper-session.d.ts.map +1 -1
- package/dist/wrapper-session.js +56 -19
- package/dist/wrapper-session.js.map +1 -1
- package/dist/yaml-helper-effect.d.ts +8 -0
- package/dist/yaml-helper-effect.d.ts.map +1 -0
- package/dist/yaml-helper-effect.js +79 -0
- package/dist/yaml-helper-effect.js.map +1 -0
- package/dist/yaml-helpers.d.ts +18 -0
- package/dist/yaml-helpers.d.ts.map +1 -0
- package/dist/yaml-helpers.js +116 -0
- package/dist/yaml-helpers.js.map +1 -0
- package/package.json +19 -2
- package/src/adapters/base.ts +53 -0
- package/src/adapters/claude.ts +55 -0
- package/src/adapters/codex.ts +56 -0
- package/src/adapters/index.ts +36 -0
- package/src/adapters/wrapper.ts +42 -0
- package/src/agent-relay-transport.ts +187 -0
- package/src/authored-budget.ts +69 -0
- package/src/authored-flow-error.ts +10 -0
- package/src/authored-flow-executor.ts +170 -293
- package/src/authored-flow-loader.ts +60 -3
- package/src/authored-flow-operation.ts +38 -5
- package/src/authored-helper-effect.ts +143 -0
- package/src/authored-mcp.ts +166 -0
- package/src/authored-memory.ts +55 -0
- package/src/authored-plugin-effect.ts +152 -0
- package/src/authored-step-output.ts +107 -0
- package/src/authored-worker-step.ts +181 -0
- package/src/budget-preflight.ts +31 -0
- package/src/budget.ts +49 -0
- package/src/bundle-transport.ts +79 -0
- package/src/bundle-typescript.ts +98 -0
- package/src/bundle.ts +182 -0
- package/src/child-stop.ts +138 -0
- package/src/cli/add.ts +45 -0
- package/src/cli/build.ts +214 -0
- package/src/cli/bundle-preflight.ts +28 -0
- package/src/cli/check-helper-body.ts +14 -0
- package/src/cli/check-triggers.ts +41 -0
- package/src/cli/check-typescript.ts +63 -0
- package/src/cli/check.ts +132 -14
- package/src/cli/cloud-run.ts +47 -0
- package/src/cli/deploy.ts +52 -0
- package/src/cli/deterministic-failure.ts +69 -0
- package/src/cli/direct-run.ts +79 -7
- package/src/cli/hn-monitor.ts +2 -1
- package/src/cli/replay.ts +81 -0
- package/src/cli/reuse.ts +23 -0
- package/src/cli/run-digest.ts +24 -0
- package/src/cli/run.ts +104 -21
- package/src/cli/serve-webhook.ts +246 -0
- package/src/cli/tick-runner.ts +2 -1
- package/src/cli-adapter.ts +31 -74
- package/src/cli-watch.ts +174 -0
- package/src/cli.ts +396 -17
- package/src/cloud-http.ts +100 -0
- package/src/cloud-run.ts +137 -0
- package/src/compile.ts +102 -23
- package/src/create-flow.ts +82 -0
- package/src/daemon-connection.ts +32 -1
- package/src/demo-hn-monitor.ts +2 -1
- package/src/effect-channel.ts +97 -0
- package/src/failure-kinds.ts +38 -0
- package/src/gate-contract.ts +7 -0
- package/src/helper-preflight.ts +34 -0
- package/src/helper-storage.ts +23 -0
- package/src/helper-writeback.ts +83 -0
- package/src/index.ts +26 -0
- package/src/input-binding.ts +76 -0
- package/src/journal-client.ts +20 -7
- package/src/journal-offset.ts +60 -0
- package/src/journal-reader.ts +165 -0
- package/src/json-schema.ts +34 -18
- package/src/llm-worker.ts +82 -0
- package/src/local-agent.ts +30 -0
- package/src/mcp-client.ts +97 -0
- package/src/mcp-config.ts +42 -0
- package/src/mcp-stdio.ts +84 -0
- package/src/model-pricing.ts +32 -0
- package/src/mount-registry.ts +44 -0
- package/src/named-gate-lowering.ts +147 -0
- package/src/named-gates.ts +76 -0
- package/src/observer-link.ts +368 -0
- package/src/plugin-loader.ts +88 -0
- package/src/plugin-manifest.ts +76 -0
- package/src/preflight.ts +178 -4
- package/src/progress.ts +51 -0
- package/src/protocol.ts +12 -0
- package/src/pty-sidechannel.ts +92 -0
- package/src/scope-compiler.ts +105 -0
- package/src/slack-preflight.ts +25 -0
- package/src/slack-writeback.ts +63 -0
- package/src/spec.ts +112 -4
- package/src/step-dependencies.ts +3 -1
- package/src/step-fields.ts +5 -2
- package/src/trigger-executor.ts +34 -0
- package/src/validate.ts +47 -6
- package/src/webhook-rate-limit.ts +69 -0
- package/src/webhook-signature.ts +74 -0
- package/src/worker-cli.ts +156 -11
- package/src/worker-input.ts +15 -0
- package/src/worker-lease.ts +85 -0
- package/src/worker-spend.ts +23 -0
- package/src/worker-usage.ts +48 -0
- package/src/worker.ts +27 -9
- package/src/wrapper-session.ts +50 -15
- package/src/yaml-helper-effect.ts +78 -0
- package/src/yaml-helpers.ts +131 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import type { CliIo } from '../cli.js';
|
|
3
|
+
import { BundleFailure, bucketDirectory, copyBundle, exists, parseDigestReference,
|
|
4
|
+
verifyDigest, writableBucket } from '../bundle-transport.js';
|
|
5
|
+
import { checkRunnableBundle } from './bundle-preflight.js';
|
|
6
|
+
|
|
7
|
+
export interface DeployArgs { command: 'deploy'; value: string; to: string }
|
|
8
|
+
export function parseDeployArgs(args: readonly string[]): DeployArgs | undefined {
|
|
9
|
+
let value: string | undefined;
|
|
10
|
+
let to: string | undefined;
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
const arg = args[i]!;
|
|
13
|
+
if (arg === '--to') {
|
|
14
|
+
if (to !== undefined || !args[i + 1] || args[i + 1]!.startsWith('-')) return undefined;
|
|
15
|
+
to = args[++i];
|
|
16
|
+
} else if (arg.startsWith('-') || value !== undefined) return undefined;
|
|
17
|
+
else value = arg;
|
|
18
|
+
}
|
|
19
|
+
return value && to && parseDigestReference(value) ? { command: 'deploy', value, to } : undefined;
|
|
20
|
+
}
|
|
21
|
+
export async function runDeploy(args: DeployArgs, io: CliIo): Promise<0 | 1 | 2> {
|
|
22
|
+
let started = false;
|
|
23
|
+
try {
|
|
24
|
+
const ref = parseDigestReference(args.value);
|
|
25
|
+
if (!ref) throw new BundleFailure('bundle_missing_locally', 'Expected <flow>@sha256:<64 lowercase hex characters>.');
|
|
26
|
+
const source = join(process.cwd(), 'dist', 'flows', args.value);
|
|
27
|
+
if (!await exists(source)) throw new BundleFailure('bundle_missing_locally', `Build ${args.value} locally first.`);
|
|
28
|
+
await verifyDigest(source, ref.digest);
|
|
29
|
+
const checked = await checkRunnableBundle(source, ref.name);
|
|
30
|
+
if (!checked.report.ok) {
|
|
31
|
+
for (const diagnostic of checked.report.diagnostics) io.stderr(`${diagnostic.severity.toUpperCase()} [${diagnostic.kind}] ${diagnostic.message}`);
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
const target = bucketDirectory(args.to, ref);
|
|
35
|
+
if (await exists(target)) {
|
|
36
|
+
await verifyDigest(target, ref.digest);
|
|
37
|
+
io.stderr(`deploy_noop: ${args.value}`);
|
|
38
|
+
io.stdout(`SKIPPED (already-present) ${args.value} ${args.to}`);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
await writableBucket(target);
|
|
42
|
+
started = true;
|
|
43
|
+
const copied = await copyBundle(source, target, ref.digest);
|
|
44
|
+
if (!copied) io.stderr(`deploy_noop: ${args.value}`);
|
|
45
|
+
io.stdout(`${copied ? 'DEPLOYED' : 'SKIPPED (already-present)'} ${args.value} ${args.to}`);
|
|
46
|
+
return 0;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
const kind = started ? 'deploy_partial' : error instanceof BundleFailure ? error.kind : 'bucket_unreachable';
|
|
49
|
+
io.stderr(`${started ? 'FAILED' : 'REFUSED'} [${kind}] ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
return started ? 1 : 2;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { StepFailedDetails } from '../failure-kinds.js';
|
|
2
|
+
import type { JournalClient } from '../journal-client.js';
|
|
3
|
+
|
|
4
|
+
const STDERR_TAIL_BYTES = 1_024;
|
|
5
|
+
|
|
6
|
+
/** Read completion evidence through the existing protocol, including later pages. */
|
|
7
|
+
export async function deterministicFailureDetails(
|
|
8
|
+
client: JournalClient,
|
|
9
|
+
runId: string,
|
|
10
|
+
): Promise<StepFailedDetails | undefined> {
|
|
11
|
+
const snapshot = await client.runGet(runId);
|
|
12
|
+
if (!Object.values(snapshot.steps).some(step => step.type === 'deterministic')) return undefined;
|
|
13
|
+
let fromSeq = 1;
|
|
14
|
+
const failures = new Map<string, StepFailedDetails>();
|
|
15
|
+
while (true) {
|
|
16
|
+
const { entries } = await client.journalRead(runId, fromSeq, 100);
|
|
17
|
+
if (entries.length === 0) break;
|
|
18
|
+
for (const raw of entries) {
|
|
19
|
+
const entry = record(raw);
|
|
20
|
+
const seq = entry?.['seq'];
|
|
21
|
+
if (typeof seq !== 'number' || !Number.isSafeInteger(seq) || seq < fromSeq) {
|
|
22
|
+
throw new Error('invalid journal sequence in command failure inspection');
|
|
23
|
+
}
|
|
24
|
+
fromSeq = seq + 1;
|
|
25
|
+
const stepId = entry?.['step_id'];
|
|
26
|
+
if (entry?.['entry_type'] !== 'step.completed' || typeof stepId !== 'string'
|
|
27
|
+
|| snapshot.steps[stepId]?.type !== 'deterministic') continue;
|
|
28
|
+
// A later completion supersedes an earlier failed attempt.
|
|
29
|
+
failures.delete(stepId);
|
|
30
|
+
const payload = record(entry['payload']);
|
|
31
|
+
// Post-#292 the kernel preserves the captured `{exit_code, stdout_tail,
|
|
32
|
+
// stderr_tail}` in `output` on failed completions; prefer it. Fall back
|
|
33
|
+
// to `trajectory_tail` for journal records emitted before that fix.
|
|
34
|
+
const output = record(payload?.['output']) ?? record(payload?.['trajectory_tail']);
|
|
35
|
+
const exitCode = output?.['exit_code'];
|
|
36
|
+
if (payload?.['disposition'] !== 'step_done' || payload['completionReason'] === 'success'
|
|
37
|
+
|| typeof exitCode !== 'number' || !Number.isSafeInteger(exitCode) || exitCode === 0) continue;
|
|
38
|
+
failures.set(stepId, {
|
|
39
|
+
stepId,
|
|
40
|
+
exitCode,
|
|
41
|
+
stderrTail: stderrTail(output?.['stderr_tail']),
|
|
42
|
+
hint: `flows replay ${shellQuote(runId)} --at ${shellQuote(stepId)}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [...failures.values()].at(-1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function record(value: unknown): Record<string, unknown> | undefined {
|
|
50
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
51
|
+
? value as Record<string, unknown> : undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function stderrTail(value: unknown): string {
|
|
55
|
+
if (typeof value !== 'string') return '';
|
|
56
|
+
const bytes = Buffer.from(value, 'utf8');
|
|
57
|
+
let start = Math.max(0, bytes.length - STDERR_TAIL_BYTES);
|
|
58
|
+
// Drop a partial leading code point, avoiding replacement-byte expansion.
|
|
59
|
+
while (start < bytes.length && (bytes[start]! & 0xc0) === 0x80) start += 1;
|
|
60
|
+
// Preserve tabs/newlines; replace binary controls (including ESC and CR),
|
|
61
|
+
// C1 controls and Unicode formatting controls without growing the excerpt.
|
|
62
|
+
return bytes.subarray(start).toString('utf8')
|
|
63
|
+
.replace(/[\p{Cc}\p{Cf}]/gu, character => character === '\n' || character === '\t' ? character : '?');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function shellQuote(value: string): string {
|
|
67
|
+
return /^[A-Za-z0-9_-]+$/.test(value) && !value.startsWith('-')
|
|
68
|
+
? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
69
|
+
}
|
package/src/cli/direct-run.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { McpStepError } from '../authored-mcp.js';
|
|
2
|
+
import { McpPreflightError } from './check-typescript.js';
|
|
3
|
+
import { attachLocalAgent } from '../local-agent.js';
|
|
4
|
+
import { LlmWorker } from '../llm-worker.js';
|
|
1
5
|
import {
|
|
2
6
|
AuthoredFlowExecutionError,
|
|
3
7
|
executeAuthoredFlow,
|
|
4
8
|
} from '../authored-flow-executor.js';
|
|
5
|
-
import { AuthoredFlowLoadError
|
|
9
|
+
import { AuthoredFlowLoadError } from '../authored-flow-loader.js';
|
|
6
10
|
import { DirectInputError, parseDirectInput } from '../direct-input.js';
|
|
7
11
|
import { JournalClient } from '../journal-client.js';
|
|
8
12
|
import { inputFailureReport } from './check.js';
|
|
13
|
+
import { checkAuthoredTriggers } from './check-triggers.js';
|
|
9
14
|
import {
|
|
10
15
|
connect,
|
|
11
16
|
emptyReport,
|
|
@@ -37,17 +42,44 @@ export async function runDirectFlow(
|
|
|
37
42
|
};
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
// Declared triggers are knowable before any daemon or step is started.
|
|
46
|
+
// Importing the authored module is unavoidable here — trigger sources
|
|
47
|
+
// are only observable after `flow(...).on(webhook(...))` has run — but
|
|
48
|
+
// the authored body is not called, so a side-effect-in-body flow still
|
|
49
|
+
// has its body deferred until after daemon-attach below.
|
|
50
|
+
const checked = await checkAuthoredTriggers(path);
|
|
51
|
+
if (!checked.report.ok || checked.loaded === undefined) {
|
|
52
|
+
return { exitCode: 2, report: fromCheckReport('run', checked.report) };
|
|
53
|
+
}
|
|
40
54
|
const socketPath = socketFor(dataDir);
|
|
41
55
|
const base: RunReport = { ...emptyReport('run'), path };
|
|
42
56
|
const client = new JournalClient(socketPath);
|
|
43
57
|
const connected = await connect(client, 'run', dataDir, base, options);
|
|
44
58
|
if (connected !== undefined) return connected;
|
|
45
59
|
|
|
60
|
+
let localAgent: Awaited<ReturnType<typeof attachLocalAgent>> | undefined;
|
|
61
|
+
let localLlm: LlmWorker | undefined;
|
|
62
|
+
let llmClient: JournalClient | undefined;
|
|
63
|
+
let llmFailure: unknown;
|
|
46
64
|
try {
|
|
47
|
-
const { handle, getDefinition } =
|
|
65
|
+
const { handle, getDefinition } = checked.loaded;
|
|
66
|
+
if (options.localAgent) {
|
|
67
|
+
localAgent = await attachLocalAgent(client, dataDir, options.onPtyReady);
|
|
68
|
+
// A session owns one worker registration. Keep the workspace-free LLM
|
|
69
|
+
// worker on its own connection so it cannot replace the agent worker.
|
|
70
|
+
llmClient = new JournalClient(socketPath);
|
|
71
|
+
await llmClient.connect();
|
|
72
|
+
await llmClient.hello('flows-local-llm');
|
|
73
|
+
localLlm = new LlmWorker(llmClient, `${localAgent.stream}-llm`);
|
|
74
|
+
localLlm.on('error', error => { llmFailure = error; client.close(); });
|
|
75
|
+
await localLlm.attach();
|
|
76
|
+
}
|
|
48
77
|
const result = await executeAuthoredFlow(handle, client, input, {
|
|
49
78
|
getDefinition,
|
|
79
|
+
dataDir,
|
|
50
80
|
flowPath: path,
|
|
81
|
+
onProgress: options.onProgress,
|
|
82
|
+
localAgentStream: localAgent?.stream,
|
|
51
83
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
52
84
|
...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
|
|
53
85
|
});
|
|
@@ -57,6 +89,19 @@ export async function runDirectFlow(
|
|
|
57
89
|
`authored flow "${result.name}" completed without a journal step`,
|
|
58
90
|
));
|
|
59
91
|
}
|
|
92
|
+
if (result.completionReason === 'needs_human') {
|
|
93
|
+
return {
|
|
94
|
+
exitCode: 3,
|
|
95
|
+
report: {
|
|
96
|
+
...base, ok: false, runId: terminal.runId, socketPath, status: 'parked',
|
|
97
|
+
completedSteps: result.journalSteps.length,
|
|
98
|
+
diagnostics: [...base.diagnostics, {
|
|
99
|
+
severity: 'parked', kind: 'run_parked',
|
|
100
|
+
message: `Flow "${result.name}" needs_human; see the journal for accumulated blockers.`,
|
|
101
|
+
}],
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
60
105
|
return {
|
|
61
106
|
exitCode: 0,
|
|
62
107
|
report: {
|
|
@@ -69,7 +114,21 @@ export async function runDirectFlow(
|
|
|
69
114
|
completedSteps: result.journalSteps.length,
|
|
70
115
|
},
|
|
71
116
|
};
|
|
72
|
-
} catch (
|
|
117
|
+
} catch (caught) {
|
|
118
|
+
if (caught instanceof McpPreflightError) return {
|
|
119
|
+
exitCode: 2, report: fromCheckReport('run', caught.report),
|
|
120
|
+
};
|
|
121
|
+
if (caught instanceof McpStepError) return {
|
|
122
|
+
exitCode: 1,
|
|
123
|
+
report: { ...base, ok: false, runId: caught.runId, socketPath,
|
|
124
|
+
status: 'failed', completionReason: 'step_failed',
|
|
125
|
+
diagnostics: [...base.diagnostics, { severity: 'failure', kind: 'step_failed', message: caught.message }],
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
// Preserve authored classifications/run IDs; use the worker's cause only
|
|
129
|
+
// when its connection teardown left a generic transport error.
|
|
130
|
+
const error = caught instanceof AuthoredFlowExecutionError || caught instanceof AuthoredFlowLoadError
|
|
131
|
+
? caught : llmFailure ?? localAgent?.failure ?? caught;
|
|
73
132
|
// `agent_cli_unresolved` and `unsupported_workspace_permission` are
|
|
74
133
|
// preflight-shaped refusals, not protocol failures — `flows check`
|
|
75
134
|
// returns exit 2 for the equivalent declarative-spec failures, and this
|
|
@@ -82,21 +141,31 @@ export async function runDirectFlow(
|
|
|
82
141
|
// the same limitation already documented elsewhere).
|
|
83
142
|
if (error instanceof AuthoredFlowLoadError
|
|
84
143
|
|| (error instanceof AuthoredFlowExecutionError
|
|
85
|
-
&& (error.code === '
|
|
144
|
+
&& (error.code === 'helper_slack.credential_missing'
|
|
145
|
+
|| error.code === 'helper_slack.mount_required'
|
|
146
|
+
|| error.code === 'budget_syntax_invalid'
|
|
147
|
+
|| error.code === 'budget_missing_price'
|
|
148
|
+
|| error.code === 'unsupported_header'
|
|
86
149
|
|| error.code === 'agent_cli_unresolved'
|
|
150
|
+
|| error.code === 'llm_cli_unresolved'
|
|
87
151
|
|| error.code === 'unsupported_workspace_permission'))) {
|
|
88
152
|
return {
|
|
89
153
|
exitCode: 2,
|
|
90
154
|
report: {
|
|
91
155
|
...fromCheckReport('run', inputFailureReport({
|
|
92
|
-
kind:
|
|
156
|
+
kind: error instanceof AuthoredFlowExecutionError && (
|
|
157
|
+
error.code === 'helper_slack.credential_missing'
|
|
158
|
+
|| error.code === 'helper_slack.mount_required'
|
|
159
|
+
|| error.code === 'budget_syntax_invalid'
|
|
160
|
+
|| error.code === 'budget_missing_price'
|
|
161
|
+
) ? error.code : 'invalid_spec',
|
|
93
162
|
message: error.message,
|
|
94
163
|
}, path)),
|
|
95
164
|
socketPath,
|
|
96
165
|
},
|
|
97
166
|
};
|
|
98
167
|
}
|
|
99
|
-
if (error instanceof AuthoredFlowExecutionError && error.code === 'agent_parked') {
|
|
168
|
+
if (error instanceof AuthoredFlowExecutionError && (error.code === 'agent_parked' || error.code === 'llm_parked')) {
|
|
100
169
|
return {
|
|
101
170
|
exitCode: 3,
|
|
102
171
|
report: {
|
|
@@ -116,6 +185,9 @@ export async function runDirectFlow(
|
|
|
116
185
|
const runId = error instanceof AuthoredFlowExecutionError ? error.runId : undefined;
|
|
117
186
|
return protocolFailure('run', base, socketPath, error, runId);
|
|
118
187
|
} finally {
|
|
119
|
-
|
|
188
|
+
try {
|
|
189
|
+
await localLlm?.close();
|
|
190
|
+
await localAgent?.close();
|
|
191
|
+
} finally { llmClient?.close(); client.close(); }
|
|
120
192
|
}
|
|
121
193
|
}
|
package/src/cli/hn-monitor.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { readFile } from 'node:fs/promises';
|
|
|
16
16
|
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
17
17
|
import { pollHackerNewsOnce, HnTransientFetchError, type Fetcher } from '../hn-poller.js';
|
|
18
18
|
import { AgentWorker } from '../worker.js';
|
|
19
|
+
import { socketPathFor } from '../daemon-connection.js';
|
|
19
20
|
import { JournalClient } from '../journal-client.js';
|
|
20
21
|
import type { EventSubmitResult, HelloResult, Pins } from '../protocol.js';
|
|
21
22
|
import type { CliIo } from '../cli.js';
|
|
@@ -181,7 +182,7 @@ async function defaultAttachWorker(
|
|
|
181
182
|
*/
|
|
182
183
|
export async function runHnMonitor(args: HnMonitorArgs, io: CliIo): Promise<0 | 1> {
|
|
183
184
|
const pollIntervalMs = args.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
184
|
-
const socketPath =
|
|
185
|
+
const socketPath = socketPathFor(args.dataDir);
|
|
185
186
|
|
|
186
187
|
let spec: unknown;
|
|
187
188
|
try {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { CliIo } from '../cli.js';
|
|
2
|
+
import { canonicalize } from '../canonical.js';
|
|
3
|
+
import { JournalReadError, walkJournal } from '../journal-client.js';
|
|
4
|
+
|
|
5
|
+
export interface ReplayArgs {
|
|
6
|
+
command: 'replay';
|
|
7
|
+
value: string;
|
|
8
|
+
json: boolean;
|
|
9
|
+
dataDir: string;
|
|
10
|
+
at?: string;
|
|
11
|
+
allowHumanInfluenced?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseReplayArgs(args: readonly string[]): ReplayArgs | undefined {
|
|
15
|
+
let json = false;
|
|
16
|
+
let allowHumanInfluenced = false;
|
|
17
|
+
let dataDir: string | undefined;
|
|
18
|
+
let at: string | undefined;
|
|
19
|
+
const positionals: string[] = [];
|
|
20
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
21
|
+
const argument = args[index]!;
|
|
22
|
+
if (argument === '--allow-human-influenced') {
|
|
23
|
+
if (allowHumanInfluenced) return undefined;
|
|
24
|
+
allowHumanInfluenced = true;
|
|
25
|
+
} else if (argument === '--json') {
|
|
26
|
+
if (json) return undefined;
|
|
27
|
+
json = true;
|
|
28
|
+
} else if (argument === '--data-dir' || argument === '--at') {
|
|
29
|
+
const value = args[++index];
|
|
30
|
+
if (value === undefined || value.length === 0 || value.startsWith('-')) return undefined;
|
|
31
|
+
if (argument === '--data-dir') {
|
|
32
|
+
if (dataDir !== undefined) return undefined;
|
|
33
|
+
dataDir = value;
|
|
34
|
+
} else {
|
|
35
|
+
if (at !== undefined) return undefined;
|
|
36
|
+
at = value;
|
|
37
|
+
}
|
|
38
|
+
} else if (argument.startsWith('-')) {
|
|
39
|
+
return undefined;
|
|
40
|
+
} else {
|
|
41
|
+
positionals.push(argument);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (positionals.length !== 1) return undefined;
|
|
45
|
+
return { allowHumanInfluenced, command: 'replay', value: positionals[0]!, json, dataDir: dataDir ?? '.relayflowd', at };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function replayJournal(args: ReplayArgs, io: CliIo): Promise<0 | 1 | 2> {
|
|
49
|
+
let emitted = false;
|
|
50
|
+
try {
|
|
51
|
+
for await (const event of walkJournal(args.value, args.dataDir, { at: args.at })) {
|
|
52
|
+
const payload = event.payload !== null && typeof event.payload === 'object' && !Array.isArray(event.payload)
|
|
53
|
+
? event.payload as Record<string, unknown> : {};
|
|
54
|
+
if (event.entry_type === 'step.completed' && payload['human_intervention'] === true && !args.allowHumanInfluenced) {
|
|
55
|
+
io.stderr(`REFUSED [human_influenced_run] step ${JSON.stringify(event.step_id)}; pass --allow-human-influenced to continue`);
|
|
56
|
+
return 2;
|
|
57
|
+
}
|
|
58
|
+
io.stdout(args.json ? canonicalize({
|
|
59
|
+
step_id: event.step_id,
|
|
60
|
+
kind: event.entry_type,
|
|
61
|
+
event,
|
|
62
|
+
verification: payload['verification'] ?? null,
|
|
63
|
+
spend: payload['budget'] ?? payload['budget_total'] ?? null,
|
|
64
|
+
})
|
|
65
|
+
: `${event.seq} ${event.at_ms} ${event.entry_type}`
|
|
66
|
+
+ (event.step_id === null ? '' : ` step=${JSON.stringify(event.step_id)}`)
|
|
67
|
+
+ (event.attempt === null ? '' : ` attempt=${event.attempt}`)
|
|
68
|
+
+ ` ${canonicalize(event.payload)}`);
|
|
69
|
+
emitted = true;
|
|
70
|
+
}
|
|
71
|
+
return 0;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
const diagnostic = {
|
|
74
|
+
severity: 'refusal',
|
|
75
|
+
kind: error instanceof JournalReadError ? error.code : 'journal_read_failed',
|
|
76
|
+
message: error instanceof Error ? error.message : String(error),
|
|
77
|
+
};
|
|
78
|
+
io.stderr(`${emitted ? 'FAILED' : 'REFUSED'} [${diagnostic.kind}] ${diagnostic.message}`);
|
|
79
|
+
return emitted ? 1 : 2;
|
|
80
|
+
}
|
|
81
|
+
}
|
package/src/cli/reuse.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { JournalClient } from '../journal-client.js';
|
|
2
|
+
|
|
3
|
+
/** Count durable facts, including failed executions, across paginated reads. */
|
|
4
|
+
export async function reuseSummary(client: JournalClient, runId: string, fromRunId: string): Promise<{
|
|
5
|
+
fromRunId: string; reusedSteps: number; executedSteps: number;
|
|
6
|
+
}> {
|
|
7
|
+
const reused = new Set<string>();
|
|
8
|
+
const executed = new Set<string>();
|
|
9
|
+
let fromSeq = 1;
|
|
10
|
+
while (true) {
|
|
11
|
+
const { entries } = await client.journalRead(runId, fromSeq, 1000);
|
|
12
|
+
if (entries.length === 0) break;
|
|
13
|
+
for (const raw of entries) {
|
|
14
|
+
const entry = raw as { seq: number; entry_type: string; step_id?: string; payload: { reused_from?: unknown } };
|
|
15
|
+
if (!Number.isSafeInteger(entry.seq) || entry.seq < fromSeq) throw new Error('invalid journal sequence in reuse summary');
|
|
16
|
+
fromSeq = entry.seq + 1;
|
|
17
|
+
if (entry.step_id === undefined) continue;
|
|
18
|
+
if (entry.entry_type === 'step.attempt.started') executed.add(entry.step_id);
|
|
19
|
+
if (entry.entry_type === 'step.completed' && entry.payload.reused_from !== undefined) reused.add(entry.step_id);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return { fromRunId, reusedSteps: reused.size, executedSteps: executed.size };
|
|
23
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BundleFailure, fetchBundle, parseDigestReference } from '../bundle-transport.js';
|
|
2
|
+
import { CheckFailure, inputFailureReport, readProjectConfig, type CheckExecution } from './check.js';
|
|
3
|
+
import { checkRunnableBundle } from './bundle-preflight.js';
|
|
4
|
+
import type { RunExecution } from './run.js';
|
|
5
|
+
|
|
6
|
+
export async function prepareDigestRun(reference: string, bucket?: string): Promise<CheckExecution | RunExecution> {
|
|
7
|
+
try {
|
|
8
|
+
const ref = parseDigestReference(reference)!;
|
|
9
|
+
const selected = bucket ?? readProjectConfig(process.cwd()).deploy?.bucket;
|
|
10
|
+
if (!selected) throw new BundleFailure('bucket_unconfigured', 'Set --bucket <uri> or deploy.bucket in flows.json.');
|
|
11
|
+
const directory = await fetchBundle(ref, selected);
|
|
12
|
+
const checked = await checkRunnableBundle(directory, ref.name);
|
|
13
|
+
checked.report.path = reference;
|
|
14
|
+
return checked;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error instanceof CheckFailure) return { report: inputFailureReport(error, reference) };
|
|
17
|
+
const kind = error instanceof BundleFailure && (
|
|
18
|
+
error.kind === 'bucket_unconfigured' || error.kind === 'bucket_unreachable'
|
|
19
|
+
|| error.kind === 'bundle_signature_invalid' || error.kind === 'bundle_unsupported'
|
|
20
|
+
) ? error.kind : 'bundle_unsupported';
|
|
21
|
+
return { exitCode: 2, report: { ok: false, command: 'run', path: reference, resolutions: [],
|
|
22
|
+
diagnostics: [{ severity: 'refusal', kind, message: error instanceof Error ? error.message : String(error) }] } };
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/cli/run.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import { parseDigestReference } from '../bundle-transport.js';
|
|
2
|
+
import { prepareDigestRun } from './run-digest.js';
|
|
3
|
+
import { reuseSummary } from './reuse.js';
|
|
4
|
+
import { resumeHelperEffect } from '../authored-helper-effect.js';
|
|
5
|
+
import { AuthoredFlowExecutionError } from '../authored-flow-error.js';
|
|
1
6
|
import { join, resolve } from 'node:path';
|
|
7
|
+
import type { ProgressEvent } from '../progress.js';
|
|
2
8
|
import { toKernelSpec } from '../compile.js';
|
|
9
|
+
import { socketPathFor } from '../daemon-connection.js';
|
|
3
10
|
import { ensureDaemon, type EnsureDaemonOptions } from '../daemon-lifecycle.js';
|
|
11
|
+
import { isAuthoredFlowPath } from '../direct-input.js';
|
|
4
12
|
import { daemonRefusal } from './daemon-refusal.js';
|
|
5
|
-
import type { RunFailureKind, RunWarningKind } from '../failure-kinds.js';
|
|
13
|
+
import type { RunFailureKind, RunWarningKind, StepFailedDetails } from '../failure-kinds.js';
|
|
14
|
+
import { deterministicFailureDetails } from './deterministic-failure.js';
|
|
6
15
|
import { JournalClient, JournalProtocolError } from '../journal-client.js';
|
|
7
|
-
import
|
|
16
|
+
import { attachLocalAgent } from '../local-agent.js';
|
|
8
17
|
import type {
|
|
9
18
|
RunCompletionReason,
|
|
10
19
|
RunOutcome,
|
|
@@ -13,7 +22,6 @@ import type {
|
|
|
13
22
|
import type { StepType } from '../spec.js';
|
|
14
23
|
import {
|
|
15
24
|
checkFlow,
|
|
16
|
-
type CheckInputDiagnostic,
|
|
17
25
|
type CheckReport,
|
|
18
26
|
} from './check.js';
|
|
19
27
|
|
|
@@ -25,7 +33,7 @@ export interface ParkedStep {
|
|
|
25
33
|
type: Extract<StepType, 'llm' | 'agent'>;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
export interface RunDiagnostic {
|
|
36
|
+
export interface RunDiagnostic extends StepFailedDetails {
|
|
29
37
|
severity: 'refusal' | 'failure' | 'parked' | 'warning';
|
|
30
38
|
kind: RunFailureKind | RunWarningKind | RunCompletionReason;
|
|
31
39
|
message: string;
|
|
@@ -40,10 +48,11 @@ export interface RunReport {
|
|
|
40
48
|
status?: RunStatus;
|
|
41
49
|
completionReason?: RunCompletionReason;
|
|
42
50
|
completedSteps?: number;
|
|
51
|
+
reuse?: { fromRunId: string; reusedSteps: number; executedSteps: number };
|
|
43
52
|
parkedStep?: ParkedStep;
|
|
44
53
|
projectConfigPath?: string;
|
|
45
54
|
resolutions: CheckReport['resolutions'];
|
|
46
|
-
diagnostics: Array<
|
|
55
|
+
diagnostics: Array<CheckReport['diagnostics'][number] | RunDiagnostic>;
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
export interface RunExecution {
|
|
@@ -59,6 +68,12 @@ export interface RunProgress {
|
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
export interface RunLifecycleOptions {
|
|
71
|
+
bucket?: string;
|
|
72
|
+
allowHumanInfluenced?: boolean;
|
|
73
|
+
onPtyReady?: (path: string) => void;
|
|
74
|
+
reuseFromRunId?: string;
|
|
75
|
+
onProgress?: (event: ProgressEvent) => void;
|
|
76
|
+
localAgent?: boolean;
|
|
62
77
|
signal?: AbortSignal;
|
|
63
78
|
onWait?: (progress: RunProgress) => void;
|
|
64
79
|
/**
|
|
@@ -74,7 +89,9 @@ export async function runFlow(
|
|
|
74
89
|
dataDir: string,
|
|
75
90
|
options: RunLifecycleOptions = {},
|
|
76
91
|
): Promise<RunExecution> {
|
|
77
|
-
const
|
|
92
|
+
const prepared = parseDigestReference(path) ? await prepareDigestRun(path, options.bucket) : undefined;
|
|
93
|
+
if (prepared && 'exitCode' in prepared) return prepared;
|
|
94
|
+
const checked = prepared ?? checkFlow(path);
|
|
78
95
|
if (!checked.report.ok || checked.flow === undefined) {
|
|
79
96
|
return { exitCode: 2, report: fromCheckReport('run', checked.report) };
|
|
80
97
|
}
|
|
@@ -95,14 +112,31 @@ async function executeCheckedFlow(
|
|
|
95
112
|
const connected = await connect(client, 'run', dataDir, base, options);
|
|
96
113
|
if (connected !== undefined) return connected;
|
|
97
114
|
|
|
115
|
+
let localAgent: Awaited<ReturnType<typeof attachLocalAgent>> | undefined;
|
|
98
116
|
try {
|
|
99
117
|
const spec = toKernelSpec(checked.flow!);
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
// Use the checked CLI/model and declared surfaces unchanged. The worker
|
|
119
|
+
// advertises its existing pins; the daemon still owns surface matching.
|
|
120
|
+
if (options.localAgent) localAgent = await attachLocalAgent(client, dataDir, options.onPtyReady);
|
|
121
|
+
const outcome = await client.runStart(spec, options.reuseFromRunId);
|
|
122
|
+
const execution = await classifyOutcome(client, 'run', outcome, base, socketPath, options);
|
|
123
|
+
if (options.reuseFromRunId !== undefined) {
|
|
124
|
+
execution.report.reuse = await reuseSummary(client, outcome.run_id, options.reuseFromRunId);
|
|
125
|
+
}
|
|
126
|
+
return execution;
|
|
102
127
|
} catch (error) {
|
|
103
|
-
|
|
128
|
+
if (error instanceof JournalProtocolError && (
|
|
129
|
+
error.code === 'reuse_spec_mismatch' || error.code === 'reuse_run_not_found'
|
|
130
|
+
|| error.code === 'reuse_journal_read_failed'
|
|
131
|
+
)) {
|
|
132
|
+
const failed = error.code === 'reuse_journal_read_failed';
|
|
133
|
+
return { exitCode: failed ? 1 : 2, report: { ...base, socketPath,
|
|
134
|
+
diagnostics: [...base.diagnostics, { severity: failed ? 'failure' : 'refusal',
|
|
135
|
+
kind: error.code, message: error.message }] } };
|
|
136
|
+
}
|
|
137
|
+
return protocolFailure('run', base, socketPath, localAgent?.failure ?? error);
|
|
104
138
|
} finally {
|
|
105
|
-
client.close();
|
|
139
|
+
try { await localAgent?.close(); } finally { client.close(); }
|
|
106
140
|
}
|
|
107
141
|
}
|
|
108
142
|
|
|
@@ -118,9 +152,26 @@ export async function resumeFlow(
|
|
|
118
152
|
if (connected !== undefined) return connected;
|
|
119
153
|
|
|
120
154
|
try {
|
|
121
|
-
|
|
155
|
+
// resumeHelperEffect subsumes the old resumeSlackEffect: it handles the
|
|
156
|
+
// slack effect resume plus every other provider from N's codegen. The
|
|
157
|
+
// second call the earlier rebase left is a stale reference from before
|
|
158
|
+
// the helper fanout renamed the API.
|
|
159
|
+
let outcome = await client.runResume(runId, options.allowHumanInfluenced);
|
|
160
|
+
if (await resumeHelperEffect(client, runId, dataDir)) {
|
|
161
|
+
outcome = await client.runResume(runId, options.allowHumanInfluenced);
|
|
162
|
+
}
|
|
122
163
|
return await classifyOutcome(client, 'resume', outcome, base, socketPath, options);
|
|
123
164
|
} catch (error) {
|
|
165
|
+
if (error instanceof JournalProtocolError && error.code === 'human_influenced_run') {
|
|
166
|
+
return { exitCode: 2, report: { ...base, runId, socketPath,
|
|
167
|
+
diagnostics: [{ severity: 'refusal', kind: 'human_influenced_run', message: error.message.replace(/^human_influenced_run: /, '') }] } };
|
|
168
|
+
}
|
|
169
|
+
if (error instanceof AuthoredFlowExecutionError
|
|
170
|
+
&& (error.code === 'helper_slack.credential_missing' || error.code === 'helper_slack.mount_required'
|
|
171
|
+
|| error.code === 'helper_provider.mount_required' || error.code === 'helper_provider.unsupported')) {
|
|
172
|
+
return { exitCode: 2, report: { ...base, runId, socketPath,
|
|
173
|
+
diagnostics: [{ severity: 'refusal', kind: error.code, message: error.message }] } };
|
|
174
|
+
}
|
|
124
175
|
if (!(error instanceof JournalProtocolError) || error.code !== 'run_not_found') {
|
|
125
176
|
return protocolFailure('resume', base, socketPath, error, runId);
|
|
126
177
|
}
|
|
@@ -243,11 +294,11 @@ export async function classifyOutcome(
|
|
|
243
294
|
}
|
|
244
295
|
if (inspection?.runningStep !== undefined) {
|
|
245
296
|
await waitForRunningStep(client, current.run_id, inspection.runningStep, options);
|
|
246
|
-
current = await client.runResume(current.run_id);
|
|
297
|
+
current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
|
|
247
298
|
continue;
|
|
248
299
|
}
|
|
249
300
|
if (inspection?.status === 'completed' || inspection?.status === 'failed') {
|
|
250
|
-
current = await client.runResume(current.run_id);
|
|
301
|
+
current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
|
|
251
302
|
continue;
|
|
252
303
|
}
|
|
253
304
|
// The run is still RUNNING but no step is identifiable at this instant.
|
|
@@ -275,7 +326,7 @@ export async function classifyOutcome(
|
|
|
275
326
|
// is already progressing -- it returns the current state rather than
|
|
276
327
|
// re-dispatching. This loop leans on that up to MAX_UNCLASSIFIED_POLLS
|
|
277
328
|
// times while the daemon is mid-transition.
|
|
278
|
-
current = await client.runResume(current.run_id);
|
|
329
|
+
current = await client.runResume(current.run_id, command === 'run' || options.allowHumanInfluenced);
|
|
279
330
|
continue;
|
|
280
331
|
}
|
|
281
332
|
// Fail closed rather than loop forever: if it never resolves, the original
|
|
@@ -295,15 +346,30 @@ export async function classifyOutcome(
|
|
|
295
346
|
|
|
296
347
|
if (report.ok) return { exitCode: 0, report };
|
|
297
348
|
if (current.status === 'failed' && current.completion_reason !== null) {
|
|
349
|
+
const diagnostic: RunDiagnostic = {
|
|
350
|
+
severity: 'failure',
|
|
351
|
+
kind: current.completion_reason,
|
|
352
|
+
message: `Run "${current.run_id}" failed with completionReason: ${current.completion_reason}.`,
|
|
353
|
+
};
|
|
354
|
+
if (current.completion_reason === 'step_failed') {
|
|
355
|
+
try {
|
|
356
|
+
const details = await deterministicFailureDetails(client, current.run_id);
|
|
357
|
+
if (details !== undefined) {
|
|
358
|
+
Object.assign(diagnostic, details);
|
|
359
|
+
diagnostic.message += ` Step ${JSON.stringify(details.stepId)} exit=${details.exitCode}.`
|
|
360
|
+
+ (details.stderrTail ? `\nStderr (last 1,024 bytes):\n${details.stderrTail}` : '')
|
|
361
|
+
+ `\nInspect: ${details.hint}`;
|
|
362
|
+
}
|
|
363
|
+
} catch (error) {
|
|
364
|
+
// Inspection must not erase the already known run failure.
|
|
365
|
+
diagnostic.message += ` Could not inspect command failure: ${errorMessage(error)}`;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
298
368
|
return {
|
|
299
369
|
exitCode: 1,
|
|
300
370
|
report: {
|
|
301
371
|
...report,
|
|
302
|
-
diagnostics: [...report.diagnostics,
|
|
303
|
-
severity: 'failure',
|
|
304
|
-
kind: current.completion_reason,
|
|
305
|
-
message: `Run "${current.run_id}" failed with completionReason: ${current.completion_reason}.`,
|
|
306
|
-
}],
|
|
372
|
+
diagnostics: [...report.diagnostics, diagnostic],
|
|
307
373
|
},
|
|
308
374
|
};
|
|
309
375
|
}
|
|
@@ -318,7 +384,20 @@ export async function classifyOutcome(
|
|
|
318
384
|
kind: 'run_parked',
|
|
319
385
|
message: needsHuman
|
|
320
386
|
? `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): waiting for human recovery after the worker attempt failed.`
|
|
321
|
-
: `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): no worker is attached for step type "${parkedStep.type}"
|
|
387
|
+
: `Run "${current.run_id}" parked at step "${parkedStep.id}" (${parkedStep.type}): no worker is attached for step type "${parkedStep.type}".`
|
|
388
|
+
// Only suggest the `--local-agent` remedy for YAML flows.
|
|
389
|
+
// Authored TS flows require `--input`; the bare command below
|
|
390
|
+
// would be refused (Cursor Bugbot flagged as LOW on flows#293).
|
|
391
|
+
// For TS we omit the hint rather than fabricate a syntactically
|
|
392
|
+
// valid but semantically wrong command — the direct-run refusal
|
|
393
|
+
// for TS already names its own missing --input.
|
|
394
|
+
+ (command === 'run'
|
|
395
|
+
&& parkedStep.type === 'agent'
|
|
396
|
+
&& !options.localAgent
|
|
397
|
+
&& base.path !== undefined
|
|
398
|
+
&& !isAuthoredFlowPath(base.path)
|
|
399
|
+
? ` To start a new run with a local agent worker: flows run --local-agent '${base.path.replace(/'/g, "'\\''")}'. Declared workspace or stream surfaces require a worker that holds their pins.`
|
|
400
|
+
: ''),
|
|
322
401
|
}],
|
|
323
402
|
},
|
|
324
403
|
};
|
|
@@ -461,8 +540,12 @@ function fromBase(command: RunCommand, base: CheckReport | RunReport): RunReport
|
|
|
461
540
|
return 'command' in base ? base : fromCheckReport(command, base);
|
|
462
541
|
}
|
|
463
542
|
|
|
543
|
+
// Delegates to the daemon-connection derivation so run.ts, direct-run.ts, and
|
|
544
|
+
// the daemon-lifecycle attach path all speak the same socket path. Kept as a
|
|
545
|
+
// re-export here so existing callers do not have to reach into
|
|
546
|
+
// daemon-connection.ts. See socketPathFor for the SUN_LEN reasoning (#262).
|
|
464
547
|
export function socketFor(dataDir: string): string {
|
|
465
|
-
return
|
|
548
|
+
return socketPathFor(dataDir);
|
|
466
549
|
}
|
|
467
550
|
|
|
468
551
|
function errorMessage(error: unknown): string {
|