elanous 0.2.10 → 0.2.11
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
- package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-b12b6d2f8d2d1aea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-35414e0a007b4082.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
- package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -0
- package/apps/pwa/out/inside/index.txt +31 -0
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -0
- package/apps/pwa/out/outputs/index.txt +30 -0
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -24
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -24
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/drafts/draft-cleanup.yaml +19 -0
- package/graphs/drafts/recipes.yaml +23 -0
- package/graphs/intake/intake-daily.yaml +2 -1
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/ops/secret-exposure.yaml +24 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/video/explainer-line.yaml +2 -2
- package/package.json +2 -1
- package/plugins/elanous-hwp/README.md +25 -0
- package/plugins/elanous-hwp/cli.ts +22 -0
- package/plugins/elanous-hwp/converter.ts +237 -0
- package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
- package/plugins/elanous-hwp/plugin.json +16 -0
- package/plugins/elanous-hwp/plugin.ts +40 -0
- package/scripts/ci-public-export-leak-gate.ts +75 -14
- package/scripts/ci-public-leak-gate.ts +44 -9
- package/scripts/context-hooks/claude-stop.sh +4 -0
- package/scripts/context-hooks/emit.ts +24 -0
- package/scripts/context-hooks/post-tool-use.sh +4 -0
- package/scripts/coord-channel-watch.sh +12 -0
- package/scripts/coord-requests-bridge.ts +143 -0
- package/scripts/field-feed/lib.ts +4 -0
- package/scripts/fleet/node-setup.sh +20 -3
- package/scripts/homebrew-formula-bump.ts +69 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/gate-node.ts +14 -13
- package/scripts/release-loop/mac-smoke-node.ts +229 -0
- package/scripts/release-loop/node-verdict.ts +3 -3
- package/scripts/release-loop/tui-node-checks.ts +42 -0
- package/scripts/release-loop/tui-sim-node.ts +32 -8
- package/scripts/release-loop/unattended-release.ts +5 -3
- package/scripts/release-loop/version-node.ts +61 -10
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/test-diet/node.ts +1 -1
- package/scripts/tui-regress.ts +2 -2
- package/scripts/ux/demo-rehearsal.ts +243 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
- package/skills/diagram-master/SKILL.md +366 -0
- package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
- package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
- package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
- package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
- package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
- package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
- package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
- package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
- package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
- package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
- package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
- package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
- package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
- package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
- package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
- package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
- package/skills/diagram-master/references/examples/README.md +69 -0
- package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
- package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
- package/skills/diagram-master/references/pyproject.toml +16 -0
- package/skills/diagram-master/references/quality-checklist.md +33 -0
- package/skills/diagram-master/references/routing-guide.md +164 -0
- package/skills/diagram-master/references/uv.lock +1356 -0
- package/skills/google-workspace/SKILL.md +33 -0
- package/skills/google-workspace/scripts/gws-safe.sh +177 -0
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/lecture-note-digitizer/SKILL.md +926 -0
- package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
- package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
- package/skills/lecture-note-digitizer/references/html-template.md +167 -0
- package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
- package/skills/omni-crawl/SKILL.md +21 -11
- package/skills/omni-crawl/scripts/main.ts +6 -6
- package/skills/omni-crawl/src/router.ts +3 -3
- package/skills/omni-digest/SKILL.md +17 -9
- package/skills/omni-digest/digest.md +2 -2
- package/skills/omni-digest/src/fetch.ts +30 -3
- package/skills/pitch-deck/SKILL.md +2 -2
- package/skills/pitch-deck/template.html +2 -2
- package/skills/youtube-master/SKILL.md +163 -0
- package/skills/youtube-master/package-lock.json +558 -0
- package/skills/youtube-master/package.json +13 -0
- package/skills/youtube-master/references/study-note-template.md +124 -0
- package/skills/youtube-master/scripts/main.ts +435 -0
- package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
- package/skills/youtube-master/src/audio.ts +63 -0
- package/skills/youtube-master/src/domain-staging.ts +50 -0
- package/skills/youtube-master/src/env.ts +36 -0
- package/skills/youtube-master/src/obsidian.ts +155 -0
- package/skills/youtube-master/src/router.ts +110 -0
- package/skills/youtube-master/src/stt.ts +199 -0
- package/skills/youtube-master/src/study-note.ts +175 -0
- package/skills/youtube-master/src/summarize.ts +358 -0
- package/skills/youtube-master/src/transcript.ts +76 -0
- package/skills/youtube-master/src/types.ts +91 -0
- package/skills/youtube-master/src/util.ts +93 -0
- package/skills/youtube-master/src/youtube.ts +70 -0
- package/skills/youtube-master/tsconfig.json +13 -0
- package/src/acp/server.ts +5 -2
- package/src/agent-mission/driver.ts +80 -10
- package/src/agent-mission/pty-decision.ts +71 -0
- package/src/agent-mission/review-loop.ts +30 -0
- package/src/autopilot/build/llm-conflict-merge.ts +16 -3
- package/src/autopilot/tool-registry.ts +2 -0
- package/src/boot/daemon-prompt-turn.ts +5 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/web-search.ts +3 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/index.ts +1 -0
- package/src/cli/drive-input-jail.ts +101 -0
- package/src/cli/hooks-cli.ts +17 -3
- package/src/cli/make-cli.ts +43 -0
- package/src/cli/persona-cli.ts +90 -4
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +19 -9
- package/src/cli/pr-cli.ts +51 -15
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/release-cli.ts +17 -4
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/context-bus/claude-hooks-install.ts +10 -0
- package/src/context-bus/context-now-surfaces.ts +48 -0
- package/src/context-bus/context-now.ts +104 -0
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/dashboard/index.ts +9 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +7 -1
- package/src/decisions/decision-cards.ts +10 -3
- package/src/decisions/decision-ledger.ts +13 -5
- package/src/discord/sprint21-runtime.ts +5 -1
- package/src/discord-self-message.ts +32 -0
- package/src/discord-slash-wire.ts +5 -1
- package/src/discord.ts +17 -1
- package/src/domains/core-tools.ts +3 -2
- package/src/domains/outbound-alert.ts +6 -1
- package/src/domains/telegram-kind-route.ts +51 -13
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +10 -2
- package/src/exec-requests/runner.ts +20 -6
- package/src/exec-requests/store.ts +3 -0
- package/src/execution-loop/launch-gate.ts +100 -0
- package/src/field/field-reel.ts +5 -1
- package/src/field-note/index.ts +201 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-cli.ts +61 -1
- package/src/graph-runner/graph-grow-llm.ts +37 -0
- package/src/graph-runner/graph-grow.ts +47 -0
- package/src/graph-runner/runner.ts +317 -25
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/harness-cli-command.ts +247 -7
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +23 -4
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hooks/dispatch.ts +82 -0
- package/src/hooks/expose.ts +254 -0
- package/src/hooks/github-shadow.ts +108 -0
- package/src/hooks/providers.ts +71 -5
- package/src/hooks/queue.ts +1 -1
- package/src/hooks/receiver.ts +21 -20
- package/src/index.ts +52 -14
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/discord-seat-work.ts +10 -0
- package/src/intake-plane/front-route-classifier.ts +33 -39
- package/src/intake-plane/persona-answer.ts +30 -0
- package/src/intake-plane/runtime-callables.ts +8 -1
- package/src/intake-plane/telegram-seat-work.ts +36 -2
- package/src/intake-plane/wish-folder.ts +67 -0
- package/src/intent-gate/gate.ts +30 -10
- package/src/live/detail-switch.ts +5 -0
- package/src/llm/difficulty.ts +57 -0
- package/src/llm/judge-layer.ts +101 -0
- package/src/llm/mission-router.ts +33 -19
- package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
- package/src/loops/contract/examples/steward.loop.yaml +50 -0
- package/src/loops/contract/loop-agent.schema.json +138 -0
- package/src/loops/contract/validate.ts +64 -0
- package/src/loops/registry.ts +20 -6
- package/src/market/signed-index.ts +4 -0
- package/src/maturity/bot-command-maturity.ts +45 -0
- package/src/maturity/feature-maturity.ts +26 -4
- package/src/model-tier/index.ts +2 -2
- package/src/model-tier/tier-resolver.ts +20 -20
- package/src/model-tier/types.ts +6 -6
- package/src/mss/logging/log-store.ts +15 -0
- package/src/nexus/api/config-model-tier.ts +5 -4
- package/src/nexus/api/fabric-plans.ts +53 -0
- package/src/nexus/api/harness-api.ts +5 -1
- package/src/nexus/api/health.ts +2 -0
- package/src/nexus/api/http-server.ts +36 -0
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +21 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-seats.ts +33 -0
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/seat-requests.ts +44 -2
- package/src/nexus/api/sessions-store.ts +17 -38
- package/src/nexus/api/sub-seat-charters.ts +34 -0
- package/src/nexus/api/tabs-mutations.ts +3 -1
- package/src/nexus/api/trace.ts +18 -6
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +80 -6
- package/src/nexus/index.ts +2 -0
- package/src/nexus/kinds/webterm.ts +2 -1
- package/src/nexus/webterm/pty.ts +6 -2
- package/src/onboarding/cli-auth-status.ts +80 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/org/seat-budget.ts +48 -0
- package/src/org/stall-escalation.ts +63 -0
- package/src/outputs/ledger.ts +120 -0
- package/src/persona/persona-todo.ts +79 -0
- package/src/persona/presets.ts +116 -2
- package/src/persona/team-set.ts +155 -0
- package/src/plugins/install/plugin-install.ts +14 -0
- package/src/plugins/maker/market-bundle.ts +109 -0
- package/src/plugins/maker/plugin-maker.ts +254 -11
- package/src/plugins/maker/wizard-generate.ts +103 -0
- package/src/pod-lease/admission.ts +150 -0
- package/src/pod-lease/dependency-state.ts +85 -0
- package/src/pod-lease/host-lease.ts +127 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +2 -2
- package/src/release-loop/feature-store.ts +5 -3
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/seat-dispatch/seat-ask.ts +130 -0
- package/src/seat-dispatch/seat-questions.ts +100 -0
- package/src/seat-loop/seat-loop.ts +548 -29
- package/src/seat-loop/seat-report.ts +37 -2
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +37 -1
- package/src/self-dev/draft-sweep.ts +38 -33
- package/src/self-dev/draft-triage-rules.ts +8 -5
- package/src/self-dev/fabric-plan-core.ts +297 -0
- package/src/self-dev/orchestrate.ts +36 -4
- package/src/self-dev/release-path-guard.ts +62 -0
- package/src/self-dev/shard-aggregate.ts +230 -0
- package/src/self-dev/shard-placement.ts +60 -0
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-pod-run.ts +77 -0
- package/src/self-dev/shard-run.ts +105 -0
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-cli.ts +40 -1
- package/src/self-implement/gate-scope.ts +37 -7
- package/src/self-implement/graph-variant.ts +171 -0
- package/src/self-implement/harness-policy-gates.ts +1 -1
- package/src/self-implement/headless-elanous-driver.ts +22 -3
- package/src/self-implement/host-regate.ts +22 -1
- package/src/self-implement/importer-test-index.ts +2 -1
- package/src/self-implement/l8-merge-queue.ts +130 -0
- package/src/self-implement/orchestrator.ts +242 -9
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/seams.ts +72 -11
- package/src/self-implement/test-seams.ts +1 -0
- package/src/self-implement/uncommitted-work.ts +59 -0
- package/src/session/index.ts +36 -13
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/launch.ts +42 -26
- package/src/steward/steward-cards.ts +17 -9
- package/src/steward/triage.ts +46 -14
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-orchestrator/mission.ts +5 -0
- package/src/task-orchestrator/store.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
- package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
- package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
- package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
- package/src/task-orchestrator/types.ts +2 -0
- package/src/telegram-card-followup.ts +16 -96
- package/src/telegram-commands.ts +10 -1
- package/src/telegram-project-command.ts +71 -0
- package/src/telegram-report.ts +21 -17
- package/src/telegram.ts +29 -3
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/user-config.ts +102 -20
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/grok.ts +7 -1
- package/src/web-search/index.ts +28 -1
- package/src/web-search/provider.ts +4 -0
- package/src/web-search/x-intent.ts +5 -0
- package/src/workflow-runtime/executor.ts +277 -47
- package/src/workflow-runtime/index.ts +1 -0
- package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
- package/src/workflow-runtime/plugin-kind-node.ts +1 -1
- package/src/workflow-runtime/schema.ts +79 -4
- package/src/workflow-runtime/types.ts +35 -4
- package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
- package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
- /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
// Archon-port T2.1 (2026-05-08) — DAG executor.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Ready nodes overlap up to workflow.concurrency (default 1 = one at a time); lifecycle events retain
|
|
4
|
+
// their wire shape and node_done follows actual completion order.
|
|
5
|
+
// Failed nodes may route their output to an on_error handler. Subworkflow nodes invoke the same executor
|
|
6
|
+
// recursively, with an independent run id and full child execution.
|
|
7
7
|
//
|
|
8
|
-
// Yields events as it goes — caller (CLI / SSE / tests) decides
|
|
9
|
-
//
|
|
10
|
-
// `trigger_rule: all_done` consumer (Archon parity: `all_done`
|
|
11
|
-
// downstream nodes always run regardless of upstream ok).
|
|
8
|
+
// Yields events as it goes — caller (CLI / SSE / tests) decides rendering. A failure with no on_error
|
|
9
|
+
// route and no `trigger_rule: all_done` consumer ends the run (Archon parity).
|
|
12
10
|
|
|
13
11
|
import { mkdirSync, writeFileSync } from 'fs';
|
|
14
12
|
import { join } from 'path';
|
|
@@ -32,6 +30,7 @@ import {
|
|
|
32
30
|
isPromptNode,
|
|
33
31
|
isSetNode,
|
|
34
32
|
isShowroomNode,
|
|
33
|
+
isSubworkflowNode,
|
|
35
34
|
isTaskNode,
|
|
36
35
|
isSkillNode,
|
|
37
36
|
isSwitchNode,
|
|
@@ -61,6 +60,7 @@ import { executeFilterNode } from './nodes/filter.js';
|
|
|
61
60
|
import { executeTemplateNode } from './nodes/template.js';
|
|
62
61
|
import { executeHttpRequestNode } from './nodes/http.js';
|
|
63
62
|
import { executeShowroomNode } from './nodes/showroom.js';
|
|
63
|
+
import { executeSubworkflowNode } from './nodes/subworkflow.js';
|
|
64
64
|
import { executeScheduleTriggerNode, executeWebhookTriggerNode, executeDiscordTriggerNode, executeTelegramTriggerNode, executeManualTriggerNode, executeChatTriggerNode } from './nodes/triggers.js';
|
|
65
65
|
import { executePluginKindNode, isPluginKindNode } from './plugin-kind-node.js';
|
|
66
66
|
import type {
|
|
@@ -80,6 +80,7 @@ export async function* runWorkflow(
|
|
|
80
80
|
deps: WorkflowDeps,
|
|
81
81
|
): AsyncGenerator<WorkflowEvent, Record<string, NodeOutput>, unknown> {
|
|
82
82
|
const runId = opts.runId ?? generateRunId();
|
|
83
|
+
const mode = opts.mode ?? (opts.onlyNode ? 'only' : opts.fromNode ? 'from' : 'full');
|
|
83
84
|
// Persistence (Caveat #4 follow-up): when `runDir` is set OR neither
|
|
84
85
|
// override is supplied, we own the run dir and persist node outputs +
|
|
85
86
|
// a final run.json. When only `artifactsDir` is overridden (the
|
|
@@ -97,10 +98,11 @@ export async function* runWorkflow(
|
|
|
97
98
|
workflowName: opts.workflow.name,
|
|
98
99
|
arguments: opts.arguments,
|
|
99
100
|
startedAt,
|
|
101
|
+
mode,
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
yield { type: 'workflow_start', workflow: opts.workflow.name, runId };
|
|
105
|
+
yield { type: 'workflow_start', workflow: opts.workflow.name, runId, mode };
|
|
104
106
|
|
|
105
107
|
let order: string[];
|
|
106
108
|
try {
|
|
@@ -110,14 +112,151 @@ export async function* runWorkflow(
|
|
|
110
112
|
type: 'workflow_failed',
|
|
111
113
|
error: err instanceof Error ? err.message : String(err),
|
|
112
114
|
partial: {},
|
|
115
|
+
mode,
|
|
113
116
|
};
|
|
114
117
|
return {};
|
|
115
118
|
}
|
|
116
119
|
|
|
117
|
-
const outputs: Record<string, NodeOutput> = {};
|
|
118
120
|
const nodeById = new Map(opts.workflow.nodes.map(n => [n.id, n] as const));
|
|
121
|
+
const startIndex = opts.fromNode ? order.indexOf(opts.fromNode) : 0;
|
|
122
|
+
const outputs: Record<string, NodeOutput> = {};
|
|
123
|
+
if (startIndex < 0 || (opts.onlyNode && !nodeById.has(opts.onlyNode))) {
|
|
124
|
+
yield { type: 'workflow_failed', error: 'unknown selected node', partial: outputs, mode };
|
|
125
|
+
return outputs;
|
|
126
|
+
}
|
|
127
|
+
if (opts.fromNode) {
|
|
128
|
+
const upstream = order.slice(0, startIndex);
|
|
129
|
+
if (!opts.previousOutputs || upstream.some(id => opts.previousOutputs?.[id] === undefined)) {
|
|
130
|
+
const error = 'source run missing upstream outputs';
|
|
131
|
+
if (shouldPersist && runDir) persistRunFinal(runDir, {
|
|
132
|
+
runId, workflowName: opts.workflow.name, arguments: opts.arguments,
|
|
133
|
+
startedAt, mode, ok: false, error, outputs, completedAt: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
yield { type: 'workflow_failed', error, partial: outputs, mode };
|
|
136
|
+
return outputs;
|
|
137
|
+
}
|
|
138
|
+
for (const id of upstream) outputs[id] = opts.previousOutputs[id]!;
|
|
139
|
+
}
|
|
140
|
+
const selectedOrder = opts.onlyNode ? [opts.onlyNode] : order.slice(startIndex);
|
|
141
|
+
|
|
142
|
+
// Keep the original serial path for workflows that do not opt in. Its
|
|
143
|
+
// start/done/skip sequence and gate failures are part of the CLI/SSE contract.
|
|
144
|
+
if ((opts.workflow.concurrency ?? 1) > 1 || selectedOrder.some(id => nodeById.get(id)?.on_error || opts.workflow.nodes.some(n => n.on_error === id))) {
|
|
145
|
+
const concurrency = Math.max(1, Math.min(8, opts.workflow.concurrency ?? 1));
|
|
146
|
+
const pending = new Set(selectedOrder);
|
|
147
|
+
const settled = new Set(order.slice(0, startIndex));
|
|
148
|
+
const active = new Set<string>();
|
|
149
|
+
const completed: Array<{ id: string; result: NodeOutput }> = [];
|
|
150
|
+
let wakeCompletion: (() => void) | undefined;
|
|
151
|
+
let failure: string | undefined;
|
|
152
|
+
|
|
153
|
+
while (pending.size || active.size || completed.length) {
|
|
154
|
+
if (completed.length) {
|
|
155
|
+
const { id, result } = completed.shift()!;
|
|
156
|
+
active.delete(id);
|
|
157
|
+
settled.add(id);
|
|
158
|
+
outputs[id] = result;
|
|
159
|
+
if (shouldPersist && runDir) persistNodeOutput(runDir, id, result);
|
|
160
|
+
yield { type: 'node_done', nodeId: id, result, mode, ...(result.childRunId ? { childRunId: result.childRunId } : {}) };
|
|
161
|
+
if (!result.ok && !failure) {
|
|
162
|
+
const node = nodeById.get(id)!;
|
|
163
|
+
const handler = !opts.onlyNode && node.on_error && selectedOrder.includes(node.on_error) ? node.on_error : undefined;
|
|
164
|
+
const hasAllDone = selectedOrder.some(rid => pending.has(rid) && nodeById.get(rid)?.trigger_rule === 'all_done'
|
|
165
|
+
&& dependsOnFailure(rid, id, nodeById));
|
|
166
|
+
if (!handler && !hasAllDone) {
|
|
167
|
+
failure = `node '${id}' failed: ${result.error ?? '(no error message)'}`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
for (const id of selectedOrder) {
|
|
173
|
+
if (completed.length || active.size >= concurrency || failure) break;
|
|
174
|
+
if (!pending.has(id)) continue;
|
|
175
|
+
const node = nodeById.get(id)!;
|
|
176
|
+
const sources = opts.onlyNode ? [] : opts.workflow.nodes.filter(n => n.on_error === id).map(n => n.id);
|
|
177
|
+
const prerequisites = [...(node.depends_on ?? []), ...sources];
|
|
178
|
+
if (!opts.onlyNode && !prerequisites.every(dep => settled.has(dep))) continue;
|
|
179
|
+
pending.delete(id);
|
|
180
|
+
const failedSources = sources.filter(source => outputs[source] && !outputs[source]!.ok);
|
|
181
|
+
if (sources.length && !failedSources.length) {
|
|
182
|
+
settled.add(id);
|
|
183
|
+
yield { type: 'node_skipped', nodeId: id, reason: 'on_error source did not fail', mode };
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (opts.dryRun && isTriggerVariant(node)) {
|
|
187
|
+
settled.add(id);
|
|
188
|
+
yield { type: 'node_skipped', nodeId: id, reason: 'dry-run', mode };
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const skipReason = opts.onlyNode ? null : shouldSkip(node, outputs, failedSources);
|
|
192
|
+
if (skipReason) {
|
|
193
|
+
settled.add(id);
|
|
194
|
+
yield { type: 'node_skipped', nodeId: id, reason: skipReason, mode };
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const toolPolicy: ToolPolicy = {
|
|
198
|
+
...(node.allowed_tools ? { allow: node.allowed_tools } : {}),
|
|
199
|
+
...(node.denied_tools ? { deny: node.denied_tools } : {}),
|
|
200
|
+
};
|
|
201
|
+
const ctx: NodeExecContext = {
|
|
202
|
+
arguments: opts.arguments, artifactsDir, outputs: { ...outputs },
|
|
203
|
+
resolvedProvider: node.provider ?? opts.workflow.provider,
|
|
204
|
+
resolvedModel: node.model ?? opts.workflow.model, toolPolicy,
|
|
205
|
+
...(opts.signal !== undefined ? { signal: opts.signal } : {}),
|
|
206
|
+
...(opts.screen !== undefined ? { screen: opts.screen } : {}),
|
|
207
|
+
...(opts.onTokenChunk !== undefined
|
|
208
|
+
? { onTokenChunk: (chunk: string) => opts.onTokenChunk!(id, chunk) } : {}),
|
|
209
|
+
};
|
|
210
|
+
let childRunId: string | undefined;
|
|
211
|
+
try { childRunId = isSubworkflowNode(node) && !(!opts.ignorePins && readWorkflowPin(opts.workflow.name, id) !== null) ? generateRunId() : undefined; }
|
|
212
|
+
catch { childRunId = undefined; }
|
|
213
|
+
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node), mode, ...(childRunId ? { childRunId } : {}) };
|
|
214
|
+
active.add(id);
|
|
215
|
+
const finish = (result: NodeOutput) => {
|
|
216
|
+
completed.push({ id, result });
|
|
217
|
+
wakeCompletion?.();
|
|
218
|
+
wakeCompletion = undefined;
|
|
219
|
+
};
|
|
220
|
+
// W8 must-fix: a rejected node is still a completed (failed) node — otherwise it stays active and the run never ends.
|
|
221
|
+
void executeWorkflowNode(node, ctx, opts, deps, childRunId).then(finish,
|
|
222
|
+
(err: unknown) => finish({ ok: false, output: '', error: err instanceof Error ? err.message : String(err), durationMs: 0 }));
|
|
223
|
+
}
|
|
224
|
+
if (!active.size) {
|
|
225
|
+
if (!pending.size || failure) break;
|
|
226
|
+
failure = `workflow has unresolved nodes: ${[...pending].join(', ')}`;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
if (!completed.length) await new Promise<void>(resolve => { wakeCompletion = resolve; });
|
|
230
|
+
}
|
|
231
|
+
if (!failure) {
|
|
232
|
+
const unhandled = selectedOrder.find(id => {
|
|
233
|
+
const node = nodeById.get(id)!;
|
|
234
|
+
if (!outputs[id] || outputs[id]!.ok) return false;
|
|
235
|
+
const handledByError = !opts.onlyNode && node.on_error && selectedOrder.includes(node.on_error)
|
|
236
|
+
&& outputs[node.on_error]?.ok === true;
|
|
237
|
+
const handledByAllDone = selectedOrder.some(next => nodeById.get(next)?.trigger_rule === 'all_done'
|
|
238
|
+
&& dependsOnFailure(next, id, nodeById) && outputs[next]?.ok === true);
|
|
239
|
+
return !handledByError && !handledByAllDone;
|
|
240
|
+
});
|
|
241
|
+
if (unhandled) failure = `node '${unhandled}' failed: ${outputs[unhandled]!.error ?? '(no error message)'}`;
|
|
242
|
+
}
|
|
243
|
+
if (failure) {
|
|
244
|
+
if (shouldPersist && runDir) persistRunFinal(runDir, {
|
|
245
|
+
runId, workflowName: opts.workflow.name, arguments: opts.arguments,
|
|
246
|
+
startedAt, mode, ok: false, error: failure, outputs, completedAt: Date.now(),
|
|
247
|
+
});
|
|
248
|
+
yield { type: 'workflow_failed', error: failure, partial: outputs, mode };
|
|
249
|
+
return outputs;
|
|
250
|
+
}
|
|
251
|
+
if (shouldPersist && runDir) persistRunFinal(runDir, {
|
|
252
|
+
runId, workflowName: opts.workflow.name, arguments: opts.arguments,
|
|
253
|
+
startedAt, mode, ok: true, outputs, completedAt: Date.now(),
|
|
254
|
+
});
|
|
255
|
+
yield { type: 'workflow_done', outputs, mode };
|
|
256
|
+
return outputs;
|
|
257
|
+
}
|
|
119
258
|
|
|
120
|
-
for (const id of
|
|
259
|
+
for (const id of selectedOrder) {
|
|
121
260
|
const node = nodeById.get(id);
|
|
122
261
|
if (!node) continue;
|
|
123
262
|
|
|
@@ -128,13 +267,13 @@ export async function* runWorkflow(
|
|
|
128
267
|
// usual; manualTrigger / chatTrigger are also covered by the
|
|
129
268
|
// variant family check.
|
|
130
269
|
if (opts.dryRun && isTriggerVariant(node)) {
|
|
131
|
-
yield { type: 'node_skipped', nodeId: id, reason: 'dry-run' };
|
|
270
|
+
yield { type: 'node_skipped', nodeId: id, reason: 'dry-run', mode };
|
|
132
271
|
continue;
|
|
133
272
|
}
|
|
134
273
|
|
|
135
|
-
const skipReason = shouldSkip(node, outputs);
|
|
274
|
+
const skipReason = opts.onlyNode ? null : shouldSkip(node, outputs);
|
|
136
275
|
if (skipReason) {
|
|
137
|
-
yield { type: 'node_skipped', nodeId: id, reason: skipReason };
|
|
276
|
+
yield { type: 'node_skipped', nodeId: id, reason: skipReason, mode };
|
|
138
277
|
continue;
|
|
139
278
|
}
|
|
140
279
|
|
|
@@ -163,18 +302,35 @@ export async function* runWorkflow(
|
|
|
163
302
|
: {}),
|
|
164
303
|
};
|
|
165
304
|
|
|
305
|
+
const hasPin = !opts.ignorePins && readWorkflowPin(opts.workflow.name, id) !== null;
|
|
306
|
+
if (mode === 'test' && (isExternalSideEffectNode(node) || Boolean(node.judgment))
|
|
307
|
+
&& !hasPin) {
|
|
308
|
+
const blocked: NodeOutput = { ok: false, output: '', error: 'pin required', durationMs: 0 };
|
|
309
|
+
outputs[id] = blocked;
|
|
310
|
+
if (shouldPersist && runDir) persistNodeOutput(runDir, id, blocked);
|
|
311
|
+
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node), mode };
|
|
312
|
+
yield { type: 'node_done', nodeId: id, result: blocked, mode };
|
|
313
|
+
if (shouldPersist && runDir) persistRunFinal(runDir, {
|
|
314
|
+
runId, workflowName: opts.workflow.name, arguments: opts.arguments,
|
|
315
|
+
startedAt, mode, ok: false, error: `node '${id}' failed: pin required`,
|
|
316
|
+
outputs, completedAt: Date.now(),
|
|
317
|
+
});
|
|
318
|
+
yield { type: 'workflow_failed', error: `node '${id}' failed: pin required`, partial: outputs, mode };
|
|
319
|
+
return outputs;
|
|
320
|
+
}
|
|
321
|
+
|
|
166
322
|
// RFC #2161 Phase 3 — capability requirements gate. When a node
|
|
167
323
|
// declares `requires`, verify the resolved (provider, model) pair
|
|
168
324
|
// satisfies every clause before we burn an LLM/bash call. Phase 5
|
|
169
325
|
// tightens this by layering Live Registry (apiKey/health) on top.
|
|
170
|
-
if (node.requires) {
|
|
326
|
+
if (node.requires && !hasPin) {
|
|
171
327
|
const reason = checkModelRequires(
|
|
172
328
|
ctx.resolvedProvider,
|
|
173
329
|
ctx.resolvedModel,
|
|
174
330
|
node.requires,
|
|
175
331
|
);
|
|
176
332
|
if (reason) {
|
|
177
|
-
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node) };
|
|
333
|
+
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node), mode };
|
|
178
334
|
const startedAt = Date.now();
|
|
179
335
|
const blocked: NodeOutput = {
|
|
180
336
|
ok: false,
|
|
@@ -184,11 +340,11 @@ export async function* runWorkflow(
|
|
|
184
340
|
};
|
|
185
341
|
outputs[id] = blocked;
|
|
186
342
|
if (shouldPersist && runDir) persistNodeOutput(runDir, id, blocked);
|
|
187
|
-
yield { type: 'node_done', nodeId: id, result: blocked };
|
|
188
|
-
const remaining =
|
|
343
|
+
yield { type: 'node_done', nodeId: id, result: blocked, mode };
|
|
344
|
+
const remaining = selectedOrder.slice(selectedOrder.indexOf(id) + 1);
|
|
189
345
|
const hasAllDone = remaining.some((rid) => {
|
|
190
346
|
const rn = nodeById.get(rid);
|
|
191
|
-
return rn?.trigger_rule === 'all_done';
|
|
347
|
+
return rn?.trigger_rule === 'all_done' && dependsOnFailure(rid, id, nodeById);
|
|
192
348
|
});
|
|
193
349
|
if (!hasAllDone) {
|
|
194
350
|
if (shouldPersist && runDir) {
|
|
@@ -197,6 +353,7 @@ export async function* runWorkflow(
|
|
|
197
353
|
workflowName: opts.workflow.name,
|
|
198
354
|
arguments: opts.arguments,
|
|
199
355
|
startedAt,
|
|
356
|
+
mode,
|
|
200
357
|
ok: false,
|
|
201
358
|
error: `node '${id}' blocked: ${reason}`,
|
|
202
359
|
outputs,
|
|
@@ -207,6 +364,7 @@ export async function* runWorkflow(
|
|
|
207
364
|
type: 'workflow_failed',
|
|
208
365
|
error: `node '${id}' blocked: ${reason}`,
|
|
209
366
|
partial: outputs,
|
|
367
|
+
mode,
|
|
210
368
|
};
|
|
211
369
|
return outputs;
|
|
212
370
|
}
|
|
@@ -214,14 +372,14 @@ export async function* runWorkflow(
|
|
|
214
372
|
}
|
|
215
373
|
}
|
|
216
374
|
|
|
217
|
-
if (node.judgment) {
|
|
375
|
+
if (node.judgment && !hasPin) {
|
|
218
376
|
const reason = validateJudgmentContract(node)
|
|
219
377
|
?? (node.observes?.includes('screen') && ctx.screen === undefined
|
|
220
378
|
? 'screen observation is not wired in this run'
|
|
221
379
|
: null)
|
|
222
380
|
?? (!deps.runJudgment ? 'deps.runJudgment is not wired in this runtime' : null);
|
|
223
381
|
if (reason) {
|
|
224
|
-
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node) };
|
|
382
|
+
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node), mode };
|
|
225
383
|
const nodeStartedAt = Date.now();
|
|
226
384
|
const blocked: NodeOutput = {
|
|
227
385
|
ok: false,
|
|
@@ -231,9 +389,10 @@ export async function* runWorkflow(
|
|
|
231
389
|
};
|
|
232
390
|
outputs[id] = blocked;
|
|
233
391
|
if (shouldPersist && runDir) persistNodeOutput(runDir, id, blocked);
|
|
234
|
-
yield { type: 'node_done', nodeId: id, result: blocked };
|
|
235
|
-
const remaining =
|
|
236
|
-
const hasAllDone = remaining.some((rid) => nodeById.get(rid)?.trigger_rule === 'all_done'
|
|
392
|
+
yield { type: 'node_done', nodeId: id, result: blocked, mode };
|
|
393
|
+
const remaining = selectedOrder.slice(selectedOrder.indexOf(id) + 1);
|
|
394
|
+
const hasAllDone = remaining.some((rid) => nodeById.get(rid)?.trigger_rule === 'all_done'
|
|
395
|
+
&& dependsOnFailure(rid, id, nodeById));
|
|
237
396
|
if (!hasAllDone) {
|
|
238
397
|
if (shouldPersist && runDir) {
|
|
239
398
|
persistRunFinal(runDir, {
|
|
@@ -241,6 +400,7 @@ export async function* runWorkflow(
|
|
|
241
400
|
workflowName: opts.workflow.name,
|
|
242
401
|
arguments: opts.arguments,
|
|
243
402
|
startedAt,
|
|
403
|
+
mode,
|
|
244
404
|
ok: false,
|
|
245
405
|
error: `node '${id}' blocked: ${reason}`,
|
|
246
406
|
outputs,
|
|
@@ -251,6 +411,7 @@ export async function* runWorkflow(
|
|
|
251
411
|
type: 'workflow_failed',
|
|
252
412
|
error: `node '${id}' blocked: ${reason}`,
|
|
253
413
|
partial: outputs,
|
|
414
|
+
mode,
|
|
254
415
|
};
|
|
255
416
|
return outputs;
|
|
256
417
|
}
|
|
@@ -258,23 +419,25 @@ export async function* runWorkflow(
|
|
|
258
419
|
}
|
|
259
420
|
}
|
|
260
421
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
?
|
|
264
|
-
|
|
422
|
+
const childRunId = isSubworkflowNode(node) && !hasPin ? generateRunId() : undefined;
|
|
423
|
+
yield { type: 'node_start', nodeId: id, nodeType: variantOf(node), mode,
|
|
424
|
+
...(childRunId ? { childRunId } : {}) };
|
|
425
|
+
const result = isSubworkflowNode(node) && childRunId
|
|
426
|
+
? await executeSubworkflowNode(node, ctx, deps, opts, childRunId)
|
|
427
|
+
: node.judgment && !hasPin
|
|
428
|
+
? await executeJudgmentNode(node, ctx, deps, opts.workflow.name, opts.judgmentContext)
|
|
429
|
+
: await dispatchNode(node, ctx, deps, opts.workflow.name, opts.ignorePins);
|
|
265
430
|
outputs[id] = result;
|
|
266
431
|
if (shouldPersist && runDir) persistNodeOutput(runDir, id, result);
|
|
267
|
-
yield { type: 'node_done', nodeId: id, result
|
|
432
|
+
yield { type: 'node_done', nodeId: id, result, mode,
|
|
433
|
+
...(result.childRunId ? { childRunId: result.childRunId } : {}) };
|
|
268
434
|
|
|
269
|
-
//
|
|
270
|
-
// `trigger_rule: all_done` (which means it explicitly wants to
|
|
271
|
-
// run after failures). Cheaper than a full DAG re-walk:
|
|
272
|
-
// any-downstream-all_done in the remaining order.
|
|
435
|
+
// A failed node can continue only if a dependent all_done node will consume it.
|
|
273
436
|
if (!result.ok) {
|
|
274
|
-
const remaining =
|
|
437
|
+
const remaining = selectedOrder.slice(selectedOrder.indexOf(id) + 1);
|
|
275
438
|
const hasAllDone = remaining.some(rid => {
|
|
276
439
|
const rn = nodeById.get(rid);
|
|
277
|
-
return rn?.trigger_rule === 'all_done';
|
|
440
|
+
return rn?.trigger_rule === 'all_done' && dependsOnFailure(rid, id, nodeById);
|
|
278
441
|
});
|
|
279
442
|
if (!hasAllDone) {
|
|
280
443
|
if (shouldPersist && runDir) {
|
|
@@ -283,6 +446,7 @@ export async function* runWorkflow(
|
|
|
283
446
|
workflowName: opts.workflow.name,
|
|
284
447
|
arguments: opts.arguments,
|
|
285
448
|
startedAt,
|
|
449
|
+
mode,
|
|
286
450
|
ok: false,
|
|
287
451
|
error: `node '${id}' failed: ${result.error ?? '(no error message)'}`,
|
|
288
452
|
outputs,
|
|
@@ -293,27 +457,83 @@ export async function* runWorkflow(
|
|
|
293
457
|
type: 'workflow_failed',
|
|
294
458
|
error: `node '${id}' failed: ${result.error ?? '(no error message)'}`,
|
|
295
459
|
partial: outputs,
|
|
460
|
+
mode,
|
|
296
461
|
};
|
|
297
462
|
return outputs;
|
|
298
463
|
}
|
|
299
464
|
}
|
|
300
465
|
}
|
|
301
466
|
|
|
467
|
+
// W8 must-fix: the serial path re-checks failures at the end like the parallel path — a failure whose all_done
|
|
468
|
+
// consumer was skipped (e.g. `when: false`) must not end as workflow_done.
|
|
469
|
+
const unhandled = selectedOrder.find(id => {
|
|
470
|
+
const node = nodeById.get(id);
|
|
471
|
+
if (!node || !outputs[id] || outputs[id]!.ok) return false;
|
|
472
|
+
const handledByError = !opts.onlyNode && node.on_error && selectedOrder.includes(node.on_error)
|
|
473
|
+
&& outputs[node.on_error]?.ok === true;
|
|
474
|
+
const handledByAllDone = selectedOrder.some(next => nodeById.get(next)?.trigger_rule === 'all_done'
|
|
475
|
+
&& dependsOnFailure(next, id, nodeById) && outputs[next]?.ok === true);
|
|
476
|
+
return !handledByError && !handledByAllDone;
|
|
477
|
+
});
|
|
478
|
+
if (unhandled) {
|
|
479
|
+
const error = `node '${unhandled}' failed: ${outputs[unhandled]!.error ?? '(no error message)'}`;
|
|
480
|
+
if (shouldPersist && runDir) persistRunFinal(runDir, {
|
|
481
|
+
runId, workflowName: opts.workflow.name, arguments: opts.arguments,
|
|
482
|
+
startedAt, mode, ok: false, error, outputs, completedAt: Date.now(),
|
|
483
|
+
});
|
|
484
|
+
yield { type: 'workflow_failed', error, partial: outputs, mode };
|
|
485
|
+
return outputs;
|
|
486
|
+
}
|
|
487
|
+
|
|
302
488
|
if (shouldPersist && runDir) {
|
|
303
489
|
persistRunFinal(runDir, {
|
|
304
490
|
runId,
|
|
305
491
|
workflowName: opts.workflow.name,
|
|
306
492
|
arguments: opts.arguments,
|
|
307
493
|
startedAt,
|
|
494
|
+
mode,
|
|
308
495
|
ok: true,
|
|
309
496
|
outputs,
|
|
310
497
|
completedAt: Date.now(),
|
|
311
498
|
});
|
|
312
499
|
}
|
|
313
|
-
yield { type: 'workflow_done', outputs };
|
|
500
|
+
yield { type: 'workflow_done', outputs, mode };
|
|
314
501
|
return outputs;
|
|
315
502
|
}
|
|
316
503
|
|
|
504
|
+
async function executeWorkflowNode(
|
|
505
|
+
node: DagNode,
|
|
506
|
+
ctx: NodeExecContext,
|
|
507
|
+
opts: RunWorkflowOpts,
|
|
508
|
+
deps: WorkflowDeps,
|
|
509
|
+
childRunId?: string,
|
|
510
|
+
): Promise<NodeOutput> {
|
|
511
|
+
const startedAt = Date.now();
|
|
512
|
+
// W8 must-fix: every step (pin read included) is inside the try — a throw becomes a failed result, never a stuck active node.
|
|
513
|
+
try {
|
|
514
|
+
const hasPin = !opts.ignorePins && readWorkflowPin(opts.workflow.name, node.id) !== null;
|
|
515
|
+
if (opts.mode === 'test' && (isExternalSideEffectNode(node) || Boolean(node.judgment)) && !hasPin) {
|
|
516
|
+
return { ok: false, output: '', error: 'pin required', durationMs: 0 };
|
|
517
|
+
}
|
|
518
|
+
if (node.requires && !hasPin) {
|
|
519
|
+
const reason = checkModelRequires(ctx.resolvedProvider, ctx.resolvedModel, node.requires);
|
|
520
|
+
if (reason) return { ok: false, output: '', error: `requires unmet — ${reason}`, durationMs: Date.now() - startedAt };
|
|
521
|
+
}
|
|
522
|
+
if (node.judgment && !hasPin) {
|
|
523
|
+
const reason = validateJudgmentContract(node)
|
|
524
|
+
?? (node.observes?.includes('screen') && ctx.screen === undefined ? 'screen observation is not wired in this run' : null)
|
|
525
|
+
?? (!deps.runJudgment ? 'deps.runJudgment is not wired in this runtime' : null);
|
|
526
|
+
if (reason) return { ok: false, output: '', error: `judgment contract unmet — ${reason}`, durationMs: Date.now() - startedAt };
|
|
527
|
+
}
|
|
528
|
+
if (isSubworkflowNode(node) && childRunId) return await executeSubworkflowNode(node, ctx, deps, opts, childRunId);
|
|
529
|
+
return node.judgment && !hasPin
|
|
530
|
+
? await executeJudgmentNode(node, ctx, deps, opts.workflow.name, opts.judgmentContext)
|
|
531
|
+
: await dispatchNode(node, ctx, deps, opts.workflow.name, opts.ignorePins);
|
|
532
|
+
} catch (err) {
|
|
533
|
+
return { ok: false, output: '', error: err instanceof Error ? err.message : String(err), durationMs: Date.now() - startedAt };
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
317
537
|
/** Simpler convenience: run-to-completion + collect events. */
|
|
318
538
|
export async function runWorkflowToCompletion(
|
|
319
539
|
opts: RunWorkflowOpts,
|
|
@@ -335,7 +555,13 @@ export async function runWorkflowToCompletion(
|
|
|
335
555
|
return { outputs, events, ok };
|
|
336
556
|
}
|
|
337
557
|
|
|
338
|
-
function
|
|
558
|
+
function dependsOnFailure(id: string, failedId: string, nodeById: Map<string, DagNode>, visited = new Set<string>()): boolean {
|
|
559
|
+
if (visited.has(id)) return false;
|
|
560
|
+
visited.add(id);
|
|
561
|
+
return (nodeById.get(id)?.depends_on ?? []).some(dep => dep === failedId || dependsOnFailure(dep, failedId, nodeById, visited));
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function shouldSkip(node: DagNode, outputs: Record<string, NodeOutput>, errorSources: readonly string[] = []): string | null {
|
|
339
565
|
// trigger_rule check on depends_on
|
|
340
566
|
const deps = node.depends_on ?? [];
|
|
341
567
|
if (deps.length > 0) {
|
|
@@ -343,9 +569,9 @@ function shouldSkip(node: DagNode, outputs: Record<string, NodeOutput>): string
|
|
|
343
569
|
const depResults = deps.map(d => outputs[d]).filter((o): o is NodeOutput => !!o);
|
|
344
570
|
if (rule === 'all_success') {
|
|
345
571
|
if (depResults.length !== deps.length) return `dep missing (rule=all_success)`;
|
|
346
|
-
if (
|
|
572
|
+
if (deps.some(d => !outputs[d]?.ok && !errorSources.includes(d))) return `dep failed (rule=all_success)`;
|
|
347
573
|
} else if (rule === 'one_success') {
|
|
348
|
-
if (!depResults.some(r => r.ok)) return `no successful dep (rule=one_success)`;
|
|
574
|
+
if (!depResults.some(r => r.ok) && !errorSources.length) return `no successful dep (rule=one_success)`;
|
|
349
575
|
} else if (rule === 'all_done') {
|
|
350
576
|
if (depResults.length !== deps.length) return `dep not finished (rule=all_done)`;
|
|
351
577
|
}
|
|
@@ -430,13 +656,14 @@ async function dispatchNode(
|
|
|
430
656
|
ctx: NodeExecContext,
|
|
431
657
|
deps: WorkflowDeps,
|
|
432
658
|
workflowName: string,
|
|
659
|
+
ignorePins = false,
|
|
433
660
|
): Promise<NodeOutput> {
|
|
434
661
|
// M4-4.2 (FU8 PR #1 · 2026-05-12) — pin executor seam. When a pin
|
|
435
662
|
// exists for `<workflowName>/<node.id>` in the `.pins.json` side-
|
|
436
663
|
// file, return the pinned value as the node output and skip the
|
|
437
664
|
// real LLM / HTTP / bash call. Lets workflow authors freeze a
|
|
438
665
|
// specific node's response for fast iteration on downstream nodes.
|
|
439
|
-
const pinned = readWorkflowPin(workflowName, node.id);
|
|
666
|
+
const pinned = ignorePins ? null : readWorkflowPin(workflowName, node.id);
|
|
440
667
|
if (pinned !== null) {
|
|
441
668
|
const output = pinned.value;
|
|
442
669
|
// Fire the same 3-sink emit fan-out as the dispatch reference
|
|
@@ -464,7 +691,7 @@ async function dispatchNode(
|
|
|
464
691
|
} catch { /* best-effort */ }
|
|
465
692
|
return { ok: true, output, durationMs: 0 };
|
|
466
693
|
}
|
|
467
|
-
// Plugin kinds are dispatched before
|
|
694
|
+
// Plugin kinds are dispatched before body-key core variants. A node without `kind`
|
|
468
695
|
// never enters this branch, so the core chain below is unchanged.
|
|
469
696
|
if (isPluginKindNode(node)) return executePluginKindNode(node, ctx, deps);
|
|
470
697
|
if (isPromptNode(node)) return executePromptNode(node, ctx, deps);
|
|
@@ -501,11 +728,13 @@ async function dispatchNode(
|
|
|
501
728
|
};
|
|
502
729
|
}
|
|
503
730
|
|
|
504
|
-
/**
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
731
|
+
/** Calls that may mutate state outside the workflow during test runs. */
|
|
732
|
+
function isExternalSideEffectNode(node: DagNode): boolean {
|
|
733
|
+
return isPluginKindNode(node) || isSubworkflowNode(node) || isBashNode(node) || isSkillNode(node)
|
|
734
|
+
|| isCftNode(node) || isApprovalNode(node) || isTaskNode(node)
|
|
735
|
+
|| isHttpRequestNode(node) || isIterationNode(node);
|
|
736
|
+
}
|
|
737
|
+
|
|
509
738
|
function isTriggerVariant(node: DagNode): boolean {
|
|
510
739
|
return (
|
|
511
740
|
isScheduleTriggerNode(node)
|
|
@@ -524,7 +753,7 @@ function variantOf(node: DagNode): string {
|
|
|
524
753
|
isSwitchNode, isIterationNode, isClassifyNode, isExtractNode, isSetNode,
|
|
525
754
|
isFilterNode, isTemplateNode, isHttpRequestNode, isShowroomNode, isTaskNode,
|
|
526
755
|
isScheduleTriggerNode, isWebhookTriggerNode, isDiscordTriggerNode,
|
|
527
|
-
isTelegramTriggerNode, isManualTriggerNode, isChatTriggerNode,
|
|
756
|
+
isTelegramTriggerNode, isManualTriggerNode, isChatTriggerNode, isSubworkflowNode,
|
|
528
757
|
];
|
|
529
758
|
const index = guards.findIndex((guard) => guard(node));
|
|
530
759
|
return index < 0 ? 'unknown' : WORKFLOW_CORE_KINDS[index]!;
|
|
@@ -574,6 +803,7 @@ interface RunHeader {
|
|
|
574
803
|
workflowName: string;
|
|
575
804
|
arguments: string;
|
|
576
805
|
startedAt: number;
|
|
806
|
+
mode?: RunWorkflowOpts['mode'];
|
|
577
807
|
}
|
|
578
808
|
|
|
579
809
|
interface RunFinal extends RunHeader {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { findWorkflow } from '../discovery.js';
|
|
3
|
+
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
4
|
+
import { interpolate } from '../variables.js';
|
|
5
|
+
import type { NodeExecContext, NodeOutput, RunWorkflowOpts, SubworkflowNode, WorkflowDeps } from '../types.js';
|
|
6
|
+
|
|
7
|
+
/** Execute a named workflow as one node, retaining the full child result map. */
|
|
8
|
+
export async function executeSubworkflowNode(
|
|
9
|
+
node: SubworkflowNode,
|
|
10
|
+
ctx: NodeExecContext,
|
|
11
|
+
deps: WorkflowDeps,
|
|
12
|
+
parent: RunWorkflowOpts,
|
|
13
|
+
childRunId: string,
|
|
14
|
+
): Promise<NodeOutput> {
|
|
15
|
+
const startedAt = Date.now();
|
|
16
|
+
const stack = [...(parent.workflowStack ?? []), parent.workflow.name];
|
|
17
|
+
const failure = (error: string): NodeOutput => ({
|
|
18
|
+
ok: false, output: '', error, durationMs: Date.now() - startedAt, childRunId,
|
|
19
|
+
});
|
|
20
|
+
if (stack.includes(node.workflow)) return failure(`subworkflow cycle: ${[...stack, node.workflow].join(' -> ')}`);
|
|
21
|
+
const maxDepth = parent.maxSubworkflowDepth ?? 5;
|
|
22
|
+
if (stack.length > maxDepth) return failure(`subworkflow depth exceeds ${maxDepth}`);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const child = findWorkflow(node.workflow)?.definition;
|
|
26
|
+
if (!child) return failure(`subworkflow '${node.workflow}' not found`);
|
|
27
|
+
const inputs = Object.fromEntries(Object.entries(node.inputs).map(([name, expression]) => [
|
|
28
|
+
name, interpolate(expression, ctx).text,
|
|
29
|
+
]));
|
|
30
|
+
const { runWorkflowToCompletion } = await import('../executor.js');
|
|
31
|
+
const result = await runWorkflowToCompletion({
|
|
32
|
+
workflow: child,
|
|
33
|
+
arguments: JSON.stringify(inputs),
|
|
34
|
+
runId: childRunId,
|
|
35
|
+
workflowStack: stack,
|
|
36
|
+
maxSubworkflowDepth: parent.maxSubworkflowDepth,
|
|
37
|
+
mode: 'full',
|
|
38
|
+
ignorePins: true,
|
|
39
|
+
...(parent.artifactsDir !== undefined ? { artifactsDir: `${parent.artifactsDir}/${childRunId}` } : {}),
|
|
40
|
+
...(parent.runDir !== undefined ? { runDir: `${parent.runDir}/children/${childRunId}` } : {}),
|
|
41
|
+
...(parent.runDir === undefined && parent.artifactsDir === undefined
|
|
42
|
+
? { runDir: join(process.env.ELANOUS_WORKFLOWS_RUNS_DIR?.trim() || join(elanousStateRoot(), 'workflows-runs'), childRunId) } : {}),
|
|
43
|
+
...(parent.persistRun !== undefined ? { persistRun: parent.persistRun } : {}),
|
|
44
|
+
...(parent.signal !== undefined ? { signal: parent.signal } : {}),
|
|
45
|
+
...(parent.screen !== undefined ? { screen: parent.screen } : {}),
|
|
46
|
+
...(parent.onTokenChunk !== undefined ? { onTokenChunk: parent.onTokenChunk } : {}),
|
|
47
|
+
}, deps);
|
|
48
|
+
const failedNode = Object.entries(result.outputs).find(([, output]) => !output.ok);
|
|
49
|
+
if (!result.ok || failedNode) {
|
|
50
|
+
const error = result.events.find(event => event.type === 'workflow_failed');
|
|
51
|
+
const message = error?.type === 'workflow_failed' ? error.error
|
|
52
|
+
: failedNode ? `node '${failedNode[0]}' failed: ${failedNode[1].error ?? '(no error message)'}`
|
|
53
|
+
: 'subworkflow failed';
|
|
54
|
+
return { ...failure(message), output: result.outputs };
|
|
55
|
+
}
|
|
56
|
+
return { ok: true, output: result.outputs, durationMs: Date.now() - startedAt, childRunId };
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return failure(err instanceof Error ? err.message : String(err));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -20,7 +20,7 @@ const PLACEHOLDER = /\{\{([^{}]*)\}\}/g;
|
|
|
20
20
|
const INPUT_REF = /^inputs\.([A-Za-z_][A-Za-z0-9_]*)$/;
|
|
21
21
|
|
|
22
22
|
export function isPluginKindNode(node: DagNode): node is PluginKindNode {
|
|
23
|
-
return typeof (node as PluginKindNode).kind === 'string';
|
|
23
|
+
return typeof (node as PluginKindNode).kind === 'string' && node.kind !== 'subworkflow';
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function pluginKindRunName(run: NodeKindRun): 'bash' | 'http' | 'skill' | 'mcp' {
|