elanous 0.2.5 → 0.2.7
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/.env.example +10 -7
- package/README.md +9 -4
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5391-8793f88b03b30161.js → 2375-cb6debea56cce4fb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{1751.50b96ea9c37b49b6.js → 2415.ed6428ff334c7ce2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{4daa2798-1363d725c79f3593.js → 2ea96958-e8c7e112de50b067.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8617.465ca22a319c95b3.js → 4323.c5dfb6f503304775.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4836-2eba6079f31b88d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8918-482b30ce2a8ebf4c.js → 5080-1613752891fcadb4.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5348-bbf838e119661eee.js → 5791-bb82743fa6299562.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{9704-3221c102623c8d73.js → 6062-73e68343a9814f6a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4440-18bb160d95819f4e.js → 6090-85a3f05f954e5697.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{f6f3850d-7f324c6566002113.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8519-f6b5d8a5833a7603.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8894-e92491a164192cc1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9454-a3e0953307216c58.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9740-67051141115ce775.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +1 -0
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5ebde04844689e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-f89e9a303515a033.js → page-10ed24f413ed66e9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-4f403cd060442c95.js → page-211810b6c93ab66a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-0ac5d053f0444d21.js → page-624f7a2f89b60c8f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-5a5fb385a4df0ffe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-80497e93a878ddc5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-7457f52683562161.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-cee86394de407aa6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4ff8edab44196b8c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-92e4f44428d5e290.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-b7dcf5d48a854b76.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-51480757e7d68b92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2a05dfe80c8bdf16.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d9979633aa82f8e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-30533117beb53625.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-f7857826c2f97ad7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-07267f1391b96aba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-bccce0babceae30f.js → page-55d50e9b0006a91d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-9699b1786be6171d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-43dd772aee8af75f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-a7e37af7d0399cb8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-973ab7af59c718b7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a9f8d3865b91e436.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-15e5a15db84c56aa.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a2e572e4511f2a16.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-dd107bf1c7d52a90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d42b99cdfb9f27c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-2764ff40dad5a995.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-c5f1152db116ff96.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-f933bca81ea38a6f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-c1c95739c0bff3b8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-a7aaffcf771662d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-71d18eec33b9c667.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-56adbe1a1f1379bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-2c4e59079ee357ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a81f113f3ef89d72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d422f38c052967e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fc27b00e20733146.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-2bf59c720fe9542c.js → webpack-e5bea36f183b25e6.js} +1 -1
- package/apps/pwa/out/_next/static/css/f537bdb19c69306a.css +1 -0
- package/apps/pwa/out/_next/static/keajW7DDyghEs1y8oJe6T/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +22 -22
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +22 -22
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +22 -22
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +21 -21
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +21 -21
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +21 -21
- package/apps/pwa/out/consult/index.html +1 -0
- package/apps/pwa/out/consult/index.txt +32 -0
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +22 -22
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +22 -22
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +22 -22
- package/apps/pwa/out/exec/index.html +1 -0
- package/apps/pwa/out/exec/index.txt +32 -0
- package/apps/pwa/out/field/index.html +1 -0
- package/apps/pwa/out/field/index.txt +32 -0
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/icons/elanous-16.png +0 -0
- package/apps/pwa/out/icons/elanous-180.png +0 -0
- package/apps/pwa/out/icons/elanous-192.png +0 -0
- package/apps/pwa/out/icons/elanous-32.png +0 -0
- package/apps/pwa/out/icons/elanous-512.png +0 -0
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +21 -21
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +22 -22
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +22 -22
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +21 -21
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +21 -21
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +22 -22
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +22 -22
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +22 -22
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +21 -21
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +22 -22
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +22 -22
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +22 -22
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +22 -22
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +22 -22
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +21 -21
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +22 -22
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +22 -22
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +22 -22
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +22 -22
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +22 -22
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +22 -22
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +22 -22
- package/bin/elanous.cjs +107 -0
- package/graphs/field/field-feed.yaml +24 -0
- package/graphs/field/recipes.yaml +12 -0
- package/graphs/landing/landing-heal.yaml +3 -1
- package/graphs/landing/recipes.yaml +3 -0
- package/graphs/release/recipes.yaml +13 -0
- package/graphs/release/release-loop.yaml +13 -4
- package/package.json +5 -5
- package/plugins/card-followup/README.md +42 -0
- package/plugins/card-followup/examples/card-sample.json +7 -0
- package/plugins/card-followup/graphs/card-followup.yaml +18 -0
- package/plugins/card-followup/graphs/recipes.yaml +16 -0
- package/plugins/card-followup/graphs/run-step.ts +276 -0
- package/plugins/card-followup/graphs/sales-strategy.ts +173 -0
- package/plugins/card-followup/plugin.json +25 -0
- package/plugins/doc-draft/README.md +13 -0
- package/plugins/doc-draft/examples/brief-sample.json +8 -0
- package/plugins/doc-draft/graphs/doc-draft.yaml +14 -0
- package/plugins/doc-draft/graphs/recipes.yaml +9 -0
- package/plugins/doc-draft/graphs/run-step.ts +113 -0
- package/plugins/doc-draft/plugin.json +24 -0
- package/plugins/geo-check/README.md +15 -0
- package/plugins/geo-check/examples/brand-sample.json +8 -0
- package/plugins/geo-check/graphs/geo-check.yaml +20 -0
- package/plugins/geo-check/graphs/recipes.yaml +18 -0
- package/plugins/geo-check/graphs/run-step.ts +198 -0
- package/plugins/geo-check/plugin.json +24 -0
- package/plugins/job-coach/.codex-plugin/plugin.json +1 -1
- package/plugins/job-coach/README.md +31 -1
- package/plugins/job-coach/graphs/run-step.ts +2 -2
- package/plugins/job-coach/plugin.json +1 -1
- package/plugins/job-coach/plugin.ts +1 -1
- package/scripts/affinity/endcard.sh +3 -2
- package/scripts/affinity/reframe.sh +3 -1
- package/scripts/ci-public-export-leak-gate.ts +48 -0
- package/scripts/codex-quota-alert.ts +122 -258
- package/scripts/coord-tracks.json +4 -4
- package/scripts/daemon-port-baseline.txt +1 -2
- package/scripts/field-feed/deliver-node.ts +52 -0
- package/scripts/field-feed/feed-node.ts +67 -0
- package/scripts/field-feed/lib.ts +162 -0
- package/scripts/field-feed/reel-node.ts +24 -0
- package/scripts/field-feed/start.ts +62 -0
- package/scripts/fixtures/vflow-sample.ndjson +6 -0
- package/scripts/install.sh +92 -13
- package/scripts/landing-heal/clean-checkout.ts +114 -0
- package/scripts/landing-heal/run-mission.ts +38 -3
- package/scripts/lib/android-test-device.ts +32 -0
- package/scripts/lib/pwa-scenarios/scenarios.ts +2 -1
- package/scripts/public-export.ts +8 -4
- package/scripts/release-loop/baseline-from-logs.ts +92 -0
- package/scripts/release-loop/checklist-gate-node.ts +35 -0
- package/scripts/release-loop/env-known-failures.ts +31 -0
- package/scripts/release-loop/gate-diff.ts +29 -0
- package/scripts/release-loop/gate-node.ts +124 -29
- package/scripts/release-loop/known-issues-node.ts +159 -0
- package/scripts/release-loop/npm-publish-node.ts +118 -0
- package/scripts/release-loop/ops-upgrade-node.ts +87 -0
- package/scripts/release-loop/release-readiness.ts +58 -0
- package/scripts/release-loop/shard-plan.ts +47 -0
- package/scripts/release-loop/unattended-release.ts +93 -0
- package/scripts/ux/measure-first-text.ts +102 -0
- package/scripts/ux/record-page.ts +4 -1
- package/scripts/vflow-collect.ts +20 -7
- package/scripts/vflow-search.ts +73 -0
- package/scripts/video-free-line-test-walker.ts +36 -0
- package/scripts/video-pipeline.ts +2 -2
- package/skills/explainer-video/SKILL.md +24 -3
- package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -1
- package/skills/explainer-video/engine/build.mjs +2 -2
- package/skills/explainer-video/engine/reel.mjs +235 -0
- package/skills/explainer-video/engine/reel.sh +9 -0
- package/skills/explainer-video/engine/vo.ts +58 -16
- package/skills/explainer-video/examples/elanous-0.2.5/script.json +1 -1
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +1 -1
- package/src/a2a/server.ts +2 -0
- package/src/acp/elanous-aware-peers.ts +30 -0
- package/src/acp/server.ts +91 -15
- package/src/agent/monad-agent-turn.ts +25 -6
- package/src/agent/shared-app-tools.ts +5 -3
- package/src/agent-substrate/review-intent.ts +6 -2
- package/src/agent-substrate/shard-boundary-intent.ts +70 -0
- package/src/auth/github-app-token.ts +4 -1
- package/src/autopilot/mission-origin.ts +20 -4
- package/src/autopilot/mission-phase-track.ts +11 -1
- package/src/autopilot/track-agent-shadow.ts +151 -0
- package/src/autopilot/track-agent.ts +26 -6
- package/src/autopilot/track-courier.ts +2 -2
- package/src/boot/acp-server-help.ts +16 -0
- package/src/boot/daemon-prompt-turn.ts +31 -10
- package/src/boot/daemon-tools/index.ts +7 -1
- package/src/budget/codex-credit-pace.ts +84 -0
- package/src/budget/codex-credit-plan.ts +154 -0
- package/src/budget/codex-reset-credit-state.ts +2 -0
- package/src/chat/chat-cli.ts +4 -1
- package/src/chat/short-question.ts +40 -0
- package/src/cli/agent-cli.ts +24 -15
- package/src/cli/ask-bare.ts +42 -0
- package/src/cli/cli-user-error.ts +25 -0
- package/src/cli/codex-credit-plan-view.ts +25 -0
- package/src/cli/dependence-gauge.ts +237 -0
- package/src/cli/doctor-cli.ts +5 -0
- package/src/cli/doctor-modes.ts +48 -0
- package/src/cli/intake-cli.ts +12 -2
- package/src/cli/intake-source-cli.ts +58 -0
- package/src/cli/machine-cli.ts +23 -0
- package/src/cli/msg-cli.ts +137 -0
- package/src/cli/nexus-ios-bind.ts +25 -8
- package/src/cli/phone-link.ts +117 -0
- package/src/cli/plugin-cli.ts +52 -0
- package/src/cli/pr-cli.ts +36 -0
- package/src/cli/private-ledger-commands.ts +31 -0
- package/src/cli/provider-cli.ts +5 -0
- package/src/cli/release-cli.ts +56 -12
- package/src/cli/release-run-if-ready.ts +48 -0
- package/src/cli/setup-cli.ts +27 -6
- package/src/cli/setup-recommend.ts +8 -0
- package/src/cli/usage-cli.ts +11 -1
- package/src/codex/setup.ts +27 -8
- package/src/dashboard/index.ts +1 -1
- package/src/discord.ts +56 -6
- package/src/domains/core-tools.ts +37 -14
- package/src/domains/outbound-alert.ts +55 -16
- package/src/exec-requests/planner.ts +140 -0
- package/src/exec-requests/runner.ts +338 -0
- package/src/exec-requests/store.ts +76 -0
- package/src/field/field-media.ts +250 -0
- package/src/field/field-reel.ts +196 -0
- package/src/grok/credential.ts +7 -5
- package/src/harness/aside-run-status.ts +33 -0
- package/src/harness/browser-verify.ts +48 -17
- package/src/harness/harness-cli-command.ts +25 -3
- package/src/harness/image-load-state.ts +21 -0
- package/src/harness/process-garbage.ts +45 -0
- package/src/index.ts +104 -38
- package/src/instance/leader.ts +13 -1
- package/src/intake-plane/collect-github.ts +5 -3
- package/src/intake-plane/collect-telegram-saved.ts +15 -3
- package/src/intake-plane/discord-seat-work.ts +56 -0
- package/src/intake-plane/intake-sources.ts +202 -0
- package/src/intake-plane/items.ts +28 -12
- package/src/intake-plane/seat-doc-route.ts +207 -0
- package/src/intake-plane/submit-intake-work.ts +9 -1
- package/src/intake-plane/telegram-seat-work.ts +72 -0
- package/src/llm/model-defaults.ts +24 -1
- package/src/llm.ts +5 -4
- package/src/machines/machine-ledger.ts +127 -0
- package/src/market/pack-internal-refs.ts +28 -0
- package/src/market/publish.ts +31 -4
- package/src/maturity/feature-maturity.ts +65 -0
- package/src/model-tier/turn-tier.ts +24 -0
- package/src/msg/msg-store.ts +149 -0
- package/src/native-tool-catalog.ts +2 -1
- package/src/nexus/api/chat-fast-path-config.ts +28 -0
- package/src/nexus/api/consult-requests.ts +117 -0
- package/src/nexus/api/discord-trigger-bot.ts +3 -0
- package/src/nexus/api/exec-requests.ts +51 -0
- package/src/nexus/api/field-uploads.ts +180 -0
- package/src/nexus/api/graph-approvals-feed.ts +140 -0
- package/src/nexus/api/graph-approvals.ts +120 -4
- package/src/nexus/api/harness-api.ts +219 -5
- package/src/nexus/api/http-server.ts +68 -5
- package/src/nexus/api/seat-requests.ts +254 -0
- package/src/nexus/api/trace-run-scan.ts +37 -0
- package/src/nexus/api/trace.ts +19 -3
- package/src/nexus/index.ts +3 -0
- package/src/nexus/setup-status.ts +4 -5
- package/src/notify/llm-budget-alert.ts +125 -0
- package/src/oauth/codex-account-rotation.ts +26 -4
- package/src/oauth/codex-account-store.ts +20 -2
- package/src/oauth/codex-browser-login.ts +173 -0
- package/src/oauth/codex.ts +4 -1
- package/src/oauth/fallback-chain.ts +5 -5
- package/src/oauth/store.ts +42 -5
- package/src/onboarding/continue-here.ts +29 -0
- package/src/onboarding/entry-hints.ts +8 -0
- package/src/onboarding/full-screen-io.ts +35 -3
- package/src/onboarding/help/skills.md +1 -1
- package/src/onboarding/non-interactive.ts +1 -0
- package/src/onboarding/subscription-hint.ts +27 -0
- package/src/onboarding/web-first.ts +83 -0
- package/src/onboarding.ts +230 -23
- package/src/plugins/maker/node-install.ts +92 -0
- package/src/plugins/maker/node-maker.ts +139 -0
- package/src/plugins/maker/plugin-maker.ts +220 -0
- package/src/policy/llm-policy.ts +268 -0
- package/src/prompt-library/session-guidance.ts +7 -1
- package/src/prompt-library/universal-preamble.ts +2 -2
- package/src/relay/channel.ts +184 -0
- package/src/relay/mux.ts +182 -0
- package/src/relay/relay-cli.ts +20 -0
- package/src/relay/relay-server.ts +220 -0
- package/src/relay/test-vectors.json +29 -0
- package/src/release-loop/checklist.ts +36 -9
- package/src/seat-address/seat-address.ts +34 -0
- package/src/self-dev/decompose.ts +1 -0
- package/src/self-dev/dev-pipeline.ts +6 -3
- package/src/self-dev/run-record-mirror.ts +44 -0
- package/src/self-dev/run-store.ts +12 -3
- package/src/self-implement/harness-policy-gates.ts +4 -1
- package/src/self-implement/report-origin.ts +12 -1
- package/src/self-implement/run-ledger-compact.ts +1 -1
- package/src/session/chat.ts +17 -5
- package/src/session/index.ts +23 -10
- package/src/skills/shared-agent-skill-roots.ts +25 -0
- package/src/steward/failure-streak.ts +78 -0
- package/src/steward/steward-cards.ts +24 -0
- package/src/steward/triage-budget.ts +127 -0
- package/src/steward/triage-plan.ts +75 -0
- package/src/steward/triage.ts +244 -42
- package/src/task-cards/card-store.ts +1 -1
- package/src/task-orchestrator/surfaces/pod-bun-cache.ts +18 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
- package/src/task-orchestrator/surfaces/pod-ledger-events.ts +68 -0
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +78 -4
- package/src/telegram.ts +145 -2
- package/src/tool-runtime/elanous-skills-list-runtime.ts +3 -3
- package/src/tool-runtime/self-cognition-runtimes.ts +160 -2
- package/src/user-config.ts +84 -4
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/character.ts +42 -5
- package/src/video-pipeline/recipes/explainer.ts +213 -0
- package/src/video-pipeline/recipes/ffmpeg.ts +1 -1
- package/src/video-pipeline/recipes/free-line.ts +16 -3
- package/src/video-pipeline/recipes/remote.ts +7 -1
- package/src/video-pipeline/vflow-reference.ts +109 -0
- package/src/video-pipeline/walk-line.ts +3 -2
- package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +0 -5
- package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7527.943753b6ed829f09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9238.2cd5f47f4bf7a2c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +0 -1
- package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +0 -1
- package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +0 -1
- /package/apps/pwa/out/_next/static/{ktMqfrBbf8BMGac0jqLrb → keajW7DDyghEs1y8oJe6T}/_ssgManifest.js +0 -0
package/src/acp/server.ts
CHANGED
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
type ElanousTermPayload,
|
|
67
67
|
} from './elanous-extensions.js';
|
|
68
68
|
import { createMissionTurnEmitter } from './mission-turn-emit.js';
|
|
69
|
+
import { ElanousAwarePeers } from './elanous-aware-peers.js';
|
|
69
70
|
import { enqueuePendingUserInput } from '../session/pending-input.js';
|
|
70
71
|
import {
|
|
71
72
|
ELANOUS_ASK_CANCEL_METHOD,
|
|
@@ -879,6 +880,10 @@ let activeAcpBroadcaster:
|
|
|
879
880
|
| ((sessionId: string, update: unknown) => Promise<{ delivered: number }>)
|
|
880
881
|
| null = null;
|
|
881
882
|
|
|
883
|
+
let activeAcpFeedbackBroadcaster:
|
|
884
|
+
| ((sessionId: string, env: FeedbackEnvelope) => Promise<{ delivered: number }>)
|
|
885
|
+
| null = null;
|
|
886
|
+
|
|
882
887
|
// P0b(DESIGN-cross-surface-autonomy-membrane §10) — ACP ask pusher(elanous/ask → iPhone/PWA 시트)를 모듈-레벨로
|
|
883
888
|
// 노출. daemon-runtime 이 코어 데몬 턴(SelfImplement dispatch)에 SurfaceUx confirm/question 채널을 주입할 때
|
|
884
889
|
// createAcp*Channel(sessionId, getActiveAcpAskPusher()) 로 사용. sessionPeers 로 라우팅(연결 무관)·fail-soft(null=drop).
|
|
@@ -894,8 +899,8 @@ export function getActiveAcpBroadcaster():
|
|
|
894
899
|
}
|
|
895
900
|
|
|
896
901
|
/** PLAN-ios-rich-dev-feedback-hydrate · M1-S (2026-05-13) — typed
|
|
897
|
-
* adapter
|
|
898
|
-
* `
|
|
902
|
+
* adapter that fans out a `FeedbackEnvelope` only to peers advertising
|
|
903
|
+
* `_meta.elanous`, as a `elanous/feedback/emit` envelope packaged
|
|
899
904
|
* inside an `agent_thought_chunk` sessionUpdate.
|
|
900
905
|
*
|
|
901
906
|
* Why `agent_thought_chunk` instead of a native `sessionUpdate:
|
|
@@ -912,15 +917,7 @@ export function getActiveAcpBroadcaster():
|
|
|
912
917
|
export function getActiveAcpFeedbackBroadcaster():
|
|
913
918
|
| ((sessionId: string, env: FeedbackEnvelope) => Promise<{ delivered: number }>)
|
|
914
919
|
| null {
|
|
915
|
-
|
|
916
|
-
if (!inner) return null;
|
|
917
|
-
return (sessionId, env) => {
|
|
918
|
-
const text = formatElanousFeedbackEnvelope({ method: 'emit', payload: env });
|
|
919
|
-
return inner(sessionId, {
|
|
920
|
-
sessionUpdate: 'agent_thought_chunk',
|
|
921
|
-
content: { type: 'text', text },
|
|
922
|
-
});
|
|
923
|
-
};
|
|
920
|
+
return activeAcpFeedbackBroadcaster;
|
|
924
921
|
}
|
|
925
922
|
|
|
926
923
|
/** PLAN-ios-rich-dev-feedback-hydrate M4 (HUD) — fan-out across ALL
|
|
@@ -989,6 +986,9 @@ interface AcpServerContext {
|
|
|
989
986
|
* fan-out walks the set so multi-surface clients (e.g. web PWA
|
|
990
987
|
* + TUI on the same id) all see the same stream. */
|
|
991
988
|
sessionPeers: Map<string, Set<SessionPeer>>;
|
|
989
|
+
awarePeers: ElanousAwarePeers<SessionPeer>;
|
|
990
|
+
/** One skip diagnostic per session, cleared when its last peer leaves. */
|
|
991
|
+
plainEnvelopeLogged: Set<string>;
|
|
992
992
|
dualRole: DualRoleManager;
|
|
993
993
|
/** Mints the unique suffix of a new session id. Injected so tests can
|
|
994
994
|
* pin it deterministically — production wires `mintAcpSessionToken`. */
|
|
@@ -1029,6 +1029,21 @@ interface SessionPeer {
|
|
|
1029
1029
|
peerId: string | null;
|
|
1030
1030
|
}
|
|
1031
1031
|
|
|
1032
|
+
function isFeedbackTextUpdate(update: unknown): boolean {
|
|
1033
|
+
if (!update || typeof update !== 'object') return false;
|
|
1034
|
+
const u = update as { sessionUpdate?: unknown; content?: { type?: unknown; text?: unknown } };
|
|
1035
|
+
return u.sessionUpdate === 'agent_thought_chunk'
|
|
1036
|
+
&& u.content?.type === 'text'
|
|
1037
|
+
&& typeof u.content.text === 'string'
|
|
1038
|
+
&& u.content.text.startsWith('[elanous/feedback/emit] ');
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
function logSkippedPlainEnvelope(ctx: AcpServerContext, sessionId: string, kind: string): void {
|
|
1042
|
+
if (ctx.plainEnvelopeLogged.has(sessionId)) return;
|
|
1043
|
+
ctx.plainEnvelopeLogged.add(sessionId);
|
|
1044
|
+
debug.log('acp.envelope', 'skipped-plain-client', { sessionId, kind });
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1032
1047
|
/** Wire a single `AgentSideConnection` onto the provided ndJsonStream.
|
|
1033
1048
|
* Owns all per-connection state (clientUiCaps, boundConnection ref,
|
|
1034
1049
|
* per-peer `AcpServerHandle`) so stdio and transport paths diverge
|
|
@@ -1038,7 +1053,7 @@ function wireAcpConnection(
|
|
|
1038
1053
|
stream: ReturnType<typeof ndJsonStream>,
|
|
1039
1054
|
ctx: AcpServerContext,
|
|
1040
1055
|
): AgentSideConnection {
|
|
1041
|
-
const { sessions, sessionPeers, dualRole, opts } = ctx;
|
|
1056
|
+
const { sessions, sessionPeers, awarePeers, plainEnvelopeLogged, dualRole, opts } = ctx;
|
|
1042
1057
|
// 2026-05-13 (M2 of AskUserQuestion cross-surface) — bound connection
|
|
1043
1058
|
// widened to expose `extMethod` + `extNotification` (SDK's elanous
|
|
1044
1059
|
// extension escape hatch). pushAskRequest / pushAskCancel route through
|
|
@@ -1132,6 +1147,10 @@ function wireAcpConnection(
|
|
|
1132
1147
|
}
|
|
1133
1148
|
return { delivered: 0 };
|
|
1134
1149
|
}
|
|
1150
|
+
if (isFeedbackTextUpdate(update) && !awarePeers.isElanousAware(sessionId)) {
|
|
1151
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
1152
|
+
return { delivered: 0 };
|
|
1153
|
+
}
|
|
1135
1154
|
let delivered = 0;
|
|
1136
1155
|
let dedupedByPeerId = 0;
|
|
1137
1156
|
const tasks: Promise<unknown>[] = [];
|
|
@@ -1141,6 +1160,10 @@ function wireAcpConnection(
|
|
|
1141
1160
|
// 은 모두 distinct peer 으로 취급해 send (degraded compat).
|
|
1142
1161
|
const seenPeerIds = new Set<string>();
|
|
1143
1162
|
for (const p of peers) {
|
|
1163
|
+
if (isFeedbackTextUpdate(update) && !awarePeers.isPeerAware(p)) {
|
|
1164
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1144
1167
|
if (opts2?.uiGate && !p.getUiCaps()[opts2.uiGate]) continue;
|
|
1145
1168
|
if (opts2?.termGate && !p.getTermCaps()[opts2.termGate]) continue;
|
|
1146
1169
|
if (p.peerId !== null) {
|
|
@@ -1380,6 +1403,7 @@ function wireAcpConnection(
|
|
|
1380
1403
|
clientUiCaps = parsed.ui;
|
|
1381
1404
|
clientTermCaps = parsed.term;
|
|
1382
1405
|
clientAskCaps = parsed.ask;
|
|
1406
|
+
awarePeers.markPeer(peer, req.clientCapabilities);
|
|
1383
1407
|
debug.log('acp.session', 'initialize', {
|
|
1384
1408
|
protocolVersion: req.protocolVersion,
|
|
1385
1409
|
clientName: req.clientInfo?.name ?? 'absent',
|
|
@@ -3316,7 +3340,10 @@ function wireAcpConnection(
|
|
|
3316
3340
|
if (!set) continue;
|
|
3317
3341
|
set.delete(peer);
|
|
3318
3342
|
const remaining = set.size;
|
|
3319
|
-
if (remaining === 0)
|
|
3343
|
+
if (remaining === 0) {
|
|
3344
|
+
sessionPeers.delete(sid);
|
|
3345
|
+
plainEnvelopeLogged.delete(sid);
|
|
3346
|
+
}
|
|
3320
3347
|
if (debug.enabled) {
|
|
3321
3348
|
debug.log('acp.peer.unregister', sid, { remainingPeers: remaining });
|
|
3322
3349
|
}
|
|
@@ -3451,10 +3478,14 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3451
3478
|
return true;
|
|
3452
3479
|
});
|
|
3453
3480
|
const sessionPeers = new Map<string, Set<SessionPeer>>();
|
|
3481
|
+
const awarePeers = new ElanousAwarePeers(sessionPeers);
|
|
3482
|
+
const plainEnvelopeLogged = new Set<string>();
|
|
3454
3483
|
const dualRole = opts.dualRoleManager ?? globalDualRoleManager();
|
|
3455
3484
|
const ctx: AcpServerContext = {
|
|
3456
3485
|
sessions,
|
|
3457
3486
|
sessionPeers,
|
|
3487
|
+
awarePeers,
|
|
3488
|
+
plainEnvelopeLogged,
|
|
3458
3489
|
dualRole,
|
|
3459
3490
|
nextSessionToken: mintAcpSessionToken,
|
|
3460
3491
|
agentName: opts.agentName ?? 'elanous-agent',
|
|
@@ -3478,9 +3509,17 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3478
3509
|
}
|
|
3479
3510
|
return { delivered: 0 };
|
|
3480
3511
|
}
|
|
3512
|
+
if (isFeedbackTextUpdate(update) && !awarePeers.isElanousAware(sessionId)) {
|
|
3513
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3514
|
+
return { delivered: 0 };
|
|
3515
|
+
}
|
|
3481
3516
|
const tasks: Promise<unknown>[] = [];
|
|
3482
3517
|
let delivered = 0;
|
|
3483
3518
|
for (const p of peers) {
|
|
3519
|
+
if (isFeedbackTextUpdate(update) && !awarePeers.isPeerAware(p)) {
|
|
3520
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3521
|
+
continue;
|
|
3522
|
+
}
|
|
3484
3523
|
delivered += 1;
|
|
3485
3524
|
tasks.push(p.sessionUpdate({ sessionId, update }));
|
|
3486
3525
|
}
|
|
@@ -3496,19 +3535,52 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3496
3535
|
await Promise.allSettled(tasks);
|
|
3497
3536
|
return { delivered };
|
|
3498
3537
|
};
|
|
3538
|
+
activeAcpFeedbackBroadcaster = async (sessionId, env) => {
|
|
3539
|
+
const text = formatElanousFeedbackEnvelope({ method: 'emit', payload: env });
|
|
3540
|
+
const peers = sessionPeers.get(sessionId);
|
|
3541
|
+
if (!peers || peers.size === 0) return { delivered: 0 };
|
|
3542
|
+
if (!awarePeers.isElanousAware(sessionId)) {
|
|
3543
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3544
|
+
return { delivered: 0 };
|
|
3545
|
+
}
|
|
3546
|
+
let delivered = 0;
|
|
3547
|
+
const tasks: Promise<unknown>[] = [];
|
|
3548
|
+
for (const peer of peers) {
|
|
3549
|
+
if (!awarePeers.isPeerAware(peer)) {
|
|
3550
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3551
|
+
continue;
|
|
3552
|
+
}
|
|
3553
|
+
delivered += 1;
|
|
3554
|
+
tasks.push(peer.sessionUpdate({
|
|
3555
|
+
sessionId,
|
|
3556
|
+
update: { sessionUpdate: 'agent_thought_chunk', content: { type: 'text', text } },
|
|
3557
|
+
}));
|
|
3558
|
+
}
|
|
3559
|
+
await Promise.allSettled(tasks);
|
|
3560
|
+
return { delivered };
|
|
3561
|
+
};
|
|
3499
3562
|
// PLAN-ios-rich-dev-feedback-hydrate M4 (2026-05-13) — all-sessions
|
|
3500
3563
|
// fan-out for process-wide envelope kinds (hud.segment). Iterates
|
|
3501
|
-
// sessionPeers
|
|
3564
|
+
// sessionPeers and gates each attached connection independently
|
|
3502
3565
|
// (consistent transport · same agent_thought_chunk text-in-text shape).
|
|
3503
3566
|
activeAcpAllSessionsFeedbackBroadcaster = async (envProto) => {
|
|
3504
3567
|
let fannedTo = 0;
|
|
3505
3568
|
let delivered = 0;
|
|
3506
3569
|
for (const [sessionId, peers] of sessionPeers) {
|
|
3507
3570
|
if (peers.size === 0) continue;
|
|
3508
|
-
|
|
3571
|
+
if (!awarePeers.isElanousAware(sessionId)) {
|
|
3572
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3573
|
+
continue;
|
|
3574
|
+
}
|
|
3509
3575
|
const env = { ...envProto, sessionId } as FeedbackEnvelope;
|
|
3510
3576
|
const text = formatElanousFeedbackEnvelope({ method: 'emit', payload: env });
|
|
3577
|
+
let any = false;
|
|
3511
3578
|
for (const peer of peers) {
|
|
3579
|
+
if (!awarePeers.isPeerAware(peer)) {
|
|
3580
|
+
logSkippedPlainEnvelope(ctx, sessionId, 'feedback');
|
|
3581
|
+
continue;
|
|
3582
|
+
}
|
|
3583
|
+
any = true;
|
|
3512
3584
|
try {
|
|
3513
3585
|
await peer.sessionUpdate({
|
|
3514
3586
|
sessionId,
|
|
@@ -3522,6 +3594,7 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3522
3594
|
/* swallow — best-effort fan-out */
|
|
3523
3595
|
}
|
|
3524
3596
|
}
|
|
3597
|
+
if (any) fannedTo += 1;
|
|
3525
3598
|
}
|
|
3526
3599
|
return { delivered, fannedTo };
|
|
3527
3600
|
};
|
|
@@ -3593,6 +3666,7 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3593
3666
|
try { await transport.close(); } catch { /* ignore */ }
|
|
3594
3667
|
acpServerDisposeSessions(sessions, dualRole);
|
|
3595
3668
|
activeAcpBroadcaster = null;
|
|
3669
|
+
activeAcpFeedbackBroadcaster = null;
|
|
3596
3670
|
activeAcpAskPusher = null;
|
|
3597
3671
|
activeAcpAllSessionsFeedbackBroadcaster = null;
|
|
3598
3672
|
activeAcpAllSessionsTermFrameBroadcaster = null;
|
|
@@ -3621,7 +3695,9 @@ export async function runAcpServer(opts: AcpServerOptions = {}): Promise<void> {
|
|
|
3621
3695
|
} finally {
|
|
3622
3696
|
acpServerDisposeSessions(sessions, dualRole);
|
|
3623
3697
|
activeAcpBroadcaster = null;
|
|
3698
|
+
activeAcpFeedbackBroadcaster = null;
|
|
3624
3699
|
activeAcpAskPusher = null;
|
|
3700
|
+
activeAcpAllSessionsFeedbackBroadcaster = null;
|
|
3625
3701
|
activeAcpAllSessionsTermFrameBroadcaster = null;
|
|
3626
3702
|
if (debug.enabled) {
|
|
3627
3703
|
debug.log('acp.broadcaster.lifecycle', 'clear', { mode: 'stdio' });
|
|
@@ -30,6 +30,7 @@ import { surfaceEventsDbPath, openSurfaceEventsDb, recentSentDigest, recordInbou
|
|
|
30
30
|
import { elanousSelfAccessPrompt, elanousSelfAmbientParts } from './self-ambient.js';
|
|
31
31
|
import { localRefGroundingAmbient } from './ref-grounding.js';
|
|
32
32
|
import { resolveRouteDecision } from '../llm/route-decision.js';
|
|
33
|
+
import { explicitTurnTier } from '../model-tier/turn-tier.js';
|
|
33
34
|
import type { RouteDecision } from '../llm/route-decision.js';
|
|
34
35
|
import { debug } from '../debug/log.js';
|
|
35
36
|
import { setEventLoopActivity } from '../debug/event-loop-watchdog.js';
|
|
@@ -59,7 +60,7 @@ function recentSentContext(): string {
|
|
|
59
60
|
* Bash + PtyShell + search), plus — when the finance domain pack is
|
|
60
61
|
* enabled (A0) — the analyst orientation + resource map + first-class
|
|
61
62
|
* finance tools. Drop-in for the hosting bot's `runTurnImpl`. */
|
|
62
|
-
export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource): typeof runTurn {
|
|
63
|
+
export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource, runTurnImpl: typeof runTurn = runTurn): typeof runTurn {
|
|
63
64
|
if (surface !== 'telegram' && surface !== 'discord') {
|
|
64
65
|
throw new Error(`Unsupported elanous agent session source: ${surface}`);
|
|
65
66
|
}
|
|
@@ -110,7 +111,13 @@ export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource)
|
|
|
110
111
|
// ⛔ 호출자가 모델을 핀했으면 «건드리지 않는다». 실패는 fail-soft — config 기본을 유지한다.
|
|
111
112
|
let llmOpts = opts.llmOpts;
|
|
112
113
|
let routeDecision: RouteDecision | undefined;
|
|
113
|
-
|
|
114
|
+
const explicitTier = opts.llmOpts?.model ? undefined : explicitTurnTier(cfg, opts.sessionId);
|
|
115
|
+
if (cfg.llm.provider === 'openai-codex' && explicitTier) {
|
|
116
|
+
llmOpts = { ...(llmOpts ?? {}), model: explicitTier.model };
|
|
117
|
+
debug.log('llm.route-decision', 'self-turn', {
|
|
118
|
+
surface, provider: cfg.llm.provider, model: explicitTier.model, skipped: 'explicit-tier',
|
|
119
|
+
});
|
|
120
|
+
} else if (cfg.llm.provider === 'openai-codex') {
|
|
114
121
|
try {
|
|
115
122
|
const decision = resolveRouteDecision({
|
|
116
123
|
provider: cfg.llm.provider,
|
|
@@ -212,8 +219,19 @@ export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource)
|
|
|
212
219
|
...(surfaceFileSink ? { fileSink: surfaceFileSink } : {}),
|
|
213
220
|
});
|
|
214
221
|
llmOpts = terminal.llmOpts;
|
|
215
|
-
|
|
222
|
+
let currentMessage = '';
|
|
223
|
+
let sawToolCall = false;
|
|
224
|
+
return runTurnImpl({
|
|
216
225
|
...opts,
|
|
226
|
+
onDelta: (delta) => {
|
|
227
|
+
currentMessage += delta;
|
|
228
|
+
opts.onDelta?.(delta);
|
|
229
|
+
},
|
|
230
|
+
onToolCall: (call) => {
|
|
231
|
+
currentMessage = '';
|
|
232
|
+
sawToolCall = true;
|
|
233
|
+
opts.onToolCall?.(call);
|
|
234
|
+
},
|
|
217
235
|
llmOpts,
|
|
218
236
|
systemPrompt: terminal.systemPromptParts.join('\n\n'),
|
|
219
237
|
tools: terminal.specs,
|
|
@@ -226,11 +244,12 @@ export function makeElanousAgentRunTurn(cfg: UserConfig, surface: SessionSource)
|
|
|
226
244
|
// NEXT turn's memory_recall knows the task was CANCELLED, not silently
|
|
227
245
|
// dropped or still running. Only turnAbort (=/cancel) aborts this signal.
|
|
228
246
|
const wasAborted = opts.signal?.aborted === true;
|
|
247
|
+
const answer = sawToolCall ? currentMessage.trim() : result.text;
|
|
229
248
|
const responseText = wasAborted
|
|
230
|
-
? (
|
|
231
|
-
? `${
|
|
249
|
+
? (answer?.trim()
|
|
250
|
+
? `${answer}\n\n⏹️ 이 작업은 /cancel 로 취소되었습니다 (실행 중이던 Bash/PTY 종료됨).`
|
|
232
251
|
: '⏹️ 작업이 /cancel 로 취소되었습니다. 실행 중이던 Bash/PTY 를 종료했습니다.')
|
|
233
|
-
:
|
|
252
|
+
: answer;
|
|
234
253
|
// Block 3 — 대화 턴을 크로스서피스 기억에 기록(질의+응답·direction=inbound).
|
|
235
254
|
// fail-soft·비동기(대화 지연 없음). 이후 memory_recall 이 과거 대화도 회상.
|
|
236
255
|
try { recordInboundTurn({ surface, userText: opts.userText, responseText, sessionId: opts.sessionId }); } catch { /* noop */ }
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// financeEnabled(cfg) 게이트(operator opt-in·미enable/미cfg 시 core 만·무회귀).
|
|
13
13
|
|
|
14
14
|
import { buildCoreTools } from '../domains/core-tools.js';
|
|
15
|
+
import type { ToolRuntimeContext } from '../tool-runtime/types.js';
|
|
15
16
|
import { buildFinanceTools } from '../domains/finance-tools.js';
|
|
16
17
|
import { financeEnabled } from '../domains/finance.js';
|
|
17
18
|
import { skillExecRuntime } from '../tool-runtime/skill-exec-runtime.js';
|
|
@@ -24,7 +25,7 @@ import type { LLMToolSpec } from '../llm.js';
|
|
|
24
25
|
export interface SharedAppTools {
|
|
25
26
|
specs: LLMToolSpec[];
|
|
26
27
|
names: Set<string>;
|
|
27
|
-
dispatch: (name: string, args: Record<string, unknown
|
|
28
|
+
dispatch: (name: string, args: Record<string, unknown>, context?: ToolRuntimeContext) => Promise<unknown>;
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/** L2 core + L3 finance(gated) + skill discovery/execution 단일 조립. specs 순서 = core, finance, discovery, execution. */
|
|
@@ -35,9 +36,10 @@ export function buildSharedAppTools(cfg?: UserConfig): SharedAppTools {
|
|
|
35
36
|
const skill = skillExecRuntime;
|
|
36
37
|
const specs: LLMToolSpec[] = [...core.specs, ...(fin ? fin.specs : []), skillsList, skill.spec];
|
|
37
38
|
const names = new Set<string>([...core.names, ...(fin ? fin.names : []), skillsList.name, skill.id]);
|
|
38
|
-
|
|
39
|
+
// context(B5) — 기억 조회 같은 긴 코어 도구가 진행 한 줄(emitFeedback)을 낼 수 있게 코어까지 넘긴다.
|
|
40
|
+
const dispatch = async (name: string, args: Record<string, unknown>, context?: ToolRuntimeContext): Promise<unknown> =>
|
|
39
41
|
name === skillsList.name ? dispatchElanousSkillsList(args as ElanousSkillsListArgs) :
|
|
40
42
|
name === skill.id ? skill.run(args as unknown as SkillExecArgs, { surface: 'skill' }) :
|
|
41
|
-
fin && fin.names.has(name) ? fin.dispatch(name, args) : core.dispatch(name, args);
|
|
43
|
+
fin && fin.names.has(name) ? fin.dispatch(name, args) : core.dispatch(name, args, undefined, context);
|
|
42
44
|
return { specs, names, dispatch };
|
|
43
45
|
}
|
|
@@ -16,6 +16,7 @@ import { parseGoalType, type GoalType } from '../self-implement/goal-author.js';
|
|
|
16
16
|
import type { DesignCheckOutcome } from '../design/design-check.js';
|
|
17
17
|
import type { DesignGateResult } from '../design/design-gate.js';
|
|
18
18
|
import type { PriorDraftFinding } from '../self-implement/prior-draft-findings.js';
|
|
19
|
+
import { parseShardIdentity, shardBoundaryBlock, withoutShardIdentity } from './shard-boundary-intent.js';
|
|
19
20
|
|
|
20
21
|
export interface ReviewIntentInput {
|
|
21
22
|
/** 무엇을 왜 — 골 원문. */
|
|
@@ -534,7 +535,9 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
|
534
535
|
// ⚠️ 목표 블록에는 **추출된 절을 뺀 나머지**를 넣는다(리뷰 should-fix) — 골 원문을 통째로 넣고
|
|
535
536
|
// 그 안의 수용기준을 다시 목록으로 붙이면 **같은 내용이 두 번** 들어가 4000자 예산을 먹고,
|
|
536
537
|
// 후순위 블록(스코프 경계)이 불필요하게 잘린다.
|
|
537
|
-
const
|
|
538
|
+
const identity = parseShardIdentity(i.goal);
|
|
539
|
+
const shardBoundary = identity ? { title: '조각 경계', text: `조각 경계\n${shardBoundaryBlock(identity)}` } : undefined;
|
|
540
|
+
const goalBody = stripExtractedSections(identity ? withoutShardIdentity(i.goal) : i.goal).trim();
|
|
538
541
|
const goal = goalBody ? { title: '목표', text: `목표\n${goalBody}` } : undefined;
|
|
539
542
|
// ⭐ **자식이 낸 증거**(diff 밖 이행 · base 적색 · 직전 반영분)를 한 묶음으로 잡아 둔다 — 아래 예산
|
|
540
543
|
// 배분에서 **목표 본문보다 먼저** 채우기 위해서다. 제목 문자열이 아니라 **동일성**으로 가른다.
|
|
@@ -563,6 +566,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
|
563
566
|
priorFindings,
|
|
564
567
|
goalFile,
|
|
565
568
|
goalType,
|
|
569
|
+
shardBoundary,
|
|
566
570
|
goal,
|
|
567
571
|
listBlock('수용기준', acceptance),
|
|
568
572
|
applied,
|
|
@@ -584,7 +588,7 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
|
|
|
584
588
|
// `…[N개 생략됨]`** 이 됐다. 그러면 리뷰는 *"실행하지 않았다 · 증거가 없다"* 를 적고 — 그것이
|
|
585
589
|
// **리뷰 입장에서 사실**이라 반박도 안 된다. 두 트랙 합쳐 **여섯 런**이 이 사인으로 죽었다.
|
|
586
590
|
// ⭐ 목표 본문을 뒤로 미뤄도 잃는 것이 적다 — **수용기준·경계는 이미 추출돼 보호 블록**에 있다.
|
|
587
|
-
const evidenceBlocks = [priorFindings, designGate, applied, preexisting, importerTestsNotRun, gateEvidence, designCheck, shardSiblings, coverage, claims, runFacts, goalFile].filter((b): b is Block => Boolean(b));
|
|
591
|
+
const evidenceBlocks = [shardBoundary, priorFindings, designGate, applied, preexisting, importerTestsNotRun, gateEvidence, designCheck, shardSiblings, coverage, claims, runFacts, goalFile].filter((b): b is Block => Boolean(b));
|
|
588
592
|
const otherBlocks = blocks.filter((block) => !protectedBlocks.includes(block) && !evidenceBlocks.includes(block) && block !== goal);
|
|
589
593
|
const order = [...protectedBlocks, ...evidenceBlocks, ...otherBlocks, ...(goal ? [goal] : [])];
|
|
590
594
|
// ⛔⭐⭐⭐ 1차는 우선순위와 무관하게 공정 몫까지만 준다. 목표 본문은 이미 추출된
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
interface ShardIdentity {
|
|
2
|
+
readonly shardId: string;
|
|
3
|
+
readonly totalShards: number;
|
|
4
|
+
readonly position: number;
|
|
5
|
+
readonly summary: string;
|
|
6
|
+
readonly siblings: readonly { readonly shardId: string; readonly summary: string }[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const SHARD_IDENTITY_SUFFIX = /(?:^|\n)## Shard identity\r?\n([\s\S]+?)\s*$/;
|
|
10
|
+
const MAX_BLOCK_CHARS = 800;
|
|
11
|
+
|
|
12
|
+
/** Read the JSON footer emitted by shardIdentityFeature, without treating other goal text as identity. */
|
|
13
|
+
export function parseShardIdentity(goalText: string): ShardIdentity | undefined {
|
|
14
|
+
const match = SHARD_IDENTITY_SUFFIX.exec(goalText);
|
|
15
|
+
if (!match) return undefined;
|
|
16
|
+
try {
|
|
17
|
+
const value: unknown = JSON.parse(match[1]!);
|
|
18
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined;
|
|
19
|
+
const identity = value as Record<string, unknown>;
|
|
20
|
+
if (typeof identity.shardId !== 'string' || !identity.shardId.trim()
|
|
21
|
+
|| typeof identity.summary !== 'string'
|
|
22
|
+
|| !Number.isInteger(identity.totalShards) || (identity.totalShards as number) < 1
|
|
23
|
+
|| !Number.isInteger(identity.position) || (identity.position as number) < 1
|
|
24
|
+
|| (identity.position as number) > (identity.totalShards as number)
|
|
25
|
+
|| !Array.isArray(identity.siblings)
|
|
26
|
+
|| !identity.siblings.every((sibling: unknown) => {
|
|
27
|
+
if (!sibling || typeof sibling !== 'object' || Array.isArray(sibling)) return false;
|
|
28
|
+
const item = sibling as Record<string, unknown>;
|
|
29
|
+
return typeof item.shardId === 'string' && !!item.shardId.trim() && typeof item.summary === 'string';
|
|
30
|
+
})) return undefined;
|
|
31
|
+
return identity as unknown as ShardIdentity;
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Remove only a successfully parsed footer; malformed metadata remains ordinary goal text. */
|
|
38
|
+
export function withoutShardIdentity(goalText: string): string {
|
|
39
|
+
return parseShardIdentity(goalText) ? goalText.replace(SHARD_IDENTITY_SUFFIX, '') : goalText;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function oneLine(value: string, limit: number): string {
|
|
43
|
+
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
44
|
+
return normalized.length > limit ? `${normalized.slice(0, limit - 1)}…` : normalized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Keep the sibling contract ahead of the goal body, with an explicit omission count. */
|
|
48
|
+
export function shardBoundaryBlock(identity: ShardIdentity): string {
|
|
49
|
+
const prefix = [
|
|
50
|
+
`이 PR 은 조각 ${oneLine(String(identity.position), 20)}/${oneLine(String(identity.totalShards), 20)}(${oneLine(identity.shardId, 80)}): ${oneLine(identity.summary, 240)}.`,
|
|
51
|
+
'형제 조각이 맡는 일(예: 등록·배선·화면)이 이 PR 에 없다는 이유로 must-fix 를 내지 말 것. 없어서 이 조각이 동작하지 않으면 should-fix 로 «형제 조각 <id> 에 의존» 한 줄.',
|
|
52
|
+
'형제 조각이 맡는 일:',
|
|
53
|
+
];
|
|
54
|
+
const items = identity.siblings.map((sibling) => `- ${oneLine(sibling.shardId, 80)}: ${oneLine(sibling.summary, 240)}`);
|
|
55
|
+
const header = prefix.join('\n');
|
|
56
|
+
if (header.length > MAX_BLOCK_CHARS) return header.slice(0, MAX_BLOCK_CHARS);
|
|
57
|
+
const kept: string[] = [];
|
|
58
|
+
for (const [index, item] of items.entries()) {
|
|
59
|
+
const omitted = items.length - index - 1;
|
|
60
|
+
const marker = omitted ? `…외 ${omitted}` : '';
|
|
61
|
+
if ([...prefix, ...kept, item, ...(marker ? [marker] : [])].join('\n').length > MAX_BLOCK_CHARS) break;
|
|
62
|
+
kept.push(item);
|
|
63
|
+
}
|
|
64
|
+
const omitted = items.length - kept.length;
|
|
65
|
+
const marker = omitted ? `…외 ${omitted}` : '';
|
|
66
|
+
if (marker && header.length + marker.length + 1 > MAX_BLOCK_CHARS) {
|
|
67
|
+
return `${header.slice(0, MAX_BLOCK_CHARS - marker.length - 1)}\n${marker}`;
|
|
68
|
+
}
|
|
69
|
+
return [...prefix, ...kept, ...(marker ? [marker] : [])].join('\n');
|
|
70
|
+
}
|
|
@@ -55,7 +55,10 @@ export function githubInstallationCredential(deps: GithubAutomationTokenDeps = {
|
|
|
55
55
|
const rel = join('secrets', 'github-app', 'app.json');
|
|
56
56
|
const own = join(getElanousConfigDir(), rel);
|
|
57
57
|
// An explicit config-dir override (tests · `--config-dir`) is a deliberate boundary — never reach past it.
|
|
58
|
-
|
|
58
|
+
// ELANOUS_GITHUB_APP_CONFIG_PATH pins the machine-level fallback (the bun test preload points it at nothing,
|
|
59
|
+
// so tests never mint); an explicit config-dir override still wins.
|
|
60
|
+
const pinned = process.env.ELANOUS_GITHUB_APP_CONFIG_PATH?.trim();
|
|
61
|
+
path = deps.configPath ?? (getElanousConfigDirOverride() ? own : pinned || (existsSync(own) ? own : join(prodInstanceRoot(), rel)));
|
|
59
62
|
}
|
|
60
63
|
catch {
|
|
61
64
|
try { debug.log('auth.github-app', 'token-failed', { reason: 'config-path-failed' }); } catch { /* fail open */ }
|
|
@@ -13,20 +13,36 @@ import { getUserConfig } from '../user-config.js';
|
|
|
13
13
|
import { resolveChannelBotToken } from '../channel-bot-token.js';
|
|
14
14
|
import { join } from 'node:path';
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
channel: 'telegram' | 'pwa' | 'voice' | 'cli' | 'api' | 'tui';
|
|
16
|
+
interface MissionOriginBase {
|
|
18
17
|
/** 텔레그램: 답장할 chat id. */
|
|
19
18
|
chatId?: number;
|
|
20
19
|
/** 텔레그램: 수신 봇 식별(botId=토큰 prefix). 발송 시 config 에서 토큰 해석. */
|
|
21
20
|
botId?: string;
|
|
22
|
-
/** 텔레그램 스레드(포럼) — 있으면 답장에 붙임. */
|
|
23
|
-
threadId?: number;
|
|
24
21
|
/** HITL 승인/거절 버튼을 단 알림 메시지의 message_id. 크로스서피스 싱크용 —
|
|
25
22
|
* PWA/텔레그램 어느 쪽에서 해소돼도 이 좌표(chatId+botId+이 id)로 텔레그램 메시지를
|
|
26
23
|
* edit("승인됨/거절됨")하고 버튼을 제거한다. 버튼 발송 성공 시에만 기록. */
|
|
27
24
|
hitlMessageId?: number;
|
|
28
25
|
}
|
|
29
26
|
|
|
27
|
+
export type MissionOrigin = MissionOriginBase & (
|
|
28
|
+
| {
|
|
29
|
+
channel: 'telegram' | 'pwa' | 'voice' | 'cli' | 'api' | 'tui';
|
|
30
|
+
/** 텔레그램 스레드(포럼) — 있으면 답장에 붙임. */
|
|
31
|
+
threadId?: number;
|
|
32
|
+
channelId?: never;
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
channel: 'discord';
|
|
36
|
+
/** Discord origin channel (snowflake). */
|
|
37
|
+
channelId: string;
|
|
38
|
+
/** Discord thread (snowflake), if the request came from a thread.
|
|
39
|
+
* ⛔ `threadId` 가 아니다 — 텔레그램 `threadId?: number` 와 같은 이름이면 유니온에서 `string|number` 로 넓어져
|
|
40
|
+
* 텔레그램 발송부 20여 곳의 타입이 깨진다(2026-10-01 PWA 빌드 실패 · #22246). */
|
|
41
|
+
discordThreadId?: string;
|
|
42
|
+
threadId?: never;
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
30
46
|
function originDir(): string {
|
|
31
47
|
// core 미션 fabric = autopilot/ (conatus/ 는 투자 customer 네임스페이스·대표 정정 2026-07-11).
|
|
32
48
|
// [ISO-3] ELANOUS_STATE_DIR 존중 — 격리 테스트 데몬은 운영 origin 을 못 본다.
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
|
|
4
|
-
type TrackEntry = { id: string; mark: string; owns: string[] };
|
|
4
|
+
type TrackEntry = { id: string; mark: string; owns: string[]; alias?: string };
|
|
5
|
+
|
|
6
|
+
// Seat ids became two letters on 09-30 (#22085) with the old one-letter id kept as `alias`.
|
|
7
|
+
// A track named either way is the same seat — posts and inputs still carry the old letter during the switch.
|
|
8
|
+
export function findTrack(idOrAlias: string, registry: TrackEntry[] = loadTrackRegistry()): TrackEntry | undefined {
|
|
9
|
+
return registry.find((track) => track.id === idOrAlias || track.alias === idOrAlias);
|
|
10
|
+
}
|
|
11
|
+
export function trackPostIds(idOrAlias: string, registry: TrackEntry[] = loadTrackRegistry()): string[] {
|
|
12
|
+
const track = findTrack(idOrAlias, registry);
|
|
13
|
+
return [...new Set([idOrAlias, ...(track ? [track.id, ...(track.alias ? [track.alias] : [])] : [])])];
|
|
14
|
+
}
|
|
5
15
|
|
|
6
16
|
export function loadTrackRegistry(path = resolve(import.meta.dir, '../../scripts/coord-tracks.json')): TrackEntry[] {
|
|
7
17
|
try {
|