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/cli/release-cli.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// elanous release tag --version <x.y.z> --source <commit> [--yes]
|
|
6
6
|
// elanous release verify [--version <x.y.z>]
|
|
7
7
|
// elanous release notes --from <ref> [--to <ref>]
|
|
8
|
+
// elanous release run --version <x.y.z> [--dry-run] [--json] [--if-ready]
|
|
8
9
|
//
|
|
9
10
|
// 🩸 계기(2026-09-25 v0.1.0 첫 공개): 손으로 밟은 절차에서 둘을 빠뜨릴 뻔했다 — 공개본 git 커밋(판 커밋이 공개본 커밋이 된다) ·
|
|
10
11
|
// PWA 빌드(빌드 산출은 공개본에 안 실린다 → 빠뜨리면 «웹 화면 없는 판»). 절차를 명령으로 굳힌다.
|
|
@@ -22,7 +23,11 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../instance/resolve.js
|
|
|
22
23
|
import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
|
|
23
24
|
import { envLiteral } from '../platform/env-literal.js';
|
|
24
25
|
import { userConfigPath } from '../user-config.js';
|
|
25
|
-
import { addItem, devVersion, listChecklist, removeItem, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus } from '../release-loop/checklist.js';
|
|
26
|
+
import { addItem, devVersion, listChecklist, removeItem, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition } from '../release-loop/checklist.js';
|
|
27
|
+
import { writeStdoutJson } from './stdout-json.js';
|
|
28
|
+
import { runUnattendedRelease, type UnattendedReleaseDeps } from '../../scripts/release-loop/unattended-release.js';
|
|
29
|
+
import { releaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
30
|
+
import { runReleaseIfReady } from './release-run-if-ready.js';
|
|
26
31
|
|
|
27
32
|
export const DEFAULT_PUBLIC_REPO = 'ElanvitalAI/elanous';
|
|
28
33
|
const SEMVER = /^\d+\.\d+\.\d+(?:-(?:rc|alpha|beta)\.\d+)?$/;
|
|
@@ -466,11 +471,11 @@ function checklistVersion(input: string | undefined, codenames: Record<string, s
|
|
|
466
471
|
return resolved;
|
|
467
472
|
}
|
|
468
473
|
|
|
469
|
-
function checklistOutput(v: string, codenames: Record<string, string>, mode: 'list' | 'status', json?: boolean): void {
|
|
474
|
+
async function checklistOutput(v: string, codenames: Record<string, string>, mode: 'list' | 'status', json?: boolean): Promise<void> {
|
|
470
475
|
const data = listChecklist(v);
|
|
471
476
|
const summary = summarizeChecklist(data);
|
|
472
477
|
const result = { ...data, codename: codenames[v] ?? '', ...summary };
|
|
473
|
-
if (json) {
|
|
478
|
+
if (json) { await writeStdoutJson(`${JSON.stringify(result)}\n`); return; }
|
|
474
479
|
console.log(`${v}${result.codename ? ` (${result.codename})` : ''} · 공개 ${data.released || '없음'} · 개발 ${data.dev}`);
|
|
475
480
|
if (mode === 'list') {
|
|
476
481
|
for (const item of data.items) console.log(`${({ green: '🟢', yellow: '🟡', red: '🔴', done: '✅' } as const)[item.status]} ${item.id} ${item.title}${item.owner ? ` · ${item.owner}` : ''}`);
|
|
@@ -481,7 +486,7 @@ function checklistOutput(v: string, codenames: Record<string, string>, mode: 'li
|
|
|
481
486
|
}
|
|
482
487
|
}
|
|
483
488
|
|
|
484
|
-
export function registerReleaseCommands(program: Command): void {
|
|
489
|
+
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}): void {
|
|
485
490
|
const release = program.command('release').description('공개 배포 한 판 — prepare(로컬) → publish(--yes) → verify (docs/manual/MANUAL-versioning-and-release-2026-09-25.md)');
|
|
486
491
|
const checklist = release.command('checklist').description('판별 확인표 조회·갱신')
|
|
487
492
|
.option('--version <v>', '판 또는 별칭(기본: package.json 의 개발판에서 -dev.N 제거)')
|
|
@@ -492,26 +497,28 @@ export function registerReleaseCommands(program: Command): void {
|
|
|
492
497
|
return { version: checklistVersion(opts.version, codenames), codenames, json: opts.json };
|
|
493
498
|
};
|
|
494
499
|
const withContext = (cmd: Command) => cmd.option('--version <v>', '판 또는 별칭').option('--json', '결과 JSON');
|
|
495
|
-
withContext(checklist.command('list').description('모든 칸')).action((_opts: unknown, cmd: Command) => {
|
|
500
|
+
withContext(checklist.command('list').description('모든 칸')).action(async (_opts: unknown, cmd: Command) => {
|
|
496
501
|
const { version, codenames, json } = context(cmd);
|
|
497
|
-
checklistOutput(version, codenames, 'list', json);
|
|
502
|
+
await checklistOutput(version, codenames, 'list', json);
|
|
498
503
|
});
|
|
499
|
-
withContext(checklist.command('status').description('상태 요약')).action((_opts: unknown, cmd: Command) => {
|
|
504
|
+
withContext(checklist.command('status').description('상태 요약')).action(async (_opts: unknown, cmd: Command) => {
|
|
500
505
|
const { version, codenames, json } = context(cmd);
|
|
501
|
-
checklistOutput(version, codenames, 'status', json);
|
|
506
|
+
await checklistOutput(version, codenames, 'status', json);
|
|
502
507
|
});
|
|
503
508
|
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').action((id: string, title: string, opts: { owner?: string }, cmd: Command) => {
|
|
504
509
|
const { version, json } = context(cmd);
|
|
505
510
|
const data = addItem(version, { id, title, ...(opts.owner !== undefined ? { owner: opts.owner } : {}) });
|
|
506
511
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 추가`);
|
|
507
512
|
});
|
|
508
|
-
withContext(checklist.command('set <id>').description('칸
|
|
513
|
+
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
509
514
|
.option('--status <status>', 'green|yellow|red|done').option('--evidence <evidence>', '근거').option('--owner <owner>', '담당')
|
|
510
|
-
.
|
|
515
|
+
.option('--disposition <disposition>', 'move|known-issue|block')
|
|
516
|
+
.action((id: string, opts: { status?: string; evidence?: string; owner?: string; disposition?: string }, cmd: Command) => {
|
|
511
517
|
const { version, json } = context(cmd);
|
|
512
518
|
if (opts.status !== undefined && !['green', 'yellow', 'red', 'done'].includes(opts.status)) throw new Error(`잘못된 상태: ${opts.status}`);
|
|
513
|
-
if (opts.
|
|
514
|
-
|
|
519
|
+
if (opts.disposition !== undefined && !['move', 'known-issue', 'block'].includes(opts.disposition)) throw new Error(`잘못된 처분: ${opts.disposition}`);
|
|
520
|
+
if (opts.status === undefined && opts.evidence === undefined && opts.owner === undefined && opts.disposition === undefined) throw new Error('갱신할 칸을 지정하라');
|
|
521
|
+
const data = setItem(version, id, { ...(opts.status !== undefined ? { status: opts.status as ChecklistStatus } : {}), ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.disposition !== undefined ? { disposition: opts.disposition as ChecklistDisposition } : {}) }, process.env.ELANOUS_TRACK || 'cli');
|
|
515
522
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 갱신`);
|
|
516
523
|
});
|
|
517
524
|
withContext(checklist.command('rm <id>').description('칸 삭제')).action((id: string, _opts: unknown, cmd: Command) => {
|
|
@@ -584,4 +591,41 @@ export function registerReleaseCommands(program: Command): void {
|
|
|
584
591
|
const { draftReleaseNotes, readLandedCommits, renderReleaseNotes } = await import('../../scripts/release-notes.js');
|
|
585
592
|
console.log(renderReleaseNotes(draftReleaseNotes(readLandedCommits(o.from, o.to), o.from, o.to)));
|
|
586
593
|
});
|
|
594
|
+
release.command('run')
|
|
595
|
+
.description('릴리스 루프 실행 — 원장 직전 판과 release.loop 설정으로 그래프 입력 구성 · --dry-run 은 입력만 출력')
|
|
596
|
+
.requiredOption('--version <v>', '공개할 판(x.y.z)')
|
|
597
|
+
.option('--dry-run', '체크리스트·그래프 실행 없이 전체 입력 보기')
|
|
598
|
+
.option('--if-ready', '준비되지 않았으면 사유를 출력하고 성공으로 건너뛴다')
|
|
599
|
+
.option('--json', '결과 한 줄 JSON(stdout) · 사람 줄은 stderr')
|
|
600
|
+
.action(async (o: { version: string; dryRun?: boolean; ifReady?: boolean; json?: boolean }) => {
|
|
601
|
+
if (o.ifReady && !o.dryRun) {
|
|
602
|
+
try {
|
|
603
|
+
const outcome = await runReleaseIfReady(o.version, {
|
|
604
|
+
ledgerRoot: releaseRunDeps.ledgerRoot,
|
|
605
|
+
readiness: (version, options) => releaseReadiness(version, { ledgerRoot: releaseRunDeps.ledgerRoot, checklist: releaseRunDeps.checklist, ...options }),
|
|
606
|
+
run: () => runUnattendedRelease({ version: o.version }, releaseRunDeps),
|
|
607
|
+
});
|
|
608
|
+
if (outcome.skipped) {
|
|
609
|
+
if (o.json) await writeStdoutJson(`${JSON.stringify(outcome)}\n`);
|
|
610
|
+
else console.log(`· 준비 안 됨 ${o.version} · ${outcome.reason} · ${outcome.detail}`);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const result = outcome.result;
|
|
614
|
+
const ok = result.dryRun || result.state?.status === 'done' || result.state?.status === 'awaiting-approval';
|
|
615
|
+
(o.json ? console.error : console.log)(`${result.dryRun ? '· 드라이런' : '▶ 릴리스 루프'} ${result.input.version} · 입력 ${JSON.stringify(result.input)}`);
|
|
616
|
+
if (o.json) await writeStdoutJson(`${JSON.stringify({ ok, ...result })}\n`);
|
|
617
|
+
if (!ok && !process.exitCode) process.exitCode = 1;
|
|
618
|
+
} catch (e) {
|
|
619
|
+
if (o.json) await writeStdoutJson(`${JSON.stringify({ ok: false, error: (e as Error).message })}\n`);
|
|
620
|
+
else console.error(`⛔ ${(e as Error).message}`);
|
|
621
|
+
process.exitCode = 1;
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
await jsonAction(o.json, async (log) => {
|
|
626
|
+
const result = await runUnattendedRelease({ version: o.version, dryRun: o.dryRun }, releaseRunDeps);
|
|
627
|
+
log(`${result.dryRun ? '· 드라이런' : '▶ 릴리스 루프'} ${result.input.version} · 입력 ${JSON.stringify(result.input)}`);
|
|
628
|
+
return result;
|
|
629
|
+
}, (r) => r.dryRun || r.state?.status === 'done' || r.state?.status === 'awaiting-approval');
|
|
630
|
+
});
|
|
587
631
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { closeSync, mkdirSync, openSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { debug } from '../debug/log.js';
|
|
4
|
+
import { releaseLedgerRoot } from '../instance/resolve.js';
|
|
5
|
+
import type { ReleaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
6
|
+
|
|
7
|
+
export type ReleaseIfReadySkip = { skipped: true; reason: Exclude<ReleaseReadiness, { ready: true }>['reason']; detail: string };
|
|
8
|
+
|
|
9
|
+
export async function runReleaseIfReady<T>(version: string, deps: {
|
|
10
|
+
readiness: (version: string, options?: { isPidAlive?: (pid: number) => boolean }) => ReleaseReadiness | Promise<ReleaseReadiness>;
|
|
11
|
+
run: () => Promise<T>;
|
|
12
|
+
ledgerRoot?: string;
|
|
13
|
+
pid?: number;
|
|
14
|
+
now?: () => Date;
|
|
15
|
+
}): Promise<ReleaseIfReadySkip | { skipped: false; result: T }> {
|
|
16
|
+
const skip = (readiness: Exclude<ReleaseReadiness, { ready: true }>): ReleaseIfReadySkip => {
|
|
17
|
+
const detail = readiness.reason === 'checklist-blocked'
|
|
18
|
+
? [...readiness.details.red, ...readiness.details.undecided, ...readiness.details.blocked].join(', ')
|
|
19
|
+
: readiness.details;
|
|
20
|
+
debug.log('release-loop.readiness', readiness.reason, { version, detail });
|
|
21
|
+
return { skipped: true, reason: readiness.reason, detail };
|
|
22
|
+
};
|
|
23
|
+
const readiness = await deps.readiness(version);
|
|
24
|
+
if (!readiness.ready) return skip(readiness);
|
|
25
|
+
|
|
26
|
+
const dir = join(deps.ledgerRoot ?? releaseLedgerRoot(), 'release', version);
|
|
27
|
+
mkdirSync(dir, { recursive: true });
|
|
28
|
+
const lock = join(dir, 'run.lock');
|
|
29
|
+
let fd: number;
|
|
30
|
+
try { fd = openSync(lock, 'wx', 0o600); }
|
|
31
|
+
catch (error) {
|
|
32
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;
|
|
33
|
+
const detail = 'run.lock already exists';
|
|
34
|
+
debug.log('release-loop.readiness', 'already-running', { version, detail });
|
|
35
|
+
return { skipped: true, reason: 'already-running', detail };
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
writeFileSync(fd, `${JSON.stringify({ pid: deps.pid ?? process.pid, startedAt: (deps.now ?? (() => new Date()))().toISOString() })}\n`);
|
|
39
|
+
// This call still checks publication and checklist, but must not treat our own lock as another runner.
|
|
40
|
+
const insideLock = await deps.readiness(version, { isPidAlive: () => false });
|
|
41
|
+
if (!insideLock.ready) return skip(insideLock);
|
|
42
|
+
debug.log('release-loop.readiness', 'ready', { version });
|
|
43
|
+
return { skipped: false, result: await deps.run() };
|
|
44
|
+
} finally {
|
|
45
|
+
closeSync(fd);
|
|
46
|
+
rmSync(lock);
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import
|
|
5
|
-
import { formatDoctorReport, runDoctor, type DoctorOptions, type DoctorReport } from './doctor-cli.js';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { formatDoctorReport, registerDoctorCommand, runDoctor, type DoctorOptions, type DoctorReport } from './doctor-cli.js';
|
|
6
6
|
import { applyClaudePluginSetup, planClaudePluginSetup } from './claude-plugin-setup.js';
|
|
7
|
+
import { recommendedSetup } from './setup-recommend.js';
|
|
7
8
|
import { debug } from '../debug/log.js';
|
|
8
9
|
import { getUserConfig, saveUserConfig, type UserConfig } from '../user-config.js';
|
|
9
10
|
|
|
@@ -20,6 +21,7 @@ type SetupStep = {
|
|
|
20
21
|
|
|
21
22
|
export interface SetupCliDeps extends DoctorOptions {
|
|
22
23
|
runDoctor?: (options: DoctorOptions) => DoctorReport;
|
|
24
|
+
runDoctorFix?: (args: readonly string[]) => Promise<number>;
|
|
23
25
|
readFile?: (path: string) => string;
|
|
24
26
|
exists?: (path: string) => boolean;
|
|
25
27
|
homeDir?: () => string;
|
|
@@ -154,14 +156,16 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
154
156
|
const setup = program.command('setup')
|
|
155
157
|
.description('Check OpenAI Codex setup and guide each missing credential step')
|
|
156
158
|
.option('--non-interactive', 'Report setup state without prompts or writes')
|
|
157
|
-
.
|
|
159
|
+
.option('--yes', 'Set a missing Codex provider and apply recommended doctor repairs without asking')
|
|
160
|
+
.action(async (opts: { nonInteractive?: boolean; yes?: boolean }) => {
|
|
158
161
|
const doctor = doctorRunner(deps);
|
|
159
162
|
if (opts.nonInteractive) {
|
|
160
163
|
out.log(formatSetupReport(doctor, setupSteps(deps), true));
|
|
164
|
+
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
161
165
|
setExitCode(0);
|
|
162
166
|
return;
|
|
163
167
|
}
|
|
164
|
-
if (!isStdinTty()) {
|
|
168
|
+
if (!isStdinTty() && !opts.yes) {
|
|
165
169
|
(out.error ?? out.log)('대화형 온보딩은 stdin TTY가 있는 자리에서만 실행할 수 있다. 무인 설정은 `elanous setup --non-interactive`를 사용하라.');
|
|
166
170
|
setExitCode(1);
|
|
167
171
|
return;
|
|
@@ -169,8 +173,8 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
169
173
|
let steps = setupSteps(deps);
|
|
170
174
|
const provider = steps[1]!;
|
|
171
175
|
if (!provider.complete) {
|
|
172
|
-
const
|
|
173
|
-
if (
|
|
176
|
+
const approved = opts.yes || (await prompt('Set llm.provider to openai-codex now? [y/N] '))?.trim().toLowerCase() === 'y';
|
|
177
|
+
if (approved) {
|
|
174
178
|
const config = (deps.getUserConfig ?? getUserConfig)();
|
|
175
179
|
(deps.saveUserConfig ?? saveUserConfig)({ ...config, llm: { ...config.llm, provider: 'openai-codex' } });
|
|
176
180
|
steps = setupSteps(deps);
|
|
@@ -179,6 +183,23 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
179
183
|
}
|
|
180
184
|
}
|
|
181
185
|
out.log(formatSetupReport(doctor, steps, false));
|
|
186
|
+
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
187
|
+
const accepted = opts.yes || (isStdinTty() && /^(?:y|yes)?$/i.test((await prompt('추천대로 켤까요? [Y/n] '))?.trim() ?? 'n'));
|
|
188
|
+
if (accepted) {
|
|
189
|
+
const runDoctorFix = deps.runDoctorFix ?? (async (args: readonly string[]) => {
|
|
190
|
+
const doctorProgram = new Command();
|
|
191
|
+
let exitCode = 0;
|
|
192
|
+
registerDoctorCommand(doctorProgram, {
|
|
193
|
+
out,
|
|
194
|
+
err: { error: (message) => (out.error ?? out.log)(message) },
|
|
195
|
+
setExitCode: (code) => { exitCode = code; },
|
|
196
|
+
});
|
|
197
|
+
await doctorProgram.parseAsync([...args], { from: 'user' });
|
|
198
|
+
return exitCode;
|
|
199
|
+
});
|
|
200
|
+
setExitCode(await runDoctorFix(['doctor', '--fix', '--yes']));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
182
203
|
setExitCode(0);
|
|
183
204
|
});
|
|
184
205
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function recommendedSetup(state: { chat: { fastPath: boolean } }): [string, string] {
|
|
2
|
+
return [
|
|
3
|
+
'고칠 것 고치기 — 권한·PATH·서비스 파일·파이썬 환경 등 고칠 수 있는 항목을 고칩니다(로그인·서비스 재시작은 별도): `elanous doctor --fix --yes`',
|
|
4
|
+
state.chat.fastPath
|
|
5
|
+
? '짧은 물음은 빠르게 — 켜져 있음(chat.fastPath=true): 짧은 물음에 도구 없이 먼저 답합니다. 끄기: `elanous config set chat.fastPath false`'
|
|
6
|
+
: '짧은 물음은 빠르게 — 꺼져 있음(chat.fastPath=false): 켜면 짧은 물음에 도구 없이 먼저 답합니다. 켜기: `elanous config set chat.fastPath true`',
|
|
7
|
+
];
|
|
8
|
+
}
|
package/src/cli/usage-cli.ts
CHANGED
|
@@ -12,9 +12,13 @@ import { consumeCodexResetCredits, listCodexResetCredits } from '../budget/codex
|
|
|
12
12
|
import { rollupRunUsage, type RunUsageInput } from '../budget/run-usage-rollup.js';
|
|
13
13
|
import { LogStore, logsDbPath, type LogQuery, type LogStoreRow } from '../mss/logging/log-store.js';
|
|
14
14
|
import { LOGS_SINCE_OPTION, parseSince } from './logs-cli.js';
|
|
15
|
+
import { formatCodexCreditPlan, type CodexCreditPlan } from '../budget/codex-credit-plan.js';
|
|
16
|
+
import { codexCreditPlanFromDisk } from './codex-credit-plan-view.js';
|
|
15
17
|
|
|
16
18
|
export interface UsageCliDeps {
|
|
17
19
|
readonly collect?: typeof collectUnifiedUsage;
|
|
20
|
+
/** Codex credit plan (disk only). Returns null when it cannot be read. */
|
|
21
|
+
readonly creditPlan?: () => CodexCreditPlan | null;
|
|
18
22
|
readonly out?: { log: (s: string) => void };
|
|
19
23
|
/** Read-only LogStore query seam; returns stored llm-usage rows, newest first. */
|
|
20
24
|
readonly readRunLogs?: (query: LogQuery) => LogStoreRow[];
|
|
@@ -61,6 +65,10 @@ function usageData(row: LogStoreRow): RunUsageInput | null {
|
|
|
61
65
|
} catch { return null; }
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
function defaultCreditPlan(): CodexCreditPlan | null {
|
|
69
|
+
try { return codexCreditPlanFromDisk(); } catch { return null; }
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
export function registerUsageCommand(program: Command, deps: UsageCliDeps = {}): void {
|
|
65
73
|
const out = deps.out ?? { log: (s: string) => console.log(s) };
|
|
66
74
|
const collect = deps.collect ?? collectUnifiedUsage;
|
|
@@ -71,11 +79,13 @@ export function registerUsageCommand(program: Command, deps: UsageCliDeps = {}):
|
|
|
71
79
|
.option('--json', 'JSON 출력 — 자격 값은 없다')
|
|
72
80
|
.action(async (opts: { json?: boolean }) => {
|
|
73
81
|
const report = await collect();
|
|
82
|
+
const creditPlan = (deps.creditPlan ?? defaultCreditPlan)();
|
|
74
83
|
if (opts.json) {
|
|
75
|
-
out.log(JSON.stringify(report, null, 2));
|
|
84
|
+
out.log(JSON.stringify({ ...report, codexCreditPlan: creditPlan }, null, 2));
|
|
76
85
|
return;
|
|
77
86
|
}
|
|
78
87
|
out.log(formatUnifiedUsage(report));
|
|
88
|
+
if (creditPlan) out.log(['', 'codex 크레딧', ...formatCodexCreditPlan(creditPlan).map((l) => ` ${l}`)].join('\n'));
|
|
79
89
|
});
|
|
80
90
|
|
|
81
91
|
usage
|
package/src/codex/setup.ts
CHANGED
|
@@ -62,14 +62,33 @@ export interface CodexSetupResult {
|
|
|
62
62
|
|
|
63
63
|
// ── Picker helpers (shared with onboarding) ──────────────────────────
|
|
64
64
|
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
export interface CodexAuthModeDeps {
|
|
66
|
+
loadTokens?: typeof loadTokens;
|
|
67
|
+
/** OB1 — a codex CLI login (~/.codex/auth.json) the runtime already uses; default = `inspectSubscription`. */
|
|
68
|
+
hasCodexCliLogin?: () => boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function pickCodexAuthMode(io: WizardIO, deps: CodexAuthModeDeps = {}): Promise<CodexAuthMode> {
|
|
72
|
+
const existing = (deps.loadTokens ?? loadTokens)('openai-codex');
|
|
73
|
+
// OB1 (10-01): a user already signed in to the codex CLI was sent through the device-code flow again,
|
|
74
|
+
// because only elanous's own token store counted. The runtime reads ~/.codex/auth.json, so it counts too.
|
|
75
|
+
// Same judgment as the runtime (`codexOAuthAvailable` in llm.ts) — two judgments drifting apart was the bug.
|
|
76
|
+
const codexCli = !existing && (deps.hasCodexCliLogin ?? (() => {
|
|
77
|
+
try {
|
|
78
|
+
const { codexOAuthAvailable } = require('../llm.js') as typeof import('../llm.js');
|
|
79
|
+
return codexOAuthAvailable();
|
|
80
|
+
} catch { return false; }
|
|
81
|
+
}))();
|
|
82
|
+
if (existing || codexCli) {
|
|
83
|
+
if (existing) {
|
|
84
|
+
const exp = existing.tokens.expiresAt;
|
|
85
|
+
const when = exp != null
|
|
86
|
+
? (Date.now() > exp ? 'EXPIRED' : `${Math.round((exp - Date.now()) / 60000)}min left`)
|
|
87
|
+
: 'no expiry tracked';
|
|
88
|
+
io.print(` OAuth tokens already on file (${when}).`);
|
|
89
|
+
} else {
|
|
90
|
+
io.print(' Found your ChatGPT/Codex login from the codex CLI (~/.codex/auth.json).');
|
|
91
|
+
}
|
|
73
92
|
// Sprint 11 — chooseFrom Yes/No so fullScreenIO renders the arrow
|
|
74
93
|
// picker (with 'y'/'n' + 한글 자모 quick-pick from PR #986 + #988)
|
|
75
94
|
// instead of a bare text input. The runner distinguishes 'oauth-keep'
|
package/src/dashboard/index.ts
CHANGED
|
@@ -16779,7 +16779,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
16779
16779
|
preferHistoryArrowKeys: slashQuickMode,
|
|
16780
16780
|
history: inputHistory,
|
|
16781
16781
|
placeholder: anyProviderAvailable()
|
|
16782
|
-
? '
|
|
16782
|
+
? '말 한 줄로 시작 — 질문하거나 «하니스로 구현 …» · /command · /path/to.pdf 첨부'
|
|
16783
16783
|
: '/quit /clear (run `elanous setup` — no LLM provider available)',
|
|
16784
16784
|
debugLog: debug.enabled ? (event, label, payload) => debug.log(event, label, payload) : undefined,
|
|
16785
16785
|
textInputOpts: {
|
package/src/discord.ts
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
import { markdownToTelegramHtml as _unusedMarkdownFn } from './telegram-format.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
24
24
|
import { debug } from './debug/log.js';
|
|
25
25
|
import { getUserConfig } from './user-config.js';
|
|
26
|
+
import { handleDiscordSeatWork, type DiscordSeatWorkDeps } from './intake-plane/discord-seat-work.js';
|
|
27
|
+
import { parseSeatAddress } from './seat-address/seat-address.js';
|
|
26
28
|
|
|
27
29
|
// Telegram's HTML markdown isn't directly useful for Discord (Discord
|
|
28
30
|
// uses CommonMark + its own subset). Import kept as a reminder that
|
|
@@ -163,6 +165,8 @@ export interface DiscordBotOpts {
|
|
|
163
165
|
* primary `onMessage` LLM chat path. Errors are swallowed by the
|
|
164
166
|
* caller — this is a best-effort fan-out. */
|
|
165
167
|
onTriggerTap?: (event: DcTriggerEvent) => void | Promise<void>;
|
|
168
|
+
/** Override the intake door's dependencies for isolated Discord seat-work tests. */
|
|
169
|
+
seatWorkDeps?: DiscordSeatWorkDeps;
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
/** Surface-unification v2 — minimal trigger-side event shape. Maps
|
|
@@ -204,6 +208,8 @@ export class DiscordBot {
|
|
|
204
208
|
private readonly token: string;
|
|
205
209
|
private readonly allowedUsers: Set<string>;
|
|
206
210
|
private readonly guildTextChannels: Set<string>;
|
|
211
|
+
/** The bot's own user id (from READY) — EV12c lets an allowlisted @mention open any guild channel. */
|
|
212
|
+
private selfUserId: string | undefined;
|
|
207
213
|
private readonly onMessage: DcMessageHandler;
|
|
208
214
|
private readonly maxChars: number;
|
|
209
215
|
private readonly log: (msg: string) => void;
|
|
@@ -216,6 +222,7 @@ export class DiscordBot {
|
|
|
216
222
|
private readonly onReaction: ((event: DcReactionEvent) => void | Promise<void>) | null;
|
|
217
223
|
/** Surface-unification v2 (FU-1) — workflow-runtime tap. */
|
|
218
224
|
private readonly onTriggerTap: ((event: DcTriggerEvent) => void | Promise<void>) | null;
|
|
225
|
+
private readonly seatWorkDeps: DiscordSeatWorkDeps;
|
|
219
226
|
private ws: WebSocket | null = null;
|
|
220
227
|
private running = false;
|
|
221
228
|
private heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
@@ -239,6 +246,7 @@ export class DiscordBot {
|
|
|
239
246
|
this.onInteraction = opts.onInteraction ?? null;
|
|
240
247
|
this.onReaction = opts.onReaction ?? null;
|
|
241
248
|
this.onTriggerTap = opts.onTriggerTap ?? null;
|
|
249
|
+
this.seatWorkDeps = opts.seatWorkDeps ?? {};
|
|
242
250
|
}
|
|
243
251
|
|
|
244
252
|
/** Send a raw payload on the gateway WebSocket. Voice adapter uses
|
|
@@ -604,6 +612,7 @@ export class DiscordBot {
|
|
|
604
612
|
session_id?: string;
|
|
605
613
|
};
|
|
606
614
|
this.log(`READY — logged in as @${d.user?.username ?? '?'} (${d.user?.id ?? '?'})`);
|
|
615
|
+
if (d.user?.id) this.selfUserId = d.user.id;
|
|
607
616
|
if (this.voiceTap?.onReady && d.session_id && d.user?.id) {
|
|
608
617
|
try { this.voiceTap.onReady(d.session_id, d.user.id); }
|
|
609
618
|
catch (err: any) { this.log(`voice tap onReady failed: ${err?.message ?? err}`); }
|
|
@@ -684,6 +693,20 @@ export class DiscordBot {
|
|
|
684
693
|
|
|
685
694
|
// ── Message routing ────────────────────────────────────────
|
|
686
695
|
|
|
696
|
+
/** EV12c — true when this message @mentions the bot itself (mentions array or the raw `<@id>` token). */
|
|
697
|
+
private mentionsSelf(m: Record<string, unknown>, text: string): boolean {
|
|
698
|
+
const self = this.selfUserId;
|
|
699
|
+
if (!self) return false;
|
|
700
|
+
if (Array.isArray(m.mentions) && (m.mentions as Array<{ id?: unknown }>).some(u => String(u?.id) === self)) return true;
|
|
701
|
+
return text.includes(`<@${self}>`) || text.includes(`<@!${self}>`);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
private stripSelfMention(text: string): string {
|
|
705
|
+
const self = this.selfUserId;
|
|
706
|
+
if (!self) return text;
|
|
707
|
+
return text.split(`<@!${self}>`).join('').split(`<@${self}>`).join('').replace(/\s+/g, ' ').trim();
|
|
708
|
+
}
|
|
709
|
+
|
|
687
710
|
private async handleMessageCreate(m: Record<string, unknown>): Promise<void> {
|
|
688
711
|
// Ignore bot's own messages (DM reply from our own send would
|
|
689
712
|
// re-enter here).
|
|
@@ -692,19 +715,25 @@ export class DiscordBot {
|
|
|
692
715
|
|
|
693
716
|
// DM-only v1 scope: guild_id is absent for DM channels.
|
|
694
717
|
// Voice channel commands (`/voice-join`, `/voice-leave`,
|
|
695
|
-
// `/voice-status`)
|
|
696
|
-
//
|
|
697
|
-
//
|
|
718
|
+
// `/voice-status`) and allowlisted, seat-addressed work bypass
|
|
719
|
+
// DM-only. All other guild traffic stays gated unless explicitly
|
|
720
|
+
// configured as a guild text channel.
|
|
698
721
|
const isDm = !m.guild_id;
|
|
722
|
+
const rawText = typeof m.content === 'string' ? m.content : '';
|
|
723
|
+
const mentionsSelf = this.mentionsSelf(m, rawText);
|
|
699
724
|
if (!isDm && !this.guildTextChannels.has(String(m.channel_id))) {
|
|
700
|
-
|
|
701
|
-
|
|
725
|
+
if (!/^\/voice-(join|leave|status)\b/.test(rawText.trim())
|
|
726
|
+
&& !(this.allowedUsers.has(author.id) && (parseSeatAddress(rawText) || mentionsSelf))) {
|
|
727
|
+
debug.log('discord.trigger', 'dropped', { reason: 'guild-not-chat', channelId: String(m.channel_id) });
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
702
730
|
}
|
|
703
731
|
|
|
704
732
|
// Allowlist enforcement. An empty allowlist refuses everyone —
|
|
705
733
|
// safer default than "open to the world" when the bot runs
|
|
706
734
|
// with no user config.
|
|
707
735
|
if (this.allowedUsers.size > 0 && !this.allowedUsers.has(author.id)) {
|
|
736
|
+
debug.log('discord.trigger', 'dropped', { reason: 'not-allowed', isDm });
|
|
708
737
|
this.log(`discord: refusing unknown user ${author.id}`);
|
|
709
738
|
try {
|
|
710
739
|
await this.sendMessage(
|
|
@@ -738,7 +767,7 @@ export class DiscordBot {
|
|
|
738
767
|
channelId: String(m.channel_id),
|
|
739
768
|
userId: author.id,
|
|
740
769
|
userName: author.username,
|
|
741
|
-
text:
|
|
770
|
+
text: mentionsSelf ? this.stripSelfMention(rawText) : rawText,
|
|
742
771
|
messageId: String(m.id),
|
|
743
772
|
isDm,
|
|
744
773
|
attachments,
|
|
@@ -790,6 +819,27 @@ export class DiscordBot {
|
|
|
790
819
|
}
|
|
791
820
|
}
|
|
792
821
|
|
|
822
|
+
// Addressed work is submitted only by configured owners; ordinary chat keeps its existing path.
|
|
823
|
+
if (this.allowedUsers.has(author.id) && parseSeatAddress(ctx.text)) {
|
|
824
|
+
const threadId = typeof m.thread_id === 'string' && m.thread_id ? m.thread_id : undefined;
|
|
825
|
+
const replyChannelId = threadId ?? ctx.channelId;
|
|
826
|
+
try {
|
|
827
|
+
const seatReply = await handleDiscordSeatWork(ctx.text, {
|
|
828
|
+
channelId: replyChannelId,
|
|
829
|
+
messageId: ctx.messageId,
|
|
830
|
+
...(threadId ? { threadId } : {}),
|
|
831
|
+
}, this.seatWorkDeps);
|
|
832
|
+
if (seatReply !== null) {
|
|
833
|
+
await this.sendMessage(replyChannelId, seatReply);
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
} catch (err: unknown) {
|
|
837
|
+
this.log(`discord seat work failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
838
|
+
await this.sendMessage(replyChannelId, '좌석 요청을 접수하지 못했습니다. 잠시 후 다시 보내 주세요.');
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
793
843
|
// §C5 스트리밍 flip — streaming.discord ON 이면 옛 경로(placeholder+streamer+delivery) 억제,
|
|
794
844
|
// 청크 fan-out sink 가 담당(handler chunkProducer 가 primarySurfaces=['discord']). 텔레그램 동형.
|
|
795
845
|
const dcStreamingFlip = getUserConfig().sessionFabric?.streaming?.discord === true;
|
|
@@ -15,6 +15,8 @@ import { existsSync } from 'node:fs';
|
|
|
15
15
|
import { Database } from 'bun:sqlite';
|
|
16
16
|
import type { LLMToolSpec } from '../llm.js';
|
|
17
17
|
import { debug } from '../debug/log.js';
|
|
18
|
+
import { runRecall, type RecallSearch } from '../tool-runtime/self-cognition-runtimes.js';
|
|
19
|
+
import type { ToolRuntimeContext } from '../tool-runtime/types.js';
|
|
18
20
|
import { SCHEDULE_MANAGE_SPEC, dispatchScheduleManage } from './schedule-manage-tool.js';
|
|
19
21
|
import { SESSION_MANAGE_SPEC, dispatchSessionQuery } from './session-query-tool.js';
|
|
20
22
|
import { AUTOPILOT_MISSION_SPEC, dispatchAutopilotMissions } from '../autopilot/mission-tool.js';
|
|
@@ -43,6 +45,7 @@ const MEMORY_RECALL_SPEC: LLMToolSpec = {
|
|
|
43
45
|
sinceHours: { type: 'number', description: '조회 기간 시간(기본 168=7일).' },
|
|
44
46
|
limit: { type: 'number', description: '반환 건수(기본 8).' },
|
|
45
47
|
restoreId: { type: 'string', description: '느린 복원(선택) — archived 후보의 id 를 지정하면 그 cold 기억을 S3 에서 복원(recall_count++·warm 재활성화)해 본문 반환. 회상 결과 archived 에 관련 후보가 있고 본문이 필요할 때만.' },
|
|
48
|
+
timeBudgetMs: { type: 'number', description: '기억 조회 시간 예산(밀리초·기본 60000). 초과 시 찾은 것까지 부분 반환.' },
|
|
46
49
|
},
|
|
47
50
|
required: [],
|
|
48
51
|
},
|
|
@@ -50,7 +53,7 @@ const MEMORY_RECALL_SPEC: LLMToolSpec = {
|
|
|
50
53
|
|
|
51
54
|
/** memory_recall 코어(db 주입·테스트 가능). restoreId 지정 시 느린 복원(축B P2), 아니면 회상 + archive 발견.
|
|
52
55
|
* recency+importance+relevance 스코어. restoreDeps 는 테스트 S3 mock(생략 시 기본 S3). */
|
|
53
|
-
export function recallOrRestore(mdb: Database, args: Record<string, unknown>, restoreDeps?: ArchiveS3Deps): unknown {
|
|
56
|
+
export function recallOrRestore(mdb: Database, args: Record<string, unknown>, restoreDeps?: ArchiveS3Deps, onPartial?: (result: Record<string, unknown>) => void): unknown {
|
|
54
57
|
// ★ 축B P2 느린 복원 — restoreId 지정 시 cold 기억을 S3 에서 명시적 복원(recall_count++·warm 재활성화).
|
|
55
58
|
// 자동 아님(명시적) = 복원 폭주 방지. 죽어있던 restoreFromArchive 호출부 배선.
|
|
56
59
|
if (typeof args.restoreId === 'string' && args.restoreId) {
|
|
@@ -75,15 +78,17 @@ export function recallOrRestore(mdb: Database, args: Record<string, unknown>, re
|
|
|
75
78
|
...(typeof args.sinceHours === 'number' ? { sinceHours: args.sinceHours } : {}),
|
|
76
79
|
...(typeof args.limit === 'number' ? { limit: args.limit } : {}),
|
|
77
80
|
});
|
|
81
|
+
const mappedHits = hits.map(h => ({
|
|
82
|
+
when: h.ts, surface: h.surface, kind: h.kind,
|
|
83
|
+
text: h.text.slice(0, 400), importance: h.importance,
|
|
84
|
+
score: Math.round(h.score * 1000) / 1000,
|
|
85
|
+
}));
|
|
86
|
+
onPartial?.({ hits: mappedHits, count: hits.length });
|
|
78
87
|
// M2 — cold(S3 보관) 기억 메타 발견(본문 fetch 없음·빠름). 존재+id 알리고 복원은 restoreId 로 명시적.
|
|
79
88
|
const q = typeof args.query === 'string' ? String(args.query) : '';
|
|
80
89
|
const archived = q ? searchArchive(mdb, q, { ...(typeof args.domain === 'string' && args.domain ? { domain: String(args.domain) } : {}), limit: 3 }) : [];
|
|
81
90
|
return {
|
|
82
|
-
hits:
|
|
83
|
-
when: h.ts, surface: h.surface, kind: h.kind,
|
|
84
|
-
text: h.text.slice(0, 400), importance: h.importance,
|
|
85
|
-
score: Math.round(h.score * 1000) / 1000,
|
|
86
|
-
})),
|
|
91
|
+
hits: mappedHits,
|
|
87
92
|
count: hits.length,
|
|
88
93
|
...(archived.length ? { archived: archived.map(a => ({ id: a.id, when: a.ts, summary: a.summary, note: 'cold·S3 보관(restoreId 로 느린 복원)' })) } : {}),
|
|
89
94
|
note: '내가 발송/통지한 것의 원장 회상(크로스서피스 기억·hot/warm). archived=흐려져 S3 로 이관된 cold 기억(존재+id·본문은 restoreId 로 느린 복원). 비었으면 해당 기간 발송 없음.',
|
|
@@ -91,18 +96,18 @@ export function recallOrRestore(mdb: Database, args: Record<string, unknown>, re
|
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
/** memory_recall 공유 구현(finance-tools 에서 이관). db 열기 + recallOrRestore 위임. */
|
|
94
|
-
async function dispatchMemoryRecall(args: Record<string, unknown>): Promise<unknown> {
|
|
99
|
+
async function dispatchMemoryRecall(args: Record<string, unknown>, onPartial?: (result: Record<string, unknown>) => void): Promise<unknown> {
|
|
95
100
|
if (!existsSync(surfaceEventsDbPath())) {
|
|
96
101
|
return { hits: [], note: '발송 원장 미생성 — 아직 기록된 발송이 없음(데몬 재시작 후 sendOutbound부터 적재).' };
|
|
97
102
|
}
|
|
98
103
|
const mdb = openSurfaceEventsDb();
|
|
99
|
-
try { return recallOrRestore(mdb, args); }
|
|
104
|
+
try { return recallOrRestore(mdb, args, undefined, onPartial); }
|
|
100
105
|
catch (e) { return { error: `기억 회상 실패: ${e instanceof Error ? e.message.slice(0, 100) : String(e)}` }; }
|
|
101
106
|
finally { mdb.close(); }
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
/** L2 코어 앱 도구 dispatch 핸들러 — 이름 → 구현. 새 코어 도구는 여기 추가. */
|
|
105
|
-
const CORE_TOOL_HANDLERS: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
|
|
110
|
+
const CORE_TOOL_HANDLERS: Record<string, (args: Record<string, unknown>, onPartial?: (result: Record<string, unknown>) => void) => Promise<unknown>> = {
|
|
106
111
|
schedule_manage: dispatchScheduleManage,
|
|
107
112
|
session_manage: (args) => dispatchSessionQuery(args), // 대화 세션 검색·열람·목록·삭제(내용/ID/텔레그램)
|
|
108
113
|
memory_recall: dispatchMemoryRecall,
|
|
@@ -115,26 +120,44 @@ const CORE_TOOL_HANDLERS: Record<string, (args: Record<string, unknown>) => Prom
|
|
|
115
120
|
mission_decide: dispatchMissionDecide, // 미션 결정 기록(re-ground·defer·boundary…)·3박자 주입·코어
|
|
116
121
|
};
|
|
117
122
|
|
|
123
|
+
/** Worker-side search entry: dispatch must not re-enter its own budget wrapper. */
|
|
124
|
+
export function dispatchRecallUnbudgeted(name: 'memory_recall' | 'self_recall', args: Record<string, unknown>, onPartial: (result: Record<string, unknown>) => void): Promise<unknown> {
|
|
125
|
+
return CORE_TOOL_HANDLERS[name]!(args, onPartial);
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
/** L2 코어 앱 도구 spec 목록(전 서피스 공용). */
|
|
119
|
-
|
|
129
|
+
const SELF_RECALL_BUDGET_SPEC: LLMToolSpec = {
|
|
130
|
+
...SELF_RECALL_SPEC,
|
|
131
|
+
parameters: {
|
|
132
|
+
...SELF_RECALL_SPEC.parameters,
|
|
133
|
+
properties: {
|
|
134
|
+
...(SELF_RECALL_SPEC.parameters.properties as Record<string, unknown>),
|
|
135
|
+
timeBudgetMs: { type: 'number', description: '기억 조회 시간 예산(밀리초·기본 60000). 초과 시 찾은 것까지 부분 반환.' },
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
export const CORE_TOOL_SPECS: LLMToolSpec[] = [SCHEDULE_MANAGE_SPEC, SESSION_MANAGE_SPEC, MEMORY_RECALL_SPEC, FACT_CHECK_SPEC, SELF_RECALL_BUDGET_SPEC, AUTOPILOT_MISSION_SPEC, OPS_STATUS_SPEC, SE_BUILD_SPEC, LOGS_QUERY_SPEC, MISSION_DECIDE_SPEC];
|
|
120
140
|
|
|
121
141
|
export interface CoreTools {
|
|
122
142
|
specs: LLMToolSpec[];
|
|
123
143
|
names: Set<string>;
|
|
124
|
-
dispatch: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
144
|
+
dispatch: (name: string, args: Record<string, unknown>, onPartial?: (result: Record<string, unknown>) => void, context?: ToolRuntimeContext) => Promise<unknown>;
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
/** 서피스 무관 코어 앱 도구 세트. 모든 서피스가 이걸 조립 → 코어 도구 단일 출처 상속.
|
|
128
148
|
* L1(native)·L3(finance 팩)와 조합해 쓴다. dispatch 는 이름으로 라우팅(미등록=error). */
|
|
129
|
-
export function buildCoreTools(): CoreTools {
|
|
149
|
+
export function buildCoreTools(recallSearch?: RecallSearch): CoreTools {
|
|
130
150
|
const names = new Set(CORE_TOOL_SPECS.map(s => s.name));
|
|
131
151
|
return {
|
|
132
152
|
specs: CORE_TOOL_SPECS,
|
|
133
153
|
names,
|
|
134
|
-
dispatch: async (name, args) => {
|
|
154
|
+
dispatch: async (name, args, onPartial, context) => {
|
|
135
155
|
const h = CORE_TOOL_HANDLERS[name];
|
|
136
156
|
if (!h) return { error: `unknown core tool: ${name}` };
|
|
137
|
-
|
|
157
|
+
if (name === 'memory_recall' || name === 'self_recall') {
|
|
158
|
+
return runRecall(name, args, context ?? { surface: 'skill' }, recallSearch, onPartial);
|
|
159
|
+
}
|
|
160
|
+
return h(args, onPartial);
|
|
138
161
|
},
|
|
139
162
|
};
|
|
140
163
|
}
|