elanous 0.2.18 → 0.2.20
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/{1307-30dff22c9e1f3073.js → 1307-77fad80cf54477c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +25 -0
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-d92f7ee3994e84c7.js → page-c855c24de7db74fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-4733c967b56a4277.js → page-85b316bb4235980b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-d22fd849cc22f104.js → page-9b2b26a33cb2cd42.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-bb742f995c6769e7.js → page-c9955fde67b1bcb5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-02b073a2ac793b83.js → page-7a852956c74015a3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-8a9b3594bc23289b.js → page-4ba4abe096b6c2a8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-575d4a8b4f7becb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-308111abadf35670.js → page-f5d56ff5f45ad164.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-2260e9eef0357421.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-5d97b2901e0d1ea6.js → page-7c058069c5e7fa63.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-8c3d8e63ae2e1c98.js → page-466bf0ee16ad1432.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-9b72a07d424701c6.js → page-a23bc71713bcc08f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-a572f58cd3ca5864.js → page-9cd565005b93aca6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-be5ea965a07fbc41.js → page-474cb5888ea0e8f3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-35bfec2e631d3eae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/{page-fa244bd146a00ae8.js → page-9ca21f9ad3208a61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-44d56d6391965a6a.js → page-f9ccb1b1adbea14d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-83a700d4c754d802.js → page-ec102c9b8b691e37.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-7b3170f374f77b9d.js → not-found-a9c2cfa8dda922a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-f6055495e9ed7ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-1467047104141297.js → page-db03ae3589a81c9e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4a6463b97f0ad94f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-102310930791197a.js → page-75bffecc9aa1004e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-6ed0b73bae8351d8.js → page-31d5b875760bb62d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c26fa10aac6c21c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-43336055451f6e37.js → page-68793c6e10331d66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-3cc47dca0922ab9a.js → page-46d5201d2207a511.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-a77ee355a2304ff0.js → page-d81c07a7b4f618ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-b17cd46cf0e9b8cf.js → page-be1c4e8697f22360.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cf0a4b4abead71ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-7bf54c9bb9274af8.js → page-0fd895fab9b62c1b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c6e4364d9de8f717.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0acc8e198f7b0dfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-134da468538baf48.js → page-34882c84f84021c5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-c2782b330447ffb6.js → webpack-c260571513bf43c2.js} +1 -1
- package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
- package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +1 -0
- package/apps/pwa/out/_next/static/css/d3427996da11e480.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/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/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/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/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 +16 -15
- 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 +16 -15
- 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/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +24 -23
- 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/graphs/demo/editor-recipes.yaml +22 -0
- package/graphs/ops/guardian.yaml +26 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/retro/daily.yaml +25 -0
- package/graphs/retro/recipes.yaml +24 -0
- package/package.json +1 -1
- package/scripts/ask-marker-check.ts +3 -1
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +3 -1
- package/scripts/land-global-checks.ts +89 -0
- package/scripts/lib/pch-regress-map.ts +24 -0
- package/scripts/morning-report.ts +18 -4
- package/scripts/pch-regress.ts +88 -0
- package/scripts/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +628 -65
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +229 -0
- package/scripts/release-loop/preflight.ts +6 -4
- package/scripts/release-loop/publish-window.ts +141 -0
- package/scripts/release-loop/release-docs.ts +1 -4
- package/scripts/release-loop/release-universe.ts +38 -0
- package/scripts/release-loop/resume-release.ts +67 -5
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +12 -2
- package/scripts/release-story/draft.ts +5 -1
- package/scripts/retro/shadow-compare.ts +71 -0
- package/scripts/rhythm/daily.ts +6 -1
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/agent-mission/driver.ts +34 -6
- package/src/autopilot/build/llm-conflict-merge.ts +132 -7
- package/src/autopilot/build/merge-intent.ts +135 -7
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +272 -0
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/config-drift.ts +513 -0
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +13 -7
- package/src/cli/log-event-names.ts +5 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/pr-cli.ts +20 -0
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +52 -12
- package/src/cli/retro-cli.ts +78 -0
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +193 -14
- package/src/context-bus/context-now-public.ts +1 -1
- package/src/context-bus/context-now-surfaces.ts +16 -6
- package/src/context-bus/context-now.ts +97 -3
- package/src/core-turn/short-question.ts +100 -0
- package/src/dashboard/dashboard-status-lines.ts +24 -4
- package/src/dashboard/index.ts +50 -5
- package/src/dashboard/input/slash-executor.ts +6 -2
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +68 -40
- package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +62 -23
- package/src/dashboard/slash-runtime/help-groups.ts +44 -0
- package/src/dashboard/slash-runtime/model-choices.ts +125 -0
- package/src/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +44 -13
- package/src/domains/outbound-log-probe.ts +6 -1
- package/src/domains/schedule-registry.ts +23 -0
- package/src/domains/telegram-kind-route.ts +39 -0
- package/src/domains/watch-default-scheduler.ts +95 -0
- package/src/esc-abort-gate.ts +44 -0
- package/src/graph-runner/graph-run-api.ts +205 -0
- package/src/graph-runner/runner.ts +36 -6
- package/src/harness/harness-cli-command.ts +420 -51
- package/src/harness/harness-queue.ts +315 -25
- package/src/harness/harness-salvage-cli.ts +140 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/fence-outcomes.ts +63 -0
- package/src/hq/fence-wrapper.ts +33 -0
- package/src/hq/hq.ts +17 -2
- package/src/index.ts +118 -6
- package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
- package/src/instance/test-write-guard.ts +200 -0
- package/src/intake-plane/digest.ts +39 -15
- package/src/intake-plane/harness-target.ts +4 -3
- package/src/intake-plane/intake-sources.ts +1 -0
- package/src/intake-plane/items.ts +1 -0
- package/src/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +33 -3
- package/src/loops/orchestrator/tick.ts +166 -45
- package/src/maturity/feature-maturity.ts +6 -4
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/graph-kinds.ts +10 -4
- package/src/nexus/api/graphs-api.ts +178 -6
- package/src/nexus/api/http-server.ts +54 -8
- package/src/nexus/api/loop-edges.ts +292 -17
- package/src/nexus/api/ops-api.ts +112 -29
- package/src/nexus/api/ops-board-route.ts +48 -0
- package/src/nexus/index.ts +7 -0
- package/src/onboarding/entry-hints.ts +5 -0
- package/src/onboarding.ts +24 -6
- package/src/release-loop/checklist.ts +2 -0
- package/src/release-loop/feature-store.ts +68 -18
- package/src/release-loop/gate-shards.ts +158 -0
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +51 -17
- package/src/release-loop/release-schedule.ts +6 -2
- package/src/release-loop/rubric.ts +57 -1
- package/src/retro/daily.ts +372 -0
- package/src/seat-loop/op-decide.ts +173 -0
- package/src/seat-loop/seat-loop.ts +60 -3
- package/src/seat-loop/seat-report.ts +58 -3
- package/src/self-dev/ask-launch-flow.ts +5 -4
- package/src/self-dev/ask-launch-io.ts +49 -1
- package/src/self-dev/ask-path-candidates.ts +40 -2
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/draft-sweep.ts +371 -16
- package/src/self-dev/draft-triage-rules.ts +19 -4
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +247 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/blocked-draft-policy.ts +101 -0
- package/src/self-implement/execution-clarification.ts +11 -0
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/gate-env-retry.ts +83 -0
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/orchestrator.ts +220 -6
- package/src/self-implement/run-stop.ts +123 -0
- package/src/self-implement/run-ttl.ts +258 -0
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/self-implement/salvage-retention.ts +123 -0
- package/src/self-implement/seams.ts +4 -0
- package/src/self-implement/self-implement-cli.ts +2 -0
- package/src/self-implement/sibling-resync.ts +223 -0
- package/src/self-implement/stop-autoheal.ts +204 -0
- package/src/task-agent/actions.ts +63 -2
- package/src/task-agent/board.ts +132 -0
- package/src/task-agent/card-evidence.ts +292 -0
- package/src/task-agent/completion-evidence.ts +126 -0
- package/src/task-agent/judge.ts +25 -0
- package/src/task-agent/live-moves.ts +276 -0
- package/src/task-agent/mission.ts +33 -7
- package/src/task-agent/shadow.ts +192 -15
- package/src/task-agent/task-hand.ts +124 -17
- package/src/task-orchestrator/surfaces/pod-command-job.ts +82 -8
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +233 -21
- package/src/task-orchestrator/surfaces/pod-pool.ts +155 -34
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +21 -5
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +52 -0
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/testing/real-cli-spawn.ts +106 -0
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +190 -5
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-4f936cdb30322aa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-5761612531d0146b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-8615a660c84cdb03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c39554c321576982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a3c58f5c72a5f3f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-44d5f767491692bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-61553851aa606146.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-a1f585e154e61c59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-5150ef17b5383a57.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +0 -1
- package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +0 -1
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_ssgManifest.js +0 -0
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import { mkdtempSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { parse as parseYaml } from 'yaml';
|
|
5
5
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
6
|
+
import { debug } from '../../debug/log.js';
|
|
6
7
|
import { defaultGraphsDir, loadGraphTemplatesFrom } from '../../self-implement/graph-templates.js';
|
|
7
8
|
import { loadGraphTemplates } from '../../self-implement/graph-yaml.js';
|
|
9
|
+
import { validateGraphYaml } from './graph-kinds.js';
|
|
8
10
|
import { jsonResponse } from './json-response.js';
|
|
9
11
|
|
|
10
12
|
/** Declared graph ids only. A user string is never joined onto a filesystem path. */
|
|
11
13
|
const GRAPH_ID = /^[a-z0-9-]+$/;
|
|
12
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Sidecar names a graph directory loads specially. `recipes.yaml` next to a graph is what
|
|
17
|
+
* the graph runner executes (`cmd:` recipes), so an HTTP write to `<mine>/recipes.yaml`
|
|
18
|
+
* would be a remote command path. These ids are never created, saved or reverted, and
|
|
19
|
+
* these files are never indexed as graphs.
|
|
20
|
+
*/
|
|
21
|
+
export const RESERVED_GRAPH_IDS: ReadonlySet<string> = new Set(['recipes', 'overlay', 'overlays']);
|
|
22
|
+
|
|
23
|
+
function reserved(id: string): Response | null {
|
|
24
|
+
if (!RESERVED_GRAPH_IDS.has(id)) return null;
|
|
25
|
+
debug.log('nexus.graphs', 'rejected-reserved', { id });
|
|
26
|
+
return jsonResponse({ error: 'reserved-id', id }, 400);
|
|
27
|
+
}
|
|
28
|
+
|
|
13
29
|
export interface GraphCatalogEntry {
|
|
14
30
|
id: string;
|
|
15
31
|
source: 'core' | 'mine';
|
|
@@ -45,6 +61,7 @@ function readDirYaml(dir: string): string[] {
|
|
|
45
61
|
function indexByDeclaredId(dir: string): Map<string, { file: string; text: string }> {
|
|
46
62
|
const found = new Map<string, { file: string; text: string }>();
|
|
47
63
|
for (const file of readDirYaml(dir)) {
|
|
64
|
+
if (RESERVED_GRAPH_IDS.has(file.replace(/\.ya?ml$/, ''))) continue;
|
|
48
65
|
let text: string;
|
|
49
66
|
try { text = readFileSync(join(dir, file), 'utf8'); }
|
|
50
67
|
catch { continue; }
|
|
@@ -125,6 +142,21 @@ function validateInTemp(text: string, expectedId: string): { ok: true } | { ok:
|
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
|
|
145
|
+
/** Same validator as POST /v1/graphs/validate. Invalid → 422; declared graph_id ≠ id → 400. Null = ok. */
|
|
146
|
+
function rejectGraphYaml(text: string, id: string, version?: string): Response | null {
|
|
147
|
+
const checked = validateGraphYaml('harness', text);
|
|
148
|
+
if (!checked.ok) {
|
|
149
|
+
debug.log('nexus.graphs', 'rejected-invalid', { id, ...(version ? { version } : {}), issues: checked.errors });
|
|
150
|
+
return jsonResponse({ error: 'invalid-graph', errors: checked.errors, ignoredKeys: checked.ignoredKeys }, 422);
|
|
151
|
+
}
|
|
152
|
+
if (checked.graphId !== id) {
|
|
153
|
+
const errors = [{ path: `${id}/graph_id`, message: 'graph_id 가 요청 id 와 다르다' }];
|
|
154
|
+
debug.log('nexus.graphs', 'rejected-invalid', { id, issues: errors });
|
|
155
|
+
return jsonResponse({ error: 'graph-id-mismatch', errors }, 400);
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
128
160
|
/** Core graphs are read from the same YAML loader as the harness, never rewritten by this API. */
|
|
129
161
|
export function handleGraphsGet(pathname: string, dir = defaultGraphsDir(), deps: GraphsApiDeps = {}): Response {
|
|
130
162
|
const coreDir = deps.coreDir ?? dir;
|
|
@@ -168,6 +200,8 @@ export async function handleGraphsPut(pathname: string, req: Request, deps: Grap
|
|
|
168
200
|
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
169
201
|
const id = resolveId(match[1]!);
|
|
170
202
|
if (!id) return jsonResponse({ error: 'bad_request', reason: 'invalid graph id' }, 400);
|
|
203
|
+
const reservedId = reserved(id);
|
|
204
|
+
if (reservedId) return reservedId;
|
|
171
205
|
const coreDir = deps.coreDir ?? defaultGraphsDir();
|
|
172
206
|
const mineDir = deps.mineDir ?? mineGraphsDir();
|
|
173
207
|
const core = coreCatalog(coreDir);
|
|
@@ -178,12 +212,146 @@ export async function handleGraphsPut(pathname: string, req: Request, deps: Grap
|
|
|
178
212
|
let body: { yaml?: unknown };
|
|
179
213
|
try { body = await req.json() as { yaml?: unknown }; }
|
|
180
214
|
catch { return jsonResponse({ error: 'bad_request', reason: 'json body required' }, 400); }
|
|
181
|
-
if (typeof body
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
215
|
+
if (typeof body?.yaml !== 'string') return jsonResponse({ error: 'bad_request', reason: 'yaml string required' }, 400);
|
|
216
|
+
const rejected = rejectGraphYaml(body.yaml, id);
|
|
217
|
+
if (rejected) return rejected;
|
|
184
218
|
const existing = indexByDeclaredId(mineDir).get(id)!;
|
|
185
|
-
|
|
186
|
-
return jsonResponse({
|
|
219
|
+
// Writes go only to <mine>/<id>.yaml; a hand-placed file under another name is not edited over HTTP.
|
|
220
|
+
if (existing.file !== `${id}.yaml`) return jsonResponse({ error: 'file-name-mismatch', id, file: existing.file }, 409);
|
|
221
|
+
const { version, previous } = writeWithVersion(mineDir, id, existing, body.yaml);
|
|
222
|
+
debug.log('nexus.graphs', 'saved', { id, version, previous });
|
|
223
|
+
return jsonResponse({ id, source: 'mine', editable: true, saved: true, version, previous });
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const VERSION_ID = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z(?:-\d{4})?$/;
|
|
227
|
+
export const GRAPH_VERSION_CAP = 20;
|
|
228
|
+
|
|
229
|
+
function versionsDir(mineDir: string, id: string): string {
|
|
230
|
+
return join(mineDir, '.versions', id);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Version ids are ISO timestamps (`:`/`.` → `-`), so name order is save order. */
|
|
234
|
+
export function listGraphVersions(mineDir: string, id: string): Array<{ version: string; savedAt: string; bytes: number }> {
|
|
235
|
+
const dir = versionsDir(mineDir, id);
|
|
236
|
+
// Only `.yaml` is ever written, read and reverted — a stray `.yml` is not a version.
|
|
237
|
+
return readDirYaml(dir)
|
|
238
|
+
.filter((file) => file.endsWith('.yaml'))
|
|
239
|
+
.map((file) => file.replace(/\.yaml$/, ''))
|
|
240
|
+
.filter((version) => VERSION_ID.test(version))
|
|
241
|
+
.sort()
|
|
242
|
+
.map((version) => {
|
|
243
|
+
const iso = /^(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/.exec(version);
|
|
244
|
+
let bytes = 0;
|
|
245
|
+
try { bytes = statSync(join(dir, `${version}.yaml`)).size; } catch { /* listed above; raced away */ }
|
|
246
|
+
return { version, savedAt: iso ? `${iso[1]}T${iso[2]}:${iso[3]}:${iso[4]}.${iso[5]}Z` : version, bytes };
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function recordVersion(mineDir: string, id: string, text: string): string {
|
|
251
|
+
const dir = versionsDir(mineDir, id);
|
|
252
|
+
mkdirSync(dir, { recursive: true });
|
|
253
|
+
const base = new Date().toISOString().replace(/[:.]/g, '-');
|
|
254
|
+
let version = base;
|
|
255
|
+
for (let n = 1; existsSync(join(dir, `${version}.yaml`)); n += 1) version = `${base}-${String(n).padStart(4, '0')}`;
|
|
256
|
+
writeFileSync(join(dir, `${version}.yaml`), text);
|
|
257
|
+
const all = listGraphVersions(mineDir, id);
|
|
258
|
+
for (const old of all.slice(0, Math.max(0, all.length - GRAPH_VERSION_CAP))) {
|
|
259
|
+
rmSync(join(dir, `${old.version}.yaml`), { force: true });
|
|
260
|
+
}
|
|
261
|
+
return version;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Every saved state is a version. A graph with no history yet (e.g. a fresh clone)
|
|
266
|
+
* first records its current bytes, so `previous` always points at restorable bytes.
|
|
267
|
+
*/
|
|
268
|
+
function writeWithVersion(mineDir: string, id: string, existing: { file: string; text: string }, text: string): { version: string; previous: string } {
|
|
269
|
+
const history = listGraphVersions(mineDir, id);
|
|
270
|
+
const previous = history.at(-1)?.version ?? recordVersion(mineDir, id, existing.text);
|
|
271
|
+
// Version first, then an atomic replace of the current file: a crash in between leaves
|
|
272
|
+
// the old current bytes intact (they are `previous`), never bytes that no version holds.
|
|
273
|
+
const version = recordVersion(mineDir, id, text);
|
|
274
|
+
const target = join(mineDir, `${id}.yaml`);
|
|
275
|
+
const temp = join(mineDir, `.${id}.yaml.${process.pid}.tmp`);
|
|
276
|
+
writeFileSync(temp, text);
|
|
277
|
+
renameSync(temp, target);
|
|
278
|
+
return { version, previous };
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function mineOwnership(id: string, deps: GraphsApiDeps): { mineDir: string; existing: { file: string; text: string } } | Response {
|
|
282
|
+
const reservedId = reserved(id);
|
|
283
|
+
if (reservedId) return reservedId;
|
|
284
|
+
const coreDir = deps.coreDir ?? defaultGraphsDir();
|
|
285
|
+
const mineDir = deps.mineDir ?? mineGraphsDir();
|
|
286
|
+
const existing = indexByDeclaredId(mineDir).get(id);
|
|
287
|
+
if (!existing) {
|
|
288
|
+
const core = coreCatalog(coreDir);
|
|
289
|
+
if (core.ok && indexByDeclaredId(coreDir).has(id)) return jsonResponse({ error: 'core-read-only', id }, 403);
|
|
290
|
+
return jsonResponse({ error: 'not-found', id }, 404);
|
|
291
|
+
}
|
|
292
|
+
return { mineDir, existing };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** GET /v1/graphs/<id>/versions — only «mine» graphs have history. */
|
|
296
|
+
export function handleGraphVersionsGet(pathname: string, deps: GraphsApiDeps = {}): Response {
|
|
297
|
+
const match = /^\/v1\/graphs\/([^/]+)\/versions$/.exec(pathname);
|
|
298
|
+
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
299
|
+
const id = resolveId(match[1]!);
|
|
300
|
+
if (!id) return jsonResponse({ error: 'bad_request', reason: 'invalid graph id' }, 400);
|
|
301
|
+
const owned = mineOwnership(id, deps);
|
|
302
|
+
if (owned instanceof Response) return owned;
|
|
303
|
+
return jsonResponse({ id, versions: listGraphVersions(owned.mineDir, id) });
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** POST /v1/graphs/<id>/revert {version} — restores that version; the restore is itself a new version. */
|
|
307
|
+
export async function handleGraphsRevert(pathname: string, req: Request, deps: GraphsApiDeps = {}): Promise<Response> {
|
|
308
|
+
const match = /^\/v1\/graphs\/([^/]+)\/revert$/.exec(pathname);
|
|
309
|
+
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
310
|
+
const id = resolveId(match[1]!);
|
|
311
|
+
if (!id) return jsonResponse({ error: 'bad_request', reason: 'invalid graph id' }, 400);
|
|
312
|
+
const owned = mineOwnership(id, deps);
|
|
313
|
+
if (owned instanceof Response) return owned;
|
|
314
|
+
if (owned.existing.file !== `${id}.yaml`) return jsonResponse({ error: 'file-name-mismatch', id, file: owned.existing.file }, 409);
|
|
315
|
+
let body: { version?: unknown };
|
|
316
|
+
try { body = await req.json() as { version?: unknown }; }
|
|
317
|
+
catch { return jsonResponse({ error: 'bad_request', reason: 'json body required' }, 400); }
|
|
318
|
+
if (typeof body?.version !== 'string' || !VERSION_ID.test(body.version)) {
|
|
319
|
+
return jsonResponse({ error: 'bad_request', reason: 'version string required' }, 400);
|
|
320
|
+
}
|
|
321
|
+
const target = body.version;
|
|
322
|
+
// Only a listed version id is ever joined onto a path.
|
|
323
|
+
if (!listGraphVersions(owned.mineDir, id).some((entry) => entry.version === target)) {
|
|
324
|
+
return jsonResponse({ error: 'version-not-found', id, version: target }, 404);
|
|
325
|
+
}
|
|
326
|
+
const text = readFileSync(join(versionsDir(owned.mineDir, id), `${target}.yaml`), 'utf8');
|
|
327
|
+
const rejected = rejectGraphYaml(text, id, target);
|
|
328
|
+
if (rejected) return rejected;
|
|
329
|
+
const { version, previous } = writeWithVersion(owned.mineDir, id, owned.existing, text);
|
|
330
|
+
debug.log('nexus.graphs', 'reverted', { id, version, previous, restoredFrom: target });
|
|
331
|
+
return jsonResponse({ id, source: 'mine', editable: true, reverted: true, version, previous, restoredFrom: target });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** POST /v1/graphs {id, yaml} — a brand-new «mine» graph (blank canvas → save). Records version v1. */
|
|
335
|
+
export async function handleGraphsCreate(req: Request, deps: GraphsApiDeps = {}): Promise<Response> {
|
|
336
|
+
let body: { id?: unknown; yaml?: unknown };
|
|
337
|
+
try { body = await req.json() as { id?: unknown; yaml?: unknown }; }
|
|
338
|
+
catch { return jsonResponse({ error: 'bad_request', reason: 'json body required' }, 400); }
|
|
339
|
+
const id = typeof body?.id === 'string' ? resolveId(body.id) : null;
|
|
340
|
+
if (!id) return jsonResponse({ error: 'bad_request', reason: 'id must match [a-z0-9-]' }, 400);
|
|
341
|
+
const reservedId = reserved(id);
|
|
342
|
+
if (reservedId) return reservedId;
|
|
343
|
+
if (typeof body.yaml !== 'string') return jsonResponse({ error: 'bad_request', reason: 'yaml string required' }, 400);
|
|
344
|
+
const coreDir = deps.coreDir ?? defaultGraphsDir();
|
|
345
|
+
const mineDir = deps.mineDir ?? mineGraphsDir();
|
|
346
|
+
if (indexByDeclaredId(coreDir).has(id)) return jsonResponse({ error: 'core-read-only', id }, 403);
|
|
347
|
+
if (indexByDeclaredId(mineDir).has(id) || existsSync(join(mineDir, `${id}.yaml`))) return jsonResponse({ error: 'exists', id }, 409);
|
|
348
|
+
const rejected = rejectGraphYaml(body.yaml, id);
|
|
349
|
+
if (rejected) return rejected;
|
|
350
|
+
mkdirSync(mineDir, { recursive: true });
|
|
351
|
+
writeFileSync(join(mineDir, `${id}.yaml`), body.yaml, { flag: 'wx' });
|
|
352
|
+
const version = recordVersion(mineDir, id, body.yaml);
|
|
353
|
+
debug.log('nexus.graphs', 'saved', { id, version, created: true });
|
|
354
|
+
return jsonResponse({ id, source: 'mine', editable: true, saved: true, version, previous: null }, 201);
|
|
187
355
|
}
|
|
188
356
|
|
|
189
357
|
/** Copy core bytes into «my graphs», changing only the declared graph_id. */
|
|
@@ -198,6 +366,8 @@ export async function handleGraphsClone(pathname: string, req: Request, deps: Gr
|
|
|
198
366
|
if (typeof body.newId !== 'string' || !GRAPH_ID.test(body.newId) || body.newId === id) {
|
|
199
367
|
return jsonResponse({ error: 'bad_request', reason: 'newId must match [a-z0-9-]' }, 400);
|
|
200
368
|
}
|
|
369
|
+
const reservedId = reserved(body.newId);
|
|
370
|
+
if (reservedId) return reservedId;
|
|
201
371
|
const coreDir = deps.coreDir ?? defaultGraphsDir();
|
|
202
372
|
const mineDir = deps.mineDir ?? mineGraphsDir();
|
|
203
373
|
const source = indexByDeclaredId(coreDir).get(id) ?? indexByDeclaredId(mineDir).get(id);
|
|
@@ -215,7 +385,9 @@ export async function handleGraphsClone(pathname: string, req: Request, deps: Gr
|
|
|
215
385
|
}
|
|
216
386
|
|
|
217
387
|
export async function handleGraphsMutation(pathname: string, req: Request, deps: GraphsApiDeps = {}): Promise<Response | null> {
|
|
388
|
+
if (req.method === 'POST' && pathname === '/v1/graphs') return handleGraphsCreate(req, deps);
|
|
218
389
|
if (req.method === 'PUT' && /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname)) return handleGraphsPut(pathname, req, deps);
|
|
219
390
|
if (req.method === 'POST' && /^\/v1\/graphs\/[^/]+\/clone$/.test(pathname)) return handleGraphsClone(pathname, req, deps);
|
|
391
|
+
if (req.method === 'POST' && /^\/v1\/graphs\/[^/]+\/revert$/.test(pathname)) return handleGraphsRevert(pathname, req, deps);
|
|
220
392
|
return null;
|
|
221
393
|
}
|
|
@@ -24,6 +24,7 @@ import { createProject, listProjects } from '../../project/project-store.js';
|
|
|
24
24
|
import { handleOutputsGet, type OutputsDeps } from './outputs-route.js';
|
|
25
25
|
import { buildGridData, type GridDeps } from './grid.js';
|
|
26
26
|
import { DECISIONS_PATH, handleDecisions, type DecisionsRouteDeps } from './decisions-route.js';
|
|
27
|
+
import { OPS_BOARD_PATH, handleOpsBoard, type OpsBoardDeps } from './ops-board-route.js';
|
|
27
28
|
import { CARD_FOLLOWUP_PATH, createCardFollowupJobs, type CardFollowupJobs } from './card-followup-route.js';
|
|
28
29
|
import { SKILL_EXEC_PATH, createSkillExecJobs, type SkillExecJobs } from './skill-exec-route.js';
|
|
29
30
|
import { compareTokenConstTime } from '../../acp/transport/auth.js';
|
|
@@ -166,7 +167,8 @@ import { handleHarnessAskPost, handleHarnessAskStatusGet, handleHarnessRunEvents
|
|
|
166
167
|
import { handleLoopEdgesGet } from './loop-edges.js';
|
|
167
168
|
import { handleFabricPlans, type FabricPlansRouteOpts } from './fabric-plans.js';
|
|
168
169
|
import { dispatchPersonaRoute } from './personas.js';
|
|
169
|
-
import { handleMe } from './operator.js';
|
|
170
|
+
import { handleMe, operatorSignal } from './operator.js';
|
|
171
|
+
import { handleGraphRunRoute } from '../../graph-runner/graph-run-api.js';
|
|
170
172
|
import { handleOpsApi } from './ops-api.js';
|
|
171
173
|
import { handleRoleJudge } from './role-judge.js';
|
|
172
174
|
import { handleAudioStt } from './audio-stt.js';
|
|
@@ -363,7 +365,7 @@ import {
|
|
|
363
365
|
} from './workflows.js';
|
|
364
366
|
import { handleTriggersSnapshot } from './triggers.js';
|
|
365
367
|
import { handleWorkflowTemplatesList } from './workflow-templates.js';
|
|
366
|
-
import { handleGraphsGet, handleGraphsMutation } from './graphs-api.js';
|
|
368
|
+
import { handleGraphVersionsGet, handleGraphsGet, handleGraphsMutation } from './graphs-api.js';
|
|
367
369
|
import { handleGraphKindsGet, handleGraphsValidatePost } from './graph-kinds.js';
|
|
368
370
|
import { syncInstalledPluginNodes } from '../../graph-kinds/installed-plugin-nodes.js';
|
|
369
371
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
@@ -413,6 +415,8 @@ import { handleSelfEvent } from './self-event.js';
|
|
|
413
415
|
/** 매매 «실행»은 애드온이다(대표 09-20 결정 ③ · 별도 상용 저장소 · release/trading-export.yaml) — 공개 코어엔 없다.
|
|
414
416
|
* 있으면 그 경로를 켜고, 없으면 501. 경로를 변수로 둬 공개본 타입 검사가 «모듈 없음»으로 막히지 않게 한다. */
|
|
415
417
|
const TRADE_PROPOSAL_MODULE: string = './trade-proposal.js';
|
|
418
|
+
/** PITCH-ROOM — 투자자 피치 방(덱·티저)은 비공개다(release/public-export.yaml 이 pitch-api 를 뺀다). 공개본엔 모듈이 없어 404. */
|
|
419
|
+
const PITCH_MODULE: string = './pitch-api.js';
|
|
416
420
|
import {
|
|
417
421
|
handleShowroomLayoutDelete,
|
|
418
422
|
handleShowroomLayoutGet,
|
|
@@ -482,6 +486,7 @@ export interface NexusHttpServerOpts {
|
|
|
482
486
|
/** Read-only grid measurement seam; omitted in production for live HQ and Pod pool reads. */
|
|
483
487
|
grid?: GridDeps;
|
|
484
488
|
decisions?: Pick<DecisionsRouteDeps, 'ledger'>;
|
|
489
|
+
opsBoard?: Pick<OpsBoardDeps, 'openStore'>;
|
|
485
490
|
cardFollowup?: CardFollowupJobs;
|
|
486
491
|
skillExec?: SkillExecJobs;
|
|
487
492
|
execRequests?: ExecRequestRunner;
|
|
@@ -926,6 +931,30 @@ export async function routeRequest(
|
|
|
926
931
|
if (pathname === '/v1/ops' || pathname.startsWith('/v1/ops/')) {
|
|
927
932
|
return handleOpsApi(req, opts.metaApi);
|
|
928
933
|
}
|
|
934
|
+
// PITCH-ROOM — same operatorSignal gate, inside the (private-only) pitch module.
|
|
935
|
+
if (pathname.startsWith('/v1/pitch/')) {
|
|
936
|
+
let pitch: { handlePitchApi(req: Request, metaApi: typeof opts.metaApi): Response };
|
|
937
|
+
try {
|
|
938
|
+
pitch = await import(PITCH_MODULE) as typeof pitch;
|
|
939
|
+
} catch {
|
|
940
|
+
return jsonResponse({ error: 'not-found' }, 404);
|
|
941
|
+
}
|
|
942
|
+
return pitch.handlePitchApi(req, opts.metaApi);
|
|
943
|
+
}
|
|
944
|
+
// CGE-RUN — 편집기 «실행»은 운영자 전용이다: 사용자 그래프가 셸 노드를 부를 수 있으므로 같은 출처 무토큰 통과는 받지 않는다
|
|
945
|
+
// (운영자 프록시 헤더 · owner bearer 일치 · owner 가 발급한 짧은 임시 토큰만 — 명시 토큰은 언제나 필요).
|
|
946
|
+
if (/^\/v1\/graphs\/[^/]+\/(?:run|runs\/[^/]+)$/.test(pathname)) {
|
|
947
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
948
|
+
const signal = operatorSignal(req, opts.metaApi);
|
|
949
|
+
const credential = bearerCredential(req, opts.metaApi);
|
|
950
|
+
if (!signal.operator || (signal.operatorSource !== 'op-proxy' && credential !== 'bearer-match' && credential !== 'temp-token')) {
|
|
951
|
+
debug.log('graphs.run', 'refused', { path: pathname, source: signal.operatorSource });
|
|
952
|
+
return jsonResponse({ error: 'forbidden' }, 403);
|
|
953
|
+
}
|
|
954
|
+
const routed = handleGraphRunRoute(method, pathname);
|
|
955
|
+
if (routed) return routed;
|
|
956
|
+
return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
957
|
+
}
|
|
929
958
|
|
|
930
959
|
// Default-deny for every `/v1/` path that is not on PUBLIC_ROUTES.
|
|
931
960
|
// Reuses checkAuth (same-origin exemption + constant-time bearer).
|
|
@@ -1299,12 +1328,11 @@ export async function routeRequest(
|
|
|
1299
1328
|
return handleDevices(req, opts.devices);
|
|
1300
1329
|
}
|
|
1301
1330
|
|
|
1331
|
+
// Same owner auth as the neighbouring GETs (short-lived owner tokens · same-origin PWA); #23932 compared the admin
|
|
1332
|
+
// bearer only, so a PWA on a short-lived token got 401 and the loop map stayed empty.
|
|
1302
1333
|
if (pathname === '/v1/loops/edges' && method === 'GET') {
|
|
1303
|
-
if (!opts.metaApi
|
|
1304
|
-
|
|
1305
|
-
if (!offered?.startsWith('Bearer ') || !compareTokenConstTime(offered.slice('Bearer '.length).trim(), opts.metaApi.bearerToken)) {
|
|
1306
|
-
return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1307
|
-
}
|
|
1334
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-runtime-not-wired' }, 503);
|
|
1335
|
+
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1308
1336
|
return handleLoopEdgesGet(req);
|
|
1309
1337
|
}
|
|
1310
1338
|
|
|
@@ -1381,6 +1409,21 @@ export async function routeRequest(
|
|
|
1381
1409
|
return (opts.cardFollowup ?? defaultCardFollowupJobs()).get(pathname.slice(CARD_FOLLOWUP_PATH.length + 1));
|
|
1382
1410
|
}
|
|
1383
1411
|
|
|
1412
|
+
if (pathname === OPS_BOARD_PATH && (method === 'GET' || method === 'POST')) {
|
|
1413
|
+
const peerAddress = (server as BunServerLike & { requestIP?: (request: Request) => { address: string } | null }).requestIP?.(req)?.address;
|
|
1414
|
+
const host = req.headers.get('host') ?? new URL(req.url).host;
|
|
1415
|
+
const tailnetPeer = peerAddress !== undefined && (/^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\./.test(peerAddress)
|
|
1416
|
+
|| /^fd7a:115c:a1e0:/i.test(peerAddress));
|
|
1417
|
+
const localPeer = peerAddress === '127.0.0.1' || peerAddress === '::1';
|
|
1418
|
+
const tailnetHost = /^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.\d{1,3}\.\d{1,3}(?::\d+)?$/.test(host)
|
|
1419
|
+
|| /^\[fd7a:115c:a1e0:[0-9a-f:]+\](?::\d+)?$/i.test(host) || /^[a-z0-9-]+(?:\.[a-z0-9-]+)*\.ts\.net(?::\d+)?$/i.test(host);
|
|
1420
|
+
const localHost = /^(?:localhost|127\.0\.0\.1)(?::\d+)?$/.test(host) || /^\[::1\](?::\d+)?$/.test(host);
|
|
1421
|
+
if ((!tailnetPeer && !localPeer) || (!tailnetHost && !localHost)) return jsonResponse({ error: 'forbidden' }, 403);
|
|
1422
|
+
return handleOpsBoard(req, {
|
|
1423
|
+
authorize: request => !!opts.metaApi && opts.metaApi.noAuth !== true && checkAuth(request, opts.metaApi),
|
|
1424
|
+
...opts.opsBoard,
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1384
1427
|
if (method === 'GET' && pathname === DECISIONS_PATH) {
|
|
1385
1428
|
return handleDecisions(req, {
|
|
1386
1429
|
authorize: request => !!opts.metaApi && checkAuth(request, opts.metaApi),
|
|
@@ -1460,7 +1503,7 @@ export async function routeRequest(
|
|
|
1460
1503
|
if (!opts.metaApi) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1461
1504
|
return handlePluginsRemove(req, pluginRemove[1]!, opts.metaApi, opts.pluginStateRoot);
|
|
1462
1505
|
}
|
|
1463
|
-
if ((method === 'PUT' || method === 'POST') && pathname.startsWith('/v1/graphs/')) {
|
|
1506
|
+
if ((method === 'PUT' || method === 'POST') && (pathname.startsWith('/v1/graphs/') || pathname === '/v1/graphs')) {
|
|
1464
1507
|
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
1465
1508
|
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1466
1509
|
const mutated = await handleGraphsMutation(pathname, req);
|
|
@@ -2774,6 +2817,9 @@ export async function routeRequest(
|
|
|
2774
2817
|
if (method === 'GET' && (pathname === '/v1/graphs' || /^\/v1\/graphs\/[^/]+$/.test(pathname) || /^\/v1\/graphs\/[^/]+\/yaml$/.test(pathname))) {
|
|
2775
2818
|
return handleGraphsGet(pathname);
|
|
2776
2819
|
}
|
|
2820
|
+
if (method === 'GET' && /^\/v1\/graphs\/[^/]+\/versions$/.test(pathname)) {
|
|
2821
|
+
return handleGraphVersionsGet(pathname);
|
|
2822
|
+
}
|
|
2777
2823
|
// Archon-port T2.3 (2026-05-08) — workflow GET surface.
|
|
2778
2824
|
// (POST /validate · POST /:name/run · PUT/DELETE /:name landed
|
|
2779
2825
|
// inside the mutation block above.)
|