@relayflows/sdk 2.0.9 → 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 +2 -21
- package/dist/authored-flow-error.d.ts.map +1 -1
- package/dist/authored-flow-error.js +1 -12
- 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 +116 -235
- 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 -18
- 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 -10
- package/src/authored-flow-executor.ts +171 -347
- 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 -18
- 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,10 @@
|
|
|
1
|
+
import type { NamedDataGate, VerificationSpec } from './spec.js';
|
|
2
|
+
export declare const NAMED_GATE_FAILURE_KINDS: readonly ["unknown_gate_kind", "gate_pattern_invalid", "gate_command_missing", "gate_bound_invalid"];
|
|
3
|
+
export type NamedGateFailureKind = typeof NAMED_GATE_FAILURE_KINDS[number];
|
|
4
|
+
export declare const NAMED_GATE_KEYS: Record<NamedDataGate['type'], readonly string[]>;
|
|
5
|
+
export declare function isNamedGate(gate: VerificationSpec | undefined): gate is NamedDataGate;
|
|
6
|
+
export declare function regexFlags(flags: string): number;
|
|
7
|
+
/** Called only on snapshotted data, including by the public validator. */
|
|
8
|
+
export declare function namedGateErrors(gate: Record<string, unknown>, input: unknown, at: string): string[];
|
|
9
|
+
export declare function namedGateFailure(errors: readonly string[]): NamedGateFailureKind | undefined;
|
|
10
|
+
//# sourceMappingURL=named-gates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-gates.d.ts","sourceRoot":"","sources":["../src/named-gates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjE,eAAO,MAAM,wBAAwB,sGAE3B,CAAC;AACX,MAAM,MAAM,oBAAoB,GAAG,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC;AAE3E,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAK5E,CAAC;AAEF,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,IAAI,aAAa,CAErF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CA6CnG;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,oBAAoB,GAAG,SAAS,CAE5F"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { RE2JS } from 're2js';
|
|
2
|
+
export const NAMED_GATE_FAILURE_KINDS = [
|
|
3
|
+
'unknown_gate_kind', 'gate_pattern_invalid', 'gate_command_missing', 'gate_bound_invalid',
|
|
4
|
+
];
|
|
5
|
+
export const NAMED_GATE_KEYS = {
|
|
6
|
+
references_input: ['type', 'input_key', 'in_output_at'],
|
|
7
|
+
subprocess_gate: ['type', 'command', 'from_output'],
|
|
8
|
+
word_count_bounds: ['type', 'min', 'max'],
|
|
9
|
+
regex_match: ['type', 'pattern', 'in_output_at', 'flags'],
|
|
10
|
+
};
|
|
11
|
+
export function isNamedGate(gate) {
|
|
12
|
+
return gate !== undefined && Object.hasOwn(NAMED_GATE_KEYS, gate.type);
|
|
13
|
+
}
|
|
14
|
+
export function regexFlags(flags) {
|
|
15
|
+
return (flags.includes('i') ? RE2JS.CASE_INSENSITIVE : 0)
|
|
16
|
+
| (flags.includes('m') ? RE2JS.MULTILINE : 0)
|
|
17
|
+
| (flags.includes('s') ? RE2JS.DOTALL : 0);
|
|
18
|
+
}
|
|
19
|
+
/** Called only on snapshotted data, including by the public validator. */
|
|
20
|
+
export function namedGateErrors(gate, input, at) {
|
|
21
|
+
const errors = [];
|
|
22
|
+
for (const key of ['in_output_at', 'from_output']) {
|
|
23
|
+
const path = gate[key];
|
|
24
|
+
if (path !== undefined && (!Array.isArray(path) || !path.every(segment => typeof segment === 'string' || (Number.isSafeInteger(segment) && segment >= 0)))) {
|
|
25
|
+
errors.push(`${at}.${key}: expected an array of object keys or non-negative integer indices`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
switch (gate.type) {
|
|
29
|
+
case 'references_input':
|
|
30
|
+
if (typeof gate.input_key !== 'string' || !gate.input_key.trim()
|
|
31
|
+
|| input === null || typeof input !== 'object' || !Object.hasOwn(input, gate.input_key)) {
|
|
32
|
+
errors.push(`${at}.input_key: must name a declared input binding`);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
case 'subprocess_gate':
|
|
36
|
+
if (typeof gate.command !== 'string' || !gate.command.trim() || gate.command.includes('\0')) {
|
|
37
|
+
errors.push(`${at}.command: gate_command_missing: expected a non-empty shell command`);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
case 'word_count_bounds': {
|
|
41
|
+
const { min, max } = gate;
|
|
42
|
+
if ([min, max].some(n => n !== undefined && (!Number.isSafeInteger(n) || n < 0))
|
|
43
|
+
|| (typeof min === 'number' && typeof max === 'number' && min > max)) {
|
|
44
|
+
errors.push(`${at}: gate_bound_invalid: min and max must be non-negative safe integers with min <= max`);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case 'regex_match':
|
|
49
|
+
try {
|
|
50
|
+
if (typeof gate.pattern !== 'string' || gate.pattern.length > 8192) {
|
|
51
|
+
throw new Error('pattern must be a string of at most 8192 characters');
|
|
52
|
+
}
|
|
53
|
+
const flags = gate.flags ?? '';
|
|
54
|
+
if (typeof flags !== 'string' || !/^(?!.*(.).*\1)[ims]*$/.test(flags)) {
|
|
55
|
+
throw new Error('flags must be a non-repeating subset of i, m, s');
|
|
56
|
+
}
|
|
57
|
+
RE2JS.compile(gate.pattern, regexFlags(flags));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
errors.push(`${at}: gate_pattern_invalid: ${error instanceof Error ? error.message : 'invalid RE2 pattern'}`);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
return errors;
|
|
65
|
+
}
|
|
66
|
+
export function namedGateFailure(errors) {
|
|
67
|
+
return NAMED_GATE_FAILURE_KINDS.find(kind => errors.some(error => error.includes(`${kind}:`)));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=named-gates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"named-gates.js","sourceRoot":"","sources":["../src/named-gates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observer-link support for `flows run`: mint a scoped read-only observer token
|
|
3
|
+
* from a Relaycast workspace admin key, then print
|
|
4
|
+
* `Observer: <url>?key=<ot_live_...>` on stdout so an operator can drop into the
|
|
5
|
+
* Relaycast observer dashboard with the live-stream credential pre-filled.
|
|
6
|
+
*
|
|
7
|
+
* The workspace admin key (`rk_live_*`) is refused by the realtime endpoint —
|
|
8
|
+
* only an `ot_live_*` observer token with `stream:read` may open the workspace
|
|
9
|
+
* stream. So we do the same thing the Relaycast observer dashboard does when a
|
|
10
|
+
* workspace admin logs in with their admin key: mint a fresh, uniquely-named,
|
|
11
|
+
* scoped, short-lived observer token on their behalf and hand *that* to the
|
|
12
|
+
* URL. The workspace admin key never leaves the operator's machine.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is best-effort. A missing workspace key means "no observer
|
|
15
|
+
* link, silently" — this is a parity feature relaying v1's convenience, not a
|
|
16
|
+
* requirement of a local run. A mint failure emits a labeled diagnostic to
|
|
17
|
+
* stderr and continues; a run must never fail because the observer link failed.
|
|
18
|
+
*/
|
|
19
|
+
export interface ObserverLinkEnv {
|
|
20
|
+
workspaceKey?: string;
|
|
21
|
+
/** Base URL for the mint API (`POST /v1/observer-tokens`). */
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
/** Base URL for the observer dashboard the emitted link points at. */
|
|
24
|
+
dashboardUrl?: string;
|
|
25
|
+
/** `FLOWS_NO_OBSERVER=1` suppresses the mint even when a key is present. */
|
|
26
|
+
suppressed: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Path to the `agent-relay` local workspace-key store. Structure:
|
|
30
|
+
* `{ active: string, workspaces: { [name]: { key: string } } }`. Written
|
|
31
|
+
* by `agent-relay workspace set_key` / `agent-relay workspace join`; the
|
|
32
|
+
* canonical file the `@agent-relay/cloud` package reads via
|
|
33
|
+
* `resolveActiveWorkspaceKey`. Verified against
|
|
34
|
+
* `packages/cloud/src/workspace-store.ts` in `AgentWorkforce/relay`.
|
|
35
|
+
*
|
|
36
|
+
* Respects `AGENT_RELAY_HOME` so a caller can point at a different store
|
|
37
|
+
* for tests without touching the real one. Falls back to
|
|
38
|
+
* `~/.agentworkforce/relay/workspaces.json` -- the same default that
|
|
39
|
+
* package uses.
|
|
40
|
+
*/
|
|
41
|
+
export declare function agentRelayWorkspaceStorePath(env?: NodeJS.ProcessEnv): string;
|
|
42
|
+
/**
|
|
43
|
+
* Read the active workspace key from the `agent-relay cloud login` /
|
|
44
|
+
* `agent-relay workspace set_key` store. Returns `undefined` on every
|
|
45
|
+
* failure mode -- file absent, unreadable, malformed JSON, no active
|
|
46
|
+
* workspace, active workspace has no key, key is empty -- so the caller
|
|
47
|
+
* can silently fall through to "no observer link" the same way an unset
|
|
48
|
+
* `RELAYCAST_WORKSPACE_KEY` does.
|
|
49
|
+
*
|
|
50
|
+
* A file-shape mismatch is INTENTIONALLY not a hard error: `agent-relay`
|
|
51
|
+
* may extend this file in future without warning, and refusing a flow
|
|
52
|
+
* because a fallback credential store looked odd would be strictly worse
|
|
53
|
+
* than falling back to the explicit env var (which is the primary path).
|
|
54
|
+
*/
|
|
55
|
+
export declare function readAgentRelayWorkspaceKey(env?: NodeJS.ProcessEnv, readFile?: (path: string) => string): string | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Options controlling `resolveObserverLinkEnv`'s fallback behavior. The
|
|
58
|
+
* `readWorkspaceKey` seam is what the tests inject to simulate presence,
|
|
59
|
+
* absence, and malformed shapes of the on-disk store without touching the
|
|
60
|
+
* real home directory.
|
|
61
|
+
*/
|
|
62
|
+
export interface ResolveObserverLinkEnvOptions {
|
|
63
|
+
readWorkspaceKey?: (env: NodeJS.ProcessEnv) => string | undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Env-first observer link resolution with an `agent-relay` cloud fallback.
|
|
67
|
+
*
|
|
68
|
+
* Priority (from the task spec, explicit beats implicit):
|
|
69
|
+
* 1. `RELAYCAST_WORKSPACE_KEY` if set and non-empty.
|
|
70
|
+
* 2. Active workspace key from `~/.agentworkforce/relay/workspaces.json`
|
|
71
|
+
* (populated by `agent-relay cloud login` + `agent-relay workspace
|
|
72
|
+
* set_key`), when readable.
|
|
73
|
+
* 3. Nothing -- silent skip, same as an unset primary env var.
|
|
74
|
+
*
|
|
75
|
+
* `FLOWS_NO_OBSERVER=1` still suppresses regardless of source.
|
|
76
|
+
*/
|
|
77
|
+
export declare function resolveObserverLinkEnv(env?: NodeJS.ProcessEnv, options?: ResolveObserverLinkEnvOptions): ObserverLinkEnv;
|
|
78
|
+
/**
|
|
79
|
+
* Read the observer-link config from the environment. Both trims and
|
|
80
|
+
* emptiness-checks the workspace key so a `RELAYCAST_WORKSPACE_KEY=` with no
|
|
81
|
+
* value reads the same as unset (no observer link, silently).
|
|
82
|
+
*/
|
|
83
|
+
export declare function readObserverLinkEnv(env?: NodeJS.ProcessEnv): ObserverLinkEnv;
|
|
84
|
+
/**
|
|
85
|
+
* Minimal `fetch` shape we depend on. Kept structural so tests can inject a
|
|
86
|
+
* mock without pulling in a fetch replacement library.
|
|
87
|
+
*/
|
|
88
|
+
export type ObserverFetch = (url: string, init: {
|
|
89
|
+
method: string;
|
|
90
|
+
headers: Record<string, string>;
|
|
91
|
+
body: string;
|
|
92
|
+
signal?: AbortSignal;
|
|
93
|
+
}) => Promise<{
|
|
94
|
+
ok: boolean;
|
|
95
|
+
status: number;
|
|
96
|
+
json: () => Promise<unknown>;
|
|
97
|
+
}>;
|
|
98
|
+
export interface MintObserverOptions {
|
|
99
|
+
workspaceKey: string;
|
|
100
|
+
/** Base URL of the mint API (default `https://cast.agentrelay.com`). */
|
|
101
|
+
baseUrl?: string;
|
|
102
|
+
/** Base URL of the observer dashboard the returned URL points at
|
|
103
|
+
* (default `https://agentrelay.com`). Separate axis from `baseUrl` — the
|
|
104
|
+
* mint API lives on a different subdomain from the dashboard. */
|
|
105
|
+
dashboardUrl?: string;
|
|
106
|
+
fetch?: ObserverFetch;
|
|
107
|
+
now?: () => number;
|
|
108
|
+
/** Called for the token's uniquely-suffixed name; injectable for tests. */
|
|
109
|
+
uuid?: () => string;
|
|
110
|
+
signal?: AbortSignal;
|
|
111
|
+
timeoutMs?: number;
|
|
112
|
+
}
|
|
113
|
+
export interface MintObserverOutcome {
|
|
114
|
+
observerUrl?: string;
|
|
115
|
+
/**
|
|
116
|
+
* A short diagnostic to log when mint failed. `undefined` on success or on
|
|
117
|
+
* "no observer link is possible" (missing key/suppressed) so the caller can
|
|
118
|
+
* distinguish silent-skip from "warn about the miss".
|
|
119
|
+
*/
|
|
120
|
+
warning?: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Mint an `ot_live_*` observer token via `POST /v1/observer-tokens` and return
|
|
124
|
+
* the observer dashboard URL that pre-fills it. Any failure — 4xx/5xx from the
|
|
125
|
+
* engine, malformed response, network error, timeout — returns a `warning`
|
|
126
|
+
* string and no URL. The caller must not fail the run on `warning`.
|
|
127
|
+
*/
|
|
128
|
+
export declare function mintObserverUrl(options: MintObserverOptions): Promise<MintObserverOutcome>;
|
|
129
|
+
//# sourceMappingURL=observer-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-link.d.ts","sourceRoot":"","sources":["../src/observer-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA6CH,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAwB,GACnD,MAAM,GAAG,SAAS,CAwBpB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,KAAK,MAAM,GAAG,SAAS,CAAC;CACnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,6BAAkC,GAC1C,eAAe,CAYjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,eAAe,CAiBjB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B,CAAC,CAAC;AAEH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;qEAEiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA0E9B"}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observer-link support for `flows run`: mint a scoped read-only observer token
|
|
3
|
+
* from a Relaycast workspace admin key, then print
|
|
4
|
+
* `Observer: <url>?key=<ot_live_...>` on stdout so an operator can drop into the
|
|
5
|
+
* Relaycast observer dashboard with the live-stream credential pre-filled.
|
|
6
|
+
*
|
|
7
|
+
* The workspace admin key (`rk_live_*`) is refused by the realtime endpoint —
|
|
8
|
+
* only an `ot_live_*` observer token with `stream:read` may open the workspace
|
|
9
|
+
* stream. So we do the same thing the Relaycast observer dashboard does when a
|
|
10
|
+
* workspace admin logs in with their admin key: mint a fresh, uniquely-named,
|
|
11
|
+
* scoped, short-lived observer token on their behalf and hand *that* to the
|
|
12
|
+
* URL. The workspace admin key never leaves the operator's machine.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is best-effort. A missing workspace key means "no observer
|
|
15
|
+
* link, silently" — this is a parity feature relaying v1's convenience, not a
|
|
16
|
+
* requirement of a local run. A mint failure emits a labeled diagnostic to
|
|
17
|
+
* stderr and continues; a run must never fail because the observer link failed.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
/** Scopes the minted token carries. Mirrors the observer dashboard's set. */
|
|
23
|
+
const OBSERVER_SCOPES = [
|
|
24
|
+
'stream:read',
|
|
25
|
+
'messages:read',
|
|
26
|
+
'threads:read',
|
|
27
|
+
'dms:read',
|
|
28
|
+
'channels:read',
|
|
29
|
+
'search:read',
|
|
30
|
+
'agents:read',
|
|
31
|
+
'nodes:read',
|
|
32
|
+
'deliveries:read',
|
|
33
|
+
'activity:read',
|
|
34
|
+
'files:read',
|
|
35
|
+
'reactions:read',
|
|
36
|
+
];
|
|
37
|
+
/** Token lifetime for a `flows run` session. 24h is well past the longest run. */
|
|
38
|
+
const OBSERVER_TOKEN_TTL_MS = 60 * 60 * 24 * 1000;
|
|
39
|
+
/**
|
|
40
|
+
* Default hosts for the two axes of the observer link. They are DIFFERENT
|
|
41
|
+
* subdomains and must not be conflated (empirically verified 2026-09-10):
|
|
42
|
+
*
|
|
43
|
+
* - Mint API: `POST cast.agentrelay.com/v1/observer-tokens`. `agentrelay.com`
|
|
44
|
+
* returns 404 for this path. Overridable via `RELAYCAST_API_URL`.
|
|
45
|
+
* - Observer dashboard: `agentrelay.com/observer?key=<ot_live_...>`.
|
|
46
|
+
* `cast.agentrelay.com/observer` returns 404. Overridable via
|
|
47
|
+
* `RELAYCAST_DASHBOARD_URL`.
|
|
48
|
+
*
|
|
49
|
+
* An earlier fix collapsed both to `cast.agentrelay.com` and closed #278 for
|
|
50
|
+
* the mint half only; a demo verification then landed on the 404 dashboard
|
|
51
|
+
* URL. Keep the two constants distinct.
|
|
52
|
+
*/
|
|
53
|
+
const DEFAULT_RELAYCAST_MINT_URL = 'https://cast.agentrelay.com';
|
|
54
|
+
const DEFAULT_RELAYCAST_DASHBOARD_URL = 'https://agentrelay.com';
|
|
55
|
+
/** Bounded so a stalled Relaycast API cannot delay the RUN summary. */
|
|
56
|
+
const MINT_TIMEOUT_MS = 5_000;
|
|
57
|
+
/**
|
|
58
|
+
* Path to the `agent-relay` local workspace-key store. Structure:
|
|
59
|
+
* `{ active: string, workspaces: { [name]: { key: string } } }`. Written
|
|
60
|
+
* by `agent-relay workspace set_key` / `agent-relay workspace join`; the
|
|
61
|
+
* canonical file the `@agent-relay/cloud` package reads via
|
|
62
|
+
* `resolveActiveWorkspaceKey`. Verified against
|
|
63
|
+
* `packages/cloud/src/workspace-store.ts` in `AgentWorkforce/relay`.
|
|
64
|
+
*
|
|
65
|
+
* Respects `AGENT_RELAY_HOME` so a caller can point at a different store
|
|
66
|
+
* for tests without touching the real one. Falls back to
|
|
67
|
+
* `~/.agentworkforce/relay/workspaces.json` -- the same default that
|
|
68
|
+
* package uses.
|
|
69
|
+
*/
|
|
70
|
+
export function agentRelayWorkspaceStorePath(env = process.env) {
|
|
71
|
+
const dir = env['AGENT_RELAY_HOME'] ?? join(homedir(), '.agentworkforce/relay');
|
|
72
|
+
return join(dir, 'workspaces.json');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Read the active workspace key from the `agent-relay cloud login` /
|
|
76
|
+
* `agent-relay workspace set_key` store. Returns `undefined` on every
|
|
77
|
+
* failure mode -- file absent, unreadable, malformed JSON, no active
|
|
78
|
+
* workspace, active workspace has no key, key is empty -- so the caller
|
|
79
|
+
* can silently fall through to "no observer link" the same way an unset
|
|
80
|
+
* `RELAYCAST_WORKSPACE_KEY` does.
|
|
81
|
+
*
|
|
82
|
+
* A file-shape mismatch is INTENTIONALLY not a hard error: `agent-relay`
|
|
83
|
+
* may extend this file in future without warning, and refusing a flow
|
|
84
|
+
* because a fallback credential store looked odd would be strictly worse
|
|
85
|
+
* than falling back to the explicit env var (which is the primary path).
|
|
86
|
+
*/
|
|
87
|
+
export function readAgentRelayWorkspaceKey(env = process.env, readFile = defaultReadFile) {
|
|
88
|
+
let raw;
|
|
89
|
+
try {
|
|
90
|
+
raw = readFile(agentRelayWorkspaceStorePath(env));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(raw);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
103
|
+
return undefined;
|
|
104
|
+
const activeName = parsed.active;
|
|
105
|
+
if (typeof activeName !== 'string' || activeName === '')
|
|
106
|
+
return undefined;
|
|
107
|
+
const workspaces = parsed.workspaces;
|
|
108
|
+
if (typeof workspaces !== 'object' || workspaces === null)
|
|
109
|
+
return undefined;
|
|
110
|
+
const entry = workspaces[activeName];
|
|
111
|
+
if (typeof entry !== 'object' || entry === null)
|
|
112
|
+
return undefined;
|
|
113
|
+
const key = entry.key;
|
|
114
|
+
if (typeof key !== 'string')
|
|
115
|
+
return undefined;
|
|
116
|
+
const trimmed = key.trim();
|
|
117
|
+
return trimmed === '' ? undefined : trimmed;
|
|
118
|
+
}
|
|
119
|
+
function defaultReadFile(filePath) {
|
|
120
|
+
return readFileSync(filePath, 'utf8');
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Env-first observer link resolution with an `agent-relay` cloud fallback.
|
|
124
|
+
*
|
|
125
|
+
* Priority (from the task spec, explicit beats implicit):
|
|
126
|
+
* 1. `RELAYCAST_WORKSPACE_KEY` if set and non-empty.
|
|
127
|
+
* 2. Active workspace key from `~/.agentworkforce/relay/workspaces.json`
|
|
128
|
+
* (populated by `agent-relay cloud login` + `agent-relay workspace
|
|
129
|
+
* set_key`), when readable.
|
|
130
|
+
* 3. Nothing -- silent skip, same as an unset primary env var.
|
|
131
|
+
*
|
|
132
|
+
* `FLOWS_NO_OBSERVER=1` still suppresses regardless of source.
|
|
133
|
+
*/
|
|
134
|
+
export function resolveObserverLinkEnv(env = process.env, options = {}) {
|
|
135
|
+
const primary = readObserverLinkEnv(env);
|
|
136
|
+
if (primary.workspaceKey !== undefined || primary.suppressed) {
|
|
137
|
+
return primary;
|
|
138
|
+
}
|
|
139
|
+
const readWorkspaceKey = options.readWorkspaceKey ?? readAgentRelayWorkspaceKey;
|
|
140
|
+
const fallback = readWorkspaceKey(env);
|
|
141
|
+
if (fallback === undefined)
|
|
142
|
+
return primary;
|
|
143
|
+
return {
|
|
144
|
+
...primary,
|
|
145
|
+
workspaceKey: fallback,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Read the observer-link config from the environment. Both trims and
|
|
150
|
+
* emptiness-checks the workspace key so a `RELAYCAST_WORKSPACE_KEY=` with no
|
|
151
|
+
* value reads the same as unset (no observer link, silently).
|
|
152
|
+
*/
|
|
153
|
+
export function readObserverLinkEnv(env = process.env) {
|
|
154
|
+
const rawKey = env['RELAYCAST_WORKSPACE_KEY'];
|
|
155
|
+
const workspaceKey = typeof rawKey === 'string' ? rawKey.trim() : '';
|
|
156
|
+
const rawApi = env['RELAYCAST_API_URL'];
|
|
157
|
+
const baseUrl = typeof rawApi === 'string' && rawApi.trim() !== ''
|
|
158
|
+
? rawApi.trim()
|
|
159
|
+
: undefined;
|
|
160
|
+
const rawDashboard = env['RELAYCAST_DASHBOARD_URL'];
|
|
161
|
+
const dashboardUrl = typeof rawDashboard === 'string' && rawDashboard.trim() !== ''
|
|
162
|
+
? rawDashboard.trim()
|
|
163
|
+
: undefined;
|
|
164
|
+
return {
|
|
165
|
+
...(workspaceKey !== '' ? { workspaceKey } : {}),
|
|
166
|
+
...(baseUrl !== undefined ? { baseUrl } : {}),
|
|
167
|
+
...(dashboardUrl !== undefined ? { dashboardUrl } : {}),
|
|
168
|
+
suppressed: env['FLOWS_NO_OBSERVER'] === '1',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Mint an `ot_live_*` observer token via `POST /v1/observer-tokens` and return
|
|
173
|
+
* the observer dashboard URL that pre-fills it. Any failure — 4xx/5xx from the
|
|
174
|
+
* engine, malformed response, network error, timeout — returns a `warning`
|
|
175
|
+
* string and no URL. The caller must not fail the run on `warning`.
|
|
176
|
+
*/
|
|
177
|
+
export async function mintObserverUrl(options) {
|
|
178
|
+
const doFetch = options.fetch ?? (globalThis.fetch);
|
|
179
|
+
if (typeof doFetch !== 'function') {
|
|
180
|
+
return { warning: 'no fetch implementation available' };
|
|
181
|
+
}
|
|
182
|
+
const rawApi = options.baseUrl ?? DEFAULT_RELAYCAST_MINT_URL;
|
|
183
|
+
const rawDashboard = options.dashboardUrl ?? DEFAULT_RELAYCAST_DASHBOARD_URL;
|
|
184
|
+
let mintUrl;
|
|
185
|
+
let observerBase;
|
|
186
|
+
try {
|
|
187
|
+
mintUrl = new URL('/v1/observer-tokens', rawApi);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return { warning: `invalid RELAYCAST_API_URL "${rawApi}"` };
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
observerBase = new URL('/observer', rawDashboard);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return { warning: `invalid RELAYCAST_DASHBOARD_URL "${rawDashboard}"` };
|
|
197
|
+
}
|
|
198
|
+
const uuid = (options.uuid ?? defaultUuid)();
|
|
199
|
+
const now = options.now ?? (() => Date.now());
|
|
200
|
+
const timeoutMs = options.timeoutMs ?? MINT_TIMEOUT_MS;
|
|
201
|
+
const deadline = AbortSignal.timeout(timeoutMs);
|
|
202
|
+
const signal = options.signal
|
|
203
|
+
? AbortSignal.any([options.signal, deadline])
|
|
204
|
+
: deadline;
|
|
205
|
+
const payload = {
|
|
206
|
+
name: `flows-run-${uuid}`,
|
|
207
|
+
description: 'Auto-minted by `flows run` for the observer dashboard link.',
|
|
208
|
+
scopes: OBSERVER_SCOPES,
|
|
209
|
+
filters: { include_dms: true },
|
|
210
|
+
expires_at: new Date(now() + OBSERVER_TOKEN_TTL_MS).toISOString(),
|
|
211
|
+
};
|
|
212
|
+
let response;
|
|
213
|
+
try {
|
|
214
|
+
response = await doFetch(mintUrl.toString(), {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
headers: {
|
|
217
|
+
Authorization: `Bearer ${options.workspaceKey}`,
|
|
218
|
+
'Content-Type': 'application/json',
|
|
219
|
+
},
|
|
220
|
+
body: JSON.stringify(payload),
|
|
221
|
+
signal,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return { warning: `network error: ${errorMessage(error)}` };
|
|
226
|
+
}
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
return { warning: `mint API returned HTTP ${response.status}` };
|
|
229
|
+
}
|
|
230
|
+
let body;
|
|
231
|
+
try {
|
|
232
|
+
body = await response.json();
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
return { warning: `malformed response: ${errorMessage(error)}` };
|
|
236
|
+
}
|
|
237
|
+
const token = pickToken(body);
|
|
238
|
+
if (token === undefined) {
|
|
239
|
+
return { warning: 'mint API response missing ot_live_ token' };
|
|
240
|
+
}
|
|
241
|
+
// `URL.searchParams.set` percent-encodes any exotic characters the token
|
|
242
|
+
// could carry. It also collapses the leading `/observer` path correctly.
|
|
243
|
+
observerBase.searchParams.set('key', token);
|
|
244
|
+
return { observerUrl: observerBase.toString() };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Pick `data.token` from a `POST /v1/observer-tokens` response, refusing any
|
|
248
|
+
* shape that is not a plain `ot_live_*` string. Anything else is treated as
|
|
249
|
+
* "response too weird to trust" and produces no URL.
|
|
250
|
+
*/
|
|
251
|
+
function pickToken(body) {
|
|
252
|
+
if (typeof body !== 'object' || body === null)
|
|
253
|
+
return undefined;
|
|
254
|
+
const data = body['data'];
|
|
255
|
+
if (typeof data !== 'object' || data === null)
|
|
256
|
+
return undefined;
|
|
257
|
+
const token = data['token'];
|
|
258
|
+
if (typeof token !== 'string' || !token.startsWith('ot_live_'))
|
|
259
|
+
return undefined;
|
|
260
|
+
return token;
|
|
261
|
+
}
|
|
262
|
+
function defaultUuid() {
|
|
263
|
+
// `crypto.randomUUID()` is available on every Node 20+ target the SDK
|
|
264
|
+
// supports. The token name is not a security surface — it only has to be
|
|
265
|
+
// unique per (workspace, name) — so the fallback is a plain timestamp.
|
|
266
|
+
const c = globalThis.crypto;
|
|
267
|
+
return c?.randomUUID?.() ?? String(Date.now());
|
|
268
|
+
}
|
|
269
|
+
function errorMessage(error) {
|
|
270
|
+
if (error instanceof Error)
|
|
271
|
+
return error.message;
|
|
272
|
+
return 'unknown error';
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=observer-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-link.js","sourceRoot":"","sources":["../src/observer-link.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Step } from '@relayflows/surface';
|
|
2
|
+
import { type PluginManifest, type PluginVerb } from './plugin-manifest.js';
|
|
3
|
+
export interface LoadedPlugin {
|
|
4
|
+
readonly directory: string;
|
|
5
|
+
readonly manifest: PluginManifest;
|
|
6
|
+
}
|
|
7
|
+
export declare function findPluginProject(start: string): string | undefined;
|
|
8
|
+
export declare function readPlugin(directory: string, packageName: string): LoadedPlugin;
|
|
9
|
+
export declare function probePlugin(plugin: LoadedPlugin, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
10
|
+
export declare function loadPlugins(start: string): Promise<readonly LoadedPlugin[]>;
|
|
11
|
+
export declare function pluginHelpers(plugins: readonly LoadedPlugin[], invoke: (plugin: LoadedPlugin, verb: PluginVerb, args: unknown) => Step<unknown>): Record<string, unknown>;
|
|
12
|
+
export declare function invokePlugin(plugin: LoadedPlugin, verb: PluginVerb, args: unknown, idempotencyKey: string): Promise<unknown>;
|
|
13
|
+
//# sourceMappingURL=plugin-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-loader.d.ts","sourceRoot":"","sources":["../src/plugin-loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAiF,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE3J,MAAM,WAAW,YAAY;IAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;CAAE;AAC/F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQnE;AACD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAS/E;AACD,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW3G;AACD,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CA2BjF;AACD,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAczK;AACD,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAIlI"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { Ajv } from 'ajv';
|
|
5
|
+
import { snapshotJsonValue } from './json-value.js';
|
|
6
|
+
import { assertSupportedPlugin, PluginError, pluginPackageName, validatePluginManifest } from './plugin-manifest.js';
|
|
7
|
+
export function findPluginProject(start) {
|
|
8
|
+
let current = resolve(start);
|
|
9
|
+
for (;;) {
|
|
10
|
+
if (existsSync(join(current, 'flows.json')))
|
|
11
|
+
return current;
|
|
12
|
+
const parent = dirname(current);
|
|
13
|
+
if (parent === current)
|
|
14
|
+
return undefined;
|
|
15
|
+
current = parent;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function readPlugin(directory, packageName) {
|
|
19
|
+
const path = join(directory, 'flows-plugin.json');
|
|
20
|
+
if (!existsSync(path))
|
|
21
|
+
throw new PluginError('plugin_manifest_missing', `${packageName} has no flows-plugin.json.`);
|
|
22
|
+
let input;
|
|
23
|
+
try {
|
|
24
|
+
input = JSON.parse(readFileSync(path, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new PluginError('plugin_manifest_invalid', `${packageName} manifest is unreadable or invalid JSON.`);
|
|
28
|
+
}
|
|
29
|
+
const manifest = validatePluginManifest(input, packageName);
|
|
30
|
+
assertSupportedPlugin(manifest);
|
|
31
|
+
return Object.freeze({ directory, manifest });
|
|
32
|
+
}
|
|
33
|
+
export async function probePlugin(plugin, env = process.env) {
|
|
34
|
+
for (const credential of plugin.manifest.preflight.credentials) {
|
|
35
|
+
if (!env[credential]?.trim())
|
|
36
|
+
throw new PluginError('plugin_credential_missing', `${plugin.manifest.name} requires ${credential}.`);
|
|
37
|
+
}
|
|
38
|
+
for (const server of plugin.manifest.preflight.servers) {
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(server, { method: 'HEAD', signal: AbortSignal.timeout(5000) });
|
|
41
|
+
await response.body?.cancel();
|
|
42
|
+
if (!response.ok)
|
|
43
|
+
throw new Error('unsuccessful response');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new PluginError('plugin_server_unreachable', `${plugin.manifest.name} cannot reach ${server}.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function loadPlugins(start) {
|
|
51
|
+
const root = findPluginProject(start);
|
|
52
|
+
if (root === undefined)
|
|
53
|
+
return Object.freeze([]);
|
|
54
|
+
let config;
|
|
55
|
+
try {
|
|
56
|
+
config = JSON.parse(readFileSync(join(root, 'flows.json'), 'utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new PluginError('plugin_manifest_invalid', 'Invalid flows.json.');
|
|
60
|
+
}
|
|
61
|
+
if (config === null || typeof config !== 'object' || (config.plugins !== undefined && (!Array.isArray(config.plugins) || !config.plugins.every(p => typeof p === 'string')))) {
|
|
62
|
+
throw new PluginError('plugin_manifest_invalid', 'flows.json plugins must be package names.');
|
|
63
|
+
}
|
|
64
|
+
const scope = join(root, 'node_modules/@flows');
|
|
65
|
+
const names = new Set(config.plugins?.map(pluginPackageName));
|
|
66
|
+
if (existsSync(scope))
|
|
67
|
+
for (const name of readdirSync(scope).sort()) {
|
|
68
|
+
if (name.startsWith('helper-') && !names.has(`@flows/${name}`)) {
|
|
69
|
+
throw new PluginError('plugin_unlisted', `@flows/${name} is installed but not declared in flows.json plugins. Run flows add ${name}.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const plugins = [...names].sort().map(name => readPlugin(join(root, 'node_modules', name), name));
|
|
73
|
+
const namespaces = new Set();
|
|
74
|
+
for (const plugin of plugins) {
|
|
75
|
+
for (const namespace of new Set(plugin.manifest.verbs.map(v => v.namespace))) {
|
|
76
|
+
if (namespaces.has(namespace))
|
|
77
|
+
throw new PluginError('plugin_manifest_invalid', `Duplicate plugin namespace ${namespace}.`);
|
|
78
|
+
namespaces.add(namespace);
|
|
79
|
+
}
|
|
80
|
+
await probePlugin(plugin);
|
|
81
|
+
if (!existsSync(join(plugin.directory, 'src/index.js')))
|
|
82
|
+
throw new PluginError('plugin_manifest_invalid', `${plugin.manifest.name} requires src/index.js.`);
|
|
83
|
+
}
|
|
84
|
+
return Object.freeze(plugins);
|
|
85
|
+
}
|
|
86
|
+
export function pluginHelpers(plugins, invoke) {
|
|
87
|
+
const helpers = Object.create(null);
|
|
88
|
+
const ajv = new Ajv({ strict: false });
|
|
89
|
+
for (const plugin of plugins)
|
|
90
|
+
for (const verb of plugin.manifest.verbs) {
|
|
91
|
+
const validate = ajv.compile(verb.args);
|
|
92
|
+
const namespace = helpers[verb.namespace] ??= Object.create(null);
|
|
93
|
+
namespace[verb.method] = args => {
|
|
94
|
+
const snapshot = snapshotJsonValue(args, `f.${verb.namespace}.${verb.method} arguments`);
|
|
95
|
+
if (!validate(snapshot))
|
|
96
|
+
throw new PluginError('plugin_manifest_invalid', `Invalid arguments for ${verb.namespace}.${verb.method}: ${ajv.errorsText(validate.errors)}`);
|
|
97
|
+
return invoke(plugin, verb, snapshot);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
for (const helper of Object.values(helpers))
|
|
101
|
+
Object.freeze(helper);
|
|
102
|
+
return Object.freeze(helpers);
|
|
103
|
+
}
|
|
104
|
+
export async function invokePlugin(plugin, verb, args, idempotencyKey) {
|
|
105
|
+
const module = await import(pathToFileURL(join(plugin.directory, 'src/index.js')).href);
|
|
106
|
+
if (typeof module.execute !== 'function')
|
|
107
|
+
throw new Error('plugin_runtime_invalid: expected execute export');
|
|
108
|
+
return snapshotJsonValue(await module.execute(verb.namespace, verb.method, args, Object.freeze({ idempotencyKey })), 'plugin output');
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=plugin-loader.js.map
|