@synergenius/flow-weaver 0.33.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -226
- package/NOTICE +13 -0
- package/README.md +152 -244
- package/dist/agent/agent-loop.d.ts +4 -2
- package/dist/agent/cli-session.d.ts +3 -3
- package/dist/agent/cli-session.js +511 -438
- package/dist/agent/cli-spawn-config.d.ts +4 -4
- package/dist/agent/gate.d.ts +164 -0
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +174 -28
- package/dist/agent/mcp-bridge.d.ts +1 -1
- package/dist/agent/mcp-bridge.js +114 -128
- package/dist/agent/mcp-tool-server.d.ts +2 -2
- package/dist/agent/mcp-tool-server.js +147 -189
- package/dist/agent/profiles.d.ts +69 -0
- package/dist/agent/providers/anthropic.d.ts +2 -4
- package/dist/agent/providers/claude-cli.d.ts +4 -5
- package/dist/agent/providers/openai-compat.d.ts +8 -1
- package/dist/agent/streaming.d.ts +2 -2
- package/dist/agent/types.d.ts +16 -10
- package/dist/api/builder.d.ts +3 -3
- package/dist/api/compile.d.ts +9 -4
- package/dist/api/durable-validation.d.ts +15 -0
- package/dist/api/generate-in-place.d.ts +21 -19
- package/dist/api/generate.d.ts +21 -16
- package/dist/api/generated-module/local-node-functions.d.ts +24 -0
- package/dist/api/generated-module/module-format.d.ts +23 -0
- package/dist/api/generated-module/module-writer.d.ts +34 -0
- package/dist/api/generated-module/node-type-imports.d.ts +39 -0
- package/dist/api/generated-module/preamble.d.ts +16 -0
- package/dist/api/generated-module/workflow-functions.d.ts +29 -0
- package/dist/api/graph-identity.d.ts +39 -0
- package/dist/api/helpers.d.ts +4 -60
- package/dist/api/in-place/built-in-nodes.d.ts +18 -0
- package/dist/api/in-place/function-body.d.ts +21 -0
- package/dist/api/in-place/fw-imports.d.ts +30 -0
- package/dist/api/in-place/macro-coverage.d.ts +14 -0
- package/dist/api/in-place/node-type-functions.d.ts +18 -0
- package/dist/api/in-place/node-type-jsdoc.d.ts +20 -0
- package/dist/api/in-place/orphaned-node-types.d.ts +16 -0
- package/dist/api/in-place/runtime-section.d.ts +16 -0
- package/dist/api/in-place/signature.d.ts +47 -0
- package/dist/api/in-place/source-file.d.ts +19 -0
- package/dist/api/in-place/workflow-jsdoc.d.ts +19 -0
- package/dist/api/index.d.ts +18 -21
- package/dist/api/index.js +259 -53
- package/dist/api/inline-engine.generated.d.ts +3 -0
- package/dist/api/inline-runtime.d.ts +10 -2
- package/dist/api/manipulation/connections.d.ts +1 -1
- package/dist/api/manipulation/index.d.ts +8 -8
- package/dist/api/manipulation/node-types.d.ts +1 -1
- package/dist/api/manipulation/nodes.d.ts +3 -13
- package/dist/api/manipulation/ports.d.ts +1 -1
- package/dist/api/manipulation/scopes.d.ts +1 -1
- package/dist/api/manipulation/workflow.d.ts +1 -1
- package/dist/api/modify-operation.d.ts +0 -2
- package/dist/api/parse.d.ts +22 -1
- package/dist/api/port-references.d.ts +66 -0
- package/dist/api/query.d.ts +18 -2
- package/dist/api/templates.d.ts +1 -1
- package/dist/api/transform.d.ts +1 -1
- package/dist/api/validate.d.ts +1 -1
- package/dist/api/validation-registry.d.ts +2 -2
- package/dist/artifacts/brief.d.ts +43 -0
- package/dist/artifacts/index.d.ts +31 -0
- package/dist/artifacts/pdf.d.ts +19 -0
- package/dist/ast/builder.d.ts +3 -3
- package/dist/ast/index.d.ts +4 -4
- package/dist/ast/index.js +60 -5
- package/dist/ast/serialization-node.d.ts +1 -1
- package/dist/ast/serialization.d.ts +1 -1
- package/dist/ast/types.d.ts +82 -291
- package/dist/ast/workflow-utils.d.ts +4 -4
- package/dist/built-in-nodes/coercion-types.d.ts +1 -1
- package/dist/built-in-nodes/delay.d.ts +3 -1
- package/dist/built-in-nodes/generated-registry.d.ts +1 -1
- package/dist/built-in-nodes/index.d.ts +6 -5
- package/dist/built-in-nodes/index.js +79 -5
- package/dist/built-in-nodes/invoke-workflow.d.ts +2 -1
- package/dist/built-in-nodes/mock-types.d.ts +45 -14
- package/dist/built-in-nodes/sleep.d.ts +12 -0
- package/dist/built-in-nodes/wait-for-agent.d.ts +2 -1
- package/dist/built-in-nodes/wait-for-event.d.ts +2 -1
- package/dist/chevrotain-parser/coerce-parser.d.ts +1 -1
- package/dist/chevrotain-parser/connect-parser.d.ts +1 -1
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +1 -1
- package/dist/chevrotain-parser/index.d.ts +20 -23
- package/dist/chevrotain-parser/node-parser.d.ts +7 -8
- package/dist/chevrotain-parser/parse-line.d.ts +54 -0
- package/dist/chevrotain-parser/tokens.d.ts +0 -17
- package/dist/chevrotain-parser/trigger-cancel-parser.d.ts +6 -1
- package/dist/chunks/chunk-4EUSHAY6.js +298 -0
- package/dist/chunks/chunk-4KDUEOFD.js +197 -0
- package/dist/chunks/chunk-5Y3AIUWY.js +911 -0
- package/dist/chunks/chunk-6KMVP6AU.js +20 -0
- package/dist/chunks/chunk-6PNJORFL.js +128 -0
- package/dist/chunks/chunk-7AAQNGRH.js +2001 -0
- package/dist/chunks/chunk-7YYKTPJ5.js +22705 -0
- package/dist/chunks/chunk-A5MBOFVY.js +33 -0
- package/dist/chunks/chunk-AXNQRVJB.js +18 -0
- package/dist/chunks/chunk-B6HQ6YS5.js +572 -0
- package/dist/chunks/chunk-CY3RNVML.js +296 -0
- package/dist/chunks/chunk-CYHYDLV4.js +653 -0
- package/dist/chunks/chunk-CZBCCK4Y.js +82 -0
- package/dist/chunks/chunk-DCMGQP5V.js +505 -0
- package/dist/chunks/chunk-DIAA66GL.js +72 -0
- package/dist/chunks/chunk-DUO6H5PR.js +20 -0
- package/dist/chunks/chunk-E5WN7IGO.js +125 -0
- package/dist/chunks/chunk-EFGFXXQF.js +184 -0
- package/dist/chunks/chunk-F3RTZV2A.js +2811 -0
- package/dist/chunks/chunk-FMTLP5ZX.js +1397 -0
- package/dist/chunks/chunk-HKZLQJDV.js +79 -0
- package/dist/chunks/chunk-INDEVYEC.js +146 -0
- package/dist/chunks/chunk-JQTF4R5L.js +390 -0
- package/dist/chunks/chunk-KMCAYNUM.js +331 -0
- package/dist/chunks/chunk-KMWCCOUJ.js +1444 -0
- package/dist/chunks/chunk-KU3CLJI2.js +338 -0
- package/dist/chunks/chunk-NDSTGMKR.js +3300 -0
- package/dist/chunks/chunk-NQNLUAPO.js +505 -0
- package/dist/chunks/chunk-O2U2LO57.js +466 -0
- package/dist/chunks/chunk-OOQG7UPP.js +457 -0
- package/dist/chunks/chunk-OZQAW5ZG.js +112 -0
- package/dist/chunks/chunk-P2CVDGHR.js +487 -0
- package/dist/chunks/chunk-P44RIZ7C.js +592 -0
- package/dist/chunks/chunk-PEZCT37T.js +1475 -0
- package/dist/chunks/chunk-PKWSAW6O.js +152 -0
- package/dist/chunks/chunk-Q6MDDZMT.js +4373 -0
- package/dist/chunks/chunk-QDE4Z7KW.js +6 -0
- package/dist/chunks/chunk-QJDAVSNY.js +8 -0
- package/dist/chunks/chunk-QYPORSLO.js +7552 -0
- package/dist/chunks/chunk-R4QGNK34.js +183 -0
- package/dist/chunks/chunk-REEYC73I.js +3002 -0
- package/dist/chunks/chunk-SEWDMQ6Q.js +46 -0
- package/dist/chunks/chunk-TAIUWKZB.js +3057 -0
- package/dist/chunks/chunk-TN4YZ3O7.js +196 -0
- package/dist/chunks/chunk-TRMFB43C.js +143 -0
- package/dist/chunks/chunk-VO4QXG2X.js +1016 -0
- package/dist/chunks/chunk-VP2P3BPA.js +1002 -0
- package/dist/chunks/chunk-VQ7H33J4.js +2176 -0
- package/dist/chunks/chunk-VWA7MCV2.js +105 -0
- package/dist/chunks/chunk-XAV22WD7.js +253 -0
- package/dist/chunks/chunk-YSPBPZDV.js +148 -0
- package/dist/chunks/chunk-ZKEGXO73.js +282 -0
- package/dist/chunks/chunk-ZMGN6F3S.js +4256 -0
- package/dist/chunks/grammar-diagrams-AI7VDXOM.js +14 -0
- package/dist/chunks/index.min-ECJD6GZC.js +37 -0
- package/dist/chunks/manifest-EPTR5MYH.js +21 -0
- package/dist/chunks/openapi-document-6TCGVDUW.js +69 -0
- package/dist/chunks/registry-K2U5KUTY.js +23 -0
- package/dist/chunks/serialization-node-UGY6CFH6.js +38 -0
- package/dist/chunks/validate-GEKSZPIN.js +24 -0
- package/dist/chunks/validation-registry-IQZX3UE3.js +7 -0
- package/dist/chunks/validator-VXFHLPDW.js +26 -0
- package/dist/chunks/workflow-executor-KBGFKHNR.js +36 -0
- package/dist/cli/commands/agents.d.ts +16 -0
- package/dist/cli/commands/artifact.d.ts +10 -0
- package/dist/cli/commands/compile.d.ts +0 -30
- package/dist/cli/commands/console.d.ts +32 -0
- package/dist/cli/commands/context.d.ts +0 -3
- package/dist/cli/commands/describe.js +386 -352
- package/dist/cli/commands/dev.d.ts +9 -4
- package/dist/cli/commands/diagram.d.ts +3 -5
- package/dist/cli/commands/doctor.d.ts +27 -4
- package/dist/cli/commands/doctor.js +3307 -633
- package/dist/cli/commands/export.d.ts +6 -4
- package/dist/cli/commands/grammar.d.ts +0 -3
- package/dist/cli/commands/implement.d.ts +1 -1
- package/dist/cli/commands/init/agent-handoff.d.ts +28 -0
- package/dist/cli/commands/init/config.d.ts +3 -0
- package/dist/cli/commands/init/files.d.ts +12 -0
- package/dist/cli/commands/init/naming.d.ts +13 -0
- package/dist/cli/commands/init/output.d.ts +12 -0
- package/dist/cli/commands/init/setup.d.ts +21 -0
- package/dist/cli/commands/init/types.d.ts +53 -0
- package/dist/cli/commands/init-personas.d.ts +9 -1
- package/dist/cli/commands/init.d.ts +24 -88
- package/dist/cli/commands/market.d.ts +1 -1
- package/dist/cli/commands/mcp-setup.d.ts +1 -4
- package/dist/cli/commands/modify.d.ts +0 -5
- package/dist/cli/commands/openapi.d.ts +9 -11
- package/dist/cli/commands/run.d.ts +0 -4
- package/dist/cli/commands/serve.d.ts +24 -26
- package/dist/cli/commands/status.d.ts +1 -1
- package/dist/cli/exports.d.ts +3 -4
- package/dist/cli/exports.js +124 -23
- package/dist/cli/flow-weaver-agents-H653446S.mjs +81 -0
- package/dist/cli/flow-weaver-artifact-WBFYTW76.mjs +58 -0
- package/dist/cli/flow-weaver-chunk-265CEK74.mjs +2 -0
- package/dist/cli/flow-weaver-chunk-2C7PZCV5.mjs +186 -0
- package/dist/cli/flow-weaver-chunk-3BSYCWPL.mjs +3109 -0
- package/dist/cli/flow-weaver-chunk-3MKUQP3D.mjs +547 -0
- package/dist/cli/flow-weaver-chunk-3ZLMPQTH.mjs +27 -0
- package/dist/cli/flow-weaver-chunk-4DVY73ML.mjs +280 -0
- package/dist/cli/flow-weaver-chunk-54M4KNEL.mjs +200 -0
- package/dist/cli/flow-weaver-chunk-55QMUZIA.mjs +256 -0
- package/dist/cli/flow-weaver-chunk-6ZUJ7LMX.mjs +2003 -0
- package/dist/cli/flow-weaver-chunk-7ET6N32V.mjs +419 -0
- package/dist/cli/flow-weaver-chunk-7G63RR4K.mjs +8880 -0
- package/dist/cli/flow-weaver-chunk-A6M5K3W7.mjs +4418 -0
- package/dist/cli/flow-weaver-chunk-AA3NATMX.mjs +154 -0
- package/dist/cli/flow-weaver-chunk-APX6MQ5A.mjs +5652 -0
- package/dist/cli/flow-weaver-chunk-BHCC5FE5.mjs +17 -0
- package/dist/cli/flow-weaver-chunk-DM4BBRRU.mjs +35 -0
- package/dist/cli/flow-weaver-chunk-DRN7KPWY.mjs +168 -0
- package/dist/cli/flow-weaver-chunk-EKWF27G6.mjs +23 -0
- package/dist/cli/flow-weaver-chunk-EM5HWQ4R.mjs +338 -0
- package/dist/cli/flow-weaver-chunk-FPPPU2DG.mjs +226 -0
- package/dist/cli/flow-weaver-chunk-GAQXZHNO.mjs +3005 -0
- package/dist/cli/flow-weaver-chunk-GBUNNP33.mjs +1329 -0
- package/dist/cli/flow-weaver-chunk-HMAKDE55.mjs +636 -0
- package/dist/cli/flow-weaver-chunk-HQ3ZAN44.mjs +367 -0
- package/dist/cli/flow-weaver-chunk-I4APCXYN.mjs +21442 -0
- package/dist/cli/flow-weaver-chunk-IJJ4JXTL.mjs +2297 -0
- package/dist/cli/flow-weaver-chunk-J7EPZW2I.mjs +33 -0
- package/dist/cli/flow-weaver-chunk-KOEMJHLG.mjs +83 -0
- package/dist/cli/flow-weaver-chunk-M6CBWQKJ.mjs +271 -0
- package/dist/cli/flow-weaver-chunk-MHJ4N652.mjs +1580 -0
- package/dist/cli/flow-weaver-chunk-MKAFQWLP.mjs +202 -0
- package/dist/cli/flow-weaver-chunk-MMV2XGD3.mjs +3291 -0
- package/dist/cli/flow-weaver-chunk-MSI2UJES.mjs +125 -0
- package/dist/cli/flow-weaver-chunk-N767YRAI.mjs +48 -0
- package/dist/cli/flow-weaver-chunk-NQKKWDGF.mjs +56 -0
- package/dist/cli/flow-weaver-chunk-NYZDQYFU.mjs +45 -0
- package/dist/cli/flow-weaver-chunk-OMVWSNHJ.mjs +14 -0
- package/dist/cli/flow-weaver-chunk-PUWZ47H5.mjs +2188 -0
- package/dist/cli/flow-weaver-chunk-QOPRVDES.mjs +46 -0
- package/dist/cli/flow-weaver-chunk-RIWE7YTR.mjs +216 -0
- package/dist/cli/flow-weaver-chunk-S63Q3JIU.mjs +789 -0
- package/dist/cli/flow-weaver-chunk-T7X5A23H.mjs +558 -0
- package/dist/cli/flow-weaver-chunk-TLV3VZUN.mjs +2 -0
- package/dist/cli/flow-weaver-chunk-TS5P3PIN.mjs +194 -0
- package/dist/cli/flow-weaver-chunk-U3EO3X4B.mjs +649 -0
- package/dist/cli/flow-weaver-chunk-UNFS3NQP.mjs +34 -0
- package/dist/cli/flow-weaver-chunk-V6DHWFQG.mjs +2811 -0
- package/dist/cli/flow-weaver-chunk-VXWNLYQU.mjs +9 -0
- package/dist/cli/flow-weaver-chunk-W3YNK26P.mjs +149 -0
- package/dist/cli/flow-weaver-chunk-XG2WKXYZ.mjs +324 -0
- package/dist/cli/flow-weaver-chunk-YLSRZWFK.mjs +2219 -0
- package/dist/cli/flow-weaver-chunk-YVPURWS6.mjs +40 -0
- package/dist/cli/flow-weaver-chunk-Z44JK332.mjs +582 -0
- package/dist/cli/flow-weaver-chunk-Z5ZJPNSY.mjs +517 -0
- package/dist/cli/flow-weaver-chunk-ZQALO25T.mjs +594 -0
- package/dist/cli/flow-weaver-compile-A2CABDSB.mjs +37 -0
- package/dist/cli/flow-weaver-console-6EBHDBTN.mjs +71 -0
- package/dist/cli/flow-weaver-context-ECLYANFF.mjs +17 -0
- package/dist/cli/flow-weaver-context-ZRUMW2KE.mjs +69 -0
- package/dist/cli/flow-weaver-create-WIP4EFNP.mjs +124 -0
- package/dist/cli/flow-weaver-deployment-WJJRK7NO.mjs +14 -0
- package/dist/cli/flow-weaver-describe-XDIFF5LI.mjs +41 -0
- package/dist/cli/flow-weaver-dev-LG2NSQAU.mjs +196 -0
- package/dist/cli/flow-weaver-diagram-3EVQARQE.mjs +52 -0
- package/dist/cli/flow-weaver-diagram-7LR7O4M2.mjs +44 -0
- package/dist/cli/flow-weaver-diff-USF7DJLU.mjs +85 -0
- package/dist/cli/flow-weaver-docs-QU2ZOXKH.mjs +96 -0
- package/dist/cli/flow-weaver-doctor-K447YWHR.mjs +43 -0
- package/dist/cli/flow-weaver-export-LAS6N56Y.mjs +140 -0
- package/dist/cli/flow-weaver-grammar-RIRUS3Q6.mjs +49 -0
- package/dist/cli/flow-weaver-grammar-diagrams-WXRTW5SK.mjs +15 -0
- package/dist/cli/flow-weaver-implement-5JG6BCFZ.mjs +114 -0
- package/dist/cli/flow-weaver-index.min-OR5SIHXD.mjs +39 -0
- package/dist/cli/flow-weaver-init-34YZNPQX.mjs +972 -0
- package/dist/cli/flow-weaver-init-personas-NOGZTQQ2.mjs +48 -0
- package/dist/cli/flow-weaver-manifest-4JNUSEB3.mjs +18 -0
- package/dist/cli/flow-weaver-market-WA4CKHKV.mjs +444 -0
- package/dist/cli/flow-weaver-mcp-setup-O26MGXSD.mjs +22 -0
- package/dist/cli/flow-weaver-migrate-VFVEUTPH.mjs +119 -0
- package/dist/cli/flow-weaver-modify-VM3JP5K6.mjs +97 -0
- package/dist/cli/flow-weaver-openapi-IRBWI3HM.mjs +71 -0
- package/dist/cli/flow-weaver-openapi-document-7N6YMPG3.mjs +30 -0
- package/dist/cli/flow-weaver-pack-commands-OS2QRXAK.mjs +146 -0
- package/dist/cli/flow-weaver-registry-5MLFRPPT.mjs +25 -0
- package/dist/cli/flow-weaver-run-DSTLSTHR.mjs +555 -0
- package/dist/cli/flow-weaver-serialization-node-LE6PCG4M.mjs +50 -0
- package/dist/cli/flow-weaver-serve-NVLCLSOW.mjs +192 -0
- package/dist/cli/flow-weaver-server-7IERLVXE.mjs +2925 -0
- package/dist/cli/flow-weaver-server-KWF4PXYC.mjs +19112 -0
- package/dist/cli/flow-weaver-status-75W2S3YB.mjs +138 -0
- package/dist/cli/flow-weaver-strip-AZPXUYVA.mjs +79 -0
- package/dist/cli/flow-weaver-templates-DSNMB6K7.mjs +72 -0
- package/dist/cli/flow-weaver-validate-A4UWDQN6.mjs +19 -0
- package/dist/cli/flow-weaver-validate-GRBZ5W4C.mjs +296 -0
- package/dist/cli/flow-weaver-validation-registry-BINGUNXX.mjs +9 -0
- package/dist/cli/flow-weaver-validator-TY56CI42.mjs +21 -0
- package/dist/cli/flow-weaver-watch-OPPERXL6.mjs +114 -0
- package/dist/cli/flow-weaver-workflow-executor-6AHYPXAN.mjs +26 -0
- package/dist/cli/flow-weaver.mjs +3557 -89498
- package/dist/cli/index.d.ts +5 -2
- package/dist/cli/pack-commands-needed.d.ts +12 -0
- package/dist/cli/program.d.ts +14 -0
- package/dist/cli/templates/ai/mock-provider.d.ts +1 -1
- package/dist/cli/templates/index.d.ts +1 -8
- package/dist/cli/templates/nodes/agent-router.d.ts +1 -1
- package/dist/cli/templates/nodes/aggregator.d.ts +1 -1
- package/dist/cli/templates/nodes/conversation-memory.d.ts +1 -1
- package/dist/cli/templates/nodes/http.d.ts +1 -1
- package/dist/cli/templates/nodes/human-approval.d.ts +1 -1
- package/dist/cli/templates/nodes/json-extractor.d.ts +1 -1
- package/dist/cli/templates/nodes/llm-call.d.ts +1 -1
- package/dist/cli/templates/nodes/prompt-template.d.ts +1 -1
- package/dist/cli/templates/nodes/rag-retriever.d.ts +1 -1
- package/dist/cli/templates/nodes/tool-executor.d.ts +1 -1
- package/dist/cli/templates/nodes/transformer.d.ts +1 -1
- package/dist/cli/templates/nodes/validator.d.ts +1 -1
- package/dist/cli/templates/shared/approval-types.d.ts +1 -1
- package/dist/cli/templates/shared/case.d.ts +14 -0
- package/dist/cli/templates/shared/llm-types.d.ts +4 -4
- package/dist/cli/templates/workflows/aggregator.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-agent.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-chat.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-rag.d.ts +1 -1
- package/dist/cli/templates/workflows/ai-react.d.ts +1 -1
- package/dist/cli/templates/workflows/approval.d.ts +10 -0
- package/dist/cli/templates/workflows/conditional.d.ts +2 -2
- package/dist/cli/templates/workflows/error-handler.d.ts +2 -2
- package/dist/cli/templates/workflows/foreach.d.ts +1 -1
- package/dist/cli/templates/workflows/sequential.d.ts +1 -1
- package/dist/cli/templates/workflows/webhook.d.ts +1 -1
- package/dist/cli/utils/interactive.d.ts +6 -0
- package/dist/cli/utils/json-option.d.ts +8 -0
- package/dist/cli/utils/logger.d.ts +2 -0
- package/dist/compiler/durable-source-proof.d.ts +23 -0
- package/dist/compiler/executable-artifact.d.ts +29 -0
- package/dist/compiler/index.d.ts +4 -0
- package/dist/compiler/index.js +36 -0
- package/dist/console/app.js +106 -0
- package/dist/console/assets/synergenius.svg +18 -0
- package/dist/console/author.d.ts +32 -0
- package/dist/console/cli-catalog.d.ts +21 -0
- package/dist/console/cli-run.d.ts +35 -0
- package/dist/console/cli-run.js +46 -0
- package/dist/console/debug.d.ts +67 -0
- package/dist/console/diff-view.d.ts +96 -0
- package/dist/console/export.d.ts +36 -0
- package/dist/console/git.d.ts +27 -0
- package/dist/console/index.d.ts +4 -0
- package/dist/console/index.html +16 -0
- package/dist/console/index.js +203 -0
- package/dist/console/packs.d.ts +100 -0
- package/dist/console/request-guard.d.ts +10 -0
- package/dist/console/respond.d.ts +16 -0
- package/dist/console/router.d.ts +64 -0
- package/dist/console/routes-agents.d.ts +14 -0
- package/dist/console/routes-project.d.ts +3 -0
- package/dist/console/routes-runs.d.ts +3 -0
- package/dist/console/routes-services.d.ts +7 -0
- package/dist/console/routes-tools.d.ts +3 -0
- package/dist/console/runs.d.ts +69 -0
- package/dist/console/scan.d.ts +49 -0
- package/dist/console/schema.d.ts +74 -0
- package/dist/console/server.d.ts +34 -0
- package/dist/console/server.js +43264 -0
- package/dist/console/services.d.ts +119 -0
- package/dist/console/source.d.ts +23 -0
- package/dist/console/status.d.ts +68 -0
- package/dist/console/styles.css +1023 -0
- package/dist/console/terminals.d.ts +22 -0
- package/dist/console/workflow-view.d.ts +153 -0
- package/dist/constants.d.ts +5 -1
- package/dist/constants.js +56 -167
- package/dist/context/index.d.ts +10 -0
- package/dist/context/index.js +14 -191
- package/dist/coordinator/agent-gate.d.ts +107 -0
- package/dist/coordinator/bundle-digest.d.ts +20 -0
- package/dist/coordinator/clock-tick.d.ts +4 -0
- package/dist/coordinator/effect-receipts.d.ts +10 -0
- package/dist/coordinator/errors.d.ts +31 -0
- package/dist/coordinator/file-store.d.ts +3 -0
- package/dist/coordinator/gate-labeling.d.ts +33 -0
- package/dist/coordinator/gate-resolution.d.ts +28 -0
- package/dist/coordinator/index.d.ts +12 -0
- package/dist/coordinator/index.js +107 -0
- package/dist/coordinator/memory-store.d.ts +3 -0
- package/dist/coordinator/params.d.ts +18 -0
- package/dist/coordinator/run-annotations.d.ts +6 -0
- package/dist/coordinator/run-context.d.ts +11 -0
- package/dist/coordinator/run-ending.d.ts +5 -0
- package/dist/coordinator/run-outcome.d.ts +31 -0
- package/dist/coordinator/run-resume.d.ts +6 -0
- package/dist/coordinator/run-start.d.ts +4 -0
- package/dist/coordinator/run-store.d.ts +275 -0
- package/dist/coordinator/run-trace.d.ts +41 -0
- package/dist/coordinator/run-views.d.ts +12 -0
- package/dist/coordinator/runs-dir.d.ts +26 -0
- package/dist/coordinator/store.d.ts +67 -0
- package/dist/coordinator/time.d.ts +39 -0
- package/dist/coordinator/workflow-selection.d.ts +6 -0
- package/dist/deployment/index.d.ts +11 -16
- package/dist/deployment/index.js +541 -50
- package/dist/deployment/targets/base.d.ts +11 -13
- package/dist/deployment/targets/openapi-parts.d.ts +92 -0
- package/dist/diagram/arms.d.ts +70 -0
- package/dist/diagram/ascii-renderer.d.ts +1 -1
- package/dist/diagram/geometry.d.ts +22 -29
- package/dist/diagram/graph/bounds.d.ts +30 -0
- package/dist/diagram/graph/metrics.d.ts +21 -0
- package/dist/diagram/graph/nodes.d.ts +33 -0
- package/dist/diagram/graph/placement.d.ts +22 -0
- package/dist/diagram/graph/ports.d.ts +23 -0
- package/dist/diagram/graph/routing.d.ts +40 -0
- package/dist/diagram/graph/scopes.d.ts +30 -0
- package/dist/diagram/index.d.ts +15 -23
- package/dist/diagram/index.js +632 -111
- package/dist/diagram/labels.d.ts +12 -0
- package/dist/diagram/lanes.d.ts +93 -0
- package/dist/diagram/layout.d.ts +1 -1
- package/dist/diagram/material-symbols.d.ts +7 -0
- package/dist/diagram/orthogonal-router.d.ts +15 -51
- package/dist/diagram/process-view.d.ts +79 -0
- package/dist/diagram/spine.d.ts +25 -0
- package/dist/diagram/theme.d.ts +3 -5
- package/dist/diagram/types.d.ts +6 -20
- package/dist/diff/index.js +53 -9
- package/dist/diff/types.d.ts +1 -5
- package/dist/doc-metadata/extractors/annotations.d.ts +0 -4
- package/dist/doc-metadata/extractors/cli-commands.d.ts +2 -1
- package/dist/doc-metadata/extractors/core-metadata.d.ts +19 -4
- package/dist/doc-metadata/extractors/error-codes.d.ts +1 -1
- package/dist/doc-metadata/extractors/mcp-tools.d.ts +7 -3
- package/dist/doc-metadata/index.d.ts +1 -2
- package/dist/doc-metadata/index.js +2368 -9
- package/dist/doc-metadata/types.d.ts +7 -24
- package/dist/docs/guide.d.ts +33 -0
- package/dist/docs/index.d.ts +7 -4
- package/dist/docs/index.js +298 -298
- package/dist/docs/pack-topics.d.ts +18 -0
- package/dist/editor-completions/annotationValues.d.ts +1 -1
- package/dist/editor-completions/contextParser.d.ts +3 -2
- package/dist/editor-completions/dataTypes.d.ts +1 -1
- package/dist/editor-completions/goToDefinition.d.ts +1 -1
- package/dist/editor-completions/index.d.ts +8 -8
- package/dist/editor-completions/index.js +1244 -175
- package/dist/editor-completions/jsDocAnnotations.d.ts +1 -1
- package/dist/editor-completions/modifierCompletions.d.ts +1 -1
- package/dist/export/index.d.ts +7 -1
- package/dist/generated-branding.js +8 -21
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +7 -3
- package/dist/generator/annotation-generator.d.ts +84 -0
- package/dist/generator/async-detection.d.ts +1 -1
- package/dist/{body-generator.d.ts → generator/body-generator.d.ts} +7 -3
- package/dist/generator/code-utils.d.ts +15 -60
- package/dist/generator/connection-reads.d.ts +94 -0
- package/dist/generator/control-flow-plan.d.ts +74 -0
- package/dist/generator/control-flow.d.ts +1 -1
- package/dist/generator/exit-assembly.d.ts +11 -0
- package/dist/generator/index.d.ts +4 -5
- package/dist/generator/index.js +34 -11
- package/dist/generator/input-port-values.d.ts +22 -0
- package/dist/generator/{scope-function-generator.d.ts → node-arguments.d.ts} +76 -1
- package/dist/generator/node-invocation.d.ts +74 -0
- package/dist/{node-types-generator.d.ts → generator/node-types-generator.d.ts} +3 -2
- package/dist/generator/scope-closure.d.ts +23 -0
- package/dist/generator/scoped-child.d.ts +49 -0
- package/dist/{sugar-optimizer.d.ts → generator/sugar-optimizer.d.ts} +1 -1
- package/dist/generator/unified.d.ts +14 -2
- package/dist/generator/workflow-generator.d.ts +37 -0
- package/dist/index.d.ts +29 -26
- package/dist/index.js +1322 -92
- package/dist/jsdoc-port-sync/apply-diff.d.ts +15 -0
- package/dist/jsdoc-port-sync/callback-signature.d.ts +17 -0
- package/dist/jsdoc-port-sync/diff.d.ts +5 -7
- package/dist/jsdoc-port-sync/incomplete-lines.d.ts +41 -0
- package/dist/jsdoc-port-sync/index.d.ts +11 -11
- package/dist/jsdoc-port-sync/index.js +88 -45
- package/dist/jsdoc-port-sync/jsdoc-to-signature.d.ts +66 -0
- package/dist/jsdoc-port-sync/port-parser.d.ts +6 -24
- package/dist/jsdoc-port-sync/port-tag-placement.d.ts +55 -0
- package/dist/jsdoc-port-sync/scoped-ports.d.ts +21 -0
- package/dist/jsdoc-port-sync/signature-parser.d.ts +8 -1
- package/dist/jsdoc-port-sync/signature-to-jsdoc.d.ts +77 -0
- package/dist/jsdoc-port-sync/sync.d.ts +4 -1
- package/dist/marketplace/index.d.ts +5 -3
- package/dist/marketplace/index.js +62 -10
- package/dist/marketplace/install.d.ts +24 -0
- package/dist/marketplace/manifest.d.ts +1 -1
- package/dist/marketplace/npmrc.d.ts +24 -0
- package/dist/marketplace/registry.d.ts +46 -11
- package/dist/marketplace/types.d.ts +41 -24
- package/dist/marketplace/validator.d.ts +1 -1
- package/dist/mcp/debug-session.d.ts +2 -4
- package/dist/mcp/dist-imports.d.ts +12 -0
- package/dist/mcp/response-utils.d.ts +11 -9
- package/dist/mcp/server.d.ts +0 -1
- package/dist/mcp/tools-context.d.ts +11 -0
- package/dist/mcp/tools-diagram.d.ts +1 -2
- package/dist/mcp/tools-export.d.ts +2 -2
- package/dist/mcp/tools-marketplace.d.ts +1 -1
- package/dist/mcp/tools-run.d.ts +17 -0
- package/dist/mcp/tools-workflow.d.ts +3 -0
- package/dist/mcp/types.d.ts +4 -14
- package/dist/mcp/workflow-executor.d.ts +57 -19
- package/dist/npm-packages.d.ts +1 -1
- package/dist/npm-packages.js +10 -473
- package/dist/parser/annotation-parser.d.ts +88 -0
- package/dist/parser/annotation-suggestion.d.ts +23 -0
- package/dist/parser/durable-effect-contract.d.ts +10 -0
- package/dist/parser/expression-references.d.ts +101 -0
- package/dist/parser/external-node-types.d.ts +69 -0
- package/dist/{function-like.d.ts → parser/function-like.d.ts} +10 -3
- package/dist/parser/generated-sections.d.ts +25 -0
- package/dist/parser/import-resolution.d.ts +67 -0
- package/dist/parser/import-stub.d.ts +29 -0
- package/dist/parser/jsdoc/config-types.d.ts +209 -0
- package/dist/parser/jsdoc/graph-tags.d.ts +54 -0
- package/dist/parser/jsdoc/node-type-block.d.ts +23 -0
- package/dist/parser/jsdoc/parse-line-once.d.ts +11 -0
- package/dist/parser/jsdoc/port-tags.d.ts +42 -0
- package/dist/parser/jsdoc/runtime-tags.d.ts +65 -0
- package/dist/parser/jsdoc/signature-types.d.ts +52 -0
- package/dist/parser/jsdoc/workflow-block.d.ts +22 -0
- package/dist/parser/jsdoc-parser.d.ts +23 -0
- package/dist/parser/macro-expansion.d.ts +80 -0
- package/dist/parser/module-resolution.d.ts +38 -0
- package/dist/parser/node-inference.d.ts +39 -0
- package/dist/parser/npm-node-types.d.ts +24 -0
- package/dist/parser/pack-handlers.d.ts +12 -0
- package/dist/parser/path-data-resolution.d.ts +75 -0
- package/dist/parser/port-inference.d.ts +15 -0
- package/dist/{resolve-package-types.d.ts → parser/resolve-package-types.d.ts} +4 -0
- package/dist/parser/serialize-deploy-annotations.d.ts +19 -0
- package/dist/parser/tag-registry.d.ts +22 -0
- package/dist/parser/workflow-extraction.d.ts +39 -0
- package/dist/runtime/ExecutionContext.d.ts +87 -99
- package/dist/runtime/continuation-core.d.ts +147 -0
- package/dist/runtime/continuation.d.ts +48 -0
- package/dist/runtime/debug-controller.d.ts +7 -22
- package/dist/runtime/durable-execution.d.ts +176 -0
- package/dist/runtime/events.d.ts +16 -1
- package/dist/runtime/executable-module-contract.d.ts +16 -0
- package/dist/runtime/index.d.ts +13 -10
- package/dist/runtime/index.js +947 -9
- package/dist/runtime/strict-json.d.ts +15 -0
- package/dist/server/access.d.ts +12 -0
- package/dist/server/api.d.ts +126 -0
- package/dist/server/callback-delivery.d.ts +62 -0
- package/dist/server/callback-url.d.ts +44 -0
- package/dist/server/context.d.ts +35 -0
- package/dist/server/http-error.d.ts +10 -0
- package/dist/server/index.d.ts +7 -1
- package/dist/server/index.js +125 -6
- package/dist/server/openapi-document.d.ts +33 -0
- package/dist/server/openapi.d.ts +32 -0
- package/dist/server/respond.d.ts +35 -0
- package/dist/server/route-params.d.ts +17 -0
- package/dist/server/route-plan.d.ts +41 -0
- package/dist/server/routes-catalog.d.ts +5 -0
- package/dist/server/routes-declared.d.ts +12 -0
- package/dist/server/routes-runs.d.ts +8 -0
- package/dist/server/run-driver.d.ts +58 -0
- package/dist/server/run-view.d.ts +26 -0
- package/dist/server/transport.d.ts +35 -0
- package/dist/server/types.d.ts +143 -52
- package/dist/server/webhook-server.d.ts +12 -38
- package/dist/server/workflow-registry.d.ts +7 -4
- package/dist/service-registry.d.ts +49 -0
- package/dist/service-registry.js +123 -0
- package/dist/testing/assertions.d.ts +2 -2
- package/dist/testing/index.d.ts +14 -13
- package/dist/testing/index.js +582 -24
- package/dist/testing/mock-approval.d.ts +3 -5
- package/dist/testing/mock-llm.d.ts +2 -3
- package/dist/testing/recorder.d.ts +5 -6
- package/dist/testing/replayer.d.ts +6 -7
- package/dist/testing/run-store-check.d.ts +3 -0
- package/dist/testing/token-tracker.d.ts +2 -2
- package/dist/{type-mappings.d.ts → types/type-mappings.d.ts} +13 -1
- package/dist/utils/error-utils.d.ts +4 -2
- package/dist/utils/port-ordering.d.ts +2 -2
- package/dist/utils/port-tag-utils.d.ts +1 -1
- package/dist/validation/agent-detection.d.ts +17 -5
- package/dist/validation/agent-rules.d.ts +6 -7
- package/dist/validation/core-rules.d.ts +49 -0
- package/dist/validation/design-rules.d.ts +9 -3
- package/dist/validation/rule-registry.d.ts +3 -3
- package/dist/validation/rules/connections.d.ts +27 -0
- package/dist/validation/rules/context.d.ts +11 -0
- package/dist/validation/rules/cycles.d.ts +17 -0
- package/dist/validation/rules/data-flow.d.ts +19 -0
- package/dist/validation/rules/scope-topology.d.ts +35 -0
- package/dist/validation/rules/type-compatibility.d.ts +30 -0
- package/dist/validation/type-checker.d.ts +39 -0
- package/dist/validation/validator-helpers.d.ts +31 -0
- package/dist/validation/validator.d.ts +30 -0
- package/docs/reference/advanced-annotations.md +277 -60
- package/docs/reference/built-in-nodes.md +164 -94
- package/docs/reference/cancellation.md +44 -0
- package/docs/reference/cli-reference.md +252 -234
- package/docs/reference/compilation.md +36 -109
- package/docs/reference/concepts.md +80 -63
- package/docs/reference/console.md +169 -0
- package/docs/reference/debugging.md +26 -57
- package/docs/reference/deployment.md +217 -143
- package/docs/reference/durable-gates.md +445 -0
- package/docs/reference/error-codes.md +90 -43
- package/docs/reference/export-interface.md +91 -26
- package/docs/reference/iterative-development.md +50 -28
- package/docs/reference/jsdoc-grammar.md +66 -311
- package/docs/reference/library.md +250 -0
- package/docs/reference/marketplace.md +301 -152
- package/docs/reference/mcp-tools.md +102 -0
- package/docs/reference/node-conversion.md +84 -59
- package/docs/reference/orientation.md +68 -0
- package/docs/reference/scaffold.md +5 -4
- package/docs/reference/tutorial.md +106 -166
- package/docs/reference/visual-reference.md +1 -1
- package/package.json +85 -50
- package/dist/agent/agent-loop.js +0 -156
- package/dist/agent/cli-spawn-config.js +0 -65
- package/dist/agent/device-connection.d.ts +0 -79
- package/dist/agent/device-connection.js +0 -184
- package/dist/agent/env-allowlist.js +0 -60
- package/dist/agent/providers/anthropic.js +0 -198
- package/dist/agent/providers/claude-cli.js +0 -161
- package/dist/agent/providers/openai-compat.js +0 -205
- package/dist/agent/providers/platform.d.ts +0 -23
- package/dist/agent/providers/platform.js +0 -132
- package/dist/agent/streaming.js +0 -186
- package/dist/agent/types.js +0 -20
- package/dist/annotation-generator.d.ts +0 -50
- package/dist/annotation-generator.js +0 -743
- package/dist/api/builder.js +0 -345
- package/dist/api/command-runner.js +0 -787
- package/dist/api/compile.js +0 -148
- package/dist/api/extract-types.js +0 -57
- package/dist/api/generate-in-place.js +0 -1477
- package/dist/api/generate.js +0 -514
- package/dist/api/helpers.js +0 -285
- package/dist/api/inline-runtime.js +0 -526
- package/dist/api/manipulation/connections.js +0 -151
- package/dist/api/manipulation/index.js +0 -41
- package/dist/api/manipulation/node-types.js +0 -200
- package/dist/api/manipulation/nodes.js +0 -355
- package/dist/api/manipulation/ports.js +0 -228
- package/dist/api/manipulation/scopes.js +0 -156
- package/dist/api/manipulation/workflow.js +0 -116
- package/dist/api/modify-operation.js +0 -177
- package/dist/api/parse.js +0 -115
- package/dist/api/patterns.d.ts +0 -112
- package/dist/api/patterns.js +0 -303
- package/dist/api/query.js +0 -840
- package/dist/api/templates.js +0 -117
- package/dist/api/transform.js +0 -40
- package/dist/api/validate.js +0 -64
- package/dist/api/validation-registry.js +0 -10
- package/dist/api/workflow-file-operations.js +0 -180
- package/dist/ast/builder.js +0 -395
- package/dist/ast/serialization-node.js +0 -30
- package/dist/ast/serialization.js +0 -134
- package/dist/ast/types.js +0 -2
- package/dist/ast/workflow-utils.js +0 -114
- package/dist/body-generator.js +0 -35
- package/dist/built-in-nodes/coercion-types.js +0 -61
- package/dist/built-in-nodes/delay.js +0 -29
- package/dist/built-in-nodes/generated-registry.js +0 -299
- package/dist/built-in-nodes/invoke-workflow.js +0 -36
- package/dist/built-in-nodes/mock-types.js +0 -42
- package/dist/built-in-nodes/wait-for-agent.js +0 -31
- package/dist/built-in-nodes/wait-for-event.js +0 -25
- package/dist/chevrotain-parser/coerce-parser.js +0 -103
- package/dist/chevrotain-parser/connect-parser.js +0 -136
- package/dist/chevrotain-parser/fan-parser.js +0 -149
- package/dist/chevrotain-parser/grammar-diagrams.js +0 -273
- package/dist/chevrotain-parser/index.js +0 -31
- package/dist/chevrotain-parser/map-parser.js +0 -130
- package/dist/chevrotain-parser/node-parser.js +0 -558
- package/dist/chevrotain-parser/path-parser.js +0 -140
- package/dist/chevrotain-parser/port-parser.js +0 -519
- package/dist/chevrotain-parser/position-parser.d.ts +0 -20
- package/dist/chevrotain-parser/position-parser.js +0 -83
- package/dist/chevrotain-parser/scope-parser.js +0 -104
- package/dist/chevrotain-parser/tokens.js +0 -429
- package/dist/chevrotain-parser/trigger-cancel-parser.js +0 -291
- package/dist/cli/commands/account.d.ts +0 -4
- package/dist/cli/commands/account.js +0 -50
- package/dist/cli/commands/ai-credentials.d.ts +0 -12
- package/dist/cli/commands/ai-credentials.js +0 -95
- package/dist/cli/commands/apikey.d.ts +0 -4
- package/dist/cli/commands/apikey.js +0 -64
- package/dist/cli/commands/auth.d.ts +0 -9
- package/dist/cli/commands/auth.js +0 -255
- package/dist/cli/commands/compile.js +0 -331
- package/dist/cli/commands/connect.d.ts +0 -4
- package/dist/cli/commands/connect.js +0 -163
- package/dist/cli/commands/context.js +0 -51
- package/dist/cli/commands/create.js +0 -139
- package/dist/cli/commands/deploy.d.ts +0 -6
- package/dist/cli/commands/deploy.js +0 -74
- package/dist/cli/commands/dev.js +0 -227
- package/dist/cli/commands/diagram.js +0 -39
- package/dist/cli/commands/diff.js +0 -57
- package/dist/cli/commands/docs.js +0 -74
- package/dist/cli/commands/export.js +0 -153
- package/dist/cli/commands/grammar.js +0 -40
- package/dist/cli/commands/implement.js +0 -91
- package/dist/cli/commands/init-personas.js +0 -541
- package/dist/cli/commands/init.js +0 -797
- package/dist/cli/commands/market.js +0 -440
- package/dist/cli/commands/mcp-setup.js +0 -433
- package/dist/cli/commands/migrate.js +0 -91
- package/dist/cli/commands/modify.js +0 -58
- package/dist/cli/commands/openapi.js +0 -71
- package/dist/cli/commands/org.d.ts +0 -8
- package/dist/cli/commands/org.js +0 -136
- package/dist/cli/commands/pattern.d.ts +0 -34
- package/dist/cli/commands/pattern.js +0 -186
- package/dist/cli/commands/plugin.d.ts +0 -16
- package/dist/cli/commands/plugin.js +0 -176
- package/dist/cli/commands/run.js +0 -742
- package/dist/cli/commands/serve.js +0 -93
- package/dist/cli/commands/status.js +0 -123
- package/dist/cli/commands/strip.js +0 -61
- package/dist/cli/commands/templates.js +0 -58
- package/dist/cli/commands/validate.js +0 -267
- package/dist/cli/commands/watch.js +0 -71
- package/dist/cli/config/credentials.d.ts +0 -15
- package/dist/cli/config/credentials.js +0 -43
- package/dist/cli/config/platform-client.d.ts +0 -123
- package/dist/cli/config/platform-client.js +0 -248
- package/dist/cli/env-setup.js +0 -12
- package/dist/cli/index.js +0 -850
- package/dist/cli/pack-commands.js +0 -122
- package/dist/cli/postinstall.d.ts +0 -16
- package/dist/cli/postinstall.js +0 -119
- package/dist/cli/templates/ai/mock-provider.js +0 -64
- package/dist/cli/templates/ai/types.js +0 -5
- package/dist/cli/templates/approvals/index.d.ts +0 -15
- package/dist/cli/templates/approvals/index.js +0 -241
- package/dist/cli/templates/index.js +0 -123
- package/dist/cli/templates/nodes/agent-router.js +0 -114
- package/dist/cli/templates/nodes/aggregator.js +0 -63
- package/dist/cli/templates/nodes/conversation-memory.js +0 -85
- package/dist/cli/templates/nodes/http.js +0 -80
- package/dist/cli/templates/nodes/human-approval.js +0 -109
- package/dist/cli/templates/nodes/json-extractor.js +0 -119
- package/dist/cli/templates/nodes/llm-call.js +0 -106
- package/dist/cli/templates/nodes/prompt-template.js +0 -52
- package/dist/cli/templates/nodes/rag-retriever.js +0 -128
- package/dist/cli/templates/nodes/tool-executor.js +0 -108
- package/dist/cli/templates/nodes/transformer.js +0 -68
- package/dist/cli/templates/nodes/validator.js +0 -62
- package/dist/cli/templates/pack-loader.js +0 -58
- package/dist/cli/templates/providers/index.js +0 -239
- package/dist/cli/templates/shared/approval-types.js +0 -31
- package/dist/cli/templates/shared/llm-types.js +0 -109
- package/dist/cli/templates/workflows/aggregator.js +0 -101
- package/dist/cli/templates/workflows/ai-agent.js +0 -326
- package/dist/cli/templates/workflows/ai-chat.js +0 -167
- package/dist/cli/templates/workflows/ai-rag.js +0 -184
- package/dist/cli/templates/workflows/ai-react.js +0 -293
- package/dist/cli/templates/workflows/conditional.js +0 -139
- package/dist/cli/templates/workflows/error-handler.js +0 -145
- package/dist/cli/templates/workflows/foreach.js +0 -140
- package/dist/cli/templates/workflows/sequential.js +0 -200
- package/dist/cli/templates/workflows/webhook.js +0 -158
- package/dist/cli/utils/cli-helpers.d.ts +0 -44
- package/dist/cli/utils/cli-helpers.js +0 -99
- package/dist/cli/utils/logger.js +0 -126
- package/dist/cli/utils/parse-int-strict.js +0 -17
- package/dist/cli/utils/safe-write.js +0 -54
- package/dist/deployment/config/defaults.d.ts +0 -29
- package/dist/deployment/config/defaults.js +0 -98
- package/dist/deployment/config/loader.d.ts +0 -24
- package/dist/deployment/config/loader.js +0 -237
- package/dist/deployment/config/types.d.ts +0 -117
- package/dist/deployment/config/types.js +0 -5
- package/dist/deployment/core/adapters.d.ts +0 -66
- package/dist/deployment/core/adapters.js +0 -156
- package/dist/deployment/core/executor.d.ts +0 -62
- package/dist/deployment/core/executor.js +0 -197
- package/dist/deployment/core/formatters.d.ts +0 -42
- package/dist/deployment/core/formatters.js +0 -146
- package/dist/deployment/openapi/generator.d.ts +0 -146
- package/dist/deployment/openapi/generator.js +0 -347
- package/dist/deployment/openapi/schema-converter.d.ts +0 -49
- package/dist/deployment/openapi/schema-converter.js +0 -192
- package/dist/deployment/targets/base.js +0 -855
- package/dist/deployment/types.d.ts +0 -140
- package/dist/deployment/types.js +0 -8
- package/dist/diagram/ascii-renderer.js +0 -528
- package/dist/diagram/geometry.js +0 -1267
- package/dist/diagram/html-viewer.d.ts +0 -21
- package/dist/diagram/html-viewer.js +0 -1689
- package/dist/diagram/layout.js +0 -143
- package/dist/diagram/orthogonal-router.js +0 -568
- package/dist/diagram/renderer.d.ts +0 -3
- package/dist/diagram/renderer.js +0 -266
- package/dist/diagram/theme.js +0 -282
- package/dist/diagram/types.js +0 -2
- package/dist/diff/WorkflowDiffer.js +0 -429
- package/dist/diff/formatDiff.js +0 -239
- package/dist/diff/impact.js +0 -119
- package/dist/diff/types.js +0 -35
- package/dist/doc-metadata/extractors/annotations.js +0 -638
- package/dist/doc-metadata/extractors/cli-commands.js +0 -326
- package/dist/doc-metadata/extractors/core-metadata.js +0 -61
- package/dist/doc-metadata/extractors/error-codes.js +0 -372
- package/dist/doc-metadata/extractors/grammar-rules.js +0 -51
- package/dist/doc-metadata/extractors/mcp-tools.js +0 -705
- package/dist/doc-metadata/extractors/plugin-api.d.ts +0 -19
- package/dist/doc-metadata/extractors/plugin-api.js +0 -279
- package/dist/doc-metadata/types.js +0 -5
- package/dist/editor-completions/annotationValues.js +0 -146
- package/dist/editor-completions/contextParser.js +0 -410
- package/dist/editor-completions/dataTypes.js +0 -95
- package/dist/editor-completions/goToDefinition.js +0 -112
- package/dist/editor-completions/jsDocAnnotations.js +0 -359
- package/dist/editor-completions/modifierCompletions.js +0 -197
- package/dist/editor-completions/types.js +0 -8
- package/dist/export/index.js +0 -212
- package/dist/extensions/index.d.ts +0 -16
- package/dist/extensions/index.js +0 -17
- package/dist/friendly-errors.js +0 -761
- package/dist/function-like.js +0 -84
- package/dist/generator/async-detection.js +0 -56
- package/dist/generator/code-utils.js +0 -551
- package/dist/generator/compile-target-registry.d.ts +0 -20
- package/dist/generator/compile-target-registry.js +0 -20
- package/dist/generator/control-flow.js +0 -358
- package/dist/generator/dev-mode-registry.d.ts +0 -27
- package/dist/generator/dev-mode-registry.js +0 -20
- package/dist/generator/scope-function-generator.js +0 -397
- package/dist/generator/unified.js +0 -1831
- package/dist/generator.d.ts +0 -54
- package/dist/generator.js +0 -101
- package/dist/jsdoc-parser.d.ts +0 -377
- package/dist/jsdoc-parser.js +0 -1189
- package/dist/jsdoc-port-sync/constants.js +0 -103
- package/dist/jsdoc-port-sync/diff.js +0 -319
- package/dist/jsdoc-port-sync/port-parser.js +0 -579
- package/dist/jsdoc-port-sync/rename.js +0 -256
- package/dist/jsdoc-port-sync/signature-parser.js +0 -559
- package/dist/jsdoc-port-sync/sync.js +0 -653
- package/dist/marketplace/manifest.js +0 -194
- package/dist/marketplace/registry.js +0 -198
- package/dist/marketplace/types.js +0 -9
- package/dist/marketplace/validator.js +0 -150
- package/dist/mcp/agent-channel.d.ts +0 -35
- package/dist/mcp/agent-channel.js +0 -61
- package/dist/mcp/auto-registration.d.ts +0 -3
- package/dist/mcp/auto-registration.js +0 -62
- package/dist/mcp/debug-session.js +0 -25
- package/dist/mcp/index.d.ts +0 -11
- package/dist/mcp/index.js +0 -10
- package/dist/mcp/pack-tools.js +0 -59
- package/dist/mcp/prompts.js +0 -68
- package/dist/mcp/response-utils.js +0 -97
- package/dist/mcp/run-registry.d.ts +0 -29
- package/dist/mcp/run-registry.js +0 -24
- package/dist/mcp/server.js +0 -63
- package/dist/mcp/tools-context.js +0 -51
- package/dist/mcp/tools-debug.js +0 -451
- package/dist/mcp/tools-diagram.js +0 -97
- package/dist/mcp/tools-docs.js +0 -62
- package/dist/mcp/tools-export.js +0 -222
- package/dist/mcp/tools-marketplace.js +0 -132
- package/dist/mcp/tools-model.d.ts +0 -3
- package/dist/mcp/tools-model.js +0 -279
- package/dist/mcp/tools-pattern.d.ts +0 -3
- package/dist/mcp/tools-pattern.js +0 -604
- package/dist/mcp/tools-query.js +0 -377
- package/dist/mcp/tools-resources.js +0 -41
- package/dist/mcp/tools-template.js +0 -119
- package/dist/mcp/tools-workflow-run.d.ts +0 -40
- package/dist/mcp/tools-workflow-run.js +0 -150
- package/dist/mcp/types.js +0 -2
- package/dist/mcp/workflow-executor.js +0 -242
- package/dist/migration/registry.js +0 -29
- package/dist/node-types-generator.js +0 -139
- package/dist/parser/tag-registry.js +0 -57
- package/dist/parser.d.ts +0 -232
- package/dist/parser.js +0 -2500
- package/dist/plugin/PluginPanel.d.ts +0 -12
- package/dist/plugin/PluginPanel.js +0 -5
- package/dist/plugin/index.d.ts +0 -13
- package/dist/plugin/index.js +0 -14
- package/dist/plugin/types.d.ts +0 -75
- package/dist/plugin/types.js +0 -8
- package/dist/resolve-package-types.js +0 -123
- package/dist/runtime/CancellationError.js +0 -20
- package/dist/runtime/ExecutionContext.js +0 -280
- package/dist/runtime/builtin-functions.js +0 -549
- package/dist/runtime/checkpoint.d.ts +0 -84
- package/dist/runtime/checkpoint.js +0 -225
- package/dist/runtime/debug-controller.js +0 -247
- package/dist/runtime/events.js +0 -2
- package/dist/runtime/function-registry.js +0 -66
- package/dist/runtime/parameter-resolver.js +0 -113
- package/dist/server/types.js +0 -5
- package/dist/server/webhook-server.js +0 -269
- package/dist/server/workflow-registry.js +0 -202
- package/dist/shared-project.js +0 -28
- package/dist/sugar-optimizer.js +0 -498
- package/dist/testing/assertions.js +0 -127
- package/dist/testing/mock-approval.js +0 -98
- package/dist/testing/mock-llm.js +0 -119
- package/dist/testing/recorder.js +0 -70
- package/dist/testing/replayer.js +0 -143
- package/dist/testing/token-tracker.js +0 -94
- package/dist/type-checker.d.ts +0 -42
- package/dist/type-checker.js +0 -190
- package/dist/type-mappings.js +0 -131
- package/dist/types/branded-ports.d.ts +0 -151
- package/dist/types/branded-ports.js +0 -121
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.js +0 -5
- package/dist/types.d.ts +0 -139
- package/dist/types.js +0 -15
- package/dist/utils/error-utils.js +0 -27
- package/dist/utils/lru-cache.js +0 -40
- package/dist/utils/port-ordering.js +0 -81
- package/dist/utils/port-tag-utils.js +0 -41
- package/dist/utils/string-distance.js +0 -56
- package/dist/validation/agent-detection.js +0 -115
- package/dist/validation/agent-rules.js +0 -262
- package/dist/validation/design-rules.js +0 -377
- package/dist/validation/rule-registry.js +0 -37
- package/dist/validator.d.ts +0 -113
- package/dist/validator.js +0 -1631
- package/docs/reference/patterns.md +0 -159
- package/scripts/postinstall.cjs +0 -86
- /package/dist/{shared-project.d.ts → parser/shared-project.d.ts} +0 -0
- /package/dist/{friendly-errors.d.ts → validation/friendly-errors.d.ts} +0 -0
|
@@ -0,0 +1,1580 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from "module";
|
|
2
|
+
const require = __createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
AmbiguousWorkflowError,
|
|
5
|
+
BundleChangedError,
|
|
6
|
+
InvalidAnswerError,
|
|
7
|
+
MissingOutputsError,
|
|
8
|
+
ParseError,
|
|
9
|
+
RunBusyError,
|
|
10
|
+
RunNotFoundError,
|
|
11
|
+
RunNotWaitingError,
|
|
12
|
+
answerAgentGate,
|
|
13
|
+
createLocalCoordinator,
|
|
14
|
+
defaultRunsDir,
|
|
15
|
+
isAnswering,
|
|
16
|
+
noteAnswerMisfit,
|
|
17
|
+
reclaimStaleAgentAnswers,
|
|
18
|
+
transcriptName
|
|
19
|
+
} from "./flow-weaver-chunk-YLSRZWFK.mjs";
|
|
20
|
+
import {
|
|
21
|
+
MissingParamsError
|
|
22
|
+
} from "./flow-weaver-chunk-EKWF27G6.mjs";
|
|
23
|
+
import {
|
|
24
|
+
loadAgentProfiles
|
|
25
|
+
} from "./flow-weaver-chunk-TS5P3PIN.mjs";
|
|
26
|
+
import {
|
|
27
|
+
parseWorkflow
|
|
28
|
+
} from "./flow-weaver-chunk-W3YNK26P.mjs";
|
|
29
|
+
import {
|
|
30
|
+
VERSION
|
|
31
|
+
} from "./flow-weaver-chunk-VXWNLYQU.mjs";
|
|
32
|
+
import {
|
|
33
|
+
getErrorMessage
|
|
34
|
+
} from "./flow-weaver-chunk-OMVWSNHJ.mjs";
|
|
35
|
+
import {
|
|
36
|
+
Ze
|
|
37
|
+
} from "./flow-weaver-chunk-GAQXZHNO.mjs";
|
|
38
|
+
|
|
39
|
+
// src/server/workflow-registry.ts
|
|
40
|
+
import * as fs from "fs";
|
|
41
|
+
import * as path from "path";
|
|
42
|
+
var WorkflowRegistry = class {
|
|
43
|
+
constructor(workflowDir, options = {}) {
|
|
44
|
+
this.workflowDir = workflowDir;
|
|
45
|
+
this.options = options;
|
|
46
|
+
}
|
|
47
|
+
workflowDir;
|
|
48
|
+
options;
|
|
49
|
+
endpoints = /* @__PURE__ */ new Map();
|
|
50
|
+
watcher = null;
|
|
51
|
+
debounceTimers = /* @__PURE__ */ new Map();
|
|
52
|
+
startTime = Date.now();
|
|
53
|
+
/**
|
|
54
|
+
* Initialize the registry by discovering all workflows
|
|
55
|
+
*/
|
|
56
|
+
async initialize() {
|
|
57
|
+
await this.discoverWorkflows();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Discover all workflow files in the configured directory
|
|
61
|
+
*/
|
|
62
|
+
async discoverWorkflows() {
|
|
63
|
+
const files = await Ze("**/*.ts", {
|
|
64
|
+
cwd: this.workflowDir,
|
|
65
|
+
absolute: true,
|
|
66
|
+
ignore: [
|
|
67
|
+
"**/*.generated.ts",
|
|
68
|
+
"**/node_modules/**",
|
|
69
|
+
"**/*.d.ts",
|
|
70
|
+
"**/*.test.ts",
|
|
71
|
+
"**/*.spec.ts"
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
this.endpoints.clear();
|
|
75
|
+
for (const file of files) {
|
|
76
|
+
try {
|
|
77
|
+
const content = fs.readFileSync(file, "utf8");
|
|
78
|
+
if (!content.includes("@flowWeaver")) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
let result = await parseWorkflow(file, { projectDir: path.dirname(file) });
|
|
82
|
+
if (result.errors.length && result.availableWorkflows.length > 1) {
|
|
83
|
+
result = await parseWorkflow(file, { projectDir: path.dirname(file), workflowName: result.availableWorkflows[0] });
|
|
84
|
+
}
|
|
85
|
+
if (result.errors.length) continue;
|
|
86
|
+
for (const workflow of result.allWorkflows) {
|
|
87
|
+
const endpoint = {
|
|
88
|
+
name: workflow.name,
|
|
89
|
+
functionName: workflow.functionName,
|
|
90
|
+
filePath: file,
|
|
91
|
+
method: "POST",
|
|
92
|
+
path: `/workflows/${workflow.name}`,
|
|
93
|
+
inputSchema: this.extractInputSchema(workflow),
|
|
94
|
+
outputSchema: this.extractOutputSchema(workflow),
|
|
95
|
+
description: workflow.description,
|
|
96
|
+
gates: workflow.instances.filter((i) => workflow.nodeTypes.find((n) => n.name === i.nodeType || n.functionName === i.nodeType)?.durableGate !== void 0).length,
|
|
97
|
+
routes: workflow.options?.http ?? []
|
|
98
|
+
};
|
|
99
|
+
this.endpoints.set(workflow.name, endpoint);
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Extract JSON Schema for workflow input ports
|
|
107
|
+
*/
|
|
108
|
+
extractInputSchema(workflow) {
|
|
109
|
+
const schema = {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: {}
|
|
112
|
+
};
|
|
113
|
+
const required = [];
|
|
114
|
+
for (const [portName, port] of Object.entries(workflow.startPorts || {})) {
|
|
115
|
+
if (portName === "execute") continue;
|
|
116
|
+
schema.properties[portName] = {
|
|
117
|
+
...this.dataTypeToJsonSchema(port.dataType),
|
|
118
|
+
...port.label && { description: port.label }
|
|
119
|
+
};
|
|
120
|
+
if (!port.optional) {
|
|
121
|
+
required.push(portName);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (required.length > 0) {
|
|
125
|
+
schema.required = required;
|
|
126
|
+
}
|
|
127
|
+
return schema;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Extract JSON Schema for workflow output ports
|
|
131
|
+
*/
|
|
132
|
+
extractOutputSchema(workflow) {
|
|
133
|
+
const schema = {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {}
|
|
136
|
+
};
|
|
137
|
+
for (const [portName, port] of Object.entries(workflow.exitPorts || {})) {
|
|
138
|
+
if (portName === "onSuccess" || portName === "onFailure") continue;
|
|
139
|
+
schema.properties[portName] = {
|
|
140
|
+
...this.dataTypeToJsonSchema(port.dataType),
|
|
141
|
+
...port.label && { description: port.label }
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return schema;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* A Flow Weaver data type as a JSON Schema fragment. `ANY` has no JSON
|
|
148
|
+
* Schema type: it is the empty schema, which admits anything.
|
|
149
|
+
*/
|
|
150
|
+
dataTypeToJsonSchema(dataType) {
|
|
151
|
+
const mapping = {
|
|
152
|
+
STRING: "string",
|
|
153
|
+
NUMBER: "number",
|
|
154
|
+
BOOLEAN: "boolean",
|
|
155
|
+
OBJECT: "object",
|
|
156
|
+
ARRAY: "array",
|
|
157
|
+
STEP: "boolean"
|
|
158
|
+
};
|
|
159
|
+
const type = mapping[dataType];
|
|
160
|
+
return type ? { type } : {};
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get a specific endpoint by workflow name
|
|
164
|
+
*/
|
|
165
|
+
getEndpoint(name) {
|
|
166
|
+
return this.endpoints.get(name);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get all registered endpoints
|
|
170
|
+
*/
|
|
171
|
+
getAllEndpoints() {
|
|
172
|
+
return Array.from(this.endpoints.values());
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Get server uptime in seconds
|
|
176
|
+
*/
|
|
177
|
+
getUptime() {
|
|
178
|
+
return Math.floor((Date.now() - this.startTime) / 1e3);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Start watching for file changes. After a change settles, the workflows
|
|
182
|
+
* are discovered again and `onChange` runs. A rediscovery that fails goes
|
|
183
|
+
* to `onError`, which by default writes it to stderr, and the next change
|
|
184
|
+
* tries again.
|
|
185
|
+
*/
|
|
186
|
+
async startWatching(onChange, onError = (error) => {
|
|
187
|
+
console.error(`Rediscovering workflows in ${this.workflowDir} failed: ${getErrorMessage(error)}`);
|
|
188
|
+
}) {
|
|
189
|
+
try {
|
|
190
|
+
const chokidar = await import("chokidar");
|
|
191
|
+
const watcher = chokidar.watch(this.workflowDir, {
|
|
192
|
+
persistent: true,
|
|
193
|
+
ignoreInitial: true,
|
|
194
|
+
ignored: ["**/*.generated.ts", "**/node_modules/**", "**/*.d.ts"],
|
|
195
|
+
awaitWriteFinish: {
|
|
196
|
+
stabilityThreshold: 300,
|
|
197
|
+
pollInterval: 100
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
this.watcher = watcher;
|
|
201
|
+
watcher.on("all", (event, filePath) => {
|
|
202
|
+
if (!filePath.endsWith(".ts")) return;
|
|
203
|
+
const existingTimer = this.debounceTimers.get(filePath);
|
|
204
|
+
if (existingTimer) {
|
|
205
|
+
clearTimeout(existingTimer);
|
|
206
|
+
}
|
|
207
|
+
const timer = setTimeout(() => {
|
|
208
|
+
this.debounceTimers.delete(filePath);
|
|
209
|
+
this.discoverWorkflows().then(() => onChange()).catch(onError);
|
|
210
|
+
}, 500);
|
|
211
|
+
this.debounceTimers.set(filePath, timer);
|
|
212
|
+
});
|
|
213
|
+
} catch {
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Stop watching for file changes
|
|
218
|
+
*/
|
|
219
|
+
async stopWatching() {
|
|
220
|
+
for (const timer of this.debounceTimers.values()) {
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
}
|
|
223
|
+
this.debounceTimers.clear();
|
|
224
|
+
if (this.watcher) {
|
|
225
|
+
await this.watcher.close();
|
|
226
|
+
this.watcher = null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/server/openapi.ts
|
|
232
|
+
function buildOpenApi(input) {
|
|
233
|
+
const { endpoints, mounted, legacy, secured } = input;
|
|
234
|
+
const base = input.base ?? "";
|
|
235
|
+
const paths = {};
|
|
236
|
+
const run = { $ref: "#/components/schemas/Run" };
|
|
237
|
+
const error = { $ref: "#/components/schemas/Error" };
|
|
238
|
+
for (const c of mounted) {
|
|
239
|
+
const e = c.endpoint;
|
|
240
|
+
const props = e.inputSchema?.properties ?? {};
|
|
241
|
+
const required = e.inputSchema?.required ?? [];
|
|
242
|
+
const inPath = new Set(c.keys);
|
|
243
|
+
const rest = Object.fromEntries(Object.entries(props).filter(([k]) => !inPath.has(k)));
|
|
244
|
+
const restRequired = required.filter((k) => !inPath.has(k));
|
|
245
|
+
const oaPath = c.route.path.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "{$1}");
|
|
246
|
+
const parameters = c.keys.map((k) => ({ name: k, in: "path", required: true, schema: props[k] ?? {} }));
|
|
247
|
+
const op = {
|
|
248
|
+
operationId: `${c.route.method.toLowerCase()}_${e.functionName}${c.keys.length ? `_by_${c.keys.join("_")}` : ""}`,
|
|
249
|
+
summary: e.description || `${c.route.method} ${c.route.path}`,
|
|
250
|
+
tags: ["endpoints"],
|
|
251
|
+
...c.route.auth === "none" ? { security: [] } : {},
|
|
252
|
+
responses: {
|
|
253
|
+
"200": { description: "The workflow ran to its end", content: { "application/json": { schema: e.outputSchema ?? { type: "object" } } } },
|
|
254
|
+
"202": { description: `Paused at a gate${c.route.mode === "async" ? ", or running" : ""}. Follow Location`, headers: { Location: { schema: { type: "string" } } }, content: { "application/json": { schema: run } } },
|
|
255
|
+
"400": { description: "Bad parameters, or a refused callback URL", content: { "application/json": { schema: error } } },
|
|
256
|
+
"409": { description: "Idempotency-Key reused with different parameters", content: { "application/json": { schema: error } } },
|
|
257
|
+
"422": { description: "The workflow finished on its failure path", content: { "application/json": { schema: e.outputSchema ?? { type: "object" } } } },
|
|
258
|
+
"500": { description: "The run failed", content: { "application/json": { schema: error } } }
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
if (c.route.method === "GET" || c.route.method === "DELETE") {
|
|
262
|
+
parameters.push(...Object.entries(rest).map(([k, s]) => ({ name: k, in: "query", required: restRequired.includes(k), schema: s })));
|
|
263
|
+
if (c.route.callback) parameters.push({ name: "callbackUrl", in: "query", required: false, schema: { type: "string", format: "uri" }, description: "Receives the final response by POST" });
|
|
264
|
+
} else {
|
|
265
|
+
op.requestBody = {
|
|
266
|
+
required: restRequired.length > 0,
|
|
267
|
+
content: {
|
|
268
|
+
"application/json": { schema: { type: "object", properties: { ...rest, ...c.route.callback ? { callbackUrl: { type: "string", format: "uri", description: "Receives the final response by POST" } } : {} }, ...restRequired.length ? { required: restRequired } : {} } },
|
|
269
|
+
"application/x-www-form-urlencoded": { schema: { type: "object", properties: rest, ...restRequired.length ? { required: restRequired } : {} } }
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
parameters.push({ name: "Idempotency-Key", in: "header", required: false, schema: { type: "string" }, description: "The same key gives the same run" });
|
|
274
|
+
parameters.push({ name: "Prefer", in: "header", required: false, schema: { type: "string", enum: ["respond-async"] }, description: "Answer 202 before the first step runs" });
|
|
275
|
+
op.parameters = parameters;
|
|
276
|
+
paths[oaPath] = { ...paths[oaPath] ?? {}, [c.route.method.toLowerCase()]: op };
|
|
277
|
+
}
|
|
278
|
+
if (legacy) {
|
|
279
|
+
for (const e of endpoints) {
|
|
280
|
+
paths[e.path] = {
|
|
281
|
+
...paths[e.path] ?? {},
|
|
282
|
+
get: { operationId: `describe_${e.functionName}`, summary: `Describe ${e.name}`, tags: ["workflows"], responses: { "200": { description: "The endpoint and its schemas" } } },
|
|
283
|
+
post: {
|
|
284
|
+
operationId: `run_${e.functionName}`,
|
|
285
|
+
summary: `Run ${e.name} (run resource)`,
|
|
286
|
+
tags: ["workflows"],
|
|
287
|
+
parameters: [{ name: "async", in: "query", schema: { type: "boolean" } }],
|
|
288
|
+
requestBody: { required: true, content: { "application/json": { schema: e.inputSchema || { type: "object", additionalProperties: true } } } },
|
|
289
|
+
responses: { "200": { description: "Completed", content: { "application/json": { schema: run } } }, "202": { description: "Waiting at a gate, or running when async", content: { "application/json": { schema: run } } }, "500": { description: "Failed", content: { "application/json": { schema: run } } } }
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const runId = { name: "runId", in: "path", required: true, schema: { type: "string" } };
|
|
295
|
+
paths["/runs"] = { get: { operationId: "listRuns", summary: "List runs", tags: ["runs"], parameters: [{ name: "workflow", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Runs, newest first" } } } };
|
|
296
|
+
paths["/runs/{runId}"] = { get: { operationId: "getRun", summary: "One run", tags: ["runs"], parameters: [runId], responses: { "200": { description: "The run", content: { "application/json": { schema: run } } }, "404": { description: "No such run" } } } };
|
|
297
|
+
paths["/runs/{runId}/resolve"] = { post: { operationId: "resolveRun", summary: "Answer the gate a run is waiting at", tags: ["runs"], parameters: [runId, { name: "async", in: "query", schema: { type: "boolean" } }], requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { answer: { description: "The gate's result" }, reject: { type: "string" } } } } } }, responses: { "200": { description: "Completed", content: { "application/json": { schema: run } } }, "202": { description: "Waiting at the next gate", content: { "application/json": { schema: run } } }, "409": { description: "Not waiting, the file changed, or an agent is answering", content: { "application/json": { schema: error } } } } } };
|
|
298
|
+
paths["/runs/{runId}/cancel"] = { post: { operationId: "cancelRun", summary: "Stop a run", tags: ["runs"], parameters: [runId], responses: { "200": { description: "The run", content: { "application/json": { schema: run } } } } } };
|
|
299
|
+
paths["/runs/{runId}/events"] = { get: { operationId: "runEvents", summary: "Follow a run as server-sent events", tags: ["runs"], parameters: [runId], responses: { "200": { description: "text/event-stream: run, event, agent, synced" } } } };
|
|
300
|
+
paths["/runs/{runId}/agent"] = { get: { operationId: "runAgent", summary: "The transcript of the agent that answered the latest agent gate", tags: ["runs"], parameters: [runId], responses: { "200": { description: "The transcript" }, "404": { description: "No agent answered this run" } } } };
|
|
301
|
+
paths["/health"] = { get: { operationId: "health", summary: "Liveness", tags: ["meta"], security: [], responses: { "200": { description: "ok" } } } };
|
|
302
|
+
return {
|
|
303
|
+
openapi: "3.0.3",
|
|
304
|
+
info: {
|
|
305
|
+
title: input.info?.title ?? "Flow Weaver API",
|
|
306
|
+
version: input.info?.version ?? VERSION,
|
|
307
|
+
description: input.info?.description ?? `${mounted.length} declared endpoint(s)${legacy ? ` and ${endpoints.length} workflow(s) as run resources` : ""}. A workflow that pauses at a gate answers 202 with a run id.`
|
|
308
|
+
},
|
|
309
|
+
servers: [{ url: `${input.serverUrl ?? ""}${base}` || "/" }],
|
|
310
|
+
paths,
|
|
311
|
+
tags: [{ name: "endpoints" }, { name: "workflows" }, { name: "runs" }, { name: "meta" }],
|
|
312
|
+
components: {
|
|
313
|
+
schemas: {
|
|
314
|
+
Run: { type: "object", properties: { runId: { type: "string" }, workflow: { type: "string" }, status: { type: "string", enum: ["running", "waiting", "completed", "failed", "cancelled"] }, gate: { type: "object" }, agent: { type: "object" }, result: {}, error, links: { type: "object" } } },
|
|
315
|
+
Error: { type: "object", properties: { error: { type: "object", properties: { code: { type: "string" }, message: { type: "string" }, details: {} } } } }
|
|
316
|
+
},
|
|
317
|
+
...secured ? { securitySchemes: { bearer: { type: "http", scheme: "bearer" } } } : {}
|
|
318
|
+
},
|
|
319
|
+
...secured ? { security: [{ bearer: [] }] } : {}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/server/access.ts
|
|
324
|
+
import { timingSafeEqual } from "node:crypto";
|
|
325
|
+
|
|
326
|
+
// src/server/http-error.ts
|
|
327
|
+
var HttpError = class extends Error {
|
|
328
|
+
constructor(status, code, message, details, headers) {
|
|
329
|
+
super(message);
|
|
330
|
+
this.status = status;
|
|
331
|
+
this.code = code;
|
|
332
|
+
this.details = details;
|
|
333
|
+
this.headers = headers;
|
|
334
|
+
this.name = "HttpError";
|
|
335
|
+
}
|
|
336
|
+
status;
|
|
337
|
+
code;
|
|
338
|
+
details;
|
|
339
|
+
headers;
|
|
340
|
+
};
|
|
341
|
+
function errorToHttp(err) {
|
|
342
|
+
if (err instanceof HttpError) return err;
|
|
343
|
+
if (err instanceof ParseError) return new HttpError(400, "PARSE_ERROR", err.message);
|
|
344
|
+
if (err instanceof AmbiguousWorkflowError) return new HttpError(400, "AMBIGUOUS_WORKFLOW", err.message);
|
|
345
|
+
if (err instanceof RunNotFoundError) return new HttpError(404, "RUN_NOT_FOUND", err.message);
|
|
346
|
+
if (err instanceof RunNotWaitingError) return new HttpError(409, "RUN_NOT_WAITING", err.message);
|
|
347
|
+
if (err instanceof BundleChangedError) return new HttpError(409, "BUNDLE_CHANGED", err.message);
|
|
348
|
+
if (err instanceof MissingOutputsError) return new HttpError(400, "MISSING_OUTPUTS", err.message);
|
|
349
|
+
if (err instanceof InvalidAnswerError) return new HttpError(400, "INVALID_INPUT", err.message);
|
|
350
|
+
if (err instanceof RunBusyError) return new HttpError(409, "RUN_IN_FLIGHT", err.message, void 0, { "Retry-After": "2" });
|
|
351
|
+
if (err instanceof MissingParamsError) return new HttpError(400, "VALIDATION_ERROR", err.message, err.missing.map((k) => ({ path: k, message: "required" })));
|
|
352
|
+
const name = err?.name;
|
|
353
|
+
if (name === "ContinuationRefusalError") return new HttpError(409, "CONTINUATION_REFUSED", getErrorMessage(err));
|
|
354
|
+
return new HttpError(500, "EXECUTION_ERROR", getErrorMessage(err));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/server/respond.ts
|
|
358
|
+
function header(req, name) {
|
|
359
|
+
const v = req.headers[name.toLowerCase()];
|
|
360
|
+
return Array.isArray(v) ? v[0] : v;
|
|
361
|
+
}
|
|
362
|
+
function json(res, status, body, extra = {}) {
|
|
363
|
+
const text = JSON.stringify(body);
|
|
364
|
+
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8", "Content-Length": Buffer.byteLength(text), ...extra });
|
|
365
|
+
res.end(text);
|
|
366
|
+
}
|
|
367
|
+
function html(res, body) {
|
|
368
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
369
|
+
res.end(body);
|
|
370
|
+
}
|
|
371
|
+
function decodeSegment(raw) {
|
|
372
|
+
try {
|
|
373
|
+
return decodeURIComponent(raw);
|
|
374
|
+
} catch {
|
|
375
|
+
throw new HttpError(400, "BAD_PATH", `the path segment "${raw}" is not valid percent-encoding`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
var isForm = (req) => /application\/x-www-form-urlencoded/i.test(header(req, "content-type") ?? "");
|
|
379
|
+
function parseBodyText(text, form) {
|
|
380
|
+
const t = text.trim();
|
|
381
|
+
if (!t) return {};
|
|
382
|
+
if (form) {
|
|
383
|
+
const out = {};
|
|
384
|
+
for (const [k, v] of new URLSearchParams(t)) out[k] = v;
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
387
|
+
let parsed;
|
|
388
|
+
try {
|
|
389
|
+
parsed = JSON.parse(t);
|
|
390
|
+
} catch {
|
|
391
|
+
throw new HttpError(400, "INVALID_JSON", "the body is not valid JSON");
|
|
392
|
+
}
|
|
393
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new HttpError(400, "INVALID_JSON", "the body must be a JSON object");
|
|
394
|
+
return parsed;
|
|
395
|
+
}
|
|
396
|
+
async function readBody(req, given, maxBody) {
|
|
397
|
+
const form = isForm(req);
|
|
398
|
+
const pre = given !== void 0 ? given : req.body;
|
|
399
|
+
if (pre !== void 0 && pre !== null) {
|
|
400
|
+
if (typeof pre === "string") return { body: parseBodyText(pre, form), form };
|
|
401
|
+
if (Buffer.isBuffer(pre) || pre instanceof Uint8Array) return { body: parseBodyText(Buffer.from(pre).toString("utf8"), form), form };
|
|
402
|
+
if (typeof pre !== "object" || Array.isArray(pre)) throw new HttpError(400, "INVALID_JSON", "the body must be a JSON object");
|
|
403
|
+
return { body: pre, form };
|
|
404
|
+
}
|
|
405
|
+
const chunks = [];
|
|
406
|
+
let size = 0;
|
|
407
|
+
for await (const chunk of req) {
|
|
408
|
+
const buf = typeof chunk === "string" ? Buffer.from(chunk) : Buffer.from(chunk);
|
|
409
|
+
size += buf.length;
|
|
410
|
+
if (size > maxBody) throw new HttpError(413, "BODY_TOO_LARGE", `the body may not exceed ${maxBody} bytes`);
|
|
411
|
+
chunks.push(buf);
|
|
412
|
+
}
|
|
413
|
+
return { body: parseBodyText(Buffer.concat(chunks).toString("utf8"), form), form };
|
|
414
|
+
}
|
|
415
|
+
function wantsAsync(req, url) {
|
|
416
|
+
const q = url.searchParams.get("async");
|
|
417
|
+
if (q !== null) return q !== "0" && q !== "false";
|
|
418
|
+
return /respond-async/i.test(header(req, "prefer") ?? "");
|
|
419
|
+
}
|
|
420
|
+
function waitBudget(req, maxWait) {
|
|
421
|
+
const m = /wait=(\d+(?:\.\d+)?)/i.exec(header(req, "prefer") ?? "");
|
|
422
|
+
return m ? Math.min(maxWait, Math.max(0, Number(m[1]) * 1e3)) : maxWait;
|
|
423
|
+
}
|
|
424
|
+
async function settledWithin(segment, ms) {
|
|
425
|
+
let timer;
|
|
426
|
+
const done = await Promise.race([
|
|
427
|
+
segment.then(() => true, () => true),
|
|
428
|
+
new Promise((r) => {
|
|
429
|
+
timer = setTimeout(() => r(false), ms);
|
|
430
|
+
timer.unref?.();
|
|
431
|
+
})
|
|
432
|
+
]);
|
|
433
|
+
if (timer) clearTimeout(timer);
|
|
434
|
+
if (!done) segment.catch(() => void 0);
|
|
435
|
+
return done;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/server/access.ts
|
|
439
|
+
var isLoopback = (host) => ["127.0.0.1", "localhost", "::1", "[::1]"].includes(host);
|
|
440
|
+
function authorized(req, token) {
|
|
441
|
+
if (!token) return true;
|
|
442
|
+
const raw = req.headers.authorization;
|
|
443
|
+
const line = Array.isArray(raw) ? raw[0] : raw;
|
|
444
|
+
const given = /^Bearer\s+(.+)$/i.exec(line ?? "")?.[1]?.trim() ?? "";
|
|
445
|
+
const a = Buffer.from(given), b = Buffer.from(token);
|
|
446
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
447
|
+
}
|
|
448
|
+
function cors(req, res, allowed) {
|
|
449
|
+
if (!allowed) return;
|
|
450
|
+
let origin;
|
|
451
|
+
if (Array.isArray(allowed)) {
|
|
452
|
+
const requested = header(req, "origin");
|
|
453
|
+
origin = requested !== void 0 && allowed.includes(requested) ? requested : void 0;
|
|
454
|
+
res.setHeader("Vary", "Origin");
|
|
455
|
+
} else {
|
|
456
|
+
origin = allowed;
|
|
457
|
+
}
|
|
458
|
+
if (!origin) return;
|
|
459
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
460
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
|
|
461
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Prefer, Idempotency-Key, X-Callback-Url");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/server/route-plan.ts
|
|
465
|
+
var RESERVED_PATHS = ["/health", "/workflows", "/runs", "/openapi.json", "/docs"];
|
|
466
|
+
var RESERVED = RESERVED_PATHS;
|
|
467
|
+
var isReserved = (p) => RESERVED.some((r) => p === r || p.startsWith(`${r}/`));
|
|
468
|
+
function planRoutes(list) {
|
|
469
|
+
const mounted = [];
|
|
470
|
+
const problems = [];
|
|
471
|
+
const seen = /* @__PURE__ */ new Map();
|
|
472
|
+
for (const owner of list) {
|
|
473
|
+
for (const route of owner.routes) {
|
|
474
|
+
if (isReserved(route.path)) {
|
|
475
|
+
problems.push(`${owner.name}: @http ${route.method} ${route.path} is under a reserved path (${RESERVED.join(", ")}), so it is not mounted`);
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
const key = `${route.method} ${route.path}`;
|
|
479
|
+
const other = seen.get(key);
|
|
480
|
+
if (other) {
|
|
481
|
+
problems.push(`${owner.name}: @http ${key} is already declared by ${other}, not mounted`);
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
seen.set(key, owner.name);
|
|
485
|
+
mounted.push({ owner, route });
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return { mounted, problems };
|
|
489
|
+
}
|
|
490
|
+
function compileRoute(routePath) {
|
|
491
|
+
const keys = [];
|
|
492
|
+
const pattern = routePath.split("/").map((seg) => {
|
|
493
|
+
if (seg.startsWith(":")) {
|
|
494
|
+
keys.push(seg.slice(1));
|
|
495
|
+
return "([^/]+)";
|
|
496
|
+
}
|
|
497
|
+
return seg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
498
|
+
}).join("/");
|
|
499
|
+
return { regex: new RegExp(`^${pattern}/?$`), keys };
|
|
500
|
+
}
|
|
501
|
+
function mountRoutes(endpoints) {
|
|
502
|
+
const plan = planRoutes(endpoints.map((endpoint) => ({ name: endpoint.name, routes: endpoint.routes ?? [], endpoint })));
|
|
503
|
+
return { compiled: plan.mounted.map(({ owner, route }) => ({ endpoint: owner.endpoint, route, ...compileRoute(route.path) })), problems: plan.problems };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// src/server/api.ts
|
|
507
|
+
import * as path3 from "node:path";
|
|
508
|
+
|
|
509
|
+
// src/server/routes-declared.ts
|
|
510
|
+
import { randomUUID, createHash } from "node:crypto";
|
|
511
|
+
|
|
512
|
+
// src/server/callback-url.ts
|
|
513
|
+
import { lookup } from "node:dns/promises";
|
|
514
|
+
import * as http from "node:http";
|
|
515
|
+
import * as https from "node:https";
|
|
516
|
+
import { isIP } from "node:net";
|
|
517
|
+
function isPrivateAddress(ip) {
|
|
518
|
+
const v = isIP(ip);
|
|
519
|
+
if (v === 4) {
|
|
520
|
+
const [a, b] = ip.split(".").map(Number);
|
|
521
|
+
return a === 10 || a === 127 || a === 0 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 100 && b >= 64 && b <= 127;
|
|
522
|
+
}
|
|
523
|
+
if (v === 6) {
|
|
524
|
+
const low = canonicalIPv6(ip);
|
|
525
|
+
if (low === "::1" || low === "::") return true;
|
|
526
|
+
if (low.startsWith("fc") || low.startsWith("fd")) return true;
|
|
527
|
+
if (/^fe[89ab]/.test(low)) return true;
|
|
528
|
+
const mapped = low.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
|
|
529
|
+
if (mapped) {
|
|
530
|
+
const [hi, lo] = [parseInt(mapped[1], 16), parseInt(mapped[2], 16)];
|
|
531
|
+
return isPrivateAddress(`${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
function canonicalIPv6(ip) {
|
|
537
|
+
try {
|
|
538
|
+
return new URL(`http://[${ip}]/`).hostname.slice(1, -1);
|
|
539
|
+
} catch {
|
|
540
|
+
return ip.toLowerCase();
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
var hostMatches = (host, pattern) => {
|
|
544
|
+
const p = pattern.toLowerCase();
|
|
545
|
+
if (p.startsWith("*.")) return host.endsWith(p.slice(1)) && host.length > p.length - 1;
|
|
546
|
+
return host === p;
|
|
547
|
+
};
|
|
548
|
+
var systemResolve = (host) => lookup(host, { all: true });
|
|
549
|
+
function judgeUrl(raw, policy) {
|
|
550
|
+
let url;
|
|
551
|
+
try {
|
|
552
|
+
url = new URL(raw);
|
|
553
|
+
} catch {
|
|
554
|
+
return { refused: "not a valid URL" };
|
|
555
|
+
}
|
|
556
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return { refused: "only http and https callbacks are delivered" };
|
|
557
|
+
if (url.username || url.password) return { refused: "credentials in the URL are not allowed" };
|
|
558
|
+
const host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
559
|
+
if (policy.allow) {
|
|
560
|
+
const verdict = policy.allow(url);
|
|
561
|
+
if (verdict !== true) return { refused: typeof verdict === "string" ? verdict : "refused by the server's callback policy" };
|
|
562
|
+
return { url, host, publicOnly: false };
|
|
563
|
+
}
|
|
564
|
+
if (policy.hosts) {
|
|
565
|
+
return policy.hosts.some((h) => hostMatches(host, h)) ? { url, host, publicOnly: false } : { refused: `${host} is not among the hosts this server delivers callbacks to` };
|
|
566
|
+
}
|
|
567
|
+
if (policy.allowPrivate) return { url, host, publicOnly: false };
|
|
568
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host.endsWith(".internal")) return { refused: `${host} is a private host, and callbacks go to public addresses only` };
|
|
569
|
+
return { url, host, publicOnly: true };
|
|
570
|
+
}
|
|
571
|
+
async function addressesOf(host, publicOnly, resolve2) {
|
|
572
|
+
const literal = isIP(host);
|
|
573
|
+
let found;
|
|
574
|
+
if (literal) found = [{ address: host, family: literal }];
|
|
575
|
+
else {
|
|
576
|
+
try {
|
|
577
|
+
found = await resolve2(host);
|
|
578
|
+
} catch {
|
|
579
|
+
return { refused: `${host} does not resolve` };
|
|
580
|
+
}
|
|
581
|
+
if (!found.length) return { refused: `${host} does not resolve` };
|
|
582
|
+
}
|
|
583
|
+
const bad = publicOnly ? found.find((a) => isPrivateAddress(a.address)) : void 0;
|
|
584
|
+
if (bad) {
|
|
585
|
+
return { refused: literal ? `${host} is a private address, and callbacks go to public addresses only` : `${host} resolves to ${bad.address}, a private address, and callbacks go to public addresses only` };
|
|
586
|
+
}
|
|
587
|
+
return found;
|
|
588
|
+
}
|
|
589
|
+
async function refuseCallbackUrl(raw, policy = {}, resolve2 = systemResolve) {
|
|
590
|
+
const judged = judgeUrl(raw, policy);
|
|
591
|
+
if ("refused" in judged) return judged.refused;
|
|
592
|
+
if (!judged.publicOnly) return void 0;
|
|
593
|
+
const found = await addressesOf(judged.host, true, resolve2);
|
|
594
|
+
return "refused" in found ? found.refused : void 0;
|
|
595
|
+
}
|
|
596
|
+
async function callbackTarget(raw, policy = {}, resolve2 = systemResolve) {
|
|
597
|
+
const judged = judgeUrl(raw, policy);
|
|
598
|
+
if ("refused" in judged) return judged;
|
|
599
|
+
const found = await addressesOf(judged.host, judged.publicOnly, resolve2);
|
|
600
|
+
if ("refused" in found) return found;
|
|
601
|
+
return { url: judged.url, address: found[0].address, family: found[0].family };
|
|
602
|
+
}
|
|
603
|
+
function postCallback(target, headers, body, timeoutMs) {
|
|
604
|
+
const { url, address, family } = target;
|
|
605
|
+
const send = url.protocol === "https:" ? https.request : http.request;
|
|
606
|
+
return new Promise((resolve2, reject) => {
|
|
607
|
+
const req = send(url, {
|
|
608
|
+
method: "POST",
|
|
609
|
+
headers: { ...headers, "Content-Length": String(Buffer.byteLength(body)) },
|
|
610
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
611
|
+
// Every connection goes to the checked address, whatever the name resolves to now.
|
|
612
|
+
lookup: (_host, options, callback) => {
|
|
613
|
+
if (options.all) callback(null, [{ address, family }]);
|
|
614
|
+
else callback(null, address, family);
|
|
615
|
+
}
|
|
616
|
+
}, (res) => {
|
|
617
|
+
res.resume();
|
|
618
|
+
res.on("end", () => resolve2(res.statusCode ?? 0));
|
|
619
|
+
res.on("error", reject);
|
|
620
|
+
});
|
|
621
|
+
req.on("error", reject);
|
|
622
|
+
req.end(body);
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// src/server/route-params.ts
|
|
627
|
+
function coerce(value, schema) {
|
|
628
|
+
const type = schema?.type;
|
|
629
|
+
if (type === "number") {
|
|
630
|
+
const n = Number(value);
|
|
631
|
+
return Number.isFinite(n) ? n : value;
|
|
632
|
+
}
|
|
633
|
+
if (type === "boolean") return value === "true" ? true : value === "false" ? false : value;
|
|
634
|
+
if (type === "object" || type === "array" || type === void 0) {
|
|
635
|
+
if (/^[[{]/.test(value.trim())) {
|
|
636
|
+
try {
|
|
637
|
+
return JSON.parse(value);
|
|
638
|
+
} catch {
|
|
639
|
+
return value;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
function paramsFor(c, m, url, body, form, dev) {
|
|
646
|
+
const schemas = c.endpoint.inputSchema?.properties ?? {};
|
|
647
|
+
const props = (k) => Object.hasOwn(schemas, k) ? schemas[k] : void 0;
|
|
648
|
+
const params = {};
|
|
649
|
+
const set = (k, v) => {
|
|
650
|
+
if (k !== "__proto__") params[k] = v;
|
|
651
|
+
};
|
|
652
|
+
let callbackUrl;
|
|
653
|
+
let mocks;
|
|
654
|
+
if (c.route.method === "GET" || c.route.method === "DELETE") {
|
|
655
|
+
for (const [k, v] of url.searchParams) {
|
|
656
|
+
if (k === "async") continue;
|
|
657
|
+
if (k === "callbackUrl") {
|
|
658
|
+
callbackUrl = v;
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
set(k, coerce(v, props(k)));
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
for (const [k, v] of Object.entries(body)) {
|
|
665
|
+
if (k === "callbackUrl" && typeof v === "string") {
|
|
666
|
+
callbackUrl = v;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (k === "mocks" && dev && typeof v === "object" && v !== null) {
|
|
670
|
+
mocks = v;
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
set(k, form && typeof v === "string" ? coerce(v, props(k)) : v);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
c.keys.forEach((k, i) => {
|
|
677
|
+
set(k, coerce(decodeSegment(m[i + 1]), props(k)));
|
|
678
|
+
});
|
|
679
|
+
const missing = (c.endpoint.inputSchema?.required ?? []).filter((k) => !Object.hasOwn(params, k) || params[k] === void 0);
|
|
680
|
+
if (missing.length) throw new HttpError(400, "VALIDATION_ERROR", `missing parameter${missing.length === 1 ? "" : "s"}: ${missing.join(", ")}`, missing.map((k) => ({ path: k, message: "required" })));
|
|
681
|
+
for (const [k, v] of Object.entries(params)) {
|
|
682
|
+
const t = props(k)?.type;
|
|
683
|
+
if (t === "number" && typeof v !== "number") throw new HttpError(400, "VALIDATION_ERROR", `parameter ${k} must be a number`, [{ path: k, message: "must be a number" }]);
|
|
684
|
+
if (t === "boolean" && typeof v !== "boolean") throw new HttpError(400, "VALIDATION_ERROR", `parameter ${k} must be true or false`, [{ path: k, message: "must be a boolean" }]);
|
|
685
|
+
if (t === "string" && typeof v !== "string") throw new HttpError(400, "VALIDATION_ERROR", `parameter ${k} must be text`, [{ path: k, message: "must be a string" }]);
|
|
686
|
+
}
|
|
687
|
+
return { params, callbackUrl: c.route.callback ? callbackUrl : void 0, mocks };
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/server/run-view.ts
|
|
691
|
+
var CONTROL = /* @__PURE__ */ new Set(["onSuccess", "onFailure"]);
|
|
692
|
+
function runView(id, base, l, rec) {
|
|
693
|
+
const links = { self: `${base}/runs/${id}`, events: `${base}/runs/${id}/events`, result: `${base}/runs/${id}/result` };
|
|
694
|
+
if (l && !rec) {
|
|
695
|
+
return l.error ? { runId: id, workflow: l.workflow, status: "failed", startedAt: new Date(l.startedAt).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString(), params: l.params, error: { code: "EXECUTION_ERROR", message: l.error }, links } : { runId: id, workflow: l.workflow, status: "running", startedAt: new Date(l.startedAt).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString(), params: l.params, links: { ...links, cancel: `${base}/runs/${id}/cancel` } };
|
|
696
|
+
}
|
|
697
|
+
if (l && rec) {
|
|
698
|
+
return { runId: id, workflow: rec.workflowName, status: "running", startedAt: rec.createdAt, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), params: rec.params, agent: rec.agent, links: { ...links, cancel: `${base}/runs/${id}/cancel` } };
|
|
699
|
+
}
|
|
700
|
+
if (!rec) return void 0;
|
|
701
|
+
const out = { runId: id, workflow: rec.workflowName, status: rec.status, startedAt: rec.createdAt, updatedAt: rec.updatedAt, params: rec.params, links };
|
|
702
|
+
if (rec.status === "waiting" && rec.gate) {
|
|
703
|
+
out.gate = { id: rec.gate.id, kind: rec.gate.kind, node: rec.gate.node, inputs: rec.gate.inputs, absent: rec.gate.absent, outputs: rec.gate.outputs, hasFailurePort: rec.gate.hasFailurePort };
|
|
704
|
+
if (rec.due) out.due = rec.due;
|
|
705
|
+
out.links = { ...links, resolve: `${base}/runs/${id}/resolve`, cancel: `${base}/runs/${id}/cancel` };
|
|
706
|
+
}
|
|
707
|
+
if (rec.agent) out.agent = rec.agent;
|
|
708
|
+
if (rec.status === "completed") out.result = rec.result;
|
|
709
|
+
if (rec.status === "failed") out.error = { code: "EXECUTION_ERROR", message: rec.error ?? "failed" };
|
|
710
|
+
return out;
|
|
711
|
+
}
|
|
712
|
+
function dataOf(result) {
|
|
713
|
+
if (typeof result !== "object" || result === null || Array.isArray(result)) return { data: { result }, failed: false };
|
|
714
|
+
const r = result;
|
|
715
|
+
const data = {};
|
|
716
|
+
for (const [k, v] of Object.entries(r)) if (!CONTROL.has(k)) data[k] = v;
|
|
717
|
+
return { data, failed: r.onFailure === true };
|
|
718
|
+
}
|
|
719
|
+
var statusFor = (run) => run.status === "completed" ? 200 : run.status === "failed" ? 500 : 202;
|
|
720
|
+
|
|
721
|
+
// src/server/routes-declared.ts
|
|
722
|
+
function stable(v) {
|
|
723
|
+
if (Array.isArray(v)) return `[${v.map(stable).join(",")}]`;
|
|
724
|
+
if (typeof v === "object" && v !== null) return `{${Object.keys(v).sort().map((k) => `${JSON.stringify(k)}:${stable(v[k])}`).join(",")}}`;
|
|
725
|
+
return JSON.stringify(v) ?? "null";
|
|
726
|
+
}
|
|
727
|
+
function idempotentRunId(scope, key) {
|
|
728
|
+
const h = createHash("sha256").update(`${scope}\0${key}`).digest("hex");
|
|
729
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-8${h.slice(17, 20)}-${h.slice(20, 32)}`;
|
|
730
|
+
}
|
|
731
|
+
async function answerDeclared(ctx, res, id, base, replayed, executionTime) {
|
|
732
|
+
const snap = await ctx.runs.snapshot(id, base);
|
|
733
|
+
const extra = { "X-Run-Id": id, ...replayed ? { "Idempotent-Replayed": "true" } : {} };
|
|
734
|
+
if (snap.status === "completed") {
|
|
735
|
+
const { data, failed } = dataOf(snap.result);
|
|
736
|
+
return json(res, failed ? 422 : 200, data, extra);
|
|
737
|
+
}
|
|
738
|
+
if (snap.status === "failed") return json(res, 500, { error: snap.error, runId: id, links: snap.links }, extra);
|
|
739
|
+
if (snap.status === "cancelled") return json(res, 410, { error: { code: "RUN_CANCELLED", message: "the run was cancelled" }, runId: id, links: snap.links }, extra);
|
|
740
|
+
if (executionTime !== void 0) snap.executionTime = executionTime;
|
|
741
|
+
return json(res, 202, snap, { ...extra, Location: snap.links.result, "Retry-After": "2" });
|
|
742
|
+
}
|
|
743
|
+
async function declaredRoute(ctx, req, res, c, m, url, base, given) {
|
|
744
|
+
const { coordinator, runs } = ctx;
|
|
745
|
+
if (c.route.auth !== "none" && !authorized(req, ctx.token)) throw new HttpError(401, "UNAUTHORIZED", "a bearer token is required");
|
|
746
|
+
const { body, form } = c.route.method === "GET" || c.route.method === "DELETE" ? { body: {}, form: false } : await readBody(req, given, ctx.maxBody);
|
|
747
|
+
const { params, callbackUrl, mocks } = paramsFor(c, m, url, body, form, ctx.dev);
|
|
748
|
+
if (callbackUrl) {
|
|
749
|
+
const why = await refuseCallbackUrl(callbackUrl, ctx.callbackPolicy);
|
|
750
|
+
if (why) throw new HttpError(400, "CALLBACK_REFUSED", `callbackUrl refused: ${why}`, [{ path: "callbackUrl", message: why }]);
|
|
751
|
+
}
|
|
752
|
+
const idem = header(req, "idempotency-key");
|
|
753
|
+
const id = idem ? idempotentRunId(`${c.route.method} ${c.route.path}`, idem) : randomUUID();
|
|
754
|
+
if (idem) {
|
|
755
|
+
const before = (await coordinator.record(id))?.params ?? runs.inFlightParams(id);
|
|
756
|
+
if (before) {
|
|
757
|
+
if (stable(before) !== stable(params)) throw new HttpError(409, "IDEMPOTENCY_MISMATCH", "this Idempotency-Key was already used with different parameters");
|
|
758
|
+
return answerDeclared(ctx, res, id, base, true);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
runs.admit();
|
|
762
|
+
const started = Date.now();
|
|
763
|
+
const async = c.route.mode === "async" || wantsAsync(req, url);
|
|
764
|
+
const segment = runs.start(c.endpoint, id, params, mocks);
|
|
765
|
+
const noteWhenPossible = (async () => {
|
|
766
|
+
for (let i = 0; i < 50 && !await coordinator.record(id); i++) await new Promise((r) => setTimeout(r, 20));
|
|
767
|
+
if (!await coordinator.record(id)) return;
|
|
768
|
+
await coordinator.keep(id, "http", { route: { method: c.route.method, path: c.route.path }, ...callbackUrl ? { callbackUrl } : {} });
|
|
769
|
+
if (callbackUrl) runs.callbacks.owe(id);
|
|
770
|
+
})();
|
|
771
|
+
if (async) {
|
|
772
|
+
segment.catch(() => void 0);
|
|
773
|
+
void noteWhenPossible;
|
|
774
|
+
return json(res, 202, await runs.snapshot(id, base), { "X-Run-Id": id, Location: `${base}/runs/${id}/result` });
|
|
775
|
+
}
|
|
776
|
+
if (!await settledWithin(segment, waitBudget(req, ctx.maxWait))) {
|
|
777
|
+
void noteWhenPossible;
|
|
778
|
+
return answerDeclared(ctx, res, id, base, false, Date.now() - started);
|
|
779
|
+
}
|
|
780
|
+
await segment;
|
|
781
|
+
await noteWhenPossible;
|
|
782
|
+
void runs.callbacks.deliver(id);
|
|
783
|
+
return answerDeclared(ctx, res, id, base, false, Date.now() - started);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// src/server/routes-runs.ts
|
|
787
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
788
|
+
async function answerSegment(ctx, req, res, id, url, base, started, segment) {
|
|
789
|
+
const { runs } = ctx;
|
|
790
|
+
if (wantsAsync(req, url)) {
|
|
791
|
+
segment.catch(() => void 0);
|
|
792
|
+
return json(res, 202, await runs.snapshot(id, base), { Location: `${base}/runs/${id}` });
|
|
793
|
+
}
|
|
794
|
+
if (await settledWithin(segment, waitBudget(req, ctx.maxWait))) await segment;
|
|
795
|
+
const snap = await runs.snapshot(id, base);
|
|
796
|
+
snap.executionTime = Date.now() - started;
|
|
797
|
+
return json(res, statusFor(snap), snap, snap.status === "running" ? { Location: snap.links.self, "Retry-After": "2" } : {});
|
|
798
|
+
}
|
|
799
|
+
async function legacyStart(ctx, req, res, endpoint, url, base, given) {
|
|
800
|
+
const { runs } = ctx;
|
|
801
|
+
const { body: b } = await readBody(req, given, ctx.maxBody);
|
|
802
|
+
const envelope = "params" in b && typeof b.params === "object" && b.params !== null && !Array.isArray(b.params) && Object.keys(b).every((k) => ["params", "mocks"].includes(k));
|
|
803
|
+
const params = envelope ? b.params : b;
|
|
804
|
+
const mocks = envelope && ctx.dev && typeof b.mocks === "object" && b.mocks !== null ? b.mocks : void 0;
|
|
805
|
+
runs.admit();
|
|
806
|
+
const id = randomUUID2();
|
|
807
|
+
const started = Date.now();
|
|
808
|
+
return answerSegment(ctx, req, res, id, url, base, started, runs.start(endpoint, id, params, mocks));
|
|
809
|
+
}
|
|
810
|
+
async function resolveRoute(ctx, req, res, id, url, base, given) {
|
|
811
|
+
const { runs } = ctx;
|
|
812
|
+
const { body: b } = await readBody(req, given, ctx.maxBody);
|
|
813
|
+
const hasAnswer = "answer" in b, hasReject = "reject" in b;
|
|
814
|
+
if (hasAnswer === hasReject) throw new HttpError(400, "INVALID_INPUT", "give exactly one of answer or reject");
|
|
815
|
+
const input = hasReject ? { reject: String(b.reject ?? "") } : { answer: b.answer };
|
|
816
|
+
runs.admit();
|
|
817
|
+
const started = Date.now();
|
|
818
|
+
return answerSegment(ctx, req, res, id, url, base, started, runs.resume(id, input));
|
|
819
|
+
}
|
|
820
|
+
async function serveRuns(ctx, req, res, method, p, url, base, given) {
|
|
821
|
+
const { runs, coordinator } = ctx;
|
|
822
|
+
if (method === "GET" && p === "/runs") {
|
|
823
|
+
json(res, 200, await runs.listRuns(url.searchParams.get("workflow") ?? void 0, base));
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
const m = p.match(/^\/runs\/([^/]+)(?:\/(events|resolve|cancel|agent|result))?$/);
|
|
827
|
+
if (!m) return false;
|
|
828
|
+
const id = m[1];
|
|
829
|
+
const snap = await runs.snapshot(id, base);
|
|
830
|
+
if (!snap) throw new HttpError(404, "RUN_NOT_FOUND", `no run with id ${id}`);
|
|
831
|
+
if (!m[2] && method === "GET") {
|
|
832
|
+
json(res, 200, snap);
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
if (m[2] === "result" && method === "GET") {
|
|
836
|
+
await answerDeclared(ctx, res, id, base, false);
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
if (m[2] === "events" && method === "GET") {
|
|
840
|
+
await runs.follow(req, res, id, base);
|
|
841
|
+
return true;
|
|
842
|
+
}
|
|
843
|
+
if (m[2] === "agent" && method === "GET") {
|
|
844
|
+
const rec = await coordinator.record(id);
|
|
845
|
+
const gateId = rec?.agent?.gateId;
|
|
846
|
+
const kept = gateId ? await coordinator.kept(id, transcriptName(gateId)) : void 0;
|
|
847
|
+
if (!kept) throw new HttpError(404, "NO_TRANSCRIPT", "no agent has answered this run");
|
|
848
|
+
json(res, 200, kept);
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
if (m[2] === "resolve" && method === "POST") {
|
|
852
|
+
await resolveRoute(ctx, req, res, id, url, base, given);
|
|
853
|
+
return true;
|
|
854
|
+
}
|
|
855
|
+
if (m[2] === "cancel" && method === "POST") {
|
|
856
|
+
await runs.cancel(id);
|
|
857
|
+
json(res, 200, await runs.snapshot(id, base));
|
|
858
|
+
return true;
|
|
859
|
+
}
|
|
860
|
+
throw new HttpError(405, "METHOD_NOT_ALLOWED", `${method} is not allowed here`);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// src/server/routes-catalog.ts
|
|
864
|
+
function describeEndpoint(e) {
|
|
865
|
+
return { name: e.name, path: e.path, method: e.method, description: e.description, gates: e.gates, routes: e.routes ?? [], inputSchema: e.inputSchema, outputSchema: e.outputSchema };
|
|
866
|
+
}
|
|
867
|
+
function health(ctx) {
|
|
868
|
+
const { registry } = ctx;
|
|
869
|
+
return { status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString(), workflows: registry.getAllEndpoints().length, uptime: registry.getUptime(), version: VERSION, auth: ctx.token ? "token" : "open", agents: ctx.agents, routes: ctx.mounted().compiled.length };
|
|
870
|
+
}
|
|
871
|
+
async function serveCatalog(ctx, req, res, method, p, url, base, given) {
|
|
872
|
+
const { registry } = ctx;
|
|
873
|
+
if (method === "GET" && p === "/health") {
|
|
874
|
+
json(res, 200, health(ctx));
|
|
875
|
+
return true;
|
|
876
|
+
}
|
|
877
|
+
if (method === "GET" && p === "/workflows") {
|
|
878
|
+
json(res, 200, { count: registry.getAllEndpoints().length, workflows: registry.getAllEndpoints().map(describeEndpoint), problems: ctx.mounted().problems });
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
if (method === "GET" && p === "/openapi.json") {
|
|
882
|
+
json(res, 200, ctx.openapi(void 0, base));
|
|
883
|
+
return true;
|
|
884
|
+
}
|
|
885
|
+
if (method === "GET" && p === "/docs") {
|
|
886
|
+
if (!ctx.docs) throw new HttpError(404, "NOT_FOUND", "docs are off. Start with --swagger, or docs: true");
|
|
887
|
+
html(res, swaggerPage(`${base}/openapi.json`));
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
const m = p.match(/^\/workflows\/([^/]+)$/);
|
|
891
|
+
if (!m) return false;
|
|
892
|
+
const endpoint = registry.getEndpoint(decodeSegment(m[1]));
|
|
893
|
+
if (!endpoint) throw new HttpError(404, "WORKFLOW_NOT_FOUND", `Workflow "${m[1]}" not found`);
|
|
894
|
+
if (method === "GET") {
|
|
895
|
+
json(res, 200, describeEndpoint(endpoint));
|
|
896
|
+
return true;
|
|
897
|
+
}
|
|
898
|
+
if (method === "POST") {
|
|
899
|
+
if (!ctx.legacy && (endpoint.routes?.length ?? 0) > 0) throw new HttpError(404, "USE_DECLARED_ROUTE", `use ${endpoint.routes.map((r) => `${r.method} ${r.path}`).join(" or ")}`);
|
|
900
|
+
if (!ctx.legacy) throw new HttpError(404, "NOT_AN_ENDPOINT", `${endpoint.name} declares no @http route`);
|
|
901
|
+
await legacyStart(ctx, req, res, endpoint, url, base, given);
|
|
902
|
+
return true;
|
|
903
|
+
}
|
|
904
|
+
throw new HttpError(405, "METHOD_NOT_ALLOWED", `${method} is not allowed here`);
|
|
905
|
+
}
|
|
906
|
+
function swaggerPage(specUrl) {
|
|
907
|
+
return `<!DOCTYPE html>
|
|
908
|
+
<html lang="en">
|
|
909
|
+
<head>
|
|
910
|
+
<meta charset="UTF-8">
|
|
911
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
912
|
+
<title>Flow Weaver API Documentation</title>
|
|
913
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css">
|
|
914
|
+
</head>
|
|
915
|
+
<body>
|
|
916
|
+
<div id="swagger-ui"></div>
|
|
917
|
+
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
|
|
918
|
+
<script>
|
|
919
|
+
SwaggerUIBundle({ url: ${JSON.stringify(specUrl)}, dom_id: '#swagger-ui', presets: [SwaggerUIBundle.presets.apis, SwaggerUIBundle.SwaggerUIStandalonePreset], layout: 'BaseLayout' });
|
|
920
|
+
</script>
|
|
921
|
+
</body>
|
|
922
|
+
</html>`;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/server/run-driver.ts
|
|
926
|
+
import * as path2 from "node:path";
|
|
927
|
+
import * as fs3 from "node:fs";
|
|
928
|
+
|
|
929
|
+
// src/console/schema.ts
|
|
930
|
+
import * as fs2 from "node:fs";
|
|
931
|
+
import { Project } from "ts-morph";
|
|
932
|
+
var MAX_DEPTH = 4;
|
|
933
|
+
var project;
|
|
934
|
+
var loaded = /* @__PURE__ */ new Map();
|
|
935
|
+
function source(file) {
|
|
936
|
+
project ??= new Project({ compilerOptions: { strict: true, skipLibCheck: true }, skipAddingFilesFromTsConfig: true });
|
|
937
|
+
const mtime = fs2.statSync(file).mtimeMs;
|
|
938
|
+
const existing = project.getSourceFile(file);
|
|
939
|
+
if (existing && loaded.get(file) === mtime) return existing;
|
|
940
|
+
if (existing) existing.refreshFromFileSystemSync();
|
|
941
|
+
const sf = existing ?? project.addSourceFileAtPath(file);
|
|
942
|
+
loaded.set(file, mtime);
|
|
943
|
+
return sf;
|
|
944
|
+
}
|
|
945
|
+
function toSchema(t, depth = 0) {
|
|
946
|
+
if (depth > MAX_DEPTH) return { type: "any", text: t.getText() };
|
|
947
|
+
if (t.isBoolean()) return { type: "boolean" };
|
|
948
|
+
if (t.isUnion()) {
|
|
949
|
+
const parts = t.getUnionTypes();
|
|
950
|
+
const real = parts.filter((p) => !p.isNull() && !p.isUndefined());
|
|
951
|
+
const optional = real.length !== parts.length;
|
|
952
|
+
if (real.length && real.every((p) => p.isBooleanLiteral())) return { type: "boolean", optional };
|
|
953
|
+
if (real.length && real.every((p) => p.isStringLiteral() || p.isNumberLiteral()))
|
|
954
|
+
return { type: "enum", values: real.map((p) => p.getLiteralValue()), optional };
|
|
955
|
+
if (real.length === 1) return { ...toSchema(real[0], depth), optional };
|
|
956
|
+
return { type: "any", text: t.getText(), optional };
|
|
957
|
+
}
|
|
958
|
+
if (t.isString()) return { type: "string" };
|
|
959
|
+
if (t.isNumber()) return { type: "number" };
|
|
960
|
+
if (t.isStringLiteral() || t.isNumberLiteral()) return { type: "enum", values: [t.getLiteralValue()] };
|
|
961
|
+
if (t.isArray()) return { type: "array", items: toSchema(t.getArrayElementTypeOrThrow(), depth + 1), text: t.getText() };
|
|
962
|
+
if (t.isObject()) {
|
|
963
|
+
const props = t.getProperties();
|
|
964
|
+
if (!props.length || t.getStringIndexType()) return { type: "object", text: t.getText() };
|
|
965
|
+
const fields = {};
|
|
966
|
+
for (const p of props) {
|
|
967
|
+
const decl = p.getDeclarations()[0];
|
|
968
|
+
const s = decl ? toSchema(p.getTypeAtLocation(decl), depth + 1) : { type: "any" };
|
|
969
|
+
fields[p.getName()] = { ...s, optional: s.optional || p.isOptional() };
|
|
970
|
+
}
|
|
971
|
+
return { type: "object", fields, text: t.getText() };
|
|
972
|
+
}
|
|
973
|
+
return { type: "any", text: t.getText() };
|
|
974
|
+
}
|
|
975
|
+
function gateOutputSchemas(ast, gateId, fallbackFile) {
|
|
976
|
+
const typeOf = (id) => {
|
|
977
|
+
const inst = ast.instances.find((i) => i.id === id);
|
|
978
|
+
return inst ? ast.nodeTypes.find((n) => n.name === inst.nodeType) ?? ast.nodeTypes.find((n) => n.functionName === inst.nodeType) : void 0;
|
|
979
|
+
};
|
|
980
|
+
const nt = typeOf(gateId);
|
|
981
|
+
const nodeFile = nt?.sourceLocation?.file ?? fallbackFile;
|
|
982
|
+
if (nt?.functionText) {
|
|
983
|
+
const own = nodeOutputSchema(nodeFile, nt.functionName);
|
|
984
|
+
if (own && Object.keys(own).length) return own;
|
|
985
|
+
}
|
|
986
|
+
const control = /* @__PURE__ */ new Set(["execute", "onSuccess", "onFailure"]);
|
|
987
|
+
const out = {};
|
|
988
|
+
for (const conn of ast.connections) {
|
|
989
|
+
if (conn.from.node !== gateId || control.has(conn.from.port)) continue;
|
|
990
|
+
const targetType = typeOf(conn.to.node);
|
|
991
|
+
if (!targetType?.functionText) continue;
|
|
992
|
+
const schema = nodeInputSchema(targetType.sourceLocation?.file ?? fallbackFile, targetType.functionName, conn.to.port);
|
|
993
|
+
if (schema) out[conn.from.port] = schema;
|
|
994
|
+
}
|
|
995
|
+
return Object.keys(out).length ? out : null;
|
|
996
|
+
}
|
|
997
|
+
function workflowParamsSchema(file, fnName) {
|
|
998
|
+
try {
|
|
999
|
+
const params = source(file).getFunction(fnName)?.getParameters()[1]?.getType();
|
|
1000
|
+
if (!params) return null;
|
|
1001
|
+
const s = toSchema(params);
|
|
1002
|
+
return s.type === "object" && s.fields ? s.fields : null;
|
|
1003
|
+
} catch {
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function nodeInputSchema(file, fnName, paramName) {
|
|
1008
|
+
try {
|
|
1009
|
+
const fn = source(file).getFunction(fnName);
|
|
1010
|
+
if (!fn) return null;
|
|
1011
|
+
const params = fn.getParameters();
|
|
1012
|
+
const param = params.find((p) => p.getName() === paramName);
|
|
1013
|
+
if (!param) return null;
|
|
1014
|
+
const s = toSchema(param.getType());
|
|
1015
|
+
return { ...s, optional: s.optional || param.hasQuestionToken() };
|
|
1016
|
+
} catch {
|
|
1017
|
+
return null;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
function nodeOutputSchema(file, fnName) {
|
|
1021
|
+
try {
|
|
1022
|
+
const fn = source(file).getFunction(fnName);
|
|
1023
|
+
if (!fn) return null;
|
|
1024
|
+
let ret = fn.getReturnType();
|
|
1025
|
+
if (ret.getSymbol()?.getName() === "Promise") ret = ret.getTypeArguments()[0];
|
|
1026
|
+
const s = toSchema(ret);
|
|
1027
|
+
if (s.type !== "object" || !s.fields) return null;
|
|
1028
|
+
const { onSuccess: _s, onFailure: _f, ...data } = s.fields;
|
|
1029
|
+
return data;
|
|
1030
|
+
} catch {
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// src/server/callback-delivery.ts
|
|
1036
|
+
import { createHmac } from "node:crypto";
|
|
1037
|
+
var CALLBACK_BACKOFF_MS = [2e3, 1e4, 6e4, 3e5, 9e5];
|
|
1038
|
+
var ATTEMPT_TIMEOUT_MS = 1e4;
|
|
1039
|
+
function createCallbackDelivery(opts) {
|
|
1040
|
+
const { coordinator } = opts;
|
|
1041
|
+
const now = opts.now ?? Date.now;
|
|
1042
|
+
const pending = /* @__PURE__ */ new Set();
|
|
1043
|
+
const delivering = /* @__PURE__ */ new Set();
|
|
1044
|
+
function bodyFor(rec) {
|
|
1045
|
+
const body = { runId: rec.runId, workflow: rec.workflowName, status: rec.status };
|
|
1046
|
+
if (rec.status === "completed") {
|
|
1047
|
+
const { data, failed } = opts.outputs(rec.result);
|
|
1048
|
+
body.result = data;
|
|
1049
|
+
body.failed = failed;
|
|
1050
|
+
}
|
|
1051
|
+
if (rec.status === "failed") body.error = { code: "EXECUTION_ERROR", message: rec.error };
|
|
1052
|
+
return body;
|
|
1053
|
+
}
|
|
1054
|
+
async function deliver(id) {
|
|
1055
|
+
const note = await coordinator.kept(id, "http");
|
|
1056
|
+
if (!note?.callbackUrl || note.delivered || note.gaveUp) {
|
|
1057
|
+
pending.delete(id);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const rec = await coordinator.record(id);
|
|
1061
|
+
if (!rec) {
|
|
1062
|
+
pending.delete(id);
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (rec.status === "waiting" || opts.inFlight(id)) {
|
|
1066
|
+
pending.add(id);
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
if (note.nextAt && Date.parse(note.nextAt) > now()) {
|
|
1070
|
+
pending.add(id);
|
|
1071
|
+
return;
|
|
1072
|
+
}
|
|
1073
|
+
if (delivering.has(id)) return;
|
|
1074
|
+
delivering.add(id);
|
|
1075
|
+
const attempt = (note.attempts ?? 0) + 1;
|
|
1076
|
+
try {
|
|
1077
|
+
const text = JSON.stringify(bodyFor(rec));
|
|
1078
|
+
const headers = { "Content-Type": "application/json", "X-Flow-Weaver-Run": id, "X-Flow-Weaver-Status": rec.status, "X-Flow-Weaver-Attempt": String(attempt) };
|
|
1079
|
+
if (opts.token) headers["X-Flow-Weaver-Signature"] = `sha256=${createHmac("sha256", opts.token).update(text).digest("hex")}`;
|
|
1080
|
+
let error = "";
|
|
1081
|
+
let status;
|
|
1082
|
+
try {
|
|
1083
|
+
const target = await callbackTarget(note.callbackUrl, opts.policy);
|
|
1084
|
+
if ("refused" in target) throw new Error(`callbackUrl refused at delivery: ${target.refused}`);
|
|
1085
|
+
status = await postCallback(target, headers, text, ATTEMPT_TIMEOUT_MS);
|
|
1086
|
+
if (status >= 200 && status < 300) {
|
|
1087
|
+
await coordinator.keep(id, "http", { ...note, attempts: attempt, delivered: new Date(now()).toISOString() });
|
|
1088
|
+
pending.delete(id);
|
|
1089
|
+
opts.onCallback?.({ runId: id, url: note.callbackUrl, ok: true, status, attempt });
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
error = status >= 300 && status < 400 ? `callback answered ${status}, redirects are not followed` : `callback answered ${status}`;
|
|
1093
|
+
} catch (e) {
|
|
1094
|
+
error = getErrorMessage(e);
|
|
1095
|
+
}
|
|
1096
|
+
const gaveUp = attempt >= CALLBACK_BACKOFF_MS.length;
|
|
1097
|
+
const next = { ...note, attempts: attempt, lastError: error, ...gaveUp ? { gaveUp: new Date(now()).toISOString() } : { nextAt: new Date(now() + CALLBACK_BACKOFF_MS[attempt - 1]).toISOString() } };
|
|
1098
|
+
if (await coordinator.record(id)) await coordinator.keep(id, "http", next);
|
|
1099
|
+
if (gaveUp) pending.delete(id);
|
|
1100
|
+
else pending.add(id);
|
|
1101
|
+
opts.onCallback?.({ runId: id, url: note.callbackUrl, ok: false, status, error, attempt, gaveUp });
|
|
1102
|
+
} finally {
|
|
1103
|
+
delivering.delete(id);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
return {
|
|
1107
|
+
deliver,
|
|
1108
|
+
/** A run now owes a callback: remember it, and try at once. */
|
|
1109
|
+
owe(id) {
|
|
1110
|
+
pending.add(id);
|
|
1111
|
+
void deliver(id);
|
|
1112
|
+
},
|
|
1113
|
+
/** Find the runs of these workflows that still owe a callback, as when the API starts. */
|
|
1114
|
+
async scan(workflowNames) {
|
|
1115
|
+
for (const s of await coordinator.list()) {
|
|
1116
|
+
if (!workflowNames.has(s.workflowName)) continue;
|
|
1117
|
+
const note = await coordinator.kept(s.runId, "http");
|
|
1118
|
+
if (note?.callbackUrl && !note.delivered && !note.gaveUp) pending.add(s.runId);
|
|
1119
|
+
}
|
|
1120
|
+
},
|
|
1121
|
+
/** Try every callback still owed. */
|
|
1122
|
+
async deliverPending() {
|
|
1123
|
+
for (const id of [...pending]) await deliver(id);
|
|
1124
|
+
},
|
|
1125
|
+
/** The runs still owing a callback. */
|
|
1126
|
+
pending: () => [...pending]
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// src/server/run-driver.ts
|
|
1131
|
+
function createRunDriver(opts) {
|
|
1132
|
+
const { dir, coordinator } = opts;
|
|
1133
|
+
const live = /* @__PURE__ */ new Map();
|
|
1134
|
+
const agentEvents = /* @__PURE__ */ new Map();
|
|
1135
|
+
const subs = /* @__PURE__ */ new Map();
|
|
1136
|
+
let profilesCache;
|
|
1137
|
+
const callbacks = createCallbackDelivery({
|
|
1138
|
+
coordinator,
|
|
1139
|
+
policy: opts.callbacks,
|
|
1140
|
+
token: opts.token,
|
|
1141
|
+
inFlight: (id) => live.has(id),
|
|
1142
|
+
outputs: (result) => dataOf(result),
|
|
1143
|
+
onCallback: opts.onCallback
|
|
1144
|
+
});
|
|
1145
|
+
function profiles() {
|
|
1146
|
+
const file = path2.join(dir, ".flowweaver", "agents.yaml");
|
|
1147
|
+
let mtime;
|
|
1148
|
+
try {
|
|
1149
|
+
mtime = fs3.statSync(file).mtimeMs;
|
|
1150
|
+
} catch {
|
|
1151
|
+
mtime = 0;
|
|
1152
|
+
}
|
|
1153
|
+
if (!profilesCache || profilesCache.mtime !== mtime) profilesCache = { mtime, profiles: loadAgentProfiles(dir) };
|
|
1154
|
+
return profilesCache.profiles;
|
|
1155
|
+
}
|
|
1156
|
+
async function snapshot(id, base = "") {
|
|
1157
|
+
const l = live.get(id);
|
|
1158
|
+
const rec = await coordinator.record(id);
|
|
1159
|
+
return runView(id, base, l, rec);
|
|
1160
|
+
}
|
|
1161
|
+
async function listRuns(workflow, base) {
|
|
1162
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1163
|
+
const runs = [];
|
|
1164
|
+
for (const l of live.values()) {
|
|
1165
|
+
if (workflow && l.workflow !== workflow) continue;
|
|
1166
|
+
const s = await snapshot(l.id, base);
|
|
1167
|
+
if (s) {
|
|
1168
|
+
runs.push(s);
|
|
1169
|
+
seen.add(l.id);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
const names = opts.workflowNames();
|
|
1173
|
+
for (const r of await coordinator.list()) {
|
|
1174
|
+
if (seen.has(r.runId) || !names.has(r.workflowName)) continue;
|
|
1175
|
+
if (workflow && r.workflowName !== workflow) continue;
|
|
1176
|
+
const s = await snapshot(r.runId, base);
|
|
1177
|
+
if (s) runs.push(s);
|
|
1178
|
+
}
|
|
1179
|
+
runs.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
1180
|
+
return { count: runs.length, runs };
|
|
1181
|
+
}
|
|
1182
|
+
function push(id, msg) {
|
|
1183
|
+
const set = subs.get(id);
|
|
1184
|
+
if (!set?.size) return;
|
|
1185
|
+
const line = `data: ${JSON.stringify(msg)}
|
|
1186
|
+
|
|
1187
|
+
`;
|
|
1188
|
+
for (const res of set) res.write(line);
|
|
1189
|
+
}
|
|
1190
|
+
async function announce(id) {
|
|
1191
|
+
const run = await snapshot(id);
|
|
1192
|
+
push(id, { type: "run", run });
|
|
1193
|
+
if (run) {
|
|
1194
|
+
try {
|
|
1195
|
+
opts.onRun?.(run);
|
|
1196
|
+
} catch {
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async function drive(l, segment) {
|
|
1201
|
+
live.set(l.id, l);
|
|
1202
|
+
const onEvent = (ev) => {
|
|
1203
|
+
const entry = { t: ev.timestamp, e: ev.data ?? ev };
|
|
1204
|
+
l.events.push(entry);
|
|
1205
|
+
push(l.id, { type: "event", ...entry });
|
|
1206
|
+
};
|
|
1207
|
+
try {
|
|
1208
|
+
await segment(l, onEvent);
|
|
1209
|
+
live.delete(l.id);
|
|
1210
|
+
} catch (err) {
|
|
1211
|
+
if (await coordinator.record(l.id)) live.delete(l.id);
|
|
1212
|
+
else l.error = getErrorMessage(err);
|
|
1213
|
+
}
|
|
1214
|
+
await announce(l.id);
|
|
1215
|
+
void afterSegment(l.id);
|
|
1216
|
+
}
|
|
1217
|
+
async function afterSegment(id) {
|
|
1218
|
+
const rec = await coordinator.record(id);
|
|
1219
|
+
if (!rec) return;
|
|
1220
|
+
if (rec.status === "completed" || rec.status === "failed" || rec.status === "cancelled") {
|
|
1221
|
+
void callbacks.deliver(id);
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
if (!opts.agents || rec.status !== "waiting" || rec.gate?.kind !== "agent") return;
|
|
1225
|
+
try {
|
|
1226
|
+
const step = await answerAgentGate(coordinator, id, {
|
|
1227
|
+
projectDir: dir,
|
|
1228
|
+
env: opts.env,
|
|
1229
|
+
profiles: profiles(),
|
|
1230
|
+
provider: opts.agentProvider,
|
|
1231
|
+
outputSchema: (r) => outputShape(r),
|
|
1232
|
+
onEvent: (e) => {
|
|
1233
|
+
const entry = { t: Date.now(), e };
|
|
1234
|
+
(agentEvents.get(id) ?? agentEvents.set(id, []).get(id)).push(entry);
|
|
1235
|
+
push(id, { ...e, t: entry.t });
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
await announce(id);
|
|
1239
|
+
if (step.kind === "answer") await resume(id, { answer: step.answer });
|
|
1240
|
+
else if (step.kind === "reject") await resume(id, { reject: step.reason });
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
if (await noteAnswerMisfit(coordinator, id, err)) await announce(id);
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
async function outputShape(rec) {
|
|
1246
|
+
try {
|
|
1247
|
+
const parsed = await parseWorkflow(rec.filePath, { workflowName: rec.workflowName, projectDir: path2.dirname(rec.filePath) });
|
|
1248
|
+
if (parsed.errors.length || !rec.gate) return void 0;
|
|
1249
|
+
const inst = parsed.ast.instances.find((i) => i.id === rec.gate.node);
|
|
1250
|
+
const nt = inst ? parsed.ast.nodeTypes.find((n) => n.name === inst.nodeType) ?? parsed.ast.nodeTypes.find((n) => n.functionName === inst.nodeType) : void 0;
|
|
1251
|
+
const types = Object.fromEntries(rec.gate.outputs.map((o) => [o, nt?.outputs?.[o]?.tsType ?? "unknown"]));
|
|
1252
|
+
return { schema: gateOutputSchemas(parsed.ast, rec.gate.node, rec.filePath), types };
|
|
1253
|
+
} catch {
|
|
1254
|
+
return void 0;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
function admit() {
|
|
1258
|
+
if (live.size >= opts.maxInFlight) throw new HttpError(503, "BUSY", `${live.size} runs are in flight, the limit here. Try again shortly`, void 0, { "Retry-After": "2" });
|
|
1259
|
+
}
|
|
1260
|
+
async function start(endpoint, id, params, mocks) {
|
|
1261
|
+
await drive({ id, workflow: endpoint.name, params, startedAt: Date.now(), events: [], abort: new AbortController() }, (l, onEvent) => coordinator.start(
|
|
1262
|
+
{ filePath: endpoint.filePath, workflowName: endpoint.functionName, params, runId: id, mocks, agents: opts.agents ? "auto" : "manual", origin: opts.origin ?? "http" },
|
|
1263
|
+
{ onEvent, trace: opts.trace === true, abortSignal: l.abort.signal }
|
|
1264
|
+
));
|
|
1265
|
+
}
|
|
1266
|
+
async function resume(id, input) {
|
|
1267
|
+
if (live.has(id)) throw new HttpError(409, "RUN_IN_FLIGHT", "the run is already resuming");
|
|
1268
|
+
const rec = await coordinator.record(id);
|
|
1269
|
+
if (rec?.gate && isAnswering(rec.agent, rec.gate.id)) throw new HttpError(409, "AGENT_ANSWERING", `agent profile ${rec.agent.profile} is answering this gate`);
|
|
1270
|
+
const resolve2 = "reject" in input ? { reject: input.reject } : { answer: input.answer };
|
|
1271
|
+
await coordinator.checkResume({ runId: id, input: resolve2 });
|
|
1272
|
+
if (!rec) throw new RunNotFoundError(id);
|
|
1273
|
+
await drive({ id, workflow: rec.workflowName, params: rec.params, startedAt: Date.parse(rec.createdAt), events: [], abort: new AbortController() }, (l, onEvent) => coordinator.resume({ runId: id, input: resolve2 }, { onEvent, trace: opts.trace === true, abortSignal: l.abort.signal }));
|
|
1274
|
+
}
|
|
1275
|
+
async function cancel(id) {
|
|
1276
|
+
const l = live.get(id);
|
|
1277
|
+
if (l) {
|
|
1278
|
+
l.abort.abort();
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if ((await coordinator.record(id))?.status === "waiting") {
|
|
1282
|
+
await coordinator.cancel(id);
|
|
1283
|
+
await announce(id);
|
|
1284
|
+
void callbacks.deliver(id);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
async function tick() {
|
|
1288
|
+
let moved;
|
|
1289
|
+
try {
|
|
1290
|
+
moved = await coordinator.tick();
|
|
1291
|
+
} catch {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
for (const run of [...moved.woke, ...moved.timedOut]) {
|
|
1295
|
+
await announce(run.runId);
|
|
1296
|
+
await afterSegment(run.runId);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
async function follow(req, res, id, base) {
|
|
1300
|
+
const first = await snapshot(id, base);
|
|
1301
|
+
const kept = await coordinator.trace(id);
|
|
1302
|
+
res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" });
|
|
1303
|
+
res.write(`data: ${JSON.stringify({ type: "run", run: first })}
|
|
1304
|
+
|
|
1305
|
+
`);
|
|
1306
|
+
const entries = [];
|
|
1307
|
+
for (const e of [...kept, ...live.get(id)?.events ?? []]) entries.push({ t: e.t, line: JSON.stringify({ type: "event", ...e }) });
|
|
1308
|
+
for (const a of agentEvents.get(id) ?? []) entries.push({ t: a.t, line: JSON.stringify({ ...a.e, t: a.t }) });
|
|
1309
|
+
entries.sort((a, b) => a.t - b.t);
|
|
1310
|
+
for (const e of entries) res.write(`data: ${e.line}
|
|
1311
|
+
|
|
1312
|
+
`);
|
|
1313
|
+
res.write(`data: ${JSON.stringify({ type: "synced" })}
|
|
1314
|
+
|
|
1315
|
+
`);
|
|
1316
|
+
const set = subs.get(id) ?? subs.set(id, /* @__PURE__ */ new Set()).get(id);
|
|
1317
|
+
set.add(res);
|
|
1318
|
+
req.on("close", () => {
|
|
1319
|
+
set.delete(res);
|
|
1320
|
+
if (!set.size) subs.delete(id);
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
return {
|
|
1324
|
+
callbacks,
|
|
1325
|
+
admit,
|
|
1326
|
+
start,
|
|
1327
|
+
resume,
|
|
1328
|
+
cancel,
|
|
1329
|
+
tick,
|
|
1330
|
+
snapshot,
|
|
1331
|
+
listRuns,
|
|
1332
|
+
follow,
|
|
1333
|
+
/** The parameters of a run this process is driving, before the store has its record. */
|
|
1334
|
+
inFlightParams: (id) => live.get(id)?.params,
|
|
1335
|
+
/** Stop what is in flight and end every stream. */
|
|
1336
|
+
close() {
|
|
1337
|
+
for (const l of live.values()) l.abort.abort();
|
|
1338
|
+
for (const set of subs.values()) for (const res of set) res.end();
|
|
1339
|
+
subs.clear();
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// src/server/transport.ts
|
|
1345
|
+
async function fetchAdapter(handle, request3, opts) {
|
|
1346
|
+
const url = new URL(request3.url);
|
|
1347
|
+
const headers = {};
|
|
1348
|
+
request3.headers.forEach((v, k) => {
|
|
1349
|
+
headers[k.toLowerCase()] = v;
|
|
1350
|
+
});
|
|
1351
|
+
const closeListeners = [];
|
|
1352
|
+
request3.signal?.addEventListener("abort", () => closeListeners.forEach((f) => f()));
|
|
1353
|
+
const req = {
|
|
1354
|
+
method: request3.method,
|
|
1355
|
+
url: url.pathname + url.search,
|
|
1356
|
+
headers,
|
|
1357
|
+
async *[Symbol.asyncIterator]() {
|
|
1358
|
+
if (!request3.body) return;
|
|
1359
|
+
const reader = request3.body.getReader();
|
|
1360
|
+
for (; ; ) {
|
|
1361
|
+
const { value, done } = await reader.read();
|
|
1362
|
+
if (done) return;
|
|
1363
|
+
yield value;
|
|
1364
|
+
}
|
|
1365
|
+
},
|
|
1366
|
+
on: (_e, l) => closeListeners.push(l)
|
|
1367
|
+
};
|
|
1368
|
+
const encoder = new TextEncoder();
|
|
1369
|
+
let controller;
|
|
1370
|
+
let status = 200;
|
|
1371
|
+
const outHeaders = new Headers();
|
|
1372
|
+
let resolveResponse;
|
|
1373
|
+
const response = new Promise((r) => {
|
|
1374
|
+
resolveResponse = r;
|
|
1375
|
+
});
|
|
1376
|
+
const stream = new ReadableStream({ start(c) {
|
|
1377
|
+
controller = c;
|
|
1378
|
+
}, cancel() {
|
|
1379
|
+
closeListeners.forEach((f) => f());
|
|
1380
|
+
} });
|
|
1381
|
+
let sent = false, ended = false;
|
|
1382
|
+
const send = () => {
|
|
1383
|
+
if (sent) return;
|
|
1384
|
+
sent = true;
|
|
1385
|
+
resolveResponse(new Response(status === 204 || status === 304 ? null : stream, { status, headers: outHeaders }));
|
|
1386
|
+
};
|
|
1387
|
+
const res = {
|
|
1388
|
+
get headersSent() {
|
|
1389
|
+
return sent;
|
|
1390
|
+
},
|
|
1391
|
+
writeHead(s, h) {
|
|
1392
|
+
status = s;
|
|
1393
|
+
for (const [k, v] of Object.entries(h ?? {})) outHeaders.set(k, String(v));
|
|
1394
|
+
send();
|
|
1395
|
+
return this;
|
|
1396
|
+
},
|
|
1397
|
+
setHeader(k, v) {
|
|
1398
|
+
outHeaders.set(k, v);
|
|
1399
|
+
return this;
|
|
1400
|
+
},
|
|
1401
|
+
write(chunk) {
|
|
1402
|
+
send();
|
|
1403
|
+
controller?.enqueue(encoder.encode(chunk));
|
|
1404
|
+
return true;
|
|
1405
|
+
},
|
|
1406
|
+
end(chunk) {
|
|
1407
|
+
if (ended) return this;
|
|
1408
|
+
if (chunk) this.write(chunk);
|
|
1409
|
+
send();
|
|
1410
|
+
ended = true;
|
|
1411
|
+
try {
|
|
1412
|
+
controller?.close();
|
|
1413
|
+
} catch {
|
|
1414
|
+
}
|
|
1415
|
+
return this;
|
|
1416
|
+
}
|
|
1417
|
+
};
|
|
1418
|
+
void handle(req, res, opts).then((handled) => {
|
|
1419
|
+
if (!handled && !sent) {
|
|
1420
|
+
status = 404;
|
|
1421
|
+
outHeaders.set("Content-Type", "application/json");
|
|
1422
|
+
res.end(JSON.stringify({ error: { code: "NOT_FOUND", message: `no route for ${request3.method} ${url.pathname}` } }));
|
|
1423
|
+
} else if (!ended) res.end();
|
|
1424
|
+
}).catch((err) => {
|
|
1425
|
+
if (!sent) {
|
|
1426
|
+
status = 500;
|
|
1427
|
+
res.end(JSON.stringify({ error: { code: "INTERNAL", message: getErrorMessage(err) } }));
|
|
1428
|
+
} else res.end();
|
|
1429
|
+
});
|
|
1430
|
+
return response;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// src/server/api.ts
|
|
1434
|
+
var DEFAULT_MAX_BODY = 1024 * 1024;
|
|
1435
|
+
function createWorkflowApi(options) {
|
|
1436
|
+
const dir = path3.resolve(options.dir);
|
|
1437
|
+
const registry = new WorkflowRegistry(dir);
|
|
1438
|
+
const coordinator = createLocalCoordinator(options.store ? { store: options.store } : { rootDir: options.runsDir ?? defaultRunsDir(dir) });
|
|
1439
|
+
let compiled = [];
|
|
1440
|
+
let routeProblems = [];
|
|
1441
|
+
let readyPromise;
|
|
1442
|
+
const legacy = options.legacyRoutes !== false;
|
|
1443
|
+
const agentsOn = options.agents !== false;
|
|
1444
|
+
const runs = createRunDriver({
|
|
1445
|
+
dir,
|
|
1446
|
+
coordinator,
|
|
1447
|
+
workflowNames: () => new Set(registry.getAllEndpoints().map((e) => e.functionName)),
|
|
1448
|
+
agents: agentsOn,
|
|
1449
|
+
env: options.env,
|
|
1450
|
+
agentProvider: options.agentProvider,
|
|
1451
|
+
trace: options.trace,
|
|
1452
|
+
origin: options.origin,
|
|
1453
|
+
maxInFlight: options.maxInFlight ?? 32,
|
|
1454
|
+
onRun: options.onRun,
|
|
1455
|
+
callbacks: options.callbacks,
|
|
1456
|
+
token: options.token,
|
|
1457
|
+
onCallback: options.onCallback
|
|
1458
|
+
});
|
|
1459
|
+
let sweeper;
|
|
1460
|
+
const ctx = {
|
|
1461
|
+
registry,
|
|
1462
|
+
coordinator,
|
|
1463
|
+
runs,
|
|
1464
|
+
token: options.token,
|
|
1465
|
+
dev: options.dev,
|
|
1466
|
+
docs: options.docs,
|
|
1467
|
+
legacy,
|
|
1468
|
+
agents: agentsOn,
|
|
1469
|
+
maxBody: options.maxBodyBytes ?? DEFAULT_MAX_BODY,
|
|
1470
|
+
maxWait: options.maxWaitMs ?? 6e4,
|
|
1471
|
+
callbackPolicy: options.callbacks,
|
|
1472
|
+
mounted: () => ({ compiled, problems: routeProblems }),
|
|
1473
|
+
openapi: (serverUrl, base) => openapi(serverUrl, base)
|
|
1474
|
+
};
|
|
1475
|
+
function compileRoutes() {
|
|
1476
|
+
({ compiled, problems: routeProblems } = mountRoutes(registry.getAllEndpoints()));
|
|
1477
|
+
}
|
|
1478
|
+
async function ready() {
|
|
1479
|
+
readyPromise ??= (async () => {
|
|
1480
|
+
await registry.initialize();
|
|
1481
|
+
compileRoutes();
|
|
1482
|
+
if (options.watch) await registry.startWatching(compileRoutes);
|
|
1483
|
+
await reclaimStaleAgentAnswers(coordinator);
|
|
1484
|
+
await runs.callbacks.scan(new Set(registry.getAllEndpoints().map((e) => e.functionName)));
|
|
1485
|
+
const every = options.callbacks?.sweepMs ?? 3e3;
|
|
1486
|
+
sweeper = setInterval(() => {
|
|
1487
|
+
void sweep();
|
|
1488
|
+
}, every);
|
|
1489
|
+
sweeper.unref?.();
|
|
1490
|
+
})();
|
|
1491
|
+
return readyPromise;
|
|
1492
|
+
}
|
|
1493
|
+
async function sweep() {
|
|
1494
|
+
await runs.tick();
|
|
1495
|
+
await runs.callbacks.deliverPending();
|
|
1496
|
+
}
|
|
1497
|
+
async function handle(req, res, opts = {}) {
|
|
1498
|
+
await ready();
|
|
1499
|
+
const base = (opts.basePath ?? "").replace(/\/$/, "");
|
|
1500
|
+
const url = new URL(req.url ?? "/", "http://x");
|
|
1501
|
+
let p = url.pathname;
|
|
1502
|
+
if (base && p.startsWith(base)) p = p.slice(base.length) || "/";
|
|
1503
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
1504
|
+
try {
|
|
1505
|
+
for (const c of compiled) {
|
|
1506
|
+
if (c.route.method !== method) continue;
|
|
1507
|
+
const m = p.match(c.regex);
|
|
1508
|
+
if (!m) continue;
|
|
1509
|
+
cors(req, res, options.cors);
|
|
1510
|
+
await declaredRoute(ctx, req, res, c, m, url, base, opts.body);
|
|
1511
|
+
return true;
|
|
1512
|
+
}
|
|
1513
|
+
if (method === "OPTIONS" && (compiled.some((c) => p.match(c.regex)) || isReserved(p))) {
|
|
1514
|
+
cors(req, res, options.cors);
|
|
1515
|
+
res.writeHead(204);
|
|
1516
|
+
res.end();
|
|
1517
|
+
return true;
|
|
1518
|
+
}
|
|
1519
|
+
if (!isReserved(p)) return false;
|
|
1520
|
+
cors(req, res, options.cors);
|
|
1521
|
+
const open = p === "/health" || options.docs && (p === "/docs" || p === "/openapi.json");
|
|
1522
|
+
if (!open && !authorized(req, options.token)) throw new HttpError(401, "UNAUTHORIZED", "a bearer token is required");
|
|
1523
|
+
if (await serveCatalog(ctx, req, res, method, p, url, base, opts.body)) return true;
|
|
1524
|
+
if (await serveRuns(ctx, req, res, method, p, url, base, opts.body)) return true;
|
|
1525
|
+
throw new HttpError(404, "NOT_FOUND", `no route for ${method} ${p}`);
|
|
1526
|
+
} catch (err) {
|
|
1527
|
+
const e = errorToHttp(err);
|
|
1528
|
+
const body = { error: { code: e.code, message: e.message, ...e.details !== void 0 ? { details: e.details } : {}, ...options.dev && err instanceof Error && err.stack ? { stack: err.stack } : {} } };
|
|
1529
|
+
if (!res.headersSent) json(res, e.status, body, e.headers ?? {});
|
|
1530
|
+
else res.end();
|
|
1531
|
+
return true;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
function openapi(serverUrl, base = "") {
|
|
1535
|
+
return buildOpenApi({ endpoints: registry.getAllEndpoints(), mounted: compiled.map((c) => ({ endpoint: c.endpoint, route: c.route, keys: c.keys })), legacy, secured: !!options.token, serverUrl, base });
|
|
1536
|
+
}
|
|
1537
|
+
const api = {
|
|
1538
|
+
ready,
|
|
1539
|
+
handle,
|
|
1540
|
+
node: () => (req, res) => {
|
|
1541
|
+
handle(req, res).then((handled) => {
|
|
1542
|
+
if (!handled && !res.headersSent) json(res, 404, { error: { code: "NOT_FOUND", message: `no route for ${req.method} ${req.url}` } });
|
|
1543
|
+
}).catch((err) => {
|
|
1544
|
+
if (!res.headersSent) json(res, 500, { error: { code: "INTERNAL", message: getErrorMessage(err) } });
|
|
1545
|
+
});
|
|
1546
|
+
},
|
|
1547
|
+
express: () => (req, res, next) => {
|
|
1548
|
+
handle(req, res, { basePath: req.baseUrl ?? "" }).then((handled) => {
|
|
1549
|
+
if (!handled) next();
|
|
1550
|
+
}).catch(next);
|
|
1551
|
+
},
|
|
1552
|
+
fetch: (request3, opts) => fetchAdapter(handle, request3, opts),
|
|
1553
|
+
openapi: (serverUrl) => openapi(serverUrl),
|
|
1554
|
+
routes: () => ({
|
|
1555
|
+
routes: compiled.map((c) => ({ method: c.route.method, path: c.route.path, workflow: c.endpoint.name, file: c.endpoint.filePath, mode: c.route.mode ?? "sync", auth: c.route.auth ?? "bearer", callback: !!c.route.callback, gates: c.endpoint.gates ?? 0 })),
|
|
1556
|
+
problems: routeProblems
|
|
1557
|
+
}),
|
|
1558
|
+
endpoints: () => registry.getAllEndpoints(),
|
|
1559
|
+
deliverCallbacks: sweep,
|
|
1560
|
+
tick: runs.tick,
|
|
1561
|
+
close: async () => {
|
|
1562
|
+
if (sweeper) clearInterval(sweeper);
|
|
1563
|
+
sweeper = void 0;
|
|
1564
|
+
await registry.stopWatching();
|
|
1565
|
+
runs.close();
|
|
1566
|
+
}
|
|
1567
|
+
};
|
|
1568
|
+
return api;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
export {
|
|
1572
|
+
WorkflowRegistry,
|
|
1573
|
+
buildOpenApi,
|
|
1574
|
+
isLoopback,
|
|
1575
|
+
RESERVED_PATHS,
|
|
1576
|
+
planRoutes,
|
|
1577
|
+
gateOutputSchemas,
|
|
1578
|
+
workflowParamsSchema,
|
|
1579
|
+
createWorkflowApi
|
|
1580
|
+
};
|