elanous 0.2.12 → 0.2.14
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/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-6e7e0377c1db0bdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9906-482c6619b3fdda20.js → 8060-cc008cc6fedfa818.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-7b2b4f378354869a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-1abfe3aec3be6bdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-1512d91c7491ed62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-a627db94ec6904a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-e6b84ab07d3567d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-fed69f9759d248d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-a67e11ba962337b5.js → page-15374909d8f1aebd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-012a742f81218b01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-99effd9d893a43dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-938de57ae0315e46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-160089123a40dd91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-629e1ede482ec6eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-793fa536b3a6ef37.js → page-2ce5471926761fdd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-27e99b4e54a849d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-32cde713be47cddb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e7e10cd3386222e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e64caff084f7ce21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-db07eaffba0df7e3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e1e47d8d940aba3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-86f91034bd5cabe5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-ce4d8a1215ce53a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-58043db78ba519ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-357750dfb91bf960.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-e297866051595d81.js → page-274703bc41b71333.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-3b7e821dc492bdfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-f8da5dc6f3752276.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2f810b18d89ecba6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
- package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +1 -0
- package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +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 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- 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/loops/index.html +1 -0
- package/apps/pwa/out/loops/index.txt +30 -0
- 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 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- 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 -23
- 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 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/examples/teams/personas/backend.yaml +4 -0
- package/examples/teams/personas/pm.yaml +4 -0
- package/examples/teams/personas/qa.yaml +4 -0
- package/examples/teams/small-product.yaml +20 -0
- package/graphs/lecture/lecture-note.yaml +28 -0
- package/graphs/lecture/recipes.yaml +17 -0
- package/graphs/orchestrator/orchestrator.yaml +59 -0
- package/graphs/orchestrator/recipes.yaml +18 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/rhythm/daily.yaml +38 -0
- package/graphs/rhythm/recipes.yaml +18 -0
- package/graphs/rhythm/weekly.yaml +39 -0
- package/graphs/video/recipes.yaml +3 -0
- package/graphs/video/youtube-summary.yaml +17 -0
- package/package.json +2 -1
- package/scripts/audit-test-state-writes.ts +72 -17
- package/scripts/brand/check.ts +186 -0
- package/scripts/context-hooks/emit.ts +36 -14
- package/scripts/coord-channel-watch.sh +1 -0
- package/scripts/coord-post.sh +11 -1
- package/scripts/discord-seat-probe.ts +144 -0
- package/scripts/docs-cli-check.ts +23 -6
- package/scripts/expose-rubric-check.ts +118 -0
- package/scripts/expose-rubric-suggest.ts +163 -0
- package/scripts/heal/run-role.ts +14 -0
- package/scripts/hq/hq-standby.sh +65 -0
- package/scripts/hq/standby-promote.ts +173 -0
- package/scripts/hq/standby-role.ts +59 -0
- package/scripts/hq/standby-snapshot.ts +226 -0
- package/scripts/hq/standby-verify.ts +223 -0
- package/scripts/lecture-note/node.ts +256 -0
- package/scripts/lessons/handbook-page.ts +85 -0
- package/scripts/release-loop/gate-node.ts +62 -15
- package/scripts/release-loop/ops-upgrade-node.ts +17 -5
- package/scripts/release-loop/publish-node.ts +14 -1
- package/scripts/release-loop/unattended-release.ts +23 -1
- package/scripts/release-loop/vault-note-node.ts +196 -0
- package/scripts/release-story/draft.ts +172 -0
- package/scripts/rhythm/daily.ts +383 -0
- package/scripts/rhythm/weekly.ts +294 -0
- package/scripts/skills/public-check.ts +169 -0
- package/scripts/test-deterministic.ts +57 -11
- package/scripts/test-diet/effectiveness.ts +195 -0
- package/scripts/test-diet/lib.ts +16 -8
- package/scripts/test-diet/node.ts +77 -9
- package/scripts/ux/demo-rehearsal.ts +2 -2
- package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
- package/scripts/video/youtube-summary.ts +133 -0
- package/skills/diagram-master/SKILL.md +42 -49
- package/skills/diagram-master/references/pyproject.toml +4 -1
- package/skills/diagram-master/references/routing-guide.md +4 -2
- package/skills/grill-me/SKILL.md +1 -0
- package/skills/omni-crawl/SKILL.md +16 -16
- package/skills/omni-crawl/package-lock.json +1 -544
- package/skills/omni-crawl/package.json +3 -4
- package/skills/omni-crawl/scripts/main.ts +13 -13
- package/skills/omni-crawl/scripts/monitor.ts +8 -8
- package/skills/omni-crawl/src/apify.ts +13 -2
- package/skills/omni-crawl/src/capture.ts +6 -0
- package/skills/omni-crawl/src/registry.ts +2 -2
- package/skills/omni-crawl/src/stdout-json.ts +4 -0
- package/skills/omni-digest/SKILL.md +10 -11
- package/skills/omni-digest/package-lock.json +0 -545
- package/skills/omni-digest/package.json +2 -5
- package/skills/omni-digest/scripts/main.ts +3 -3
- package/skills/omni-digest/src/delegate.ts +5 -5
- package/skills/omni-digest/src/fetch.ts +2 -2
- package/skills/omni-digest/src/media.ts +25 -11
- package/skills/omni-digest/src/visual.ts +3 -2
- package/skills/omni-market/scripts/main.ts +1 -1
- package/skills/omni-market/scripts/stdout-json.ts +4 -0
- package/skills/youtube-master/SKILL.md +13 -13
- package/skills/youtube-master/package-lock.json +0 -545
- package/skills/youtube-master/package.json +2 -5
- package/skills/youtube-master/scripts/main.ts +2 -2
- package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
- package/skills/youtube-master/src/util.ts +30 -7
- package/src/agent/identity-env.ts +11 -0
- package/src/agent-mission/driver.ts +15 -10
- package/src/agent-mission/duo.ts +94 -0
- package/src/agent-mission/pty-decision.ts +1 -1
- package/src/autopilot/build/llm-conflict-merge.ts +45 -8
- package/src/autopilot/build/merge-intent.ts +53 -0
- package/src/autopilot/track-agent-shadow.ts +2 -1
- package/src/autopilot/track-agent.ts +4 -1
- package/src/boot/daemon-prompt-request.ts +3 -0
- package/src/boot/daemon-prompt-turn.ts +6 -2
- package/src/boot/daemon-runtime.ts +48 -16
- package/src/chat/index.ts +2 -0
- package/src/claims/claims-ledger.ts +232 -0
- package/src/claims/claims-render.ts +157 -0
- package/src/cli/claims-cli.ts +94 -0
- package/src/cli/decisions-cli.ts +84 -20
- package/src/cli/docs-cli.ts +2 -0
- package/src/cli/flow-cli.ts +11 -0
- package/src/cli/freeze-cli.ts +45 -0
- package/src/cli/lesson-cli.ts +108 -0
- package/src/cli/logs-cli.ts +104 -2
- package/src/cli/logs-model-input.ts +131 -0
- package/src/cli/outputs-cli.ts +92 -0
- package/src/cli/persona-cli.ts +29 -0
- package/src/cli/pod-cli.ts +10 -3
- package/src/cli/pr-cli.ts +44 -2
- package/src/cli/private-ledger-commands.ts +54 -4
- package/src/cli/pty-drive-verdict.ts +11 -2
- package/src/cli/release-cli.ts +248 -45
- package/src/cli/rfc-status.ts +91 -0
- package/src/connectors/linear.ts +5 -3
- package/src/context-bus/condense.ts +189 -0
- package/src/context-bus/context-day.ts +82 -0
- package/src/context-bus/context-now-public.ts +86 -0
- package/src/context-bus/context-now-surfaces.ts +70 -4
- package/src/context-bus/context-now.ts +4 -3
- package/src/context-bus/long-term-memory.ts +201 -24
- package/src/context-bus/nightly-condense.ts +1 -1
- package/src/dashboard/index.ts +75 -22
- package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
- package/src/dashboard/slash-runtime/loops-table.ts +77 -0
- package/src/decisions/decision-cards.ts +13 -7
- package/src/decisions/decision-ledger.ts +83 -18
- package/src/discord/sprint21-runtime.ts +16 -0
- package/src/discord-self-message.ts +8 -0
- package/src/discord-slash-wire.ts +31 -2
- package/src/domains/outbound-alert.ts +1 -1
- package/src/elanous-config-dir.ts +29 -4
- package/src/execution-loop/launch-gate.ts +29 -14
- package/src/flow/cards.ts +239 -0
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/graph-approval-card.ts +2 -2
- package/src/graph-runner/graph-grow.ts +64 -11
- package/src/graph-runner/graph-tick.ts +13 -2
- package/src/graph-runner/runner.ts +111 -22
- package/src/harness/harness-cli-command.ts +178 -27
- package/src/harness/harness-incidents.ts +43 -12
- package/src/harness/harness-pod-dispatch.ts +2 -0
- package/src/harness/harness-queue-child.ts +37 -0
- package/src/harness/harness-queue.ts +494 -0
- package/src/harness/helper-scan.ts +139 -0
- package/src/harness/model-input-observation.ts +37 -0
- package/src/hooks/github-shadow.ts +72 -2
- package/src/hooks/receiver.ts +4 -2
- package/src/hq/hq.ts +318 -0
- package/src/hq/lease.ts +210 -0
- package/src/hq/ledger-write-target.ts +41 -0
- package/src/hq/promote.ts +301 -0
- package/src/index.ts +281 -27
- package/src/intake-plane/discord-seat-work.ts +13 -6
- package/src/intake-plane/linear-wish.ts +72 -0
- package/src/intake-plane/persona-answer.ts +5 -0
- package/src/intake-plane/telegram-seat-work.ts +13 -6
- package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
- package/src/intake-plane/wish-card.ts +53 -2
- package/src/intake-plane/wish-folder.ts +5 -2
- package/src/intake-plane/wish-reply.ts +72 -0
- package/src/lessons/lesson-import.ts +106 -0
- package/src/lessons/lesson-ledger.ts +206 -0
- package/src/loops/activity.ts +203 -0
- package/src/loops/budget.ts +32 -0
- package/src/loops/checker.ts +180 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
- package/src/loops/loop-cli.ts +72 -6
- package/src/loops/neighbors.ts +40 -0
- package/src/loops/observe.ts +59 -0
- package/src/loops/orchestrator/author-depth.ts +164 -0
- package/src/loops/orchestrator/author-input-check.ts +77 -0
- package/src/loops/orchestrator/author-ledger.ts +230 -0
- package/src/loops/orchestrator/finish-rate.ts +175 -0
- package/src/loops/orchestrator/overlap.ts +180 -0
- package/src/loops/orchestrator/resync-shadow.ts +227 -0
- package/src/loops/orchestrator/tick.ts +302 -0
- package/src/loops/orchestrator/traffic.ts +165 -0
- package/src/loops/package/verify.ts +125 -0
- package/src/loops/registry.ts +454 -9
- package/src/loops/status-rows.ts +118 -0
- package/src/loops/verdict.ts +34 -0
- package/src/maturity/bot-slash-catalog.ts +66 -0
- package/src/maturity/feature-maturity.ts +8 -5
- package/src/memory.ts +37 -4
- package/src/nexus/api/card-followup-route.ts +118 -0
- package/src/nexus/api/dashboard.ts +6 -1
- package/src/nexus/api/decisions-route.ts +68 -0
- package/src/nexus/api/http-server.ts +65 -2
- package/src/nexus/api/merge-approvals-gate.ts +1 -1
- package/src/nexus/api/personas.ts +2 -1
- package/src/nexus/api/schedules-read.ts +5 -1
- package/src/nexus/api/skill-exec-route.ts +97 -0
- package/src/nexus/api/task-cards-api.ts +44 -5
- package/src/nexus/api/workflows.ts +2 -1
- package/src/persona/loader.ts +18 -0
- package/src/persona/persona-todo.ts +14 -9
- package/src/persona/presets.ts +2 -1
- package/src/persona/team.ts +105 -0
- package/src/persona/types.ts +4 -0
- package/src/pod-lease/host-lease.ts +130 -20
- package/src/release-loop/auto-start.ts +48 -0
- package/src/release-loop/checklist.ts +13 -4
- package/src/release-loop/feature-store.ts +28 -16
- package/src/release-loop/landed-but-yellow.ts +12 -0
- package/src/release-loop/landing-freeze.ts +121 -0
- package/src/release-loop/placement.ts +242 -0
- package/src/release-loop/release-schedule.ts +3 -1
- package/src/seat-dispatch/ceo-commands.ts +2 -2
- package/src/seat-dispatch/seat-ask.ts +73 -15
- package/src/seat-dispatch/seat-questions.ts +58 -0
- package/src/seat-loop/seat-loop.ts +495 -46
- package/src/seat-loop/seat-pack.ts +127 -0
- package/src/self-dev/ask-launch-flow.ts +3 -0
- package/src/self-dev/dev-pipeline.ts +6 -2
- package/src/self-dev/draft-sweep.ts +76 -0
- package/src/self-dev/run-store.ts +73 -1
- package/src/self-dev/run-supervisor.ts +8 -0
- package/src/self-dev/self-orchestrate-runtime.ts +5 -1
- package/src/self-implement/budget-gate.ts +29 -0
- package/src/self-implement/expose-gate.ts +47 -0
- package/src/self-implement/frozen-merges.ts +294 -0
- package/src/self-implement/gate-cli.ts +10 -4
- package/src/self-implement/gate-scope.ts +46 -9
- package/src/self-implement/goal-archive.ts +222 -0
- package/src/self-implement/goal-lookup.ts +147 -0
- package/src/self-implement/heal-intake.ts +79 -0
- package/src/self-implement/host-regate.ts +25 -2
- package/src/self-implement/l8-merge-queue.ts +157 -1
- package/src/self-implement/orchestrator.ts +114 -10
- package/src/self-implement/revert-guard.ts +62 -0
- package/src/self-implement/run-ledger.ts +1 -1
- package/src/self-implement/seams.ts +28 -8
- package/src/session/index.ts +2 -0
- package/src/steward/launch.ts +5 -1
- package/src/steward/readiness.ts +125 -0
- package/src/steward/rescue.ts +75 -0
- package/src/steward/triage.ts +48 -9
- package/src/task-cards/card-cli.ts +86 -0
- package/src/task-cards/card-store.ts +10 -6
- package/src/task-orchestrator/surfaces/pod-lease.ts +23 -8
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
- package/src/task-orchestrator/surfaces/pod-pool.ts +27 -10
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +112 -18
- package/src/telegram-commands.ts +27 -3
- package/src/telegram-dispatch-forward.ts +1 -1
- package/src/telegram-fabric-plan.ts +90 -0
- package/src/telegram-loops-command.ts +44 -0
- package/src/telegram-project-command.ts +10 -4
- package/src/telegram.ts +5 -0
- package/src/tool-runtime/elanous-control-runtimes.ts +2 -1
- package/src/user-config.ts +204 -16
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/executor.ts +4 -0
- package/src/workflow-runtime/node-catalog.ts +13 -0
- package/src/workflow-runtime/nodes/knowledge.ts +38 -0
- package/src/workflow-runtime/schema.ts +17 -1
- package/src/workflow-runtime/storage.ts +31 -13
- package/src/workflow-runtime/types.ts +13 -1
- package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +0 -25
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5c05b0da4bc1392c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
- /package/apps/pwa/out/_next/static/{-6XrAoD3eU7NyMHAE4xPS → x6mjI6vqOkVVu0jFuDkz1}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { defaultBaseUrl, defaultToken } from './telegram-dispatch-forward.js';
|
|
2
|
+
import type { FabricPlan } from './self-dev/fabric-plan-core.js';
|
|
3
|
+
import type { TelegramBot, TgIncoming } from './telegram.js';
|
|
4
|
+
|
|
5
|
+
export interface TelegramFabricPlanDeps {
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
baseUrl?: () => string | null;
|
|
8
|
+
token?: () => string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Only a successful daemon draft is offered for approval; no execution endpoint is called here. */
|
|
12
|
+
export function attachTelegramFabricPlan(
|
|
13
|
+
bot: Pick<TelegramBot, 'isOwnerAllowed' | 'sendMessage' | 'sendInlineKeyboard' | 'onCallbackQuery' | 'answerCallbackQuery'>,
|
|
14
|
+
deps: TelegramFabricPlanDeps = {},
|
|
15
|
+
): (ctx: TgIncoming) => Promise<boolean> {
|
|
16
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
17
|
+
const pending = new Map<string, { chatId: number; userId: number; threadId?: number; messageId: number }>();
|
|
18
|
+
const endpoint = (path: string): { url: string; token: string | null } => {
|
|
19
|
+
const base = (deps.baseUrl ?? defaultBaseUrl)();
|
|
20
|
+
if (!base) throw new Error('데몬에 연결할 수 없습니다');
|
|
21
|
+
return { url: `${base}${path}`, token: (deps.token ?? defaultToken)() };
|
|
22
|
+
};
|
|
23
|
+
const post = async (path: string, body?: unknown): Promise<unknown> => {
|
|
24
|
+
const { url, token } = endpoint(path);
|
|
25
|
+
const response = await fetchImpl(url, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: { 'content-type': 'application/json', ...(token ? { authorization: `Bearer ${token}` } : {}) },
|
|
28
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) throw new Error(`데몬 응답 ${response.status}`);
|
|
31
|
+
return response.json();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
bot.onCallbackQuery(async (q) => {
|
|
35
|
+
const match = /^fabric:(approve|edit):([a-f0-9-]{36})$/i.exec(q.data);
|
|
36
|
+
if (!match) return;
|
|
37
|
+
const planId = match[2]!;
|
|
38
|
+
const original = pending.get(planId);
|
|
39
|
+
if (!original || !bot.isOwnerAllowed(q.userId) || q.userId !== original.userId
|
|
40
|
+
|| q.chatId !== original.chatId || q.threadId !== original.threadId || q.messageId !== original.messageId) {
|
|
41
|
+
await bot.answerCallbackQuery(q.id, { text: '이 초안의 요청자만 선택할 수 있습니다' });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (match[1] === 'edit') {
|
|
45
|
+
pending.delete(planId);
|
|
46
|
+
await bot.answerCallbackQuery(q.id);
|
|
47
|
+
await bot.sendMessage(original.chatId, '고칠 내용을 반영해 «아크: <복합 문장>»으로 다시 보내세요. 이 초안은 승인되지 않았습니다.', { threadId: original.threadId });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await post(`/v1/fabric/plans/${planId}/approve`);
|
|
52
|
+
pending.delete(planId);
|
|
53
|
+
await bot.answerCallbackQuery(q.id, { text: '승인되었습니다' });
|
|
54
|
+
await bot.sendMessage(original.chatId, `아크 초안 ${planId} 승인됨 — 실행은 별도 단계입니다.`, { threadId: original.threadId });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
await bot.answerCallbackQuery(q.id, { text: `승인 실패: ${error instanceof Error ? error.message : String(error)}` });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return async (ctx) => {
|
|
61
|
+
if (ctx.attachments.length || ctx.video || !ctx.text.startsWith('아크:')) return false;
|
|
62
|
+
const request = ctx.text.slice('아크:'.length).trim();
|
|
63
|
+
if (!request || request.includes('\n')) {
|
|
64
|
+
await bot.sendMessage(ctx.chatId, '«아크: <복합 문장>» 한 줄로 보내세요.', { replyTo: ctx.messageId, threadId: ctx.threadId });
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const body = await post('/v1/fabric/decompose', { request }) as { plan?: FabricPlan };
|
|
69
|
+
const plan = body.plan;
|
|
70
|
+
if (!plan || plan.status !== 'draft' || !/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/i.test(plan.id)
|
|
71
|
+
|| !Array.isArray(plan.nodes) || plan.nodes.length === 0) throw new Error('초안 형식 오류');
|
|
72
|
+
const steps = plan.nodes.map((node, i) => `${i + 1}. ${node.title}`).join('\n');
|
|
73
|
+
const preview = `아크 초안 · 실행 전 검토\n${steps}`;
|
|
74
|
+
const reply = { replyTo: ctx.messageId, threadId: ctx.threadId };
|
|
75
|
+
for (let offset = 0; offset + 4000 < preview.length; offset += 4000) {
|
|
76
|
+
const sent = await bot.sendMessage(ctx.chatId, preview.slice(offset, offset + 4000), reply);
|
|
77
|
+
if (sent?.messageId === undefined) throw new Error('단계 미리보기를 전부 전달하지 못했습니다 — 승인 불가');
|
|
78
|
+
}
|
|
79
|
+
const finalOffset = Math.floor((preview.length - 1) / 4000) * 4000;
|
|
80
|
+
const sent = await bot.sendInlineKeyboard(ctx.chatId, preview.slice(finalOffset), [[
|
|
81
|
+
{ text: '승인', data: `fabric:approve:${plan.id}` },
|
|
82
|
+
{ text: '고치기', data: `fabric:edit:${plan.id}` },
|
|
83
|
+
]], reply);
|
|
84
|
+
if (sent?.messageId !== undefined) pending.set(plan.id, { chatId: ctx.chatId, userId: ctx.userId, threadId: ctx.threadId, messageId: sent.messageId });
|
|
85
|
+
} catch (error) {
|
|
86
|
+
await bot.sendMessage(ctx.chatId, `아크 초안 생성 실패: ${error instanceof Error ? error.message : String(error)}`, { replyTo: ctx.messageId, threadId: ctx.threadId });
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { dashboardLoops } from './domains/dashboard-data.js';
|
|
2
|
+
import { readSchedulesInventory } from './nexus/api/schedules-read.js';
|
|
3
|
+
import { loadLoopRows, LOOP_SCHEDULES_PATH, LOOPS_PATH, type LoopRow } from './loops/status-rows.js';
|
|
4
|
+
|
|
5
|
+
interface LoopsSources {
|
|
6
|
+
schedules: () => unknown;
|
|
7
|
+
loops: () => unknown;
|
|
8
|
+
now: () => number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const defaultSources: LoopsSources = {
|
|
12
|
+
schedules: () => ({ schedules: readSchedulesInventory() }),
|
|
13
|
+
loops: () => ({ loops: dashboardLoops() }),
|
|
14
|
+
now: Date.now,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const clean = (text: string) => text.replace(/[\r\n\t]+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
18
|
+
|
|
19
|
+
/** Read the same two inventories and apply the same row verdicts as PWA /loops. */
|
|
20
|
+
export async function telegramLoopsStatus(args: string[], sources: LoopsSources = defaultSources): Promise<string> {
|
|
21
|
+
if (args.length) return '사용법: /loops';
|
|
22
|
+
try {
|
|
23
|
+
const rows = await loadLoopRows(async (path) => {
|
|
24
|
+
if (path === LOOP_SCHEDULES_PATH) return sources.schedules();
|
|
25
|
+
if (path === LOOPS_PATH) return sources.loops();
|
|
26
|
+
throw new Error('unknown inventory');
|
|
27
|
+
}, sources.now());
|
|
28
|
+
if (!rows.length) return '등록된 루프·크론이 없습니다.';
|
|
29
|
+
const counts = (['늦음', '실패', '살아 있음', '꺼짐', '판정 불가'] as const)
|
|
30
|
+
.map(verdict => `${verdict} ${rows.filter(row => row.verdict === verdict).length}`);
|
|
31
|
+
const priority: Record<LoopRow['verdict'], number> = { '늦음': 0, '실패': 1, '살아 있음': 2, '꺼짐': 3, '판정 불가': 4 };
|
|
32
|
+
const lines = rows.slice().sort((a, b) => priority[a.verdict] - priority[b.verdict]).map(row =>
|
|
33
|
+
`• ${row.verdict === '늦음' ? '🔴' : row.verdict === '실패' ? '❌' : row.verdict === '살아 있음' ? '🟢' : '⚪'} ${row.verdict} · ${clean(row.name)} (${clean(row.layer)}) · ${clean(row.mode)} · 마지막 ${row.lastRun ?? '기록 없음'} · ${clean(row.id)}`);
|
|
34
|
+
let reply = ['루프·크론 현황', counts.join(' · ')].join('\n');
|
|
35
|
+
for (const [index, line] of lines.entries()) {
|
|
36
|
+
// Telegram caps a message at 4096 characters; leave space for an explicit omission count.
|
|
37
|
+
if (reply.length + line.length + 35 > 4000) return `${reply}\n… ${lines.length - index}개 더 (메시지 길이 제한)`;
|
|
38
|
+
reply += `\n${line}`;
|
|
39
|
+
}
|
|
40
|
+
return reply;
|
|
41
|
+
} catch {
|
|
42
|
+
return '루프 현황을 읽지 못했습니다. 일부 레지스트리 조회가 실패했습니다. 데몬 연결을 확인하세요.';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -35,17 +35,23 @@ export function projectCommand(deps: TelegramProjectCommandDeps = {
|
|
|
35
35
|
debug.log('telegram.project', 'listed', { projects: projects.slice(0, 20).map(p => ({ id: p.id, name: p.name })) });
|
|
36
36
|
if (ctx.isDm && ctx.chatId === ctx.userId
|
|
37
37
|
&& String(ctx.userId) === telegramDecisionOwner(ctxOptions.userConfig) && ctxOptions.sendButtons) {
|
|
38
|
-
const
|
|
38
|
+
const eligible = projects.filter(p => {
|
|
39
39
|
const bytes = Buffer.byteLength(`prj:${p.id}`, 'utf8');
|
|
40
40
|
if (bytes <= 64) return true;
|
|
41
41
|
debug.log('telegram.project', 'button-rejected', { reason: 'callback-data-too-long', projectId: p.id, bytes });
|
|
42
42
|
return false;
|
|
43
|
-
})
|
|
44
|
-
|
|
43
|
+
});
|
|
44
|
+
const visible = eligible.slice(0, 7);
|
|
45
|
+
if (current && eligible.some(p => p.id === current.id) && !visible.some(p => p.id === current.id)) {
|
|
46
|
+
visible[visible.length - 1] = current;
|
|
47
|
+
}
|
|
48
|
+
const buttons = visible.map(p => ({ text: `${p.id === current?.id ? '✓ ' : ''}${p.name}`, data: `prj:${p.id}` }));
|
|
49
|
+
buttons.push({ text: `${session.projectId ? '' : '✓ '}받은 대화로`, data: 'prj:-' });
|
|
45
50
|
const rows: Array<Array<{ text: string; data: string }>> = [];
|
|
46
51
|
for (let i = 0; i < buttons.length; i += 2) rows.push(buttons.slice(i, i + 2));
|
|
47
52
|
try {
|
|
48
53
|
await ctxOptions.sendButtons('프로젝트를 선택하세요', rows);
|
|
54
|
+
return;
|
|
49
55
|
} catch (err) {
|
|
50
56
|
debug.log('telegram.project', 'button-rejected', {
|
|
51
57
|
reason: 'send-failed', error: err instanceof Error ? err.message : String(err),
|
|
@@ -140,6 +146,6 @@ export function attachTelegramProjectButtons(
|
|
|
140
146
|
deps.update(session.id, m => { m.projectId = project.id; });
|
|
141
147
|
debug.log('telegram.project', 'button-moved', { chatId, sessionId: session.id, projectId: project.id });
|
|
142
148
|
await bot.answerCallbackQuery(q.id);
|
|
143
|
-
await bot.sendMessage(chatId,
|
|
149
|
+
await bot.sendMessage(chatId, `지금 프로젝트: ${project.name}`);
|
|
144
150
|
});
|
|
145
151
|
}
|
package/src/telegram.ts
CHANGED
|
@@ -77,6 +77,7 @@ import { handleTelegramFieldNote } from './field-note/telegram.js';
|
|
|
77
77
|
import type { TranscriptionEngine, FieldAudio } from './field-note/transcribe.js';
|
|
78
78
|
import { maybeHandleCardPhoto, type CardPhotoDeps } from './telegram-card-followup.js';
|
|
79
79
|
import { attachTelegramProjectButtons } from './telegram-project-command.js';
|
|
80
|
+
import { attachTelegramFabricPlan } from './telegram-fabric-plan.js';
|
|
80
81
|
|
|
81
82
|
export type TgAttachmentKind = 'photo' | 'voice' | 'audio' | 'document';
|
|
82
83
|
|
|
@@ -229,6 +230,7 @@ export interface TelegramBotOpts {
|
|
|
229
230
|
fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
230
231
|
/** Test seam for the business-card graph and its private run root. */
|
|
231
232
|
cardFollowupDeps?: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
233
|
+
fabricPlanDeps?: import('./telegram-fabric-plan.js').TelegramFabricPlanDeps;
|
|
232
234
|
}
|
|
233
235
|
|
|
234
236
|
/** Surface-unification v2 (FU-2) — Telegram trigger event passed to
|
|
@@ -350,6 +352,7 @@ export class TelegramBot {
|
|
|
350
352
|
private readonly fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
351
353
|
private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
352
354
|
private readonly seatWorkDeps: TelegramSeatWorkDeps;
|
|
355
|
+
private readonly handleFabricPlan: (ctx: TgIncoming) => Promise<boolean>;
|
|
353
356
|
private seatAskTimer: ReturnType<typeof setInterval> | null = null;
|
|
354
357
|
/** 앨범 id → `#현장` 행사 · 답장 디바운스. 태그된 앨범만 들어온다. */
|
|
355
358
|
private readonly fieldGroups = new Map<string, {
|
|
@@ -388,6 +391,7 @@ export class TelegramBot {
|
|
|
388
391
|
this.fieldNoteEngine = opts.fieldNoteEngine;
|
|
389
392
|
this.fieldNoteDecodeAudio = opts.fieldNoteDecodeAudio;
|
|
390
393
|
this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
|
|
394
|
+
this.handleFabricPlan = attachTelegramFabricPlan(this, opts.fabricPlanDeps);
|
|
391
395
|
this.seatWorkDeps = { ...opts.seatWorkDeps, askDeps: { ...opts.seatWorkDeps?.askDeps,
|
|
392
396
|
channel: 'telegram', botId: this.botId,
|
|
393
397
|
send: opts.seatWorkDeps?.askDeps?.send ?? (async (origin, text) => {
|
|
@@ -1539,6 +1543,7 @@ export class TelegramBot {
|
|
|
1539
1543
|
await this.refuseMessage(ctx);
|
|
1540
1544
|
return;
|
|
1541
1545
|
}
|
|
1546
|
+
if (await this.handleFabricPlan(ctx)) return;
|
|
1542
1547
|
// 현장 업로드 — `#현장` 캡션(또는 태그된 앨범의 나머지)의 사진·영상은 LLM 대신 현장 폴더로.
|
|
1543
1548
|
if (await this.tryHandleFieldUpload(ctx)) return;
|
|
1544
1549
|
if (await handleTelegramFieldNote(ctx, {
|
|
@@ -3,6 +3,7 @@ import { StringDecoder } from 'node:string_decoder';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
5
5
|
import type { LLMToolSpec } from '../llm.js';
|
|
6
|
+
import { stateDirSourceForChild } from '../agent/identity-env.js';
|
|
6
7
|
import { debug } from '../debug/log.js';
|
|
7
8
|
import { canonicalizeForBoundary, isWithinBoundary, resolveHarnessBoundary } from '../harness/harness-write-boundary.js';
|
|
8
9
|
import { getHarnessSpace } from '../harness/harness-space.js';
|
|
@@ -133,7 +134,7 @@ async function spawnHeldElanous(command: string[], cwd: string, instanceRoot: st
|
|
|
133
134
|
try {
|
|
134
135
|
child = deps.spawn(command[0]!, command.slice(1), {
|
|
135
136
|
cwd,
|
|
136
|
-
env: { ...process.env, ELANOUS_STATE_DIR: instanceRoot },
|
|
137
|
+
env: { ...process.env, ELANOUS_STATE_DIR: instanceRoot, ELANOUS_STATE_DIR_SOURCE: stateDirSourceForChild(instanceRoot) },
|
|
137
138
|
detached: true,
|
|
138
139
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
139
140
|
});
|
package/src/user-config.ts
CHANGED
|
@@ -3475,15 +3475,55 @@ export function resolveRoleModel(role: ModelRole, config: UserConfig = getUserCo
|
|
|
3475
3475
|
}
|
|
3476
3476
|
|
|
3477
3477
|
|
|
3478
|
-
export type
|
|
3478
|
+
export type OrchestratorSeat = 'OP' | 'TC' | 'MK' | 'UX';
|
|
3479
|
+
export interface OrchestratorLoopConfig {
|
|
3480
|
+
/** ORCH1 graph mode — shadow writes observations only; live appends delegations (default shadow). */
|
|
3481
|
+
mode: 'off' | 'shadow' | 'live';
|
|
3482
|
+
seatTrees: Partial<Record<OrchestratorSeat, string[]>>;
|
|
3483
|
+
seatCaps: Record<OrchestratorSeat, number>;
|
|
3484
|
+
/** Per-seat release gate; absent seats retain the spawn-budget default. */
|
|
3485
|
+
releaseGate?: Partial<Record<OrchestratorSeat, number>>;
|
|
3486
|
+
trafficMode: 'shadow' | 'live';
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
export const ORCHESTRATOR_DEFAULTS: OrchestratorLoopConfig = {
|
|
3490
|
+
mode: 'shadow', seatTrees: {}, seatCaps: { TC: 8, UX: 6, MK: 6, OP: 4 }, trafficMode: 'shadow',
|
|
3491
|
+
};
|
|
3492
|
+
|
|
3493
|
+
export function parseOrchestratorLoopConfig(raw: unknown): OrchestratorLoopConfig {
|
|
3494
|
+
const value = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw as Record<string, unknown> : {};
|
|
3495
|
+
const rawTrees = value.seatTrees && typeof value.seatTrees === 'object' && !Array.isArray(value.seatTrees)
|
|
3496
|
+
? value.seatTrees as Record<string, unknown> : {};
|
|
3497
|
+
const rawCaps = value.seatCaps && typeof value.seatCaps === 'object' && !Array.isArray(value.seatCaps)
|
|
3498
|
+
? value.seatCaps as Record<string, unknown> : {};
|
|
3499
|
+
const rawGate = value.releaseGate && typeof value.releaseGate === 'object' && !Array.isArray(value.releaseGate)
|
|
3500
|
+
? value.releaseGate as Record<string, unknown> : {};
|
|
3501
|
+
const seatTrees: OrchestratorLoopConfig['seatTrees'] = {};
|
|
3502
|
+
const seatCaps = { ...ORCHESTRATOR_DEFAULTS.seatCaps };
|
|
3503
|
+
const releaseGate: NonNullable<OrchestratorLoopConfig['releaseGate']> = {};
|
|
3504
|
+
for (const seat of ['OP', 'TC', 'MK', 'UX'] as const) {
|
|
3505
|
+
if (Array.isArray(rawTrees[seat])) seatTrees[seat] = rawTrees[seat].filter((path): path is string => typeof path === 'string' && isAbsolute(path));
|
|
3506
|
+
const cap = rawCaps[seat];
|
|
3507
|
+
if (typeof cap === 'number' && Number.isSafeInteger(cap) && cap >= 0) seatCaps[seat] = cap;
|
|
3508
|
+
const gate = rawGate[seat];
|
|
3509
|
+
if (typeof gate === 'number' && Number.isSafeInteger(gate) && gate >= 0) releaseGate[seat] = gate;
|
|
3510
|
+
}
|
|
3511
|
+
const mode = value.mode === 'off' || value.mode === 'live' ? value.mode : 'shadow';
|
|
3512
|
+
return { mode, seatTrees, seatCaps, ...(Object.keys(releaseGate).length ? { releaseGate } : {}),
|
|
3513
|
+
trafficMode: value.trafficMode === 'live' ? 'live' : 'shadow' };
|
|
3514
|
+
}
|
|
3479
3515
|
|
|
3480
|
-
export type
|
|
3516
|
+
export type StewardLoopMode = 'off' | 'shadow' | 'live' | 'rescue';
|
|
3517
|
+
|
|
3518
|
+
export type SeatLoopMode = 'off' | 'shadow' | 'on' | 'live-safe';
|
|
3481
3519
|
|
|
3482
3520
|
export interface PersonaLoopConfig { enabled: boolean }
|
|
3483
3521
|
|
|
3484
3522
|
export interface SeatLoopConfig {
|
|
3485
|
-
/**
|
|
3523
|
+
/** Shadow observes by default; live-safe acts only through the shared rescue policy, while legacy on retains its behavior. */
|
|
3486
3524
|
mode: SeatLoopMode;
|
|
3525
|
+
/** Validated loop-agent neighbor entries keyed by the observing seat. */
|
|
3526
|
+
neighbors?: Partial<Record<'OP' | 'TC' | 'MK' | 'UX', import('./loops/neighbors.js').Neighbor[]>>;
|
|
3487
3527
|
/** Seat-to-seat and human questions default to shadow even when the checklist loop is on. */
|
|
3488
3528
|
questions?: 'shadow' | 'on';
|
|
3489
3529
|
seats?: string[];
|
|
@@ -3516,25 +3556,54 @@ export function parseEventsConfig(input: unknown): EventsConfig {
|
|
|
3516
3556
|
return { mode: events.mode === 'on' ? 'on' : 'shadow', routes, linearAssignees };
|
|
3517
3557
|
}
|
|
3518
3558
|
|
|
3559
|
+
export type HqFenceRole = 'telegram-poller' | 'cron' | 'seat-loop' | 'release-run' | 'conatus' | 'git-push' | 'ledger-cli';
|
|
3560
|
+
export interface HqConfig {
|
|
3561
|
+
/** ssh host that keeps the lease record — homes push to it; it never sshes back (default cloud-vm). */
|
|
3562
|
+
arbiter?: string;
|
|
3563
|
+
/** This host's identity in the lease (default os.hostname()). */
|
|
3564
|
+
hostName?: string;
|
|
3565
|
+
/** Standby host (default node-b) — the quorum's third member; promoted only by the arbiter. */
|
|
3566
|
+
standby?: string;
|
|
3567
|
+
/** Lease TTL in seconds (default 1500 = 25 min). */
|
|
3568
|
+
ttlSeconds?: number;
|
|
3569
|
+
/** Roles that may still run when this host is fenced only for lack of quorum (never when a newer generation exists). Absent = none. */
|
|
3570
|
+
failOpenRoles?: HqFenceRole[];
|
|
3571
|
+
/** Per-host nexus health URL over the tailnet (default https://<host>.<tailnetDomain>:31415/v1/health). */
|
|
3572
|
+
healthUrls?: Record<string, string>;
|
|
3573
|
+
/** MagicDNS suffix (default: read from `tailscale status --json`). */
|
|
3574
|
+
tailnetDomain?: string;
|
|
3575
|
+
/** `tailscale` binary (default tailscale). */
|
|
3576
|
+
tailscaleBin?: string;
|
|
3577
|
+
/** Highest lease generation this host ever saw (default ~/.elanous-hq/seen-generation · 600). */
|
|
3578
|
+
seenGenerationFile?: string;
|
|
3579
|
+
/** Per-probe timeout in seconds (default 5). */
|
|
3580
|
+
probeTimeoutSeconds?: number;
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3519
3583
|
export interface UserConfig {
|
|
3520
3584
|
events?: EventsConfig;
|
|
3521
3585
|
/** Explicit HTTPS destination for doctor diagnostics; absent means no upload. */
|
|
3522
3586
|
diagnostics?: { uploadUrl?: string };
|
|
3587
|
+
/** HQ lease (본부 임대 · 10-04 HQ-HB/HQ-FENCE): arbiter host over ssh, this host's name, per-role fail-open when the arbiter is unreachable (default: fail closed). */
|
|
3588
|
+
hq?: HqConfig;
|
|
3523
3589
|
/** Root CLI help audience; absent or invalid means owner. */
|
|
3524
3590
|
cli?: { helpRole?: 'owner' | 'contributor' | 'general' };
|
|
3591
|
+
/** Daemon public demonstration mode; absent means off. */
|
|
3592
|
+
nexus?: { demoMode?: boolean };
|
|
3525
3593
|
/** Execution-phase HITL answer deadline; absent means 30 minutes. */
|
|
3526
3594
|
hitl?: { executionDeadlineMinutes?: number };
|
|
3527
3595
|
coo?: { linearProject?: string };
|
|
3528
|
-
decisions?: { linearProjection: { enabled: boolean }
|
|
3596
|
+
decisions?: { linearProjection: { enabled: boolean }; requireCrossCheck: boolean;
|
|
3597
|
+
crossCheckNeighbor: Record<EventSeat, EventSeat>; crossCheckWaitMinutes: number };
|
|
3529
3598
|
/** Per-seat goal and Pod limits; missing or invalid limits use seat-budget defaults. */
|
|
3530
3599
|
org?: { budget?: Record<string, { dailyGoals?: number; concurrentPods?: number }> };
|
|
3531
|
-
/** Steward and seat loops are parsed independently. An absent seat
|
|
3532
|
-
loops?: { steward?: { mode?: StewardLoopMode; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string>; alertAfterFailures?: number; launch?: 'off' | 'shadow' | 'live'; maxParallel?: number; podPool?: string }; seat?: SeatLoopConfig; persona?: PersonaLoopConfig };
|
|
3600
|
+
/** Steward and seat loops are parsed independently. An absent seat defaults to shadow. */
|
|
3601
|
+
loops?: { owners?: Record<string, EventSeat>; defaultOwner?: EventSeat; orchestrator?: OrchestratorLoopConfig; steward?: { mode?: StewardLoopMode; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string>; alertAfterFailures?: number; launch?: 'off' | 'shadow' | 'live'; maxParallel?: number; podPool?: string }; seat?: SeatLoopConfig; persona?: PersonaLoopConfig };
|
|
3533
3602
|
/** 🔐 Pod 의 Grok API 키 과금은 명시 opt-in 만. 생략·잘못된 값은 false.
|
|
3534
3603
|
* budgetGate 와 같은 `harness` 객체다 — 중복 선언이면 뒤 타입이 앞을 지운다. */
|
|
3535
|
-
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; difficultyPlacement?: boolean; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number };
|
|
3604
|
+
harness?: { revertGuard?: { depth: number }; pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; exposeGate?: 'warn' | 'strict'; difficultyPlacement?: boolean; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number; queue?: { seatCap?: Partial<Record<'OP' | 'TC' | 'MK' | 'UX', number>> } };
|
|
3536
3605
|
/** ☸️ Pod 실행 칸 — `pool` = 기존 기본 풀(`컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]` 쉼표 · 앞이 우선). harness 실행은 인자·ELANOUS_POD_POOL·harness.podPool 다음으로 읽는다. */
|
|
3537
|
-
pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number } };
|
|
3606
|
+
pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number }; /** 실측 권고를 Pod 발사 기본값으로 쓸지 (기본 off). */ memory?: { adviseDefaults?: boolean } };
|
|
3538
3607
|
skillRouter: SkillRouterConfig;
|
|
3539
3608
|
llm: LLMConfig;
|
|
3540
3609
|
skills: SkillsConfig;
|
|
@@ -3860,8 +3929,9 @@ function defaultConfig(): UserConfig {
|
|
|
3860
3929
|
return {
|
|
3861
3930
|
cli: { helpRole: 'owner' },
|
|
3862
3931
|
coo: { linearProject: '외부 행정·큰 일 (COO)' },
|
|
3863
|
-
decisions: { linearProjection: { enabled: false }
|
|
3864
|
-
|
|
3932
|
+
decisions: { linearProjection: { enabled: false }, requireCrossCheck: false,
|
|
3933
|
+
crossCheckNeighbor: { OP: 'TC', TC: 'OP', MK: 'OP', UX: 'OP' }, crossCheckWaitMinutes: 120 },
|
|
3934
|
+
loops: { owners: {}, defaultOwner: 'OP', orchestrator: parseOrchestratorLoopConfig(undefined), steward: { mode: 'shadow' }, seat: { mode: 'shadow', questions: 'shadow', seats: ['MK'], podPool: 'pool-node-b@node-b:8' }, persona: { enabled: false } },
|
|
3865
3935
|
skillRouter: { ...SR_DEFAULTS },
|
|
3866
3936
|
llm: { ...LLM_DEFAULTS },
|
|
3867
3937
|
skills: skillsDefaults(),
|
|
@@ -3930,7 +4000,7 @@ function defaultConfig(): UserConfig {
|
|
|
3930
4000
|
nativeStructure: { ...TOOLS_DEFAULTS.nativeStructure },
|
|
3931
4001
|
selfImplement: { ...TOOLS_DEFAULTS.selfImplement },
|
|
3932
4002
|
},
|
|
3933
|
-
harness: { budgetGate: { ...DEFAULT_BUDGET_GATE }, difficultyPlacement: false },
|
|
4003
|
+
harness: { revertGuard: { depth: 50 }, budgetGate: { ...DEFAULT_BUDGET_GATE }, exposeGate: 'warn', difficultyPlacement: false },
|
|
3934
4004
|
grounding: { sources: [] },
|
|
3935
4005
|
raw: {},
|
|
3936
4006
|
};
|
|
@@ -4341,20 +4411,95 @@ function parseStewardTracks(input: unknown): Record<string, string> | undefined
|
|
|
4341
4411
|
return Object.keys(out).length ? out : undefined;
|
|
4342
4412
|
}
|
|
4343
4413
|
|
|
4414
|
+
function parseDecisionsConfig(input: unknown): NonNullable<UserConfig['decisions']> {
|
|
4415
|
+
const defaults: Record<EventSeat, EventSeat> = { OP: 'TC', TC: 'OP', MK: 'OP', UX: 'OP' };
|
|
4416
|
+
const raw = input && typeof input === 'object' && !Array.isArray(input) ? input as Record<string, unknown> : {};
|
|
4417
|
+
const neighbors = { ...defaults };
|
|
4418
|
+
if (raw.crossCheckNeighbor !== undefined) {
|
|
4419
|
+
if (!raw.crossCheckNeighbor || typeof raw.crossCheckNeighbor !== 'object' || Array.isArray(raw.crossCheckNeighbor)) {
|
|
4420
|
+
warnUserConfigDrop('decisions.crossCheckNeighbor', '자리별 이웃 자리 객체가 아닙니다 — 기본값으로 진행합니다.');
|
|
4421
|
+
} else {
|
|
4422
|
+
const values = raw.crossCheckNeighbor as Record<string, unknown>;
|
|
4423
|
+
for (const seat of Object.keys(defaults) as EventSeat[]) {
|
|
4424
|
+
if (values[seat] === undefined) continue;
|
|
4425
|
+
const to = values[seat];
|
|
4426
|
+
if ((to === 'OP' || to === 'TC' || to === 'MK' || to === 'UX') && to !== seat) neighbors[seat] = to;
|
|
4427
|
+
else warnUserConfigDrop(`decisions.crossCheckNeighbor.${seat}`, '다른 자리가 아닙니다 — 기본값으로 진행합니다.');
|
|
4428
|
+
}
|
|
4429
|
+
for (const seat of Object.keys(values)) {
|
|
4430
|
+
if (!(seat in defaults)) warnUserConfigDrop(`decisions.crossCheckNeighbor.${seat}`, '알 수 없는 자리입니다 — 기본값으로 진행합니다.');
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
const wait = raw.crossCheckWaitMinutes;
|
|
4435
|
+
if (wait !== undefined && !(typeof wait === 'number' && Number.isSafeInteger(wait) && wait > 0)) {
|
|
4436
|
+
warnUserConfigDrop('decisions.crossCheckWaitMinutes', '양의 정수가 아닙니다 — 기본값 120으로 진행합니다.');
|
|
4437
|
+
}
|
|
4438
|
+
return { linearProjection: { enabled: (raw.linearProjection as { enabled?: unknown } | undefined)?.enabled === true },
|
|
4439
|
+
requireCrossCheck: raw.requireCrossCheck === true, crossCheckNeighbor: neighbors,
|
|
4440
|
+
crossCheckWaitMinutes: typeof wait === 'number' && Number.isSafeInteger(wait) && wait > 0 ? wait : 120 };
|
|
4441
|
+
}
|
|
4442
|
+
|
|
4443
|
+
function parseLoopOwners(input: unknown): { owners: Record<string, EventSeat>; defaultOwner: EventSeat } {
|
|
4444
|
+
const raw = input && typeof input === 'object' && !Array.isArray(input) ? input as Record<string, unknown> : {};
|
|
4445
|
+
const valid = (value: unknown): value is EventSeat => value === 'OP' || value === 'TC' || value === 'MK' || value === 'UX';
|
|
4446
|
+
const defaultOwner = valid(raw.defaultOwner) ? raw.defaultOwner : 'OP';
|
|
4447
|
+
if (raw.defaultOwner !== undefined && !valid(raw.defaultOwner)) warnUserConfigDrop('loops.defaultOwner', '잘못된 자리 — 기본 OP 로 진행');
|
|
4448
|
+
// Prototype-less: a loop titled «__proto__» (or «constructor») must keep its owner (review round 3).
|
|
4449
|
+
const owners: Record<string, EventSeat> = Object.create(null) as Record<string, EventSeat>;
|
|
4450
|
+
if (raw.owners !== undefined) {
|
|
4451
|
+
if (!raw.owners || typeof raw.owners !== 'object' || Array.isArray(raw.owners)) {
|
|
4452
|
+
warnUserConfigDrop('loops.owners', '객체가 아니다 — 기본 자리로 진행');
|
|
4453
|
+
} else {
|
|
4454
|
+
for (const [key, value] of Object.entries(raw.owners)) {
|
|
4455
|
+
if (key.trim() && valid(value)) owners[key] = value;
|
|
4456
|
+
else warnUserConfigDrop(`loops.owners.${key}`, `잘못된 자리 — 기본 ${defaultOwner} 로 진행`);
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
return { owners, defaultOwner };
|
|
4461
|
+
}
|
|
4462
|
+
|
|
4344
4463
|
function parseSeatLoopsConfig(input: unknown): SeatLoopConfig {
|
|
4345
|
-
const defaults: SeatLoopConfig = { mode: '
|
|
4464
|
+
const defaults: SeatLoopConfig = { mode: 'shadow', questions: 'shadow', seats: ['MK'], podPool: 'pool-node-b@node-b:8' };
|
|
4346
4465
|
if (!input || typeof input !== 'object' || Array.isArray(input)) return defaults;
|
|
4347
4466
|
const seat = (input as Record<string, unknown>).seat;
|
|
4348
4467
|
if (!seat || typeof seat !== 'object' || Array.isArray(seat)) return defaults;
|
|
4349
4468
|
const values = seat as Record<string, unknown>;
|
|
4350
4469
|
const mode = values.mode;
|
|
4351
4470
|
return {
|
|
4352
|
-
mode: mode === 'on' || mode === 'shadow' ? mode : '
|
|
4471
|
+
mode: mode === 'on' || mode === 'shadow' || mode === 'live-safe' || mode === 'off' ? mode : 'shadow',
|
|
4353
4472
|
questions: values.questions === 'on' ? 'on' : 'shadow',
|
|
4354
4473
|
seats: Array.isArray(values.seats) && values.seats.length > 0
|
|
4355
4474
|
&& values.seats.every((value) => typeof value === 'string' && /^(?:MK|OP|TC|UX)$/.test(value))
|
|
4356
4475
|
? [...new Set(values.seats as string[])] : ['MK'],
|
|
4357
4476
|
podPool: typeof values.podPool === 'string' && values.podPool.trim() ? values.podPool.trim() : defaults.podPool,
|
|
4477
|
+
...(() => {
|
|
4478
|
+
const raw = values.neighbors;
|
|
4479
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
|
|
4480
|
+
const neighbors: NonNullable<SeatLoopConfig['neighbors']> = {};
|
|
4481
|
+
for (const [owner, entries] of Object.entries(raw)) {
|
|
4482
|
+
if (!/^(?:OP|TC|MK|UX)$/.test(owner) || !Array.isArray(entries)) continue;
|
|
4483
|
+
const valid = entries.filter((entry): entry is import('./loops/neighbors.js').Neighbor => {
|
|
4484
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) return false;
|
|
4485
|
+
const value = entry as Record<string, unknown>;
|
|
4486
|
+
const heartbeat = value.heartbeat && typeof value.heartbeat === 'object' && !Array.isArray(value.heartbeat)
|
|
4487
|
+
? value.heartbeat as Record<string, unknown> : undefined;
|
|
4488
|
+
const onAbsent = value.onAbsent && typeof value.onAbsent === 'object' && !Array.isArray(value.onAbsent)
|
|
4489
|
+
? value.onAbsent as Record<string, unknown> : undefined;
|
|
4490
|
+
return typeof value.id === 'string' && /^(?:op|tc|mk|ux)-seat$/.test(value.id)
|
|
4491
|
+
&& value.id !== `${owner.toLowerCase()}-seat`
|
|
4492
|
+
&& Array.isArray(value.exchange) && value.exchange.length > 0
|
|
4493
|
+
&& value.exchange.every((item) => typeof item === 'string' && ['status', 'request', 'decision', 'blocked'].includes(item))
|
|
4494
|
+
&& !!heartbeat && Number.isSafeInteger(heartbeat.everyMinutes) && (heartbeat.everyMinutes as number) > 0
|
|
4495
|
+
&& Number.isSafeInteger(heartbeat.missedTicks) && (heartbeat.missedTicks as number) > 0
|
|
4496
|
+
&& !!onAbsent && typeof onAbsent.action === 'string' && ['delegate', 'defer', 'escalate'].includes(onAbsent.action)
|
|
4497
|
+
&& typeof onAbsent.delegateTo === 'string' && onAbsent.delegateTo.trim().length > 0;
|
|
4498
|
+
});
|
|
4499
|
+
neighbors[owner as keyof typeof neighbors] = valid;
|
|
4500
|
+
}
|
|
4501
|
+
return { neighbors };
|
|
4502
|
+
})(),
|
|
4358
4503
|
...(typeof values.reportPr === 'number' && Number.isSafeInteger(values.reportPr) && values.reportPr > 0
|
|
4359
4504
|
? { reportPr: values.reportPr } : {}),
|
|
4360
4505
|
...(() => {
|
|
@@ -4388,7 +4533,7 @@ function parseStewardLoopsConfig(input: unknown): UserConfig['loops'] {
|
|
|
4388
4533
|
}
|
|
4389
4534
|
}
|
|
4390
4535
|
return { steward: {
|
|
4391
|
-
mode: s.mode === 'off' || s.mode === 'shadow' || s.mode === 'live' ? s.mode :
|
|
4536
|
+
mode: s.mode === 'off' || s.mode === 'shadow' || s.mode === 'live' || s.mode === 'rescue' ? s.mode :
|
|
4392
4537
|
s.launch === 'off' || s.launch === 'shadow' || s.launch === 'live' ? s.launch : 'shadow',
|
|
4393
4538
|
// A valid legacy launch setting remains effective when mode is absent; explicit mode always wins.
|
|
4394
4539
|
...(s.launch === 'off' || s.launch === 'shadow' || s.launch === 'live' ? { launch: s.launch } : {}),
|
|
@@ -4407,6 +4552,25 @@ export function parseCliHelpRole(raw: unknown): NonNullable<UserConfig['cli']>['
|
|
|
4407
4552
|
return cli.helpRole === 'general' || cli.helpRole === 'contributor' ? cli.helpRole : 'owner';
|
|
4408
4553
|
}
|
|
4409
4554
|
|
|
4555
|
+
const HQ_FENCE_ROLES: readonly HqFenceRole[] = ['telegram-poller', 'cron', 'seat-loop', 'release-run', 'conatus', 'git-push'];
|
|
4556
|
+
/** `hq` block (HQ-HB · HQ-FENCE): keep only well-typed fields — absent/invalid fields fall back to the hq module defaults. */
|
|
4557
|
+
export function parseHqConfig(raw: unknown): HqConfig | undefined {
|
|
4558
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;
|
|
4559
|
+
const r = raw as Record<string, unknown>;
|
|
4560
|
+
const str = (v: unknown) => typeof v === 'string' && v.trim() ? v.trim() : undefined;
|
|
4561
|
+
const out: HqConfig = {};
|
|
4562
|
+
for (const key of ['arbiter', 'hostName', 'standby', 'tailnetDomain', 'tailscaleBin', 'seenGenerationFile'] as const) {
|
|
4563
|
+
const v = str(r[key]); if (v) out[key] = v;
|
|
4564
|
+
}
|
|
4565
|
+
if (typeof r.ttlSeconds === 'number' && Number.isFinite(r.ttlSeconds) && r.ttlSeconds > 0) out.ttlSeconds = r.ttlSeconds;
|
|
4566
|
+
if (typeof r.probeTimeoutSeconds === 'number' && Number.isFinite(r.probeTimeoutSeconds) && r.probeTimeoutSeconds > 0) out.probeTimeoutSeconds = r.probeTimeoutSeconds;
|
|
4567
|
+
if (Array.isArray(r.failOpenRoles)) out.failOpenRoles = r.failOpenRoles.filter((v): v is HqFenceRole => HQ_FENCE_ROLES.includes(v as HqFenceRole));
|
|
4568
|
+
if (r.healthUrls && typeof r.healthUrls === 'object' && !Array.isArray(r.healthUrls)) {
|
|
4569
|
+
out.healthUrls = Object.fromEntries(Object.entries(r.healthUrls as Record<string, unknown>).filter((e): e is [string, string] => typeof e[1] === 'string'));
|
|
4570
|
+
}
|
|
4571
|
+
return Object.keys(out).length ? out : undefined;
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4410
4574
|
export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
4411
4575
|
if (!existsSync(path)) return defaultConfigWithRuntimeProvider();
|
|
4412
4576
|
let raw: unknown;
|
|
@@ -4526,12 +4690,17 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4526
4690
|
};
|
|
4527
4691
|
}
|
|
4528
4692
|
|
|
4693
|
+
const nexus = rawObj.nexus && typeof rawObj.nexus === 'object' && !Array.isArray(rawObj.nexus)
|
|
4694
|
+
? rawObj.nexus as Record<string, unknown> : {};
|
|
4529
4695
|
return {
|
|
4696
|
+
nexus: { demoMode: nexus.demoMode === true },
|
|
4530
4697
|
...(Object.keys(seatBudgets).length ? { org: { budget: seatBudgets } } : {}),
|
|
4531
4698
|
pod: {
|
|
4532
4699
|
...(typeof legacyPod.pool === 'string' && legacyPod.pool.trim() ? { pool: legacyPod.pool.trim() } : {}),
|
|
4533
4700
|
...(typeof legacyPod.hostMirror === 'string' && legacyPod.hostMirror.trim() ? { hostMirror: legacyPod.hostMirror.trim() } : {}),
|
|
4534
4701
|
...(typeof legacyPod.groundingUrl === 'string' ? { groundingUrl: legacyPod.groundingUrl } : {}),
|
|
4702
|
+
memory: { adviseDefaults: Boolean(legacyPod.memory && typeof legacyPod.memory === 'object' && !Array.isArray(legacyPod.memory)
|
|
4703
|
+
&& (legacyPod.memory as Record<string, unknown>).adviseDefaults === true) },
|
|
4535
4704
|
lease: { perAccount: (() => {
|
|
4536
4705
|
const lease = legacyPod.lease && typeof legacyPod.lease === 'object' && !Array.isArray(legacyPod.lease)
|
|
4537
4706
|
? (legacyPod.lease as Record<string, unknown>) : {};
|
|
@@ -4540,8 +4709,20 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4540
4709
|
})() },
|
|
4541
4710
|
},
|
|
4542
4711
|
harness: {
|
|
4712
|
+
revertGuard: { depth: (() => {
|
|
4713
|
+
const value = harness.revertGuard && typeof harness.revertGuard === 'object' && !Array.isArray(harness.revertGuard)
|
|
4714
|
+
? (harness.revertGuard as Record<string, unknown>).depth : undefined;
|
|
4715
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0 ? value : 50;
|
|
4716
|
+
})() },
|
|
4543
4717
|
pod: { grokApiKeyOptIn: harnessPod.grokApiKeyOptIn === true },
|
|
4544
4718
|
difficultyPlacement: harness.difficultyPlacement === true,
|
|
4719
|
+
exposeGate: harness.exposeGate === 'strict' ? 'strict' : 'warn',
|
|
4720
|
+
queue: { seatCap: Object.fromEntries(Object.entries(
|
|
4721
|
+
harness.queue && typeof harness.queue === 'object' && !Array.isArray(harness.queue)
|
|
4722
|
+
&& (harness.queue as Record<string, unknown>).seatCap && typeof (harness.queue as Record<string, unknown>).seatCap === 'object'
|
|
4723
|
+
&& !Array.isArray((harness.queue as Record<string, unknown>).seatCap)
|
|
4724
|
+
? (harness.queue as { seatCap: Record<string, unknown> }).seatCap : {},
|
|
4725
|
+
).filter(([seat, cap]) => /^(OP|TC|MK|UX)$/.test(seat) && typeof cap === 'number' && Number.isSafeInteger(cap) && cap > 0)) },
|
|
4545
4726
|
...(harness.substrate === 'local' || harness.substrate === 'pod' ? { substrate: harness.substrate } : {}),
|
|
4546
4727
|
...(typeof harness.podPool === 'string' && harness.podPool.trim() ? { podPool: harness.podPool.trim() } : {}),
|
|
4547
4728
|
...(typeof harness.worktreeAddTimeoutSec === 'number' && Number.isSafeInteger(harness.worktreeAddTimeoutSec)
|
|
@@ -5186,11 +5367,12 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
5186
5367
|
&& typeof (rawObj.hitl as Record<string, unknown>).executionDeadlineMinutes === 'number'
|
|
5187
5368
|
? { hitl: { executionDeadlineMinutes: (rawObj.hitl as { executionDeadlineMinutes: number }).executionDeadlineMinutes } }
|
|
5188
5369
|
: {}),
|
|
5370
|
+
...(parseHqConfig(rawObj.hq) ? { hq: parseHqConfig(rawObj.hq)! } : {}),
|
|
5189
5371
|
cli: { helpRole: parseCliHelpRole(rawObj.cli) },
|
|
5190
5372
|
coo: { linearProject: typeof (rawObj.coo as { linearProject?: unknown } | undefined)?.linearProject === 'string' && (rawObj.coo as { linearProject: string }).linearProject.trim()
|
|
5191
5373
|
? (rawObj.coo as { linearProject: string }).linearProject.trim() : '외부 행정·큰 일 (COO)' },
|
|
5192
|
-
decisions:
|
|
5193
|
-
loops: { ...(stewardLoops ?? {}), seat: parseSeatLoopsConfig(rawObj.loops),
|
|
5374
|
+
decisions: parseDecisionsConfig(rawObj.decisions),
|
|
5375
|
+
loops: { ...(stewardLoops ?? {}), ...parseLoopOwners(rawObj.loops), orchestrator: parseOrchestratorLoopConfig((rawObj.loops as { orchestrator?: unknown } | undefined)?.orchestrator), seat: parseSeatLoopsConfig(rawObj.loops),
|
|
5194
5376
|
persona: { enabled: (rawObj.loops as { persona?: { enabled?: unknown } } | undefined)?.persona?.enabled === true } },
|
|
5195
5377
|
events: parseEventsConfig(rawObj.events),
|
|
5196
5378
|
// M1-1: sparse — undefined when the user hasn't set anything, so
|
|
@@ -5786,20 +5968,26 @@ export function saveUserConfig(
|
|
|
5786
5968
|
...rawHarness,
|
|
5787
5969
|
pod: cfg.harness?.pod ?? rawHarness.pod,
|
|
5788
5970
|
budgetGate: cfg.harness?.budgetGate ?? rawHarness.budgetGate,
|
|
5971
|
+
exposeGate: cfg.harness?.exposeGate ?? rawHarness.exposeGate,
|
|
5972
|
+
revertGuard: cfg.harness?.revertGuard ?? rawHarness.revertGuard,
|
|
5789
5973
|
difficultyPlacement: cfg.harness?.difficultyPlacement ?? rawHarness.difficultyPlacement,
|
|
5790
5974
|
defaultRepo: cfg.harness?.defaultRepo ?? rawHarness.defaultRepo,
|
|
5791
5975
|
substrate: cfg.harness?.substrate,
|
|
5792
5976
|
podPool: cfg.harness?.podPool,
|
|
5977
|
+
queue: cfg.harness?.queue ?? rawHarness.queue,
|
|
5793
5978
|
}),
|
|
5794
5979
|
...rawRest,
|
|
5795
5980
|
...(cfg.loops ? { loops: {
|
|
5796
5981
|
...rawLoops,
|
|
5982
|
+
owners: cfg.loops.owners ?? {}, defaultOwner: cfg.loops.defaultOwner ?? 'OP',
|
|
5797
5983
|
...(cfg.loops.steward ? { steward: { ...rawSteward, mode: cfg.loops.steward.mode ?? cfg.loops.steward.launch ?? 'shadow' } } : {}),
|
|
5984
|
+
...(cfg.loops.orchestrator ? { orchestrator: cfg.loops.orchestrator } : {}),
|
|
5798
5985
|
...(cfg.loops.seat ? { seat: {
|
|
5799
5986
|
mode: cfg.loops.seat.mode,
|
|
5800
5987
|
questions: cfg.loops.seat.questions ?? 'shadow',
|
|
5801
5988
|
seats: cfg.loops.seat.seats ?? ['MK'],
|
|
5802
5989
|
podPool: cfg.loops.seat.podPool ?? 'pool-node-b@node-b:8',
|
|
5990
|
+
...(cfg.loops.seat.neighbors ? { neighbors: cfg.loops.seat.neighbors } : {}),
|
|
5803
5991
|
...(cfg.loops.seat.reportPr === undefined ? {} : { reportPr: cfg.loops.seat.reportPr }),
|
|
5804
5992
|
} } : {}),
|
|
5805
5993
|
} } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commit":"
|
|
1
|
+
{"commit":"855920facfd9b702ac0c47f96011b2fd67dc0f30"}
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
isClassifyNode,
|
|
19
19
|
isExtractNode,
|
|
20
20
|
isFilterNode,
|
|
21
|
+
isKnowledgeNode,
|
|
21
22
|
isHttpRequestNode,
|
|
22
23
|
isIfNode,
|
|
23
24
|
isIterationNode,
|
|
@@ -57,6 +58,7 @@ import { executeExtractNode } from './nodes/extract.js';
|
|
|
57
58
|
import { executeSetNode } from './nodes/set.js';
|
|
58
59
|
import { executeTaskNode } from './nodes/task.js';
|
|
59
60
|
import { executeFilterNode } from './nodes/filter.js';
|
|
61
|
+
import { executeKnowledgeNode } from './nodes/knowledge.js';
|
|
60
62
|
import { executeTemplateNode } from './nodes/template.js';
|
|
61
63
|
import { executeHttpRequestNode } from './nodes/http.js';
|
|
62
64
|
import { executeShowroomNode } from './nodes/showroom.js';
|
|
@@ -706,6 +708,7 @@ async function dispatchNode(
|
|
|
706
708
|
if (isExtractNode(node)) return executeExtractNode(node, ctx, deps);
|
|
707
709
|
if (isSetNode(node)) return executeSetNode(node, ctx, deps);
|
|
708
710
|
if (isFilterNode(node)) return executeFilterNode(node, ctx, deps);
|
|
711
|
+
if (isKnowledgeNode(node)) return executeKnowledgeNode(node, ctx, deps);
|
|
709
712
|
if (isTemplateNode(node)) return executeTemplateNode(node, ctx, deps);
|
|
710
713
|
if (isHttpRequestNode(node)) return executeHttpRequestNode(node, ctx, deps);
|
|
711
714
|
if (isShowroomNode(node)) return executeShowroomNode(node, ctx, deps);
|
|
@@ -748,6 +751,7 @@ function isTriggerVariant(node: DagNode): boolean {
|
|
|
748
751
|
|
|
749
752
|
function variantOf(node: DagNode): string {
|
|
750
753
|
if (isPluginKindNode(node)) return node.kind;
|
|
754
|
+
if (isKnowledgeNode(node)) return 'knowledge';
|
|
751
755
|
const guards: ReadonlyArray<(node: DagNode) => boolean> = [
|
|
752
756
|
isPromptNode, isBashNode, isSkillNode, isCftNode, isApprovalNode, isIfNode,
|
|
753
757
|
isSwitchNode, isIterationNode, isClassifyNode, isExtractNode, isSetNode,
|