elanous 0.2.13 → 0.2.15
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/LZcstaO9_NXypPFmujolv/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-33ffcc49ab45123b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-0e2c57fe6add4b2a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e05a77df7e005b04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b8c49f6b4fa2df91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-976813c91d7394ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-1d4901eb7c2d8822.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-72d3e7ff35a8c954.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-60c7a8e1a4fe62ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-2a52b316cb143d9c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c3ce483c8d5db370.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-96f074f6538e8a2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e97be5334d83a9f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-c1343f9499d86f3f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-8739a2e0ae793130.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-d23b12bb92242558.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c7fea475488201a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-5efbf81124c474ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-06ee266953d9c879.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-153c2b3bcc89e8de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-0d6d23b40263a7ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-f5597e894c02cd33.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-73735b64bfe1ae67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f7e631e9b4daf66e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9817c7f9007466cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
- package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/ceo/index.html +1 -0
- package/apps/pwa/out/ceo/index.txt +33 -0
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -0
- package/apps/pwa/out/loops/index.txt +30 -0
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/heal/heal-loop.yaml +1 -1
- package/graphs/implement-loop.yaml +1 -1
- package/graphs/orchestrator/orchestrator.yaml +59 -0
- package/graphs/orchestrator/recipes.yaml +18 -0
- package/graphs/release/recipes.yaml +6 -0
- package/graphs/release/release-loop.yaml +6 -1
- package/graphs/rhythm/daily.yaml +38 -0
- package/graphs/rhythm/recipes.yaml +18 -0
- package/graphs/rhythm/weekly.yaml +39 -0
- package/graphs/video/recipes.yaml +3 -0
- package/graphs/video/youtube-summary.yaml +17 -0
- package/package.json +1 -1
- package/scripts/audit-test-state-writes.ts +72 -17
- package/scripts/brand/check.ts +188 -0
- package/scripts/ci-typecheck-changed.ts +50 -18
- package/scripts/coord-post.sh +11 -1
- package/scripts/docs/generate-graph-anatomy.ts +315 -0
- package/scripts/docs-cli-check.ts +23 -6
- package/scripts/expose-rubric-check.ts +118 -0
- package/scripts/expose-rubric-suggest.ts +169 -0
- package/scripts/heal/run-role.ts +14 -0
- package/scripts/hq/standby-verify.ts +11 -7
- package/scripts/lecture-note/node.ts +31 -11
- package/scripts/lessons/handbook-page.ts +112 -0
- package/scripts/marketing/generate-ax-brief.ts +140 -0
- package/scripts/marketing/generate-feature-map.ts +118 -0
- package/scripts/release-loop/checklist-gate-node.ts +53 -14
- package/scripts/release-loop/gate-node.ts +89 -14
- package/scripts/release-loop/publish-node.ts +14 -1
- package/scripts/release-loop/unattended-release.ts +23 -1
- package/scripts/release-loop/vault-note-node.ts +428 -0
- package/scripts/release-story/draft.ts +220 -0
- package/scripts/rhythm/daily.ts +570 -0
- package/scripts/rhythm/weekly.ts +315 -0
- package/scripts/skills/public-check.ts +169 -0
- package/scripts/smart-merge/resync-shadow.ts +147 -0
- package/scripts/test-deterministic.ts +4 -8
- package/scripts/test-diet/effectiveness.ts +195 -0
- package/scripts/test-diet/lib.ts +16 -8
- package/scripts/test-diet/node.ts +77 -9
- package/scripts/ux/demo-rehearsal.ts +2 -2
- package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
- package/scripts/video/youtube-summary.ts +133 -0
- package/skills/diagram-master/SKILL.md +42 -49
- package/skills/diagram-master/references/pyproject.toml +4 -1
- package/skills/diagram-master/references/routing-guide.md +4 -2
- package/skills/grill-me/SKILL.md +1 -0
- package/skills/youtube-master/SKILL.md +13 -13
- package/skills/youtube-master/package-lock.json +0 -545
- package/skills/youtube-master/package.json +2 -5
- package/skills/youtube-master/scripts/main.ts +2 -2
- package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
- package/skills/youtube-master/src/util.ts +30 -7
- package/src/agent-env/profile.ts +161 -0
- package/src/agent-mission/driver.ts +3 -3
- package/src/agent-substrate/pr-reviewer.ts +2 -0
- package/src/ask-user-question/pending-questions.ts +5 -0
- package/src/auth/github-app-token.ts +112 -13
- package/src/autopilot/build/llm-conflict-merge.ts +73 -10
- package/src/autopilot/build/merge-intent.ts +53 -0
- package/src/briefing/brief-items.ts +121 -0
- package/src/chat/index.ts +2 -0
- package/src/claims/claims-ledger.ts +232 -0
- package/src/claims/claims-render.ts +166 -0
- package/src/cli/agent-env-cli.ts +21 -0
- package/src/cli/claims-cli.ts +94 -0
- package/src/cli/decisions-cli.ts +44 -3
- package/src/cli/docs-cli.ts +2 -0
- package/src/cli/doctor-cli.ts +23 -1
- package/src/cli/doctor-node-modules.ts +147 -0
- package/src/cli/flow-cli.ts +11 -0
- package/src/cli/freeze-cli.ts +45 -0
- package/src/cli/intake-cli.ts +46 -17
- package/src/cli/lesson-cli.ts +108 -0
- package/src/cli/logs-cli.ts +104 -2
- package/src/cli/logs-model-input.ts +131 -0
- package/src/cli/pod-cli.ts +2 -0
- package/src/cli/pr-cli.ts +29 -1
- package/src/cli/private-ledger-commands.ts +54 -4
- package/src/cli/pty-drive-verdict.ts +11 -2
- package/src/cli/release-cli.ts +190 -33
- package/src/cli/rfc-status.ts +91 -0
- package/src/cli/seat-requests-cli.ts +52 -0
- package/src/connectors/linear.ts +5 -3
- package/src/context-bus/condense.ts +15 -20
- package/src/context-bus/context-now-public.ts +96 -0
- package/src/context-bus/context-now-surfaces.ts +55 -2
- package/src/context-bus/context-now.ts +6 -3
- package/src/context-bus/coord-events.ts +6 -4
- package/src/context-bus/long-term-memory.ts +92 -11
- package/src/dashboard/index.ts +75 -22
- package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
- package/src/dashboard/slash-runtime/loops-table.ts +77 -0
- package/src/decisions/decision-cards.ts +33 -7
- package/src/decisions/decision-ledger.ts +40 -1
- package/src/decisions/proact-meter.ts +286 -0
- package/src/decisions/proact1-lite.ts +86 -0
- package/src/decisions/web-push-decision-cards.ts +1 -1
- package/src/discord/sprint21-runtime.ts +16 -0
- package/src/discord-self-message.ts +8 -0
- package/src/discord-slash-wire.ts +31 -2
- package/src/domains/alert-audit.ts +271 -0
- package/src/domains/core-tools.ts +4 -3
- package/src/domains/ops-facts-tool.ts +31 -1
- package/src/domains/outbound-alert.ts +1 -1
- package/src/elanous-config-dir.ts +29 -4
- package/src/execution-loop/launch-gate.ts +29 -14
- package/src/flow/cards.ts +239 -0
- package/src/graph-runner/graph-tick.ts +4 -0
- package/src/graph-runner/runner.ts +30 -5
- package/src/harness/harness-cli-command.ts +259 -38
- package/src/harness/harness-incidents.ts +45 -12
- package/src/harness/harness-pod-dispatch.ts +102 -11
- package/src/harness/harness-queue-child.ts +3 -3
- package/src/harness/harness-queue.ts +583 -65
- package/src/harness/helper-repair.ts +87 -0
- package/src/harness/helper-scan.ts +151 -0
- package/src/harness/launch-stamp.ts +236 -0
- package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
- package/src/harness/ledger-write-guard.ts +35 -0
- package/src/harness/model-input-observation.ts +37 -0
- package/src/harness/pod-memory-policy.ts +15 -0
- package/src/harness/repository-name.ts +55 -0
- package/src/hq/fence-audit.ts +90 -0
- package/src/hq/hq.ts +63 -5
- package/src/hq/lease.ts +4 -4
- package/src/hq/move-plan.ts +126 -0
- package/src/hq/promote.ts +332 -0
- package/src/index.ts +159 -27
- package/src/intake-plane/check.ts +63 -0
- package/src/intake-plane/digest.ts +37 -15
- package/src/intake-plane/front-classifier.ts +6 -0
- package/src/intake-plane/items.ts +3 -2
- package/src/intake-plane/lens.ts +177 -0
- package/src/intake-plane/linear-wish.ts +39 -11
- package/src/intake-plane/route.ts +145 -1
- package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
- package/src/intake-plane/wish-card.ts +53 -2
- package/src/intake-plane/wish-folder.ts +5 -2
- package/src/intake-plane/wish-reply.ts +72 -0
- package/src/launch-head/seat-goal-queue-lock.fixture.ts +15 -0
- package/src/launch-head/seat-goal-queue.ts +198 -0
- package/src/lessons/lesson-import.ts +106 -0
- package/src/lessons/lesson-ledger.ts +206 -0
- package/src/loops/activity.ts +203 -0
- package/src/loops/budget.ts +63 -0
- package/src/loops/checker.ts +5 -3
- package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
- package/src/loops/loop-cli.ts +36 -4
- package/src/loops/neighbors.ts +40 -0
- package/src/loops/observe.ts +10 -0
- package/src/loops/orchestrator/author-depth.ts +220 -0
- package/src/loops/orchestrator/author-input-check.ts +82 -0
- package/src/loops/orchestrator/author-ledger.ts +232 -0
- package/src/loops/orchestrator/finish-rate.ts +175 -0
- package/src/loops/orchestrator/overlap.ts +51 -12
- package/src/loops/orchestrator/resync-shadow.ts +227 -0
- package/src/loops/orchestrator/seat-share.ts +56 -0
- package/src/loops/orchestrator/tick.ts +309 -0
- package/src/loops/orchestrator/traffic.ts +134 -13
- package/src/loops/registry.ts +535 -9
- package/src/loops/status-rows.ts +118 -0
- package/src/loops/verdict.ts +17 -5
- package/src/maturity/bot-slash-catalog.ts +66 -0
- package/src/maturity/feature-maturity.ts +9 -5
- package/src/maturity/tui-slash-availability.ts +31 -0
- package/src/mss/logging/log-store.ts +35 -4
- package/src/nexus/api/dashboard.ts +6 -1
- package/src/nexus/api/http-server.ts +33 -3
- package/src/nexus/api/loop-edges.ts +173 -0
- package/src/nexus/api/merge-approvals-gate.ts +1 -1
- package/src/nexus/api/schedules-read.ts +18 -1
- package/src/nexus/api/seat-requests.ts +79 -56
- package/src/nexus/api/task-cards-api.ts +44 -5
- package/src/nexus/api/workflows.ts +2 -1
- package/src/prompt-enhance/enhance.ts +6 -1
- package/src/release-loop/auto-start.ts +51 -0
- package/src/release-loop/checklist.ts +22 -4
- package/src/release-loop/feature-store.ts +71 -32
- package/src/release-loop/landing-freeze.ts +121 -0
- package/src/release-loop/merged-pr-checklist.ts +125 -0
- package/src/release-loop/placement.ts +302 -0
- package/src/release-loop/release-schedule.ts +3 -1
- package/src/seat-dispatch/ceo-commands.ts +2 -2
- package/src/seat-dispatch/seat-ask.ts +16 -3
- package/src/seat-dispatch/seat-questions.ts +58 -0
- package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
- package/src/seat-dispatch/seat-request-ledger.ts +133 -0
- package/src/seat-loop/seat-loop.ts +531 -40
- package/src/self-dev/dev-pipeline.ts +14 -6
- package/src/self-dev/draft-sweep.ts +162 -6
- package/src/self-dev/draft-triage-rules.ts +25 -8
- package/src/self-dev/orchestrate.ts +15 -1
- package/src/self-dev/review-provider-fallback.ts +6 -1
- package/src/self-dev/run-store.ts +73 -1
- package/src/self-dev/run-supervisor.ts +57 -2
- package/src/self-dev/self-orchestrate-runtime.ts +5 -1
- package/src/self-implement/budget-gate.ts +29 -0
- package/src/self-implement/expose-gate.ts +47 -0
- package/src/self-implement/frozen-merges.ts +295 -0
- package/src/self-implement/gate-cli.ts +10 -4
- package/src/self-implement/gate-scope.ts +46 -9
- package/src/self-implement/goal-archive.ts +222 -0
- package/src/self-implement/goal-author.ts +43 -5
- package/src/self-implement/goal-clarification-escalation.ts +5 -0
- package/src/self-implement/goal-lookup.ts +147 -0
- package/src/self-implement/heal-intake.ts +197 -0
- package/src/self-implement/host-regate.ts +32 -2
- package/src/self-implement/l8-merge-queue.ts +132 -0
- package/src/self-implement/orchestrator.ts +299 -48
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/revert-guard.ts +97 -0
- package/src/self-implement/run-ledger.ts +3 -1
- package/src/self-implement/run-status-mapping.ts +2 -0
- package/src/self-implement/seams.ts +29 -9
- package/src/self-implement/self-implement-cli.ts +1 -0
- package/src/self-implement/speed-claims.ts +338 -0
- package/src/session/index.ts +2 -0
- package/src/steward/triage.ts +74 -3
- package/src/steward/working-backwards.ts +4 -1
- package/src/task-cards/card-cli.ts +10 -2
- package/src/task-cards/card-store.ts +10 -6
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
- package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
- package/src/task-orchestrator/surfaces/pod-pool.ts +60 -8
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +224 -49
- package/src/task-orchestrator/surfaces/self-implement.ts +5 -1
- package/src/telegram-commands.ts +27 -3
- package/src/telegram-loops-command.ts +44 -0
- package/src/telegram.ts +25 -4
- package/src/user-config.ts +146 -18
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/nodes/bash.ts +9 -1
- package/src/workflow-runtime/storage.ts +31 -13
- package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-f14987d5850a31e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66c27608f651b866.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-78b40a344ed22f24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
- /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → LZcstaO9_NXypPFmujolv}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { loopCronVerdict, type LoopCronVerdict } from './verdict';
|
|
2
|
+
|
|
3
|
+
const VERDICT_LABEL: Record<LoopCronVerdict, LoopRow['verdict']> = {
|
|
4
|
+
alive: '살아 있음', late: '늦음', failed: '실패', off: '꺼짐',
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export interface LoopSchedule {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
source: string;
|
|
11
|
+
category: string | null;
|
|
12
|
+
domain: string | null;
|
|
13
|
+
runVia: string | null;
|
|
14
|
+
cron: string | null;
|
|
15
|
+
intervalMs: number | null;
|
|
16
|
+
state: 'live' | 'firing' | 'stale' | 'off';
|
|
17
|
+
next: string[];
|
|
18
|
+
lastRun: { at: string; status: string | null; exit: number | null } | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface LoopRow {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
layer: string;
|
|
25
|
+
owner: string;
|
|
26
|
+
mode: string;
|
|
27
|
+
lastRun: string | null;
|
|
28
|
+
verdict: '살아 있음' | '늦음' | '실패' | '꺼짐' | '판정 불가';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const LOOP_SCHEDULES_PATH = '/v1/schedules?includeOff=1';
|
|
32
|
+
export const LOOPS_PATH = '/v1/dashboard/loops';
|
|
33
|
+
|
|
34
|
+
interface RecordedLoop {
|
|
35
|
+
name: string;
|
|
36
|
+
label: string;
|
|
37
|
+
category?: string;
|
|
38
|
+
armed: boolean | null;
|
|
39
|
+
last: { at: string; status: string } | null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function loadLoopRows(fetchJson: (path: string) => Promise<unknown>, now: number): Promise<LoopRow[]> {
|
|
43
|
+
const [schedulesResult, loopsResult] = await Promise.allSettled([
|
|
44
|
+
fetchJson(LOOP_SCHEDULES_PATH), fetchJson(LOOPS_PATH),
|
|
45
|
+
]);
|
|
46
|
+
const schedules = schedulesResult.status === 'fulfilled' ? (schedulesResult.value as { schedules?: unknown })?.schedules : null;
|
|
47
|
+
const loops = loopsResult.status === 'fulfilled' ? (loopsResult.value as { loops?: { loops?: unknown } | null })?.loops?.loops : null;
|
|
48
|
+
if (!Array.isArray(schedules) && !Array.isArray(loops)) throw new Error('loop registries unavailable');
|
|
49
|
+
if (!Array.isArray(schedules)) throw new Error('스케줄 레지스트리 조회 실패');
|
|
50
|
+
if (!Array.isArray(loops)) throw new Error('루프 레지스트리 조회 실패');
|
|
51
|
+
// These registries have different ID namespaces even when labels match.
|
|
52
|
+
const rows = loopRows(schedules as LoopSchedule[], now).map((row) => ({ ...row, id: `schedule:${row.id}` }));
|
|
53
|
+
for (const loop of loops as RecordedLoop[]) {
|
|
54
|
+
const last = loop.last ? Date.parse(loop.last.at) : NaN;
|
|
55
|
+
const verdict = loopCronVerdict({
|
|
56
|
+
enabled: loop.armed !== false,
|
|
57
|
+
lastRunAt: loop.last?.at ?? null,
|
|
58
|
+
lastStatus: loop.last?.status.toLowerCase() ?? null,
|
|
59
|
+
intervalMs: null,
|
|
60
|
+
}, now);
|
|
61
|
+
rows.push({
|
|
62
|
+
id: `loop:${loop.name}`, name: loop.label, layer: loop.category ?? '루프', owner: '미지정',
|
|
63
|
+
mode: loop.armed === null ? '관측' : loop.armed ? 'armed' : 'off',
|
|
64
|
+
lastRun: Number.isFinite(last) ? loop.last!.at : null,
|
|
65
|
+
verdict: verdict === 'alive' ? '판정 불가' : VERDICT_LABEL[verdict],
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return rows;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function createLoopRowsRefresh(
|
|
72
|
+
fetchJson: (path: string) => Promise<unknown>,
|
|
73
|
+
onResult: (result: { rows: LoopRow[]; state: 'ready' | 'error' }) => void,
|
|
74
|
+
clock: () => number = Date.now,
|
|
75
|
+
) {
|
|
76
|
+
let sequence = 0;
|
|
77
|
+
let active = true;
|
|
78
|
+
return {
|
|
79
|
+
async refresh() {
|
|
80
|
+
const request = ++sequence;
|
|
81
|
+
try {
|
|
82
|
+
const rows = await loadLoopRows(fetchJson, clock());
|
|
83
|
+
if (active && request === sequence) onResult({ rows, state: 'ready' });
|
|
84
|
+
} catch {
|
|
85
|
+
if (active && request === sequence) onResult({ rows: [], state: 'error' });
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
dispose() { active = false; },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function loopRows(schedules: readonly LoopSchedule[], now: number): LoopRow[] {
|
|
93
|
+
return schedules.map((schedule) => {
|
|
94
|
+
const last = schedule.lastRun ? Date.parse(schedule.lastRun.at) : NaN;
|
|
95
|
+
const sharedVerdict = loopCronVerdict({
|
|
96
|
+
enabled: schedule.state !== 'off',
|
|
97
|
+
lastRunAt: schedule.lastRun?.at ?? null,
|
|
98
|
+
lastStatus: schedule.lastRun?.exit != null && schedule.lastRun.exit !== 0
|
|
99
|
+
? 'failed' : schedule.lastRun?.status != null && !['ok', 'success', 'completed'].includes(schedule.lastRun.status.toLowerCase())
|
|
100
|
+
? 'failed' : schedule.lastRun?.status?.toLowerCase() ?? null,
|
|
101
|
+
intervalMs: schedule.cron ? null : schedule.intervalMs,
|
|
102
|
+
// A cron uses daemon calendar state; fixed intervals use the 2× interval rule.
|
|
103
|
+
...(schedule.cron ? { scheduleState: schedule.state } : {}),
|
|
104
|
+
}, now);
|
|
105
|
+
const noCadence = !schedule.cron && !(schedule.intervalMs && schedule.intervalMs > 0);
|
|
106
|
+
const verdict = sharedVerdict === 'alive' && (!Number.isFinite(last) || noCadence)
|
|
107
|
+
? '판정 불가' : VERDICT_LABEL[sharedVerdict];
|
|
108
|
+
return {
|
|
109
|
+
id: schedule.id,
|
|
110
|
+
name: schedule.name,
|
|
111
|
+
layer: schedule.domain || schedule.category || schedule.source,
|
|
112
|
+
owner: '미지정',
|
|
113
|
+
mode: schedule.runVia || schedule.source,
|
|
114
|
+
lastRun: Number.isFinite(last) ? schedule.lastRun!.at : null,
|
|
115
|
+
verdict,
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
}
|
package/src/loops/verdict.ts
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
export type LoopCronVerdict = 'alive' | 'late' | 'failed' | 'off';
|
|
2
2
|
|
|
3
|
-
/** Shared display inputs for a graph loop or
|
|
4
|
-
*
|
|
3
|
+
/** Shared display inputs for a graph loop or cron job. Fixed intervals use
|
|
4
|
+
* milliseconds; calendar cron schedules supply the second actual due instant. */
|
|
5
5
|
export interface LoopCronVerdictInput {
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
lastRunAt: string | null;
|
|
8
8
|
lastStatus: string | null;
|
|
9
9
|
intervalMs: number | null;
|
|
10
|
+
/** Second scheduled execution after the last run, for calendar-based cron schedules. */
|
|
11
|
+
secondDueAt?: string | null;
|
|
12
|
+
/** Cron-aware daemon state (src/domains/schedule-state.ts). Callers pass it for cron schedules only —
|
|
13
|
+
* a fixed interval keeps its own «2× interval» rule (review must-fix: stale must not override an interval). */
|
|
14
|
+
scheduleState?: 'live' | 'firing' | 'stale' | 'off';
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
/** Pure health classification; a failed last execution takes precedence over age.
|
|
13
|
-
*
|
|
18
|
+
* Without a valid last run and a cadence/due instant, lateness needs the daemon stale signal. */
|
|
14
19
|
export function loopCronVerdict(entry: LoopCronVerdictInput, nowMs: number): LoopCronVerdict {
|
|
15
|
-
if (!entry.enabled) return 'off';
|
|
16
|
-
if (entry.lastStatus === 'failed' || entry.lastStatus === 'error' || entry.lastStatus === 'failure'
|
|
20
|
+
if (!entry.enabled || entry.scheduleState === 'off') return 'off';
|
|
21
|
+
if (entry.lastStatus === 'failed' || entry.lastStatus === 'error' || entry.lastStatus === 'failure' ||
|
|
22
|
+
entry.lastStatus === 'abandoned' || entry.lastStatus === 'expired') return 'failed';
|
|
23
|
+
if (entry.scheduleState === 'stale') return 'late';
|
|
17
24
|
const lastRunMs = entry.lastRunAt === null ? NaN : Date.parse(entry.lastRunAt);
|
|
25
|
+
if (entry.secondDueAt !== undefined) {
|
|
26
|
+
const secondDueMs = entry.secondDueAt === null ? NaN : Date.parse(entry.secondDueAt);
|
|
27
|
+
return Number.isFinite(lastRunMs) && Number.isFinite(nowMs) &&
|
|
28
|
+
Number.isFinite(secondDueMs) && secondDueMs > lastRunMs && nowMs > secondDueMs ? 'late' : 'alive';
|
|
29
|
+
}
|
|
18
30
|
if (Number.isFinite(nowMs) && Number.isFinite(lastRunMs) &&
|
|
19
31
|
entry.intervalMs !== null && Number.isFinite(entry.intervalMs) && entry.intervalMs > 0 &&
|
|
20
32
|
nowMs - lastRunMs > 2 * entry.intervalMs) return 'late';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { SlashCommand } from '../chat/index.js';
|
|
2
|
+
import type { Maturity } from './feature-maturity.js';
|
|
3
|
+
import type { BotSurface } from './bot-command-maturity.js';
|
|
4
|
+
|
|
5
|
+
export interface BotSlashCatalogEntry {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
supported: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface BotSlashCatalog {
|
|
12
|
+
commands: BotSlashCatalogEntry[];
|
|
13
|
+
/** Null means this name is already handled, or is not in the catalog. */
|
|
14
|
+
unsupportedReply(name: string): string | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The menu is a projection of registered core commands, not a second list of invented names.
|
|
18
|
+
* A bot's actual handlers take precedence over maturity metadata: a grade describes
|
|
19
|
+
* visibility, never whether an existing command can be dispatched. */
|
|
20
|
+
export function buildBotSlashCatalog(options: {
|
|
21
|
+
surface: BotSurface;
|
|
22
|
+
coreCommands: readonly Pick<SlashCommand, 'name' | 'description'>[];
|
|
23
|
+
maturity: {
|
|
24
|
+
tuiSlash: Readonly<Record<string, Maturity>>;
|
|
25
|
+
telegramCommand: Readonly<Record<string, Maturity>>;
|
|
26
|
+
discordCommand: Readonly<Record<string, Maturity>>;
|
|
27
|
+
};
|
|
28
|
+
handledCommands: readonly { name: string; description: string }[];
|
|
29
|
+
}): BotSlashCatalog {
|
|
30
|
+
const { surface, coreCommands, maturity, handledCommands } = options;
|
|
31
|
+
const grades = surface === 'telegram' ? maturity.telegramCommand : maturity.discordCommand;
|
|
32
|
+
const validName = surface === 'telegram' ? /^[a-z0-9_]{1,32}$/ : /^[a-z0-9_-]{1,32}$/;
|
|
33
|
+
const commands: BotSlashCatalogEntry[] = [];
|
|
34
|
+
const seen = new Set<string>();
|
|
35
|
+
for (const command of handledCommands) {
|
|
36
|
+
if (seen.has(command.name)) continue;
|
|
37
|
+
commands.push({ name: command.name, description: command.description, supported: true });
|
|
38
|
+
seen.add(command.name);
|
|
39
|
+
}
|
|
40
|
+
const limit = surface === 'telegram' ? 100 : 25;
|
|
41
|
+
const candidateNames = new Set<string>();
|
|
42
|
+
const candidates = coreCommands.filter((command) => {
|
|
43
|
+
const name = command.name;
|
|
44
|
+
const grade = Object.hasOwn(grades, name) ? grades[name] : undefined;
|
|
45
|
+
if (seen.has(name) || candidateNames.has(name) || !validName.test(name) || grade === undefined || grade === 'broken' || grade === 'system') return false;
|
|
46
|
+
candidateNames.add(name);
|
|
47
|
+
return true;
|
|
48
|
+
});
|
|
49
|
+
if (commands.length + candidates.length > limit) {
|
|
50
|
+
throw new Error(`${surface} command catalog exceeds ${limit} slots`);
|
|
51
|
+
}
|
|
52
|
+
for (const command of candidates) {
|
|
53
|
+
const name = command.name;
|
|
54
|
+
const description = command.description.replace(/\s+/g, ' ').trim();
|
|
55
|
+
const suffix = ` (${surface === 'telegram' ? '텔레그램' : '디스코드'} 미지원)`;
|
|
56
|
+
commands.push({ name, description: `${description.slice(0, 100 - suffix.length)}${suffix}`, supported: false });
|
|
57
|
+
seen.add(name);
|
|
58
|
+
}
|
|
59
|
+
const unsupported = new Set(commands.filter((command) => !command.supported).map((command) => command.name));
|
|
60
|
+
return {
|
|
61
|
+
commands,
|
|
62
|
+
unsupportedReply(name) {
|
|
63
|
+
return unsupported.has(name) ? `/${name}은(는) ${surface === 'telegram' ? '텔레그램' : '디스코드'}에서 아직 지원되지 않습니다. TUI에서 /${name}을(를) 사용하세요.` : null;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -41,9 +41,11 @@ export const FEATURE_MATURITY = {
|
|
|
41
41
|
'/design-check': { pwa: 'tool' },
|
|
42
42
|
'/control': { pwa: 'tool' },
|
|
43
43
|
'/scheduler': { pwa: 'ops' },
|
|
44
|
+
'/loops': { pwa: 'beta' },
|
|
44
45
|
'/ops/release': { pwa: 'ops' },
|
|
45
46
|
'/ops/seats': { pwa: 'ops' },
|
|
46
47
|
'/ops/checklist': { pwa: 'ops' },
|
|
48
|
+
'/ceo': { pwa: 'ops' },
|
|
47
49
|
'/dashboard': { pwa: 'ops' },
|
|
48
50
|
'/bots': { pwa: 'ops' },
|
|
49
51
|
'/botlab': { pwa: 'ops' },
|
|
@@ -54,10 +56,10 @@ export const FEATURE_MATURITY = {
|
|
|
54
56
|
},
|
|
55
57
|
// Canonical CLI command names only; aliases inherit their command's grade.
|
|
56
58
|
cliRoot: {
|
|
57
|
-
pty: 'beta', pr: 'beta', repo: 'beta', role: 'beta', machine: 'beta',
|
|
59
|
+
pty: 'beta', pr: 'beta', repo: 'beta', role: 'beta', machine: 'beta', 'agent-env': 'beta',
|
|
58
60
|
where: 'stable', shadow: 'beta', llm: 'beta', storage: 'beta', leader: 'beta',
|
|
59
61
|
pod: 'beta', browser: 'beta', questions: 'beta', usage: 'stable', live: 'beta',
|
|
60
|
-
research: 'beta', release: 'beta', seat: 'beta', hq: 'beta', steward: 'beta', coord: 'beta', context: 'beta', 'model-watch': 'beta', doctor: 'stable',
|
|
62
|
+
research: 'beta', release: 'beta', freeze: 'beta', flow: 'beta', seat: 'beta', hq: 'beta', steward: 'beta', coord: 'beta', context: 'beta', 'model-watch': 'beta', doctor: 'stable',
|
|
61
63
|
control: 'beta', resources: 'beta', hooks: 'beta', setup: 'stable', start: 'stable',
|
|
62
64
|
grounding: 'beta', graph: 'beta', loop: 'stable', card: 'stable', 'launch-head': 'beta',
|
|
63
65
|
a2a: 'beta', plugin: 'stable', make: 'beta', skills: 'beta', connect: 'beta', import: 'beta',
|
|
@@ -71,7 +73,7 @@ export const FEATURE_MATURITY = {
|
|
|
71
73
|
provider: 'stable', 'provider:set': 'beta', 'provider:restore': 'beta',
|
|
72
74
|
'provider:rotate': 'beta', 'provider:use': 'beta', 'status-bar': 'beta',
|
|
73
75
|
schedule: 'beta', intake: 'beta', logs: 'stable', ad: 'beta', docs: 'beta',
|
|
74
|
-
decisions: 'beta', directives: 'beta', fleet: 'beta', ops: 'stable', outputs: 'beta', publish: 'beta',
|
|
76
|
+
decisions: 'beta', directives: 'beta', claims: 'beta', lesson: 'beta', fleet: 'beta', ops: 'stable', outputs: 'beta', publish: 'beta',
|
|
75
77
|
env: 'beta', 'agent-mission': 'beta', dev: 'beta', keys: 'beta', finance: 'beta',
|
|
76
78
|
config: 'stable', tasks: 'stable', labels: 'beta', msg: 'beta', ask: 'stable',
|
|
77
79
|
onboarding: 'beta', login: 'stable', session: 'beta', chat: 'stable', repl: 'stable',
|
|
@@ -110,6 +112,8 @@ export const FEATURE_MATURITY = {
|
|
|
110
112
|
plugin: 'tool',
|
|
111
113
|
widget: 'tool',
|
|
112
114
|
log: 'tool',
|
|
115
|
+
loops: 'beta',
|
|
116
|
+
persona: 'beta', // G3 b — 대화별 페르소나(GOAL-BENCH B7 #23836)
|
|
113
117
|
memory: 'beta',
|
|
114
118
|
export: 'stable',
|
|
115
119
|
delta: 'tool',
|
|
@@ -153,7 +157,7 @@ export const FEATURE_MATURITY = {
|
|
|
153
157
|
ping: 'stable', provider: 'stable', sessions: 'stable', fork: 'stable', resume: 'stable',
|
|
154
158
|
decisions: 'stable', work: 'stable', cancel: 'stable',
|
|
155
159
|
skills: 'beta', skill: 'beta', digest: 'beta', intake: 'beta', ad: 'beta',
|
|
156
|
-
taste: 'beta', missions: 'beta', attach: 'beta', detach: 'beta', now: 'beta', project: 'beta', wish: 'beta',
|
|
160
|
+
taste: 'beta', missions: 'beta', attach: 'beta', detach: 'beta', now: 'beta', loops: 'beta', project: 'beta', wish: 'beta',
|
|
157
161
|
brain: 'tool', cc: 'tool', cdx: 'tool', gem: 'tool', local: 'tool',
|
|
158
162
|
harness: 'ops',
|
|
159
163
|
// Existing commands outside the CXO four-grade menu list are owner-only.
|
|
@@ -162,7 +166,7 @@ export const FEATURE_MATURITY = {
|
|
|
162
166
|
},
|
|
163
167
|
discordCommand: {
|
|
164
168
|
status: 'stable', sessions: 'stable', new: 'stable', fork: 'stable',
|
|
165
|
-
persona: 'beta', poll: 'beta', attach: 'beta',
|
|
169
|
+
persona: 'beta', poll: 'beta', attach: 'beta', now: 'beta',
|
|
166
170
|
brain: 'tool', cc: 'tool', cdx: 'tool', gem: 'tool',
|
|
167
171
|
relay: 'ops', showroom: 'ops', bots: 'ops', bot: 'ops', screen: 'ops', chart: 'ops',
|
|
168
172
|
routines: 'ops', botsay: 'ops', 'voice-join': 'ops', 'voice-leave': 'ops', 'voice-status': 'ops',
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SLASH_COMMANDS, type SlashCommand } from '../chat/index.js';
|
|
2
|
+
import { FEATURE_MATURITY, type Maturity } from './feature-maturity.js';
|
|
3
|
+
|
|
4
|
+
export interface TuiSlashAvailability {
|
|
5
|
+
name: string;
|
|
6
|
+
maturity: Maturity;
|
|
7
|
+
telegram: boolean;
|
|
8
|
+
discord: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Project canonical TUI commands onto the maturity map and bot-surface grade maps.
|
|
12
|
+
* An absent bot grade means unavailable; a missing TUI grade is a registry error.
|
|
13
|
+
*/
|
|
14
|
+
export function deriveTuiSlashAvailability(
|
|
15
|
+
commands: readonly Pick<SlashCommand, 'name'>[] = SLASH_COMMANDS,
|
|
16
|
+
grades: {
|
|
17
|
+
tuiSlash: Readonly<Record<string, Maturity>>;
|
|
18
|
+
telegramCommand: Readonly<Record<string, Maturity>>;
|
|
19
|
+
discordCommand: Readonly<Record<string, Maturity>>;
|
|
20
|
+
} = FEATURE_MATURITY,
|
|
21
|
+
): TuiSlashAvailability[] {
|
|
22
|
+
return commands.map(({ name }) => {
|
|
23
|
+
if (!Object.hasOwn(grades.tuiSlash, name)) throw new Error(`TUI slash command /${name} has no maturity grade`);
|
|
24
|
+
return {
|
|
25
|
+
name,
|
|
26
|
+
maturity: grades.tuiSlash[name]!,
|
|
27
|
+
telegram: Object.hasOwn(grades.telegramCommand, name),
|
|
28
|
+
discord: Object.hasOwn(grades.discordCommand, name),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -270,23 +270,54 @@ export class LogStore {
|
|
|
270
270
|
this.db.run('CREATE INDEX IF NOT EXISTS idx_logs_level ON logs(level, ts_ms)');
|
|
271
271
|
this.db.run('CREATE INDEX IF NOT EXISTS idx_logs_surface ON logs(surface, ts_ms)');
|
|
272
272
|
this.db.run('CREATE INDEX IF NOT EXISTS idx_logs_category ON logs(category, ts_ms)');
|
|
273
|
+
this.db.run(`CREATE TABLE IF NOT EXISTS pod_log_imports (
|
|
274
|
+
job TEXT NOT NULL,
|
|
275
|
+
line INTEGER NOT NULL,
|
|
276
|
+
PRIMARY KEY (job, line)
|
|
277
|
+
)`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Insert each returned Pod line at most once per job, atomically with its receipt. */
|
|
281
|
+
insertPodBatch(job: string, rows: Array<{ rec: LogRecord; surface: string; line: number }>): number {
|
|
282
|
+
if (rows.length === 0) return 0;
|
|
283
|
+
const receipt = this.db.prepare('INSERT OR IGNORE INTO pod_log_imports (job, line) VALUES (?, ?)');
|
|
284
|
+
return this.db.transaction(() => {
|
|
285
|
+
const unseen = rows.filter(({ line }) => receipt.run(job, line).changes > 0);
|
|
286
|
+
this.insertBatch(unseen, { preserveRows: true });
|
|
287
|
+
return unseen.length;
|
|
288
|
+
})();
|
|
273
289
|
}
|
|
274
290
|
|
|
275
291
|
/** 배치 insert(단일 트랜잭션). 실패는 throw — fail-soft 는 호출측(StoreSink)
|
|
276
292
|
* 책임(ops-log 의 recordOpsEvent/Safe 분업 동형). */
|
|
277
|
-
insertBatch(rows: Array<{ rec: LogRecord; surface: string }
|
|
293
|
+
insertBatch(rows: Array<{ rec: LogRecord; surface: string }>, opts: { preserveRows?: boolean } = {}): void {
|
|
278
294
|
if (rows.length === 0) return;
|
|
279
295
|
const stmt = this.db.prepare(
|
|
280
296
|
`INSERT INTO logs (ts, ts_ms, level, instance, host_id, surface, category, event, session_id, trace_id, data)
|
|
281
297
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
282
298
|
);
|
|
299
|
+
const decisionRow = this.db.prepare(`SELECT id FROM logs WHERE instance = ? AND category = 'loop.steward' AND event = 'decision'
|
|
300
|
+
AND json_valid(data) AND json_extract(data, '$.runId') = ? ORDER BY id DESC LIMIT 1`);
|
|
301
|
+
const updateDecision = this.db.prepare(`UPDATE logs SET ts = ?, ts_ms = ?, level = ?, surface = ?, data = ? WHERE id = ?`);
|
|
283
302
|
const insertAll = this.db.transaction((batch: Array<{ rec: LogRecord; surface: string }>) => {
|
|
284
303
|
for (const { rec, surface } of batch) {
|
|
285
304
|
const tsMs = Date.parse(rec.ts);
|
|
305
|
+
const timestamp = Number.isFinite(tsMs) ? tsMs : Date.now();
|
|
306
|
+
const level = deriveLogLevel(rec);
|
|
307
|
+
const data = rec.data !== undefined ? JSON.stringify(rec.data) : null;
|
|
308
|
+
const runId = rec.category === 'loop.steward' && rec.event === 'decision' &&
|
|
309
|
+
rec.data && typeof rec.data === 'object' && !Array.isArray(rec.data)
|
|
310
|
+
? (rec.data as Record<string, unknown>).runId : undefined;
|
|
311
|
+
const existing = !opts.preserveRows && typeof runId === 'string' && runId
|
|
312
|
+
? decisionRow.get(this.instance, runId) as { id: number } | undefined : undefined;
|
|
313
|
+
if (existing) {
|
|
314
|
+
updateDecision.run(rec.ts, timestamp, level, surface, data, existing.id);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
286
317
|
stmt.run(
|
|
287
318
|
rec.ts,
|
|
288
|
-
|
|
289
|
-
|
|
319
|
+
timestamp,
|
|
320
|
+
level,
|
|
290
321
|
this.instance,
|
|
291
322
|
rec.data && typeof rec.data === 'object' && !Array.isArray(rec.data)
|
|
292
323
|
&& typeof (rec.data as Record<string, unknown>).hostId === 'string'
|
|
@@ -297,7 +328,7 @@ export class LogStore {
|
|
|
297
328
|
rec.event,
|
|
298
329
|
(rec as { session_id?: string }).session_id ?? null,
|
|
299
330
|
rec.trace_id ?? null,
|
|
300
|
-
|
|
331
|
+
data,
|
|
301
332
|
);
|
|
302
333
|
}
|
|
303
334
|
});
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// GET /v1/dashboard/timeline — 신호 타임라인 (?hours=48&floor=6)
|
|
5
5
|
// GET /v1/dashboard/heatmap — 자산×국가×섹터 매력도 + US 섹터 + 뉴스 분포
|
|
6
6
|
// GET /v1/dashboard/digs — 디깅 리포트 피드 (?limit=20)
|
|
7
|
+
// GET /v1/dashboard/loop-activity — 루프 활동 그래프 (?since=24h)
|
|
7
8
|
//
|
|
8
9
|
// 전부 read-only · 캐시/로컬 SQLite 만 (dashboard-data.ts) — 라이브 fetch 없음.
|
|
9
10
|
// PWA 폴링(60s) 대상. reflection.ts 패턴(CORS·checkAuth seam) 상속.
|
|
@@ -16,12 +17,15 @@ import {
|
|
|
16
17
|
} from '../../domains/dashboard-data.js';
|
|
17
18
|
import { readLiveSnapshot } from '../../domains/market-live.js';
|
|
18
19
|
import { marketSessions } from '../../domains/finance.js';
|
|
20
|
+
import { loopActivity } from '../../loops/activity.js';
|
|
19
21
|
|
|
20
22
|
export interface DashboardRouteOpts {
|
|
21
23
|
/** Auth check seam. */
|
|
22
24
|
checkAuth?: (req: Request) => boolean;
|
|
23
25
|
/** Test seam — 실제 detached 수집 spawn 대체. */
|
|
24
26
|
spawnCollector?: () => void;
|
|
27
|
+
/** Read-only activity provider for isolated route tests. */
|
|
28
|
+
loopActivity?: typeof loopActivity;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
const CORS_HEADERS: Record<string, string> = {
|
|
@@ -43,7 +47,7 @@ export function parseDashboardPath(pathname: string): string | null {
|
|
|
43
47
|
const m = /^\/v1\/dashboard\/([^/]+)$/.exec(pathname);
|
|
44
48
|
if (!m) return null;
|
|
45
49
|
const seg = decodeURIComponent(m[1]!);
|
|
46
|
-
return ['summary', 'timeline', 'heatmap', 'digs', 'schedules', 'ontology', 'backtest', 'loops', 'ops'].includes(seg) ? seg : null;
|
|
50
|
+
return ['summary', 'timeline', 'heatmap', 'digs', 'schedules', 'ontology', 'backtest', 'loops', 'loop-activity', 'ops'].includes(seg) ? seg : null;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
/** POST /v1/dashboard/refresh-live — 온디맨드 라이브 재수집 트리거 (refresh 버튼 설계 ·
|
|
@@ -99,6 +103,7 @@ export function handleDashboard(req: Request, section: string, opts: DashboardRo
|
|
|
99
103
|
case 'ontology': return jsonResponse({ ok: true, ontology: dashboardOntology() }, 200);
|
|
100
104
|
case 'backtest': return jsonResponse({ ok: true, backtest: dashboardBacktest() }, 200);
|
|
101
105
|
case 'loops': return jsonResponse({ ok: true, loops: dashboardLoops() }, 200);
|
|
106
|
+
case 'loop-activity': return jsonResponse({ ok: true, activity: (opts.loopActivity ?? loopActivity)({ since: q.get('since') ?? '24h' }) }, 200);
|
|
102
107
|
case 'ops': {
|
|
103
108
|
const mid = q.get('mission');
|
|
104
109
|
if (mid) return jsonResponse({ ok: true, missionDetail: dashboardOpsMission(mid) }, 200);
|
|
@@ -162,6 +162,7 @@ import {
|
|
|
162
162
|
} from './vault-api.js';
|
|
163
163
|
import { handleBuildsGet, parseBuildsPath } from './builds-api.js';
|
|
164
164
|
import { handleHarnessAskPost, handleHarnessAskStatusGet, handleHarnessRunEventsGet, handleHarnessRunScreenGet, handleHarnessRunsGet, handleHarnessStopPost } from './harness-api.js';
|
|
165
|
+
import { handleLoopEdgesGet } from './loop-edges.js';
|
|
165
166
|
import { handleFabricPlans, type FabricPlansRouteOpts } from './fabric-plans.js';
|
|
166
167
|
import { dispatchPersonaRoute } from './personas.js';
|
|
167
168
|
import { handleMe } from './operator.js';
|
|
@@ -184,7 +185,9 @@ import { handleChannelBotsGet, handleChannelBotSet } from './setup-channel-bot.j
|
|
|
184
185
|
import { handleLlmRoutePredict } from './llm-route-predict.js';
|
|
185
186
|
import type { MissionRouter } from '../../llm/mission-router.js';
|
|
186
187
|
import { handleContextFetchUrl } from './context-url.js';
|
|
187
|
-
import { contextNow } from '../../context-bus/context-now.js';
|
|
188
|
+
import { contextNow, type ContextNowDeps } from '../../context-bus/context-now.js';
|
|
189
|
+
import type { ContextNowAudience } from '../../context-bus/context-now-surfaces.js';
|
|
190
|
+
import { renderVoiceNow } from '../../context-bus/context-now-surfaces.js';
|
|
188
191
|
import type { IntentPredictionService } from '../../intent-prediction/index.js';
|
|
189
192
|
import type { NotificationActionLoopback } from '../../web-push/notification-action-loopback.js';
|
|
190
193
|
import { handlePlatforms } from './platforms.js';
|
|
@@ -486,6 +489,8 @@ export interface NexusHttpServerOpts {
|
|
|
486
489
|
eventBus: NexusEventBus;
|
|
487
490
|
/** Test seam for the read-only usage collector; production uses the cached handler. */
|
|
488
491
|
usageHandler?: () => Promise<Response>;
|
|
492
|
+
/** Test seam for the context-now ledgers; production reads the live ledgers. */
|
|
493
|
+
contextNowDeps?: ContextNowDeps;
|
|
489
494
|
/** Supervisor handle — required for the write API (PR ι). When omitted
|
|
490
495
|
* (skipSupervisor mode), mutation routes return 503. */
|
|
491
496
|
supervisor?: Supervisor;
|
|
@@ -1291,6 +1296,15 @@ export async function routeRequest(
|
|
|
1291
1296
|
return handleDevices(req, opts.devices);
|
|
1292
1297
|
}
|
|
1293
1298
|
|
|
1299
|
+
if (pathname === '/v1/loops/edges' && method === 'GET') {
|
|
1300
|
+
if (!opts.metaApi?.bearerToken) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1301
|
+
const offered = req.headers.get('authorization');
|
|
1302
|
+
if (!offered?.startsWith('Bearer ') || !compareTokenConstTime(offered.slice('Bearer '.length).trim(), opts.metaApi.bearerToken)) {
|
|
1303
|
+
return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1304
|
+
}
|
|
1305
|
+
return handleLoopEdgesGet(req);
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1294
1308
|
if (pathname === '/v1/harness/runs' && method === 'GET') {
|
|
1295
1309
|
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-runtime-not-wired' }, 503);
|
|
1296
1310
|
if (!checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
@@ -2878,8 +2892,24 @@ export async function routeRequest(
|
|
|
2878
2892
|
if (result) return result;
|
|
2879
2893
|
}
|
|
2880
2894
|
if (pathname === '/v1/context/now') {
|
|
2881
|
-
|
|
2882
|
-
|
|
2895
|
+
try {
|
|
2896
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
2897
|
+
const audiences = url.searchParams.getAll('audience');
|
|
2898
|
+
if (audiences.length > 1) return jsonResponse({ error: 'invalid_audience' }, 400);
|
|
2899
|
+
const requested = audiences[0];
|
|
2900
|
+
if (requested !== undefined && requested !== 'operator' && requested !== 'user' && requested !== 'public-demo') {
|
|
2901
|
+
return jsonResponse({ error: 'invalid_audience' }, 400);
|
|
2902
|
+
}
|
|
2903
|
+
const forced = getUserConfig().nexus?.demoMode === true;
|
|
2904
|
+
const audience: ContextNowAudience = forced ? 'public-demo' : requested ?? 'operator';
|
|
2905
|
+
const answer = contextNow({ audience, ...(url.searchParams.has('topic') ? { topic: url.searchParams.get('topic') ?? '' } : {}) }, opts.contextNowDeps);
|
|
2906
|
+
debug.log('context.now', 'served', { audience, hidden: answer.hiddenCount ?? 0, forced });
|
|
2907
|
+
return jsonResponse(url.searchParams.get('format') === 'voice'
|
|
2908
|
+
? { text: renderVoiceNow(answer, audience), audience, hiddenCount: answer.hiddenCount ?? 0 }
|
|
2909
|
+
: { ...answer, audience, hiddenCount: answer.hiddenCount ?? 0 });
|
|
2910
|
+
} catch {
|
|
2911
|
+
return jsonResponse({ error: 'context-now-failed' }, 500);
|
|
2912
|
+
}
|
|
2883
2913
|
}
|
|
2884
2914
|
// §6.3 (2026-05-09) — context URL fetch (showroom).
|
|
2885
2915
|
// POST /v1/context/fetch-url
|