elanous 0.2.11 → 0.2.13
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/{1394-556de6d71bbdb0fb.js → 1394-931c9827067b2276.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3992-2e522a8ac5f2afde.js → 3992-fe5c06d6b31f8b25.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8605-ea5bee9dfae512c7.js → 8605-9da4678f8a310d18.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-6a061bd97f0b9398.js → page-e49b9b76c565a0b1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f14987d5850a31e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-7c97dcdfe2e37a60.js → page-4c1dbb21861beab2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-5721537ca8a3598c.js → page-f6bc66b919b2ea7d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-b654240a572e4c48.js → page-60603c1e056c9b25.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-b9750abc897508c3.js → page-a0ea8f5a2341ee6b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-c8b1ccda6ba7ae98.js → page-31012264da8a341f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{layout-d6b1d156fb95e74b.js → layout-50309aeb0bdd554a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/{page-9688f5b4f1ff950f.js → page-0696ee3fac9fe56c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66c27608f651b866.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-35414e0a007b4082.js → page-6ddd2109b7fc3a80.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/{page-e001823c35c9dd67.js → page-7a2bf830038a2264.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-371423d1a573d64b.js → page-1f327f18694fabca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-4b764b125339ac17.js → page-e5cef2fe6e4028df.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-cdf8e4b01067bcf1.js → page-cf596128d2b420ba.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-3a24072b35470157.js → page-f672536f14f0969f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-d37cb0d52f9b6bd5.js → page-29a709616df9b050.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-686da0df9bf23e5c.js → page-fee842d7c2151129.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-4dc614f3ce043e63.js → page-78b40a344ed22f24.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-d02c782fc792e2af.js → page-a011dd5b0bff29c5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-239c17b911b84e72.js → page-d92e32d51ab5157e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-dc6a79fb003f746c.js → page-5f21aed6932ef375.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-0fffb84cafdc9da6.js → page-1e1a53946804debf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-1218753c82d585f6.js → page-a1833cd43d832601.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/{page-4b5935e67531efb5.js → page-63d14a4d8fe1e1c1.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/{page-3285bc87caf1eaa5.js → page-2a511d320f762e06.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-ad553b0e06505ecd.js → page-1c3e03f88dac1e21.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/{page-fca096e3e860306f.js → page-c4d5289c2ea97a89.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9ebfa78f0d9885c3.js → page-b91f8952deaeaf27.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/{page-3dc5f21f7e39622d.js → page-71b43a2588489987.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +1 -0
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +14 -14
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +14 -14
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- 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/context/nightly-condense.yaml +21 -0
- package/graphs/context/recipes.yaml +12 -0
- package/graphs/demo/inside-seed.yaml +20 -0
- package/graphs/demo/recipes.yaml +12 -0
- package/graphs/lecture/lecture-note.yaml +28 -0
- package/graphs/lecture/recipes.yaml +17 -0
- package/package.json +2 -1
- package/plugins/card-followup/examples/sample-card.png +0 -0
- package/scripts/context-hooks/emit.ts +36 -14
- package/scripts/coord-channel-watch.sh +1 -0
- package/scripts/discord-seat-probe.ts +144 -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 +219 -0
- package/scripts/lecture-note/node.ts +256 -0
- package/scripts/lib/telegram-inject-args.ts +31 -0
- package/scripts/measure-pod-memory-by-goal.ts +130 -0
- package/scripts/release-loop/auto-approve-node.ts +1 -1
- package/scripts/release-loop/checklist-gate-node.ts +2 -1
- package/scripts/release-loop/gate-node.ts +61 -17
- package/scripts/release-loop/ops-upgrade-node.ts +59 -6
- package/scripts/release-loop/publish-node.ts +4 -1
- package/scripts/release-loop/version-node.ts +13 -3
- package/scripts/telegram-inject.ts +14 -6
- package/scripts/test-deterministic.ts +53 -3
- package/scripts/test-diet/remeasure-list.ts +112 -0
- package/scripts/ux/demo-rehearsal.ts +17 -13
- package/scripts/ux/demo-seed.ts +108 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +12 -5
- 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/src/agent/identity-env.ts +11 -0
- package/src/agent-mission/driver.ts +150 -23
- package/src/agent-mission/duo.ts +94 -0
- package/src/agent-mission/pty-decision.ts +2 -2
- package/src/autopilot/pty-control-loop.ts +4 -1
- 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 +1 -0
- package/src/cli/decisions-cli.ts +51 -19
- package/src/cli/outputs-cli.ts +92 -0
- package/src/cli/persona-cli.ts +45 -13
- package/src/cli/pod-cli.ts +27 -3
- package/src/cli/pod-memory-advice.ts +35 -0
- package/src/cli/pr-cli.ts +15 -1
- package/src/cli/release-cli.ts +135 -15
- package/src/context-bus/condense.ts +194 -0
- package/src/context-bus/context-day.ts +82 -0
- package/src/context-bus/context-now-surfaces.ts +32 -2
- package/src/context-bus/context-now.ts +2 -2
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/long-term-memory.ts +118 -22
- package/src/context-bus/nightly-condense.ts +153 -0
- package/src/context-bus/session-events.ts +35 -0
- package/src/dashboard/dashboard-status-lines.ts +2 -0
- package/src/dashboard/index.ts +8 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +24 -0
- package/src/decisions/decision-cards.ts +13 -7
- package/src/decisions/decision-ledger.ts +43 -17
- package/src/domains/outbound-alert.ts +99 -31
- package/src/domains/outbound-log-probe.ts +8 -0
- package/src/execution-loop/launch-gate.ts +17 -8
- package/src/field-note/telegram.ts +142 -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-llm.ts +23 -13
- package/src/graph-runner/graph-grow.ts +69 -13
- package/src/graph-runner/graph-tick.ts +9 -2
- package/src/graph-runner/runner.ts +92 -24
- package/src/harness/harness-cli-command.ts +165 -17
- package/src/harness/harness-queue-child.ts +37 -0
- package/src/harness/harness-queue.ts +306 -0
- package/src/hooks/consult-intake.ts +153 -0
- package/src/hooks/github-shadow.ts +72 -2
- package/src/hooks/receiver.ts +82 -3
- 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/index.ts +232 -16
- package/src/intake-plane/discord-seat-work.ts +36 -3
- package/src/intake-plane/linear-wish.ts +44 -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-card.ts +33 -0
- package/src/llm/difficulty.ts +1 -1
- package/src/loops/checker.ts +178 -0
- package/src/loops/loop-cli.ts +37 -3
- package/src/loops/observe.ts +49 -0
- package/src/loops/orchestrator/overlap.ts +141 -0
- package/src/loops/orchestrator/traffic.ts +150 -0
- package/src/loops/package/verify.ts +125 -0
- package/src/loops/verdict.ts +22 -0
- package/src/maturity/feature-maturity.ts +5 -4
- package/src/memory.ts +37 -4
- package/src/nexus/api/card-followup-route.ts +118 -0
- package/src/nexus/api/decisions-route.ts +68 -0
- package/src/nexus/api/http-server.ts +78 -8
- package/src/nexus/api/outbound-report.ts +40 -7
- package/src/nexus/api/personas.ts +97 -54
- package/src/nexus/api/skill-exec-route.ts +97 -0
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/nexus/api/workflow-history.ts +88 -0
- package/src/nexus/api/workflows.ts +52 -0
- package/src/nexus/outbound/delivery-ledger.ts +17 -8
- package/src/nexus/outbound/router.ts +8 -3
- package/src/persona/loader.ts +18 -0
- package/src/persona/persona-todo.ts +14 -9
- package/src/persona/presets.ts +10 -2
- package/src/persona/team.ts +105 -0
- package/src/persona/types.ts +4 -0
- package/src/plugins/maker/market-bundle.ts +2 -1
- package/src/pod-lease/host-lease.ts +130 -20
- package/src/release-loop/checklist.ts +15 -3
- package/src/release-loop/feature-store.ts +24 -10
- package/src/release-loop/landed-but-yellow.ts +60 -0
- package/src/seat-dispatch/seat-ask.ts +57 -12
- package/src/seat-loop/seat-loop.ts +253 -18
- package/src/seat-loop/seat-pack.ts +127 -0
- package/src/self-dev/ask-launch-flow.ts +3 -0
- package/src/self-dev/draft-sweep.ts +44 -10
- package/src/self-dev/draft-triage-rules.ts +54 -2
- package/src/self-implement/budget-gate.ts +29 -12
- package/src/self-implement/gate-candidate-ranking.ts +60 -0
- package/src/self-implement/gate-scope.ts +9 -8
- package/src/self-implement/headless-elanous-driver.ts +7 -2
- package/src/self-implement/l8-merge-queue.ts +157 -1
- package/src/self-implement/orchestrator.ts +15 -0
- package/src/self-implement/test-seams.ts +1 -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 +78 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -10
- package/src/task-orchestrator/surfaces/pod-lease.ts +18 -6
- package/src/task-orchestrator/surfaces/pod-pool.ts +27 -10
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +46 -8
- package/src/telegram-commands.ts +21 -0
- package/src/telegram-dispatch-forward.ts +1 -1
- package/src/telegram-fabric-plan.ts +90 -0
- package/src/telegram-project-command.ts +84 -4
- package/src/telegram.ts +37 -5
- package/src/tool-runtime/elanous-control-runtimes.ts +2 -1
- package/src/user-config.ts +101 -13
- 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/types.ts +13 -1
- package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-b12b6d2f8d2d1aea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +0 -1
- package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +0 -1
- /package/apps/pwa/out/_next/static/{Y4zKzL62sakG5momz3SoQ → D51l8jUBplJrIpWvENsDK}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{Y4zKzL62sakG5momz3SoQ → D51l8jUBplJrIpWvENsDK}/_ssgManifest.js +0 -0
package/src/telegram.ts
CHANGED
|
@@ -73,7 +73,11 @@ import { effectiveInstanceRoot } from './instance/resolve.js';
|
|
|
73
73
|
import { getElanousConfigDir } from './elanous-config-dir.js';
|
|
74
74
|
import { defaultFieldEvent, FieldUploadError, parseFieldCaption, resolveFieldMime, saveFieldMedia } from './field/field-media.js';
|
|
75
75
|
import { scheduleFieldReel, type FieldReelOptions } from './field/field-reel.js';
|
|
76
|
+
import { handleTelegramFieldNote } from './field-note/telegram.js';
|
|
77
|
+
import type { TranscriptionEngine, FieldAudio } from './field-note/transcribe.js';
|
|
76
78
|
import { maybeHandleCardPhoto, type CardPhotoDeps } from './telegram-card-followup.js';
|
|
79
|
+
import { attachTelegramProjectButtons } from './telegram-project-command.js';
|
|
80
|
+
import { attachTelegramFabricPlan } from './telegram-fabric-plan.js';
|
|
77
81
|
|
|
78
82
|
export type TgAttachmentKind = 'photo' | 'voice' | 'audio' | 'document';
|
|
79
83
|
|
|
@@ -101,6 +105,8 @@ export interface TgIncoming {
|
|
|
101
105
|
text: string;
|
|
102
106
|
messageId: number;
|
|
103
107
|
threadId?: number;
|
|
108
|
+
/** Telegram message timestamp, not poll time. */
|
|
109
|
+
receivedAt?: string;
|
|
104
110
|
isDm: boolean;
|
|
105
111
|
isGroup: boolean;
|
|
106
112
|
/** Zero or more attached media — populated by parseUpdate from
|
|
@@ -219,8 +225,12 @@ export interface TelegramBotOpts {
|
|
|
219
225
|
fieldRootDir?: () => string;
|
|
220
226
|
/** 시험에서는 실제 렌더 대신 가짜 실행기를 주입한다. */
|
|
221
227
|
fieldReel?: FieldReelOptions;
|
|
228
|
+
/** NOTE3a engine and audio decoder are injected; no transcription provider is assumed. */
|
|
229
|
+
fieldNoteEngine?: TranscriptionEngine;
|
|
230
|
+
fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
222
231
|
/** Test seam for the business-card graph and its private run root. */
|
|
223
232
|
cardFollowupDeps?: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
233
|
+
fabricPlanDeps?: import('./telegram-fabric-plan.js').TelegramFabricPlanDeps;
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
/** Surface-unification v2 (FU-2) — Telegram trigger event passed to
|
|
@@ -278,7 +288,7 @@ export function classifyTelegramText(
|
|
|
278
288
|
|
|
279
289
|
export class TelegramBot {
|
|
280
290
|
private readonly token: string;
|
|
281
|
-
|
|
291
|
+
readonly botId: string;
|
|
282
292
|
private readonly allowedUsers: Set<number>;
|
|
283
293
|
private readonly onMessage: TelegramBotOpts['onMessage'];
|
|
284
294
|
private readonly fetchImpl: typeof fetch;
|
|
@@ -338,8 +348,11 @@ export class TelegramBot {
|
|
|
338
348
|
private readonly fieldDefaultEventOpt?: string;
|
|
339
349
|
private readonly fieldRootDir: () => string;
|
|
340
350
|
private readonly fieldReel?: FieldReelOptions;
|
|
351
|
+
private readonly fieldNoteEngine?: TranscriptionEngine;
|
|
352
|
+
private readonly fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
341
353
|
private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
342
354
|
private readonly seatWorkDeps: TelegramSeatWorkDeps;
|
|
355
|
+
private readonly handleFabricPlan: (ctx: TgIncoming) => Promise<boolean>;
|
|
343
356
|
private seatAskTimer: ReturnType<typeof setInterval> | null = null;
|
|
344
357
|
/** 앨범 id → `#현장` 행사 · 답장 디바운스. 태그된 앨범만 들어온다. */
|
|
345
358
|
private readonly fieldGroups = new Map<string, {
|
|
@@ -375,7 +388,10 @@ export class TelegramBot {
|
|
|
375
388
|
this.fieldDefaultEventOpt = opts.fieldDefaultEvent;
|
|
376
389
|
this.fieldRootDir = opts.fieldRootDir ?? getElanousConfigDir;
|
|
377
390
|
this.fieldReel = opts.fieldReel;
|
|
391
|
+
this.fieldNoteEngine = opts.fieldNoteEngine;
|
|
392
|
+
this.fieldNoteDecodeAudio = opts.fieldNoteDecodeAudio;
|
|
378
393
|
this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
|
|
394
|
+
this.handleFabricPlan = attachTelegramFabricPlan(this, opts.fabricPlanDeps);
|
|
379
395
|
this.seatWorkDeps = { ...opts.seatWorkDeps, askDeps: { ...opts.seatWorkDeps?.askDeps,
|
|
380
396
|
channel: 'telegram', botId: this.botId,
|
|
381
397
|
send: opts.seatWorkDeps?.askDeps?.send ?? (async (origin, text) => {
|
|
@@ -1214,6 +1230,7 @@ export class TelegramBot {
|
|
|
1214
1230
|
userId: cq.from.id,
|
|
1215
1231
|
userName: cq.from.username ?? cq.from.first_name,
|
|
1216
1232
|
chatId: cq.message?.chat.id,
|
|
1233
|
+
threadId: cq.message?.message_thread_id,
|
|
1217
1234
|
messageId: cq.message?.message_id,
|
|
1218
1235
|
data: cq.data ?? '',
|
|
1219
1236
|
};
|
|
@@ -1526,8 +1543,16 @@ export class TelegramBot {
|
|
|
1526
1543
|
await this.refuseMessage(ctx);
|
|
1527
1544
|
return;
|
|
1528
1545
|
}
|
|
1546
|
+
if (await this.handleFabricPlan(ctx)) return;
|
|
1529
1547
|
// 현장 업로드 — `#현장` 캡션(또는 태그된 앨범의 나머지)의 사진·영상은 LLM 대신 현장 폴더로.
|
|
1530
1548
|
if (await this.tryHandleFieldUpload(ctx)) return;
|
|
1549
|
+
if (await handleTelegramFieldNote(ctx, {
|
|
1550
|
+
rootDir: this.fieldRootDir(),
|
|
1551
|
+
download: (fileId) => this.downloadFile(fileId),
|
|
1552
|
+
reply: async (incoming, text) => { await this.sendMessage(incoming.chatId, text, { replyTo: incoming.messageId, threadId: incoming.threadId }); },
|
|
1553
|
+
engine: this.fieldNoteEngine, decodeAudio: this.fieldNoteDecodeAudio,
|
|
1554
|
+
now: () => new Date(this.nowImpl()),
|
|
1555
|
+
})) return;
|
|
1531
1556
|
if (await maybeHandleCardPhoto(ctx, {
|
|
1532
1557
|
isOwner: (userId) => this.isOwnerAllowed(userId),
|
|
1533
1558
|
isFieldAlbum: (id) => this.fieldGroups.has(id),
|
|
@@ -1827,6 +1852,7 @@ export class TelegramBot {
|
|
|
1827
1852
|
const reply = await slashParse.cmd.handler(slashParse.args, ctx, {
|
|
1828
1853
|
userConfig: this.slashContext.userConfig,
|
|
1829
1854
|
allCommands: this.slashCommands,
|
|
1855
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
1830
1856
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
1831
1857
|
daemonBridge: this.slashContext.daemonBridge,
|
|
1832
1858
|
hitlConfirmChannel: this.hitlConfirmChannelForChat(ctx.chatId, ctx.threadId),
|
|
@@ -2011,6 +2037,7 @@ export class TelegramBot {
|
|
|
2011
2037
|
return await slashParse.cmd.handler(slashParse.args, ctx, {
|
|
2012
2038
|
userConfig: this.slashContext!.userConfig,
|
|
2013
2039
|
allCommands: this.slashCommands,
|
|
2040
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
2014
2041
|
streamer,
|
|
2015
2042
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
2016
2043
|
daemonBridge: this.slashContext!.daemonBridge,
|
|
@@ -2030,6 +2057,7 @@ export class TelegramBot {
|
|
|
2030
2057
|
return await runAcpViaSlash(activeBackend, [ctx.text], ctx, {
|
|
2031
2058
|
userConfig: this.slashContext!.userConfig,
|
|
2032
2059
|
allCommands: this.slashCommands,
|
|
2060
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
2033
2061
|
streamer,
|
|
2034
2062
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
2035
2063
|
daemonBridge: this.slashContext!.daemonBridge,
|
|
@@ -2270,6 +2298,7 @@ interface RawUpdate {
|
|
|
2270
2298
|
update_id: number;
|
|
2271
2299
|
message?: {
|
|
2272
2300
|
message_id: number;
|
|
2301
|
+
date?: number;
|
|
2273
2302
|
from?: { id: number; first_name?: string; username?: string };
|
|
2274
2303
|
chat: { id: number; type: 'private' | 'group' | 'supergroup' | 'channel' };
|
|
2275
2304
|
text?: string;
|
|
@@ -2286,7 +2315,7 @@ interface RawUpdate {
|
|
|
2286
2315
|
callback_query?: {
|
|
2287
2316
|
id: string;
|
|
2288
2317
|
from: { id: number; first_name?: string; username?: string };
|
|
2289
|
-
message?: { message_id: number; chat: { id: number } };
|
|
2318
|
+
message?: { message_id: number; message_thread_id?: number; chat: { id: number } };
|
|
2290
2319
|
data?: string;
|
|
2291
2320
|
chat_instance?: string;
|
|
2292
2321
|
};
|
|
@@ -2305,6 +2334,7 @@ export interface TgCallbackQuery {
|
|
|
2305
2334
|
userId: number;
|
|
2306
2335
|
userName?: string;
|
|
2307
2336
|
chatId?: number;
|
|
2337
|
+
threadId?: number;
|
|
2308
2338
|
messageId?: number;
|
|
2309
2339
|
data: string;
|
|
2310
2340
|
}
|
|
@@ -2397,6 +2427,7 @@ export function parseUpdate(u: RawUpdate): TgIncoming | null {
|
|
|
2397
2427
|
text: (typeof m.text === 'string' ? m.text : (m.caption ?? '')),
|
|
2398
2428
|
messageId: m.message_id,
|
|
2399
2429
|
threadId: m.message_thread_id,
|
|
2430
|
+
...(typeof m.date === 'number' ? { receivedAt: new Date(m.date * 1000).toISOString() } : {}),
|
|
2400
2431
|
isDm,
|
|
2401
2432
|
isGroup: !isDm,
|
|
2402
2433
|
attachments,
|
|
@@ -2912,9 +2943,10 @@ export function botFromConfig(opts: BotFromConfigOpts): TelegramBot {
|
|
|
2912
2943
|
botRef.ensureSurfaceHitl();
|
|
2913
2944
|
// DEC-TG(대표 10-02) — decision cards on the MAIN bot only (other channel pollers carry other tokens). The ticker
|
|
2914
2945
|
// itself sends only while this bot polls, so a send-only nexus bot never duplicates the standalone poller's cards.
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2946
|
+
const mainToken = resolveChannelBotToken('telegram', opts.userConfig)?.token;
|
|
2947
|
+
if (mainToken && botToken === mainToken) {
|
|
2948
|
+
attachTelegramProjectButtons(botRef, opts.userConfig);
|
|
2949
|
+
if (opts.userConfig.raw?.decisions === undefined || (opts.userConfig.raw.decisions as { cards?: unknown }).cards !== false) {
|
|
2918
2950
|
const bot = botRef;
|
|
2919
2951
|
void import('./decisions/telegram-decision-cards.js')
|
|
2920
2952
|
.then(({ attachTelegramDecisionCards }) => { attachTelegramDecisionCards(bot, opts.userConfig); })
|
|
@@ -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
|
@@ -3240,7 +3240,7 @@ export interface AutoReviewConfig {
|
|
|
3240
3240
|
};
|
|
3241
3241
|
}
|
|
3242
3242
|
|
|
3243
|
-
export type ModelRole = 'implement' | 'review' | 'research' | 'planning' | 'audit' | 'classify';
|
|
3243
|
+
export type ModelRole = 'implement' | 'review' | 'research' | 'planning' | 'audit' | 'classify' | 'graph-grow';
|
|
3244
3244
|
|
|
3245
3245
|
export interface RoleModelConfig {
|
|
3246
3246
|
implement?: string;
|
|
@@ -3249,6 +3249,7 @@ export interface RoleModelConfig {
|
|
|
3249
3249
|
planning?: string;
|
|
3250
3250
|
audit?: string;
|
|
3251
3251
|
classify?: string;
|
|
3252
|
+
'graph-grow'?: string;
|
|
3252
3253
|
}
|
|
3253
3254
|
|
|
3254
3255
|
/** Sparse provider-agnostic model tier preferences by execution role. */
|
|
@@ -3315,6 +3316,7 @@ export const ROLE_MODEL_DEFAULTS: Record<ModelRole, { environment: string; tier:
|
|
|
3315
3316
|
planning: { environment: 'ELANOUS_SKILL_PLAN_MODEL', tier: 'best' },
|
|
3316
3317
|
audit: { environment: 'ELANOUS_MEMORY_JUDGE_MODEL', tier: 'better' },
|
|
3317
3318
|
classify: { environment: 'ELANOUS_ACTION_CLASSIFIER_MODEL', tier: 'budget' },
|
|
3319
|
+
'graph-grow': { environment: 'ELANOUS_GRAPH_GROW_MODEL', tier: 'better' },
|
|
3318
3320
|
};
|
|
3319
3321
|
|
|
3320
3322
|
/** Resolve `auto` through the same runtime provider selector that dispatches LLM calls.
|
|
@@ -3473,7 +3475,34 @@ export function resolveRoleModel(role: ModelRole, config: UserConfig = getUserCo
|
|
|
3473
3475
|
}
|
|
3474
3476
|
|
|
3475
3477
|
|
|
3476
|
-
export type
|
|
3478
|
+
export type OrchestratorSeat = 'OP' | 'TC' | 'MK' | 'UX';
|
|
3479
|
+
export interface OrchestratorLoopConfig {
|
|
3480
|
+
seatTrees: Partial<Record<OrchestratorSeat, string[]>>;
|
|
3481
|
+
seatCaps: Record<OrchestratorSeat, number>;
|
|
3482
|
+
trafficMode: 'shadow' | 'live';
|
|
3483
|
+
}
|
|
3484
|
+
|
|
3485
|
+
export const ORCHESTRATOR_DEFAULTS: OrchestratorLoopConfig = {
|
|
3486
|
+
seatTrees: {}, seatCaps: { TC: 8, UX: 6, MK: 6, OP: 4 }, trafficMode: 'shadow',
|
|
3487
|
+
};
|
|
3488
|
+
|
|
3489
|
+
export function parseOrchestratorLoopConfig(raw: unknown): OrchestratorLoopConfig {
|
|
3490
|
+
const value = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw as Record<string, unknown> : {};
|
|
3491
|
+
const rawTrees = value.seatTrees && typeof value.seatTrees === 'object' && !Array.isArray(value.seatTrees)
|
|
3492
|
+
? value.seatTrees as Record<string, unknown> : {};
|
|
3493
|
+
const rawCaps = value.seatCaps && typeof value.seatCaps === 'object' && !Array.isArray(value.seatCaps)
|
|
3494
|
+
? value.seatCaps as Record<string, unknown> : {};
|
|
3495
|
+
const seatTrees: OrchestratorLoopConfig['seatTrees'] = {};
|
|
3496
|
+
const seatCaps = { ...ORCHESTRATOR_DEFAULTS.seatCaps };
|
|
3497
|
+
for (const seat of ['OP', 'TC', 'MK', 'UX'] as const) {
|
|
3498
|
+
if (Array.isArray(rawTrees[seat])) seatTrees[seat] = rawTrees[seat].filter((path): path is string => typeof path === 'string' && isAbsolute(path));
|
|
3499
|
+
const cap = rawCaps[seat];
|
|
3500
|
+
if (typeof cap === 'number' && Number.isSafeInteger(cap) && cap >= 0) seatCaps[seat] = cap;
|
|
3501
|
+
}
|
|
3502
|
+
return { seatTrees, seatCaps, trafficMode: value.trafficMode === 'live' ? 'live' : 'shadow' };
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
export type StewardLoopMode = 'off' | 'shadow' | 'live' | 'rescue';
|
|
3477
3506
|
|
|
3478
3507
|
export type SeatLoopMode = 'off' | 'shadow' | 'on';
|
|
3479
3508
|
|
|
@@ -3514,25 +3543,51 @@ export function parseEventsConfig(input: unknown): EventsConfig {
|
|
|
3514
3543
|
return { mode: events.mode === 'on' ? 'on' : 'shadow', routes, linearAssignees };
|
|
3515
3544
|
}
|
|
3516
3545
|
|
|
3546
|
+
export type HqFenceRole = 'telegram-poller' | 'cron' | 'seat-loop' | 'release-run' | 'conatus' | 'git-push' | 'ledger-cli';
|
|
3547
|
+
export interface HqConfig {
|
|
3548
|
+
/** ssh host that keeps the lease record — homes push to it; it never sshes back (default cloud-vm). */
|
|
3549
|
+
arbiter?: string;
|
|
3550
|
+
/** This host's identity in the lease (default os.hostname()). */
|
|
3551
|
+
hostName?: string;
|
|
3552
|
+
/** Standby host (default node-b) — the quorum's third member; promoted only by the arbiter. */
|
|
3553
|
+
standby?: string;
|
|
3554
|
+
/** Lease TTL in seconds (default 1500 = 25 min). */
|
|
3555
|
+
ttlSeconds?: number;
|
|
3556
|
+
/** Roles that may still run when this host is fenced only for lack of quorum (never when a newer generation exists). Absent = none. */
|
|
3557
|
+
failOpenRoles?: HqFenceRole[];
|
|
3558
|
+
/** Per-host nexus health URL over the tailnet (default https://<host>.<tailnetDomain>:31415/v1/health). */
|
|
3559
|
+
healthUrls?: Record<string, string>;
|
|
3560
|
+
/** MagicDNS suffix (default: read from `tailscale status --json`). */
|
|
3561
|
+
tailnetDomain?: string;
|
|
3562
|
+
/** `tailscale` binary (default tailscale). */
|
|
3563
|
+
tailscaleBin?: string;
|
|
3564
|
+
/** Highest lease generation this host ever saw (default ~/.elanous-hq/seen-generation · 600). */
|
|
3565
|
+
seenGenerationFile?: string;
|
|
3566
|
+
/** Per-probe timeout in seconds (default 5). */
|
|
3567
|
+
probeTimeoutSeconds?: number;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3517
3570
|
export interface UserConfig {
|
|
3518
3571
|
events?: EventsConfig;
|
|
3519
3572
|
/** Explicit HTTPS destination for doctor diagnostics; absent means no upload. */
|
|
3520
3573
|
diagnostics?: { uploadUrl?: string };
|
|
3574
|
+
/** 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). */
|
|
3575
|
+
hq?: HqConfig;
|
|
3521
3576
|
/** Root CLI help audience; absent or invalid means owner. */
|
|
3522
3577
|
cli?: { helpRole?: 'owner' | 'contributor' | 'general' };
|
|
3523
3578
|
/** Execution-phase HITL answer deadline; absent means 30 minutes. */
|
|
3524
3579
|
hitl?: { executionDeadlineMinutes?: number };
|
|
3525
3580
|
coo?: { linearProject?: string };
|
|
3526
|
-
decisions?: { linearProjection: { enabled: boolean } };
|
|
3581
|
+
decisions?: { linearProjection: { enabled: boolean }; requireCrossCheck: boolean };
|
|
3527
3582
|
/** Per-seat goal and Pod limits; missing or invalid limits use seat-budget defaults. */
|
|
3528
3583
|
org?: { budget?: Record<string, { dailyGoals?: number; concurrentPods?: number }> };
|
|
3529
3584
|
/** Steward and seat loops are parsed independently. An absent seat remains off. */
|
|
3530
|
-
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 };
|
|
3585
|
+
loops?: { 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 };
|
|
3531
3586
|
/** 🔐 Pod 의 Grok API 키 과금은 명시 opt-in 만. 생략·잘못된 값은 false.
|
|
3532
3587
|
* budgetGate 와 같은 `harness` 객체다 — 중복 선언이면 뒤 타입이 앞을 지운다. */
|
|
3533
|
-
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number };
|
|
3588
|
+
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; difficultyPlacement?: boolean; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number; queue?: { seatCap?: Partial<Record<'OP' | 'TC' | 'MK' | 'UX', number>> } };
|
|
3534
3589
|
/** ☸️ Pod 실행 칸 — `pool` = 기존 기본 풀(`컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]` 쉼표 · 앞이 우선). harness 실행은 인자·ELANOUS_POD_POOL·harness.podPool 다음으로 읽는다. */
|
|
3535
|
-
pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number } };
|
|
3590
|
+
pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number }; /** 실측 권고를 Pod 발사 기본값으로 쓸지 (기본 off). */ memory?: { adviseDefaults?: boolean } };
|
|
3536
3591
|
skillRouter: SkillRouterConfig;
|
|
3537
3592
|
llm: LLMConfig;
|
|
3538
3593
|
skills: SkillsConfig;
|
|
@@ -3700,7 +3755,7 @@ export function parseRoleLlmEntry(raw: unknown): { ok: true; spec: RoleLlmSpec }
|
|
|
3700
3755
|
return { ok: true, spec };
|
|
3701
3756
|
}
|
|
3702
3757
|
|
|
3703
|
-
export const MODEL_ROLES: readonly ModelRole[] = ['implement', 'review', 'research', 'planning', 'audit', 'classify'];
|
|
3758
|
+
export const MODEL_ROLES: readonly ModelRole[] = ['implement', 'review', 'research', 'planning', 'audit', 'classify', 'graph-grow'];
|
|
3704
3759
|
|
|
3705
3760
|
export function isModelRole(v: unknown): v is ModelRole {
|
|
3706
3761
|
return typeof v === 'string' && (MODEL_ROLES as readonly string[]).includes(v);
|
|
@@ -3858,8 +3913,8 @@ function defaultConfig(): UserConfig {
|
|
|
3858
3913
|
return {
|
|
3859
3914
|
cli: { helpRole: 'owner' },
|
|
3860
3915
|
coo: { linearProject: '외부 행정·큰 일 (COO)' },
|
|
3861
|
-
decisions: { linearProjection: { enabled: false } },
|
|
3862
|
-
loops: { steward: { mode: 'shadow' }, seat: { mode: 'off', questions: 'shadow', seats: ['MK'], podPool: 'pool-node-b@node-b:8' }, persona: { enabled: false } },
|
|
3916
|
+
decisions: { linearProjection: { enabled: false }, requireCrossCheck: false },
|
|
3917
|
+
loops: { orchestrator: parseOrchestratorLoopConfig(undefined), steward: { mode: 'shadow' }, seat: { mode: 'off', questions: 'shadow', seats: ['MK'], podPool: 'pool-node-b@node-b:8' }, persona: { enabled: false } },
|
|
3863
3918
|
skillRouter: { ...SR_DEFAULTS },
|
|
3864
3919
|
llm: { ...LLM_DEFAULTS },
|
|
3865
3920
|
skills: skillsDefaults(),
|
|
@@ -3928,7 +3983,7 @@ function defaultConfig(): UserConfig {
|
|
|
3928
3983
|
nativeStructure: { ...TOOLS_DEFAULTS.nativeStructure },
|
|
3929
3984
|
selfImplement: { ...TOOLS_DEFAULTS.selfImplement },
|
|
3930
3985
|
},
|
|
3931
|
-
harness: { budgetGate: { ...DEFAULT_BUDGET_GATE } },
|
|
3986
|
+
harness: { budgetGate: { ...DEFAULT_BUDGET_GATE }, difficultyPlacement: false },
|
|
3932
3987
|
grounding: { sources: [] },
|
|
3933
3988
|
raw: {},
|
|
3934
3989
|
};
|
|
@@ -4386,7 +4441,7 @@ function parseStewardLoopsConfig(input: unknown): UserConfig['loops'] {
|
|
|
4386
4441
|
}
|
|
4387
4442
|
}
|
|
4388
4443
|
return { steward: {
|
|
4389
|
-
mode: s.mode === 'off' || s.mode === 'shadow' || s.mode === 'live' ? s.mode :
|
|
4444
|
+
mode: s.mode === 'off' || s.mode === 'shadow' || s.mode === 'live' || s.mode === 'rescue' ? s.mode :
|
|
4390
4445
|
s.launch === 'off' || s.launch === 'shadow' || s.launch === 'live' ? s.launch : 'shadow',
|
|
4391
4446
|
// A valid legacy launch setting remains effective when mode is absent; explicit mode always wins.
|
|
4392
4447
|
...(s.launch === 'off' || s.launch === 'shadow' || s.launch === 'live' ? { launch: s.launch } : {}),
|
|
@@ -4405,6 +4460,25 @@ export function parseCliHelpRole(raw: unknown): NonNullable<UserConfig['cli']>['
|
|
|
4405
4460
|
return cli.helpRole === 'general' || cli.helpRole === 'contributor' ? cli.helpRole : 'owner';
|
|
4406
4461
|
}
|
|
4407
4462
|
|
|
4463
|
+
const HQ_FENCE_ROLES: readonly HqFenceRole[] = ['telegram-poller', 'cron', 'seat-loop', 'release-run', 'conatus', 'git-push'];
|
|
4464
|
+
/** `hq` block (HQ-HB · HQ-FENCE): keep only well-typed fields — absent/invalid fields fall back to the hq module defaults. */
|
|
4465
|
+
export function parseHqConfig(raw: unknown): HqConfig | undefined {
|
|
4466
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;
|
|
4467
|
+
const r = raw as Record<string, unknown>;
|
|
4468
|
+
const str = (v: unknown) => typeof v === 'string' && v.trim() ? v.trim() : undefined;
|
|
4469
|
+
const out: HqConfig = {};
|
|
4470
|
+
for (const key of ['arbiter', 'hostName', 'standby', 'tailnetDomain', 'tailscaleBin', 'seenGenerationFile'] as const) {
|
|
4471
|
+
const v = str(r[key]); if (v) out[key] = v;
|
|
4472
|
+
}
|
|
4473
|
+
if (typeof r.ttlSeconds === 'number' && Number.isFinite(r.ttlSeconds) && r.ttlSeconds > 0) out.ttlSeconds = r.ttlSeconds;
|
|
4474
|
+
if (typeof r.probeTimeoutSeconds === 'number' && Number.isFinite(r.probeTimeoutSeconds) && r.probeTimeoutSeconds > 0) out.probeTimeoutSeconds = r.probeTimeoutSeconds;
|
|
4475
|
+
if (Array.isArray(r.failOpenRoles)) out.failOpenRoles = r.failOpenRoles.filter((v): v is HqFenceRole => HQ_FENCE_ROLES.includes(v as HqFenceRole));
|
|
4476
|
+
if (r.healthUrls && typeof r.healthUrls === 'object' && !Array.isArray(r.healthUrls)) {
|
|
4477
|
+
out.healthUrls = Object.fromEntries(Object.entries(r.healthUrls as Record<string, unknown>).filter((e): e is [string, string] => typeof e[1] === 'string'));
|
|
4478
|
+
}
|
|
4479
|
+
return Object.keys(out).length ? out : undefined;
|
|
4480
|
+
}
|
|
4481
|
+
|
|
4408
4482
|
export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
4409
4483
|
if (!existsSync(path)) return defaultConfigWithRuntimeProvider();
|
|
4410
4484
|
let raw: unknown;
|
|
@@ -4530,6 +4604,8 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4530
4604
|
...(typeof legacyPod.pool === 'string' && legacyPod.pool.trim() ? { pool: legacyPod.pool.trim() } : {}),
|
|
4531
4605
|
...(typeof legacyPod.hostMirror === 'string' && legacyPod.hostMirror.trim() ? { hostMirror: legacyPod.hostMirror.trim() } : {}),
|
|
4532
4606
|
...(typeof legacyPod.groundingUrl === 'string' ? { groundingUrl: legacyPod.groundingUrl } : {}),
|
|
4607
|
+
memory: { adviseDefaults: Boolean(legacyPod.memory && typeof legacyPod.memory === 'object' && !Array.isArray(legacyPod.memory)
|
|
4608
|
+
&& (legacyPod.memory as Record<string, unknown>).adviseDefaults === true) },
|
|
4533
4609
|
lease: { perAccount: (() => {
|
|
4534
4610
|
const lease = legacyPod.lease && typeof legacyPod.lease === 'object' && !Array.isArray(legacyPod.lease)
|
|
4535
4611
|
? (legacyPod.lease as Record<string, unknown>) : {};
|
|
@@ -4539,6 +4615,13 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4539
4615
|
},
|
|
4540
4616
|
harness: {
|
|
4541
4617
|
pod: { grokApiKeyOptIn: harnessPod.grokApiKeyOptIn === true },
|
|
4618
|
+
difficultyPlacement: harness.difficultyPlacement === true,
|
|
4619
|
+
queue: { seatCap: Object.fromEntries(Object.entries(
|
|
4620
|
+
harness.queue && typeof harness.queue === 'object' && !Array.isArray(harness.queue)
|
|
4621
|
+
&& (harness.queue as Record<string, unknown>).seatCap && typeof (harness.queue as Record<string, unknown>).seatCap === 'object'
|
|
4622
|
+
&& !Array.isArray((harness.queue as Record<string, unknown>).seatCap)
|
|
4623
|
+
? (harness.queue as { seatCap: Record<string, unknown> }).seatCap : {},
|
|
4624
|
+
).filter(([seat, cap]) => /^(OP|TC|MK|UX)$/.test(seat) && typeof cap === 'number' && Number.isSafeInteger(cap) && cap > 0)) },
|
|
4542
4625
|
...(harness.substrate === 'local' || harness.substrate === 'pod' ? { substrate: harness.substrate } : {}),
|
|
4543
4626
|
...(typeof harness.podPool === 'string' && harness.podPool.trim() ? { podPool: harness.podPool.trim() } : {}),
|
|
4544
4627
|
...(typeof harness.worktreeAddTimeoutSec === 'number' && Number.isSafeInteger(harness.worktreeAddTimeoutSec)
|
|
@@ -5183,11 +5266,13 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
5183
5266
|
&& typeof (rawObj.hitl as Record<string, unknown>).executionDeadlineMinutes === 'number'
|
|
5184
5267
|
? { hitl: { executionDeadlineMinutes: (rawObj.hitl as { executionDeadlineMinutes: number }).executionDeadlineMinutes } }
|
|
5185
5268
|
: {}),
|
|
5269
|
+
...(parseHqConfig(rawObj.hq) ? { hq: parseHqConfig(rawObj.hq)! } : {}),
|
|
5186
5270
|
cli: { helpRole: parseCliHelpRole(rawObj.cli) },
|
|
5187
5271
|
coo: { linearProject: typeof (rawObj.coo as { linearProject?: unknown } | undefined)?.linearProject === 'string' && (rawObj.coo as { linearProject: string }).linearProject.trim()
|
|
5188
5272
|
? (rawObj.coo as { linearProject: string }).linearProject.trim() : '외부 행정·큰 일 (COO)' },
|
|
5189
|
-
decisions: { linearProjection: { enabled: ((rawObj.decisions as { linearProjection?: { enabled?: unknown } } | undefined)?.linearProjection?.enabled === true) }
|
|
5190
|
-
|
|
5273
|
+
decisions: { linearProjection: { enabled: ((rawObj.decisions as { linearProjection?: { enabled?: unknown } } | undefined)?.linearProjection?.enabled === true) },
|
|
5274
|
+
requireCrossCheck: (rawObj.decisions as { requireCrossCheck?: unknown } | undefined)?.requireCrossCheck === true },
|
|
5275
|
+
loops: { ...(stewardLoops ?? {}), orchestrator: parseOrchestratorLoopConfig((rawObj.loops as { orchestrator?: unknown } | undefined)?.orchestrator), seat: parseSeatLoopsConfig(rawObj.loops),
|
|
5191
5276
|
persona: { enabled: (rawObj.loops as { persona?: { enabled?: unknown } } | undefined)?.persona?.enabled === true } },
|
|
5192
5277
|
events: parseEventsConfig(rawObj.events),
|
|
5193
5278
|
// M1-1: sparse — undefined when the user hasn't set anything, so
|
|
@@ -5783,14 +5868,17 @@ export function saveUserConfig(
|
|
|
5783
5868
|
...rawHarness,
|
|
5784
5869
|
pod: cfg.harness?.pod ?? rawHarness.pod,
|
|
5785
5870
|
budgetGate: cfg.harness?.budgetGate ?? rawHarness.budgetGate,
|
|
5871
|
+
difficultyPlacement: cfg.harness?.difficultyPlacement ?? rawHarness.difficultyPlacement,
|
|
5786
5872
|
defaultRepo: cfg.harness?.defaultRepo ?? rawHarness.defaultRepo,
|
|
5787
5873
|
substrate: cfg.harness?.substrate,
|
|
5788
5874
|
podPool: cfg.harness?.podPool,
|
|
5875
|
+
queue: cfg.harness?.queue ?? rawHarness.queue,
|
|
5789
5876
|
}),
|
|
5790
5877
|
...rawRest,
|
|
5791
5878
|
...(cfg.loops ? { loops: {
|
|
5792
5879
|
...rawLoops,
|
|
5793
5880
|
...(cfg.loops.steward ? { steward: { ...rawSteward, mode: cfg.loops.steward.mode ?? cfg.loops.steward.launch ?? 'shadow' } } : {}),
|
|
5881
|
+
...(cfg.loops.orchestrator ? { orchestrator: cfg.loops.orchestrator } : {}),
|
|
5794
5882
|
...(cfg.loops.seat ? { seat: {
|
|
5795
5883
|
mode: cfg.loops.seat.mode,
|
|
5796
5884
|
questions: cfg.loops.seat.questions ?? 'shadow',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commit":"
|
|
1
|
+
{"commit":"5116219907580581e7bb40b93018d155deafa5c2"}
|
|
@@ -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,
|
|
@@ -207,6 +207,19 @@ export const NODE_CATALOG: readonly NodeSpec[] = [
|
|
|
207
207
|
condition: $item != 'skip'`,
|
|
208
208
|
related: ['iteration'],
|
|
209
209
|
},
|
|
210
|
+
{
|
|
211
|
+
kind: 'knowledge',
|
|
212
|
+
category: 'transform',
|
|
213
|
+
summary: '볼트 검색 · 찾은 조각을 다음 노드에',
|
|
214
|
+
yamlKey: 'knowledge',
|
|
215
|
+
required: ['query'],
|
|
216
|
+
optional: ['limit'],
|
|
217
|
+
example: `- id: notes
|
|
218
|
+
knowledge:
|
|
219
|
+
query: $ARGUMENTS
|
|
220
|
+
limit: 3`,
|
|
221
|
+
related: ['prompt'],
|
|
222
|
+
},
|
|
210
223
|
{
|
|
211
224
|
kind: 'template',
|
|
212
225
|
category: 'transform',
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { dispatchElanousObsidianSearch } from '../../tool-runtime/elanous-obsidian-search-runtime.js';
|
|
2
|
+
import type { KnowledgeNode, NodeExecContext, NodeOutput, WorkflowDeps } from '../types.js';
|
|
3
|
+
import { interpolate } from '../variables.js';
|
|
4
|
+
|
|
5
|
+
export async function executeKnowledgeNode(
|
|
6
|
+
node: KnowledgeNode,
|
|
7
|
+
ctx: NodeExecContext,
|
|
8
|
+
deps: WorkflowDeps,
|
|
9
|
+
): Promise<NodeOutput> {
|
|
10
|
+
const startedAt = Date.now();
|
|
11
|
+
try {
|
|
12
|
+
const query = interpolate(node.knowledge.query, {
|
|
13
|
+
arguments: ctx.arguments,
|
|
14
|
+
artifactsDir: ctx.artifactsDir,
|
|
15
|
+
outputs: ctx.outputs,
|
|
16
|
+
}).text;
|
|
17
|
+
const limit = node.knowledge.limit ?? 5;
|
|
18
|
+
const result = await (deps.searchObsidian ?? dispatchElanousObsidianSearch)({ query, limit });
|
|
19
|
+
const matches = result.matches;
|
|
20
|
+
return {
|
|
21
|
+
ok: true,
|
|
22
|
+
output: result.error ? '' : matches.slice(0, limit)
|
|
23
|
+
.map(match => `— ${match.path}:${match.lineNumber}\n${match.snippet.slice(0, 400)}`)
|
|
24
|
+
.join('\n\n'),
|
|
25
|
+
matches,
|
|
26
|
+
...(result.error ? { error: result.error } : matches.length === 0 ? { error: 'no matches' } : {}),
|
|
27
|
+
durationMs: Date.now() - startedAt,
|
|
28
|
+
};
|
|
29
|
+
} catch (err) {
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
output: '',
|
|
33
|
+
matches: [],
|
|
34
|
+
error: err instanceof Error ? err.message : String(err),
|
|
35
|
+
durationMs: Date.now() - startedAt,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
DiscordTriggerNode,
|
|
17
17
|
ExtractNode,
|
|
18
18
|
FilterNode,
|
|
19
|
+
KnowledgeNode,
|
|
19
20
|
HttpRequestNode,
|
|
20
21
|
IfNode,
|
|
21
22
|
IterationNode,
|
|
@@ -47,7 +48,7 @@ let resolvingSubworkflowReferences = false;
|
|
|
47
48
|
/** ⛔ 노드 변종의 SSOT — 도움말·문서가 이 배열에서 «파생»한다.
|
|
48
49
|
* 손으로 목록을 옮겨 적으면 늙는다(2026-09-22 실측: `elanous wf --help` 가 13종만 말했고
|
|
49
50
|
* 이 배열은 21종을 받고 있었다 — 여덟이 «안내 없이» 살아 있었다). */
|
|
50
|
-
export const WORKFLOW_NODE_VARIANT_KEYS = WORKFLOW_CORE_KINDS;
|
|
51
|
+
export const WORKFLOW_NODE_VARIANT_KEYS = [...WORKFLOW_CORE_KINDS] as const;
|
|
51
52
|
|
|
52
53
|
const KEBAB_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
53
54
|
const TRIGGER_RULES: readonly TriggerRule[] = [
|
|
@@ -825,6 +826,18 @@ export function validateWorkflow(raw: unknown): ValidationResult {
|
|
|
825
826
|
push(`${path}.filter.condition`, "'filter.condition' is required and must be a non-empty string");
|
|
826
827
|
}
|
|
827
828
|
}
|
|
829
|
+
} else if (variant === 'knowledge') {
|
|
830
|
+
if (!isObject(variantValue)) {
|
|
831
|
+
push(`${path}.knowledge`, "'knowledge' must be an object with a 'query' field");
|
|
832
|
+
} else {
|
|
833
|
+
if (typeof variantValue['query'] !== 'string') {
|
|
834
|
+
push(`${path}.knowledge.query`, "'knowledge.query' is required and must be a string expression");
|
|
835
|
+
}
|
|
836
|
+
const limit = variantValue['limit'];
|
|
837
|
+
if (limit !== undefined && (!Number.isInteger(limit) || (limit as number) < 1 || (limit as number) > 200)) {
|
|
838
|
+
push(`${path}.knowledge.limit`, "'knowledge.limit' must be an integer from 1 to 200");
|
|
839
|
+
}
|
|
840
|
+
}
|
|
828
841
|
} else if (variant === 'iteration') {
|
|
829
842
|
// Node-catalog N1.3 (2026-05-11) — sequential loop.
|
|
830
843
|
if (!isObject(variantValue)) {
|
|
@@ -1093,6 +1106,9 @@ export const isFilterNode = (n: DagNode): n is FilterNode =>
|
|
|
1093
1106
|
typeof (n as FilterNode).filter === 'object' && (n as FilterNode).filter !== null
|
|
1094
1107
|
&& typeof ((n as FilterNode).filter as { items?: unknown }).items === 'string'
|
|
1095
1108
|
&& typeof ((n as FilterNode).filter as { condition?: unknown }).condition === 'string';
|
|
1109
|
+
export const isKnowledgeNode = (n: DagNode): n is KnowledgeNode =>
|
|
1110
|
+
typeof (n as KnowledgeNode).knowledge === 'object' && (n as KnowledgeNode).knowledge !== null
|
|
1111
|
+
&& typeof ((n as KnowledgeNode).knowledge as { query?: unknown }).query === 'string';
|
|
1096
1112
|
export const isTemplateNode = (n: DagNode): n is TemplateNode =>
|
|
1097
1113
|
typeof (n as TemplateNode).template === 'object' && (n as TemplateNode).template !== null
|
|
1098
1114
|
&& typeof ((n as TemplateNode).template as { template?: unknown }).template === 'string';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// `depends_on` + `when` + `trigger_rule` topology.
|
|
7
7
|
|
|
8
8
|
import type { ToolPolicy } from '../tool-runtime/tool-policy.js';
|
|
9
|
+
import type { ElanousObsidianSearchArgs, ElanousObsidianSearchResult } from '../tool-runtime/elanous-obsidian-search-runtime.js';
|
|
9
10
|
import type { CapabilityRequirements } from '../registry/resolver.js';
|
|
10
11
|
|
|
11
12
|
export type { CapabilityRequirements } from '../registry/resolver.js';
|
|
@@ -21,8 +22,10 @@ export interface NodeOutput {
|
|
|
21
22
|
* (typically an error message string) so downstream `when` clauses
|
|
22
23
|
* can branch on `$<id>.error`. */
|
|
23
24
|
ok: boolean;
|
|
24
|
-
/** Error message
|
|
25
|
+
/** Error message (knowledge search errors can also occur with ok=true). */
|
|
25
26
|
error?: string;
|
|
27
|
+
/** Raw Obsidian matches for a knowledge node; output remains prompt-ready text. */
|
|
28
|
+
matches?: ElanousObsidianSearchResult['matches'];
|
|
26
29
|
/** Wall-clock duration in ms. */
|
|
27
30
|
durationMs: number;
|
|
28
31
|
/** Run id of the workflow called by a subworkflow node, including failures. */
|
|
@@ -185,6 +188,12 @@ export interface FilterNode extends DagNodeBase {
|
|
|
185
188
|
condition: string;
|
|
186
189
|
};
|
|
187
190
|
}
|
|
191
|
+
export interface KnowledgeNode extends DagNodeBase {
|
|
192
|
+
knowledge: {
|
|
193
|
+
query: string;
|
|
194
|
+
limit?: number;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
188
197
|
/** Node-catalog N4.1 (2026-05-11) — Schedule trigger. v1 = schema +
|
|
189
198
|
* executor pass-through. Daemon-side cron / interval registration is
|
|
190
199
|
* deferred to a follow-up that touches `nexus/daemon/scheduler.ts` +
|
|
@@ -513,6 +522,7 @@ export type DagNode =
|
|
|
513
522
|
| (ExtractNode & { kind?: undefined })
|
|
514
523
|
| (SetNode & { kind?: undefined })
|
|
515
524
|
| (FilterNode & { kind?: undefined })
|
|
525
|
+
| (KnowledgeNode & { kind?: undefined })
|
|
516
526
|
| (TemplateNode & { kind?: undefined })
|
|
517
527
|
| (HttpRequestNode & { kind?: undefined })
|
|
518
528
|
| (ShowroomNode & { kind?: undefined })
|
|
@@ -699,6 +709,8 @@ export interface WorkflowDeps {
|
|
|
699
709
|
body: string,
|
|
700
710
|
opts: { timeoutMs?: number; signal?: AbortSignal; cwd?: string; env?: NodeJS.ProcessEnv }
|
|
701
711
|
) => Promise<{ stdout: string; stderr: string; exitCode: number }>;
|
|
712
|
+
/** Obsidian search for knowledge nodes. Omitted = in-process vault search. */
|
|
713
|
+
searchObsidian?: (args: ElanousObsidianSearchArgs) => Promise<ElanousObsidianSearchResult>;
|
|
702
714
|
/** Create a TOX task (`task` node). Omitted = the in-process TOX
|
|
703
715
|
* `dispatchTaskCreate`. */
|
|
704
716
|
createTask?: (req: WorkflowTaskRequest) => Promise<WorkflowTaskResult>;
|