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
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
+
import { isMainThread, parentPort, Worker } from 'node:worker_threads';
|
|
3
|
+
import { debug } from '../debug/log.js';
|
|
2
4
|
import type { LLMToolSpec } from '../llm.js';
|
|
3
5
|
import type { NativeToolCatalogEntry } from '../native-tool-catalog.js';
|
|
4
|
-
import type { ToolRunResult, ToolRuntime } from './types.js';
|
|
6
|
+
import type { ToolRunResult, ToolRuntime, ToolRuntimeContext } from './types.js';
|
|
5
7
|
|
|
6
8
|
/** Canonical names for the read-only self-cognition surface. */
|
|
7
9
|
export const SELF_COGNITION_TOOL_NAMES = [
|
|
@@ -12,6 +14,7 @@ export const SELF_COGNITION_TOOL_NAMES = [
|
|
|
12
14
|
] as const;
|
|
13
15
|
|
|
14
16
|
type SelfCognitionToolName = (typeof SELF_COGNITION_TOOL_NAMES)[number];
|
|
17
|
+
type RecallToolName = 'memory_recall' | 'self_recall';
|
|
15
18
|
type CoreToolsModule = typeof import('../domains/core-tools.js');
|
|
16
19
|
|
|
17
20
|
const require = createRequire(import.meta.url);
|
|
@@ -32,12 +35,167 @@ function toToolRunResult(result: unknown): ToolRunResult {
|
|
|
32
35
|
: { output: String(result) };
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
const PROGRESS_MS = 10_000;
|
|
39
|
+
const DEFAULT_BUDGET_MS = 60_000;
|
|
40
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
41
|
+
|
|
42
|
+
function hitCount(result: ToolRunResult): number {
|
|
43
|
+
const data: Record<string, unknown> = result;
|
|
44
|
+
return Array.isArray(data.hits) ? data.hits.length
|
|
45
|
+
: Array.isArray(data.events) ? data.events.length
|
|
46
|
+
: data.restored ? 1 : 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function partialResult(name: RecallToolName, result: ToolRunResult | undefined, budgetMs: number): ToolRunResult {
|
|
50
|
+
const fallback = name === 'memory_recall' ? { hits: [], count: 0 } : { events: [], count: 0, docs: null };
|
|
51
|
+
const snapshot: Record<string, unknown> = result ?? fallback;
|
|
52
|
+
const budgetSeconds = budgetMs / 1000;
|
|
53
|
+
return {
|
|
54
|
+
...snapshot,
|
|
55
|
+
partial: true,
|
|
56
|
+
note: `${typeof snapshot.note === 'string' ? `${snapshot.note}\n` : ''}(찾던 중 ${budgetSeconds}초에서 멈췄습니다 — 더 찾을까요?)`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A deadline returns the latest completed search stage; late results cannot replace it. */
|
|
61
|
+
export async function runBudgetedRecall(
|
|
62
|
+
name: RecallToolName,
|
|
63
|
+
args: Record<string, unknown>,
|
|
64
|
+
ctx: ToolRuntimeContext,
|
|
65
|
+
search: (onPartial: (result: ToolRunResult) => void) => Promise<ToolRunResult>,
|
|
66
|
+
stop: () => void = () => {},
|
|
67
|
+
progressAfterMs = PROGRESS_MS,
|
|
68
|
+
): Promise<ToolRunResult> {
|
|
69
|
+
const started = Date.now();
|
|
70
|
+
const budgetMs = typeof args.timeBudgetMs === 'number' && Number.isFinite(args.timeBudgetMs) && args.timeBudgetMs > 0
|
|
71
|
+
? Math.min(args.timeBudgetMs, MAX_TIMER_MS) : DEFAULT_BUDGET_MS;
|
|
72
|
+
let latest: ToolRunResult | undefined;
|
|
73
|
+
let settled = false;
|
|
74
|
+
const query = typeof args.query === 'string' && args.query.trim()
|
|
75
|
+
? args.query.trim().replace(/\s+/g, ' ').slice(0, 80)
|
|
76
|
+
: name === 'self_recall' ? '자기 구현·자율행동 이력' : '최근 발송·대화';
|
|
77
|
+
const log = (event: 'progress' | 'budget-hit' | 'done', result?: ToolRunResult) => {
|
|
78
|
+
debug.log('tool.memory-recall', event, { elapsedMs: Date.now() - started, hits: hitCount(result ?? latest ?? {}) });
|
|
79
|
+
};
|
|
80
|
+
let progressTimer: ReturnType<typeof setTimeout> | undefined;
|
|
81
|
+
let budgetTimer: ReturnType<typeof setTimeout> | undefined;
|
|
82
|
+
return new Promise<ToolRunResult>((resolve, reject) => {
|
|
83
|
+
const finish = (result: ToolRunResult, budgetHit: boolean) => {
|
|
84
|
+
if (settled) return;
|
|
85
|
+
settled = true;
|
|
86
|
+
clearTimeout(progressTimer);
|
|
87
|
+
clearTimeout(budgetTimer);
|
|
88
|
+
log(budgetHit ? 'budget-hit' : 'done', result);
|
|
89
|
+
if (budgetHit) stop();
|
|
90
|
+
resolve(result);
|
|
91
|
+
};
|
|
92
|
+
progressTimer = setTimeout(() => {
|
|
93
|
+
if (settled) return;
|
|
94
|
+
const line = `기억을 찾는 중 — ${query}`;
|
|
95
|
+
ctx.emitFeedback?.({
|
|
96
|
+
envelopeVersion: 1,
|
|
97
|
+
sessionId: ctx.sessionId ?? '',
|
|
98
|
+
blockId: `${ctx.sessionId ?? 'recall'}:tool:${ctx.toolCallId ?? name}:progress`,
|
|
99
|
+
parentToolCallId: ctx.toolCallId,
|
|
100
|
+
kind: 'tool.progress', phase: 'delta', emittedAt: Date.now(), seq: 1,
|
|
101
|
+
payload: { stream: 'generic', lines: [line] }, asciiFallback: [line],
|
|
102
|
+
});
|
|
103
|
+
log('progress');
|
|
104
|
+
}, progressAfterMs);
|
|
105
|
+
budgetTimer = setTimeout(() => finish(partialResult(name, latest, budgetMs), true), budgetMs);
|
|
106
|
+
try {
|
|
107
|
+
void search(result => { if (!settled) latest = result; }).then(
|
|
108
|
+
result => finish(result, false),
|
|
109
|
+
error => {
|
|
110
|
+
if (settled) return;
|
|
111
|
+
settled = true;
|
|
112
|
+
clearTimeout(progressTimer);
|
|
113
|
+
clearTimeout(budgetTimer);
|
|
114
|
+
stop();
|
|
115
|
+
reject(error);
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
settled = true;
|
|
120
|
+
clearTimeout(progressTimer);
|
|
121
|
+
clearTimeout(budgetTimer);
|
|
122
|
+
stop();
|
|
123
|
+
reject(error);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Separate thread: synchronous SQLite and S3 restore must not block progress/deadline timers.
|
|
129
|
+
if (!isMainThread && parentPort) {
|
|
130
|
+
parentPort.on('message', async ({ name, args }: { name: RecallToolName; args: Record<string, unknown> }) => {
|
|
131
|
+
try {
|
|
132
|
+
if (name === 'self_recall') {
|
|
133
|
+
const { existsSync } = await import('node:fs');
|
|
134
|
+
const { surfaceEventsDbPath, openSurfaceEventsDb, recallEvents } = await import('../domains/surface-events.js');
|
|
135
|
+
if (existsSync(surfaceEventsDbPath())) {
|
|
136
|
+
const db = openSurfaceEventsDb();
|
|
137
|
+
try {
|
|
138
|
+
const query = typeof args.query === 'string' ? args.query : '';
|
|
139
|
+
const hits = recallEvents(db, {
|
|
140
|
+
domain: 'elanous',
|
|
141
|
+
sinceHours: typeof args.sinceHours === 'number' ? args.sinceHours : 720,
|
|
142
|
+
limit: typeof args.limit === 'number' ? args.limit : 8,
|
|
143
|
+
...(query ? { query } : {}),
|
|
144
|
+
});
|
|
145
|
+
const events = hits.map(h => ({
|
|
146
|
+
when: h.ts, tool: h.surface, kind: h.kind ?? 'impl',
|
|
147
|
+
summary: (h.summary ?? h.text).slice(0, 300), score: Math.round(h.score * 1000) / 1000,
|
|
148
|
+
}));
|
|
149
|
+
parentPort?.postMessage({ stage: 'partial', result: { events, count: events.length, docs: null } });
|
|
150
|
+
} catch { /* self_recall's episode stage is fail-soft */ } finally { db.close(); }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const result = await coreTools().dispatchRecallUnbudgeted(name, args, partial => {
|
|
154
|
+
parentPort?.postMessage({ stage: 'partial', result: partial });
|
|
155
|
+
});
|
|
156
|
+
parentPort?.postMessage({ stage: 'done', result });
|
|
157
|
+
} catch (error) {
|
|
158
|
+
parentPort?.postMessage({ stage: 'error', error: error instanceof Error ? error.message : String(error) });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type RecallSearch = (name: RecallToolName, args: Record<string, unknown>, onPartial: (result: ToolRunResult) => void) => Promise<ToolRunResult>;
|
|
164
|
+
|
|
165
|
+
export function runRecall(name: RecallToolName, args: Record<string, unknown>, ctx: ToolRuntimeContext, injectedSearch?: RecallSearch, onPartial?: (result: ToolRunResult) => void): Promise<ToolRunResult> {
|
|
166
|
+
const worker = injectedSearch ? undefined : new Worker(new URL(import.meta.url));
|
|
167
|
+
let active = true;
|
|
168
|
+
const search = (capture: (result: ToolRunResult) => void) => {
|
|
169
|
+
const report = (result: ToolRunResult) => {
|
|
170
|
+
if (!active) return;
|
|
171
|
+
capture(result);
|
|
172
|
+
onPartial?.(result);
|
|
173
|
+
};
|
|
174
|
+
return injectedSearch
|
|
175
|
+
? injectedSearch(name, args, report)
|
|
176
|
+
: new Promise<ToolRunResult>((resolve, reject) => {
|
|
177
|
+
worker!.on('message', (message: { stage: string; result?: unknown; error?: string }) => {
|
|
178
|
+
if (message.stage === 'partial') report(toToolRunResult(message.result));
|
|
179
|
+
else if (message.stage === 'done') resolve(toToolRunResult(message.result));
|
|
180
|
+
else if (message.stage === 'error') reject(new Error(message.error));
|
|
181
|
+
});
|
|
182
|
+
worker!.on('error', reject);
|
|
183
|
+
worker!.on('exit', code => { if (code !== 0) reject(new Error(`Recall worker exited: ${code}`)); });
|
|
184
|
+
worker!.postMessage({ name, args });
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
return runBudgetedRecall(name, args, ctx, search, () => { active = false; if (worker) void worker.terminate(); })
|
|
188
|
+
.finally(() => { active = false; if (worker) void worker.terminate(); });
|
|
189
|
+
}
|
|
190
|
+
|
|
35
191
|
export const SELF_COGNITION_RUNTIMES: readonly ToolRuntime[] = SELF_COGNITION_TOOL_NAMES.map(name => ({
|
|
36
192
|
id: name,
|
|
37
193
|
get spec() {
|
|
38
194
|
return coreSpec(name);
|
|
39
195
|
},
|
|
40
|
-
run: async (args) =>
|
|
196
|
+
run: async (args, ctx) => name === 'memory_recall' || name === 'self_recall'
|
|
197
|
+
? runRecall(name, args, ctx)
|
|
198
|
+
: toToolRunResult(await coreTools().buildCoreTools().dispatch(name, args)),
|
|
41
199
|
}));
|
|
42
200
|
|
|
43
201
|
/** MCP catalog metadata derived from the same name ledger as the runtimes. */
|
package/src/user-config.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
GLM_MODEL,
|
|
48
48
|
} from './config.js';
|
|
49
49
|
import type { SkillTier } from './skills/runner.js';
|
|
50
|
+
import { sharedAgentSkillRoots } from './skills/shared-agent-skill-roots.js';
|
|
50
51
|
import {
|
|
51
52
|
isModelTier,
|
|
52
53
|
isModelTierPersona,
|
|
@@ -439,6 +440,8 @@ export type SkillSetName =
|
|
|
439
440
|
export interface SkillsConfig {
|
|
440
441
|
activeSet: SkillSetName;
|
|
441
442
|
dirs: string[];
|
|
443
|
+
/** Include the existing shared ~/.agents/skills directory. Default true; false opts out. */
|
|
444
|
+
includeSharedAgentSkills?: boolean;
|
|
442
445
|
/** Explicit skill-name allowlist. When set and non-empty, the skill
|
|
443
446
|
* index filters to this list — all other skills are hidden from
|
|
444
447
|
* routing, autocompletion, and `/run-skill`. Use when a project
|
|
@@ -505,6 +508,8 @@ export interface DefaultSkillDirsOptions {
|
|
|
505
508
|
pluginsRoot?: string;
|
|
506
509
|
/** Override the installed package root. Tests pass a temp root; production omits this. */
|
|
507
510
|
bundledSkillsRoot?: string;
|
|
511
|
+
/** Override the shared-agent home for isolated discovery tests. */
|
|
512
|
+
sharedAgentHome?: string;
|
|
508
513
|
}
|
|
509
514
|
|
|
510
515
|
/** Resolve the `skills/` directory shipped with this installed package. */
|
|
@@ -527,6 +532,15 @@ export function defaultSkillDirs(
|
|
|
527
532
|
} else if (sk.dirs.length > 0) {
|
|
528
533
|
base = [...sk.dirs];
|
|
529
534
|
}
|
|
535
|
+
const shared = sharedAgentSkillRoots({
|
|
536
|
+
home: opts?.sharedAgentHome ?? REMOTE_HOME,
|
|
537
|
+
includeSharedAgentSkills: sk.includeSharedAgentSkills !== false,
|
|
538
|
+
});
|
|
539
|
+
try { debug.log('skills.roots', 'shared-agent', { found: shared.length }); }
|
|
540
|
+
catch { /* discovery remains fail-soft when observation is unavailable */ }
|
|
541
|
+
for (const dir of shared) {
|
|
542
|
+
if (!base.includes(dir)) base.push(dir);
|
|
543
|
+
}
|
|
530
544
|
base = sk.includeClaudePackageSkills === true
|
|
531
545
|
? appendClaudePackageSkillDirs(base, opts?.pluginsRoot)
|
|
532
546
|
: base;
|
|
@@ -685,6 +699,7 @@ function skillsDefaults(): SkillsConfig {
|
|
|
685
699
|
return {
|
|
686
700
|
activeSet: 'claudecode',
|
|
687
701
|
dirs: d ? [d] : [],
|
|
702
|
+
includeSharedAgentSkills: true,
|
|
688
703
|
allow: [],
|
|
689
704
|
deny: [],
|
|
690
705
|
urlRouting: urlRoutingDefaults(),
|
|
@@ -833,6 +848,8 @@ export interface TelegramConfig {
|
|
|
833
848
|
/** 발송 목적(kind) → 채널 역할. 명시 `channels` 가 있을 때만 쓴다 — 표에 없는 kind 는 옛 `reportChannel` 로 간다.
|
|
834
849
|
* 기본표는 `DEFAULT_KIND_ROLES`(telegram-report.ts) · 여기 값이 덮어쓴다. */
|
|
835
850
|
kindRoles?: Record<string, string>;
|
|
851
|
+
/** `#현장` 캡션에 행사 슬러그가 없을 때 쓸 기본 행사(예: `marketers-night-2026-10`). 없으면 `field-<로컬 날짜>`. */
|
|
852
|
+
fieldDefaultEvent?: string;
|
|
836
853
|
}
|
|
837
854
|
|
|
838
855
|
const TELEGRAM_DEFAULTS: TelegramConfig = { enabled: false, allowedUsers: [] };
|
|
@@ -884,6 +901,9 @@ export interface DiscordConfig {
|
|
|
884
901
|
allowedUsers: string[];
|
|
885
902
|
/** Channel snowflake for cron / push output (optional). */
|
|
886
903
|
homeChannel?: string;
|
|
904
|
+
/** EV12c — guild text channels where the production bot chats like a DM (allowlist still applies).
|
|
905
|
+
* Empty / absent = DM-only, as before. */
|
|
906
|
+
chatChannels?: string[];
|
|
887
907
|
/** Standalone `elanous discord-test` scope — same token, dedicated
|
|
888
908
|
* channel, isolated state. See DiscordTestChannel. */
|
|
889
909
|
testChannel?: DiscordTestChannel;
|
|
@@ -894,6 +914,7 @@ const DISCORD_DEFAULTS: DiscordConfig = { enabled: false, allowedUsers: [] };
|
|
|
894
914
|
// ── Onboarding ───────────────────────────────────────────────────────
|
|
895
915
|
|
|
896
916
|
export interface OnboardingConfig {
|
|
917
|
+
webFirst?: boolean;
|
|
897
918
|
completed: boolean;
|
|
898
919
|
completedAt?: string;
|
|
899
920
|
version: number;
|
|
@@ -1364,6 +1385,8 @@ export interface ChatCompactConfig {
|
|
|
1364
1385
|
}
|
|
1365
1386
|
|
|
1366
1387
|
export interface ChatConfig {
|
|
1388
|
+
/** Short questions may receive a tool-free first reply. Default true. */
|
|
1389
|
+
fastPath: boolean;
|
|
1367
1390
|
conciseness: ChatConcisenessConfig;
|
|
1368
1391
|
toolOutput: ChatToolOutputConfig;
|
|
1369
1392
|
autoCompact: ChatAutoCompactConfig;
|
|
@@ -1390,6 +1413,7 @@ const CHAT_CONCISENESS_DEFAULTS: ChatConcisenessConfig = {
|
|
|
1390
1413
|
};
|
|
1391
1414
|
|
|
1392
1415
|
export const CHAT_DEFAULTS: ChatConfig = {
|
|
1416
|
+
fastPath: true,
|
|
1393
1417
|
conciseness: { ...CHAT_CONCISENESS_DEFAULTS },
|
|
1394
1418
|
toolOutput: {
|
|
1395
1419
|
persistOnOverflow: true,
|
|
@@ -3322,9 +3346,16 @@ export function resolveRoleModel(role: ModelRole, config: UserConfig = getUserCo
|
|
|
3322
3346
|
}
|
|
3323
3347
|
|
|
3324
3348
|
|
|
3349
|
+
export type SeatLoopMode = 'off' | 'shadow' | 'on';
|
|
3350
|
+
|
|
3351
|
+
export interface SeatLoopConfig {
|
|
3352
|
+
/** No seat actions by default; shadow observes without execution, on permits the seat loop to act. */
|
|
3353
|
+
mode: SeatLoopMode;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3325
3356
|
export interface UserConfig {
|
|
3326
|
-
/** Steward
|
|
3327
|
-
loops?: { steward?: { mode?: 'observe' | 'act'; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string
|
|
3357
|
+
/** Steward and seat loops are parsed independently. An absent seat remains off. */
|
|
3358
|
+
loops?: { steward?: { mode?: 'observe' | 'act'; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string>; alertAfterFailures?: number }; seat?: SeatLoopConfig };
|
|
3328
3359
|
/** 🔐 Pod 의 Grok API 키 과금은 명시 opt-in 만. 생략·잘못된 값은 false.
|
|
3329
3360
|
* budgetGate 와 같은 `harness` 객체다 — 중복 선언이면 뒤 타입이 앞을 지운다. */
|
|
3330
3361
|
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string };
|
|
@@ -3428,7 +3459,7 @@ export interface UserConfig {
|
|
|
3428
3459
|
/** 승인 뒤 조율 채널 페이즈 배달(기본 OFF) 및 트랙 에이전트(기본 OFF, 최대 동시 2개). */
|
|
3429
3460
|
autopilot?: {
|
|
3430
3461
|
trackCourier?: { enabled?: boolean; channelPr?: number; handoffMinutes?: number };
|
|
3431
|
-
trackAgent?: { enabled: boolean; maxConcurrent: number };
|
|
3462
|
+
trackAgent?: { enabled: boolean; maxConcurrent: number; shadow: boolean; shadowMaxDecisionsPerDay: number };
|
|
3432
3463
|
};
|
|
3433
3464
|
/** 하니스 예산 게이트 설정. 판정은 P15 — 여기선 칸만 싣는다. 파서는 항상 기본을 채운다.
|
|
3434
3465
|
* 선택이다 — 기존 UserConfig 리터럴이 이 칸 없이 컴파일되게 한다. 해석기는 없으면 기본을 쓴다.
|
|
@@ -3616,6 +3647,10 @@ function parseAutopilotConfig(raw: unknown): UserConfig['autopilot'] | undefined
|
|
|
3616
3647
|
enabled: v.enabled === true,
|
|
3617
3648
|
maxConcurrent: typeof v.maxConcurrent === 'number' && Number.isSafeInteger(v.maxConcurrent) && v.maxConcurrent > 0
|
|
3618
3649
|
? Math.min(v.maxConcurrent, 2) : 2,
|
|
3650
|
+
shadow: v.shadow === true,
|
|
3651
|
+
shadowMaxDecisionsPerDay: typeof v.shadowMaxDecisionsPerDay === 'number'
|
|
3652
|
+
&& Number.isSafeInteger(v.shadowMaxDecisionsPerDay) && v.shadowMaxDecisionsPerDay >= 0
|
|
3653
|
+
? v.shadowMaxDecisionsPerDay : 20,
|
|
3619
3654
|
};
|
|
3620
3655
|
}
|
|
3621
3656
|
return Object.keys(parsed).length > 0 ? parsed : undefined;
|
|
@@ -3647,6 +3682,7 @@ function parseRoleLlmConfig(raw: unknown): RoleLlmConfig | undefined {
|
|
|
3647
3682
|
|
|
3648
3683
|
function defaultConfig(): UserConfig {
|
|
3649
3684
|
return {
|
|
3685
|
+
loops: { seat: { mode: 'off' } },
|
|
3650
3686
|
skillRouter: { ...SR_DEFAULTS },
|
|
3651
3687
|
llm: { ...LLM_DEFAULTS },
|
|
3652
3688
|
skills: skillsDefaults(),
|
|
@@ -3659,6 +3695,7 @@ function defaultConfig(): UserConfig {
|
|
|
3659
3695
|
logs: { retention: { ...LOGS_DEFAULTS.retention } },
|
|
3660
3696
|
shell: { ...SHELL_DEFAULTS },
|
|
3661
3697
|
chat: {
|
|
3698
|
+
fastPath: CHAT_DEFAULTS.fastPath,
|
|
3662
3699
|
conciseness: { ...CHAT_CONCISENESS_DEFAULTS },
|
|
3663
3700
|
toolOutput: { ...CHAT_DEFAULTS.toolOutput },
|
|
3664
3701
|
autoCompact: { ...CHAT_DEFAULTS.autoCompact },
|
|
@@ -4124,6 +4161,14 @@ function parseStewardTracks(input: unknown): Record<string, string> | undefined
|
|
|
4124
4161
|
return Object.keys(out).length ? out : undefined;
|
|
4125
4162
|
}
|
|
4126
4163
|
|
|
4164
|
+
function parseSeatLoopsConfig(input: unknown): SeatLoopConfig {
|
|
4165
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) return { mode: 'off' };
|
|
4166
|
+
const seat = (input as Record<string, unknown>).seat;
|
|
4167
|
+
if (!seat || typeof seat !== 'object' || Array.isArray(seat)) return { mode: 'off' };
|
|
4168
|
+
const mode = (seat as Record<string, unknown>).mode;
|
|
4169
|
+
return { mode: mode === 'on' || mode === 'shadow' ? mode : 'off' };
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4127
4172
|
function parseStewardLoopsConfig(input: unknown): UserConfig['loops'] {
|
|
4128
4173
|
if (!input || typeof input !== 'object' || Array.isArray(input)) return undefined;
|
|
4129
4174
|
const value = (input as Record<string, unknown>).steward;
|
|
@@ -4142,6 +4187,7 @@ function parseStewardLoopsConfig(input: unknown): UserConfig['loops'] {
|
|
|
4142
4187
|
...(typeof s.linearTeam === 'string' && s.linearTeam.trim() ? { linearTeam: s.linearTeam.trim() } : {}),
|
|
4143
4188
|
...(Object.keys(roles).length ? { roles } : {}),
|
|
4144
4189
|
...(typeof s.budget === 'number' && Number.isFinite(s.budget) && s.budget >= 0 ? { budget: s.budget } : {}),
|
|
4190
|
+
...(typeof s.alertAfterFailures === 'number' && Number.isSafeInteger(s.alertAfterFailures) && s.alertAfterFailures > 0 ? { alertAfterFailures: s.alertAfterFailures } : {}),
|
|
4145
4191
|
...(parseStewardTracks(s.tracks) ? { tracks: parseStewardTracks(s.tracks)! } : {}),
|
|
4146
4192
|
} };
|
|
4147
4193
|
}
|
|
@@ -4372,6 +4418,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4372
4418
|
skills: {
|
|
4373
4419
|
activeSet: normalizeSkillSet(sk.activeSet),
|
|
4374
4420
|
dirs: strArray(sk.dirs, skillsDefaults().dirs),
|
|
4421
|
+
includeSharedAgentSkills: sk.includeSharedAgentSkills !== false,
|
|
4375
4422
|
allow: strArray(sk.allow, []),
|
|
4376
4423
|
deny: strArray(sk.deny, []),
|
|
4377
4424
|
urlRouting: parseUrlRouting(sk.urlRouting),
|
|
@@ -4393,6 +4440,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4393
4440
|
testChannel: normalizeTestChannel(tg.testChannel),
|
|
4394
4441
|
...(tg.poller === 'standalone' || tg.poller === 'nexus' ? { poller: tg.poller } : {}),
|
|
4395
4442
|
...(normalizeKindRoles(tg.kindRoles) ? { kindRoles: normalizeKindRoles(tg.kindRoles)! } : {}),
|
|
4443
|
+
...(str(tg.fieldDefaultEvent) ? { fieldDefaultEvent: str(tg.fieldDefaultEvent)! } : {}),
|
|
4396
4444
|
},
|
|
4397
4445
|
discord: {
|
|
4398
4446
|
enabled: dc.enabled === true,
|
|
@@ -4406,6 +4454,9 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4406
4454
|
homeChannel: typeof dc.homeChannel === 'string' ? dc.homeChannel
|
|
4407
4455
|
: typeof dc.homeChannel === 'number' ? String(dc.homeChannel) : undefined,
|
|
4408
4456
|
testChannel: normalizeDiscordTestChannel((dc as Record<string, unknown>).testChannel),
|
|
4457
|
+
...(Array.isArray(dc.chatChannels)
|
|
4458
|
+
? { chatChannels: (dc.chatChannels as unknown[]).map(v => String(v).trim()).filter(Boolean) }
|
|
4459
|
+
: {}),
|
|
4409
4460
|
// Sprint 21 wiring sub-block (2026-05-01)
|
|
4410
4461
|
},
|
|
4411
4462
|
finance: {
|
|
@@ -4449,6 +4500,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4449
4500
|
relaxedGates: fin.relaxedGates === true,
|
|
4450
4501
|
},
|
|
4451
4502
|
onboarding: {
|
|
4503
|
+
...(typeof ob2.webFirst === 'boolean' ? { webFirst: ob2.webFirst } : {}),
|
|
4452
4504
|
completed: ob2.completed === true,
|
|
4453
4505
|
completedAt: str(ob2.completedAt),
|
|
4454
4506
|
version: typeof ob2.version === 'number' ? ob2.version : 0,
|
|
@@ -4495,6 +4547,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4495
4547
|
allowDashboardOptionalTools: sh.allowDashboardOptionalTools !== false,
|
|
4496
4548
|
},
|
|
4497
4549
|
chat: {
|
|
4550
|
+
fastPath: chat.fastPath === false || chat.fastPath === 'false' ? false : CHAT_DEFAULTS.fastPath,
|
|
4498
4551
|
conciseness: {
|
|
4499
4552
|
enabled: chatConciseness.enabled === false ? false : CHAT_CONCISENESS_DEFAULTS.enabled,
|
|
4500
4553
|
finalMessageMaxLines: clampNum(
|
|
@@ -4873,7 +4926,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4873
4926
|
goals: parseGoalsConfig(rawObj.goals),
|
|
4874
4927
|
registry: parseRegistryConfig(rawObj.registry),
|
|
4875
4928
|
tools: parseToolsConfig(rawObj.tools),
|
|
4876
|
-
...(stewardLoops
|
|
4929
|
+
loops: { ...(stewardLoops ?? {}), seat: parseSeatLoopsConfig(rawObj.loops) },
|
|
4877
4930
|
// M1-1: sparse — undefined when the user hasn't set anything, so
|
|
4878
4931
|
// resolvers fall through to zero-config defaults.
|
|
4879
4932
|
...spreadIfDefined('modelTier', parseModelTierConfig(rawObj.modelTier)),
|
|
@@ -5447,6 +5500,11 @@ export function saveUserConfig(
|
|
|
5447
5500
|
const rawHarness = rawRest.harness && typeof rawRest.harness === 'object' && !Array.isArray(rawRest.harness)
|
|
5448
5501
|
? rawRest.harness as Record<string, unknown> : {};
|
|
5449
5502
|
delete rawRest.harness;
|
|
5503
|
+
const rawAutopilot = rawRest.autopilot && typeof rawRest.autopilot === 'object' && !Array.isArray(rawRest.autopilot)
|
|
5504
|
+
? rawRest.autopilot as Record<string, unknown> : {};
|
|
5505
|
+
const rawLoops = rawRest.loops && typeof rawRest.loops === 'object' && !Array.isArray(rawRest.loops)
|
|
5506
|
+
? rawRest.loops as Record<string, unknown> : {};
|
|
5507
|
+
if (cfg.loops) delete rawRest.loops;
|
|
5450
5508
|
if (cfg.pod?.hostMirror) {
|
|
5451
5509
|
const rawPod = rawRest.pod && typeof rawRest.pod === 'object' && !Array.isArray(rawRest.pod)
|
|
5452
5510
|
? rawRest.pod as Record<string, unknown> : {};
|
|
@@ -5463,6 +5521,24 @@ export function saveUserConfig(
|
|
|
5463
5521
|
podPool: cfg.harness?.podPool,
|
|
5464
5522
|
}),
|
|
5465
5523
|
...rawRest,
|
|
5524
|
+
...(cfg.loops ? { loops: {
|
|
5525
|
+
...rawLoops,
|
|
5526
|
+
...(cfg.loops.seat ? { seat: { mode: cfg.loops.seat.mode } } : {}),
|
|
5527
|
+
} } : {}),
|
|
5528
|
+
...(cfg.autopilot ? { autopilot: {
|
|
5529
|
+
...rawAutopilot,
|
|
5530
|
+
...cfg.autopilot,
|
|
5531
|
+
...(cfg.autopilot.trackAgent ? { trackAgent: {
|
|
5532
|
+
...(rawAutopilot.trackAgent && typeof rawAutopilot.trackAgent === 'object' && !Array.isArray(rawAutopilot.trackAgent)
|
|
5533
|
+
? rawAutopilot.trackAgent as Record<string, unknown> : {}),
|
|
5534
|
+
...cfg.autopilot.trackAgent,
|
|
5535
|
+
} } : {}),
|
|
5536
|
+
...(cfg.autopilot.trackCourier ? { trackCourier: {
|
|
5537
|
+
...(rawAutopilot.trackCourier && typeof rawAutopilot.trackCourier === 'object' && !Array.isArray(rawAutopilot.trackCourier)
|
|
5538
|
+
? rawAutopilot.trackCourier as Record<string, unknown> : {}),
|
|
5539
|
+
...cfg.autopilot.trackCourier,
|
|
5540
|
+
} } : {}),
|
|
5541
|
+
} } : {}),
|
|
5466
5542
|
skillRouter: cfg.skillRouter,
|
|
5467
5543
|
llm: stripUndef({
|
|
5468
5544
|
provider: cfg.llm.provider,
|
|
@@ -5565,12 +5641,14 @@ export function saveUserConfig(
|
|
|
5565
5641
|
// ★ 2026-09-25: `poller`(T1 분리 스위치)가 파서엔 있고 이 whitelist 에 없어 `config set telegram.poller` 가
|
|
5566
5642
|
// 「직렬화 드롭」으로 조용히 사라졌다 — 운영 전환 스위치를 켤 방법이 없었다(07-22 botUsername 과 같은 모양).
|
|
5567
5643
|
poller: cfg.telegram.poller,
|
|
5644
|
+
fieldDefaultEvent: cfg.telegram.fieldDefaultEvent,
|
|
5568
5645
|
}),
|
|
5569
5646
|
discord: stripUndef({
|
|
5570
5647
|
enabled: cfg.discord.enabled,
|
|
5571
5648
|
botToken: cfg.discord.botToken,
|
|
5572
5649
|
allowedUsers: [...cfg.discord.allowedUsers],
|
|
5573
5650
|
homeChannel: cfg.discord.homeChannel,
|
|
5651
|
+
chatChannels: cfg.discord.chatChannels ? [...cfg.discord.chatChannels] : undefined,
|
|
5574
5652
|
testChannel: cfg.discord.testChannel
|
|
5575
5653
|
? stripUndef({
|
|
5576
5654
|
channelId: cfg.discord.testChannel.channelId,
|
|
@@ -5597,6 +5675,7 @@ export function saveUserConfig(
|
|
|
5597
5675
|
relaxedGates: cfg.finance.relaxedGates,
|
|
5598
5676
|
}),
|
|
5599
5677
|
onboarding: stripUndef({
|
|
5678
|
+
webFirst: cfg.onboarding.webFirst,
|
|
5600
5679
|
completed: cfg.onboarding.completed,
|
|
5601
5680
|
completedAt: cfg.onboarding.completedAt,
|
|
5602
5681
|
version: cfg.onboarding.version,
|
|
@@ -5605,6 +5684,7 @@ export function saveUserConfig(
|
|
|
5605
5684
|
logs: cfg.logs,
|
|
5606
5685
|
shell: cfg.shell,
|
|
5607
5686
|
chat: stripUndef({
|
|
5687
|
+
fastPath: cfg.chat.fastPath,
|
|
5608
5688
|
conciseness: stripUndef({
|
|
5609
5689
|
enabled: cfg.chat.conciseness.enabled,
|
|
5610
5690
|
finalMessageMaxLines: cfg.chat.conciseness.finalMessageMaxLines,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commit":"
|
|
1
|
+
{"commit":"eadd7c31e07d4414ce452d943984a2e58a01ede4"}
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
* (📏 2026-09-23: 연출 있는 shot2 = 0.708 < 연출 없는 대조군 0.851).
|
|
15
15
|
*/
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
17
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
18
19
|
import { join } from 'node:path';
|
|
20
|
+
import { searchVflowReferences } from '../vflow-reference.js';
|
|
19
21
|
import { run } from './ffmpeg.js';
|
|
20
22
|
import { resolvePython } from '../../python/resolve-python.js';
|
|
21
23
|
import { UNOBSERVED, type Recipe } from './types.js';
|
|
@@ -111,14 +113,49 @@ export const identityHoldsGate: Recipe = async (ctx) => {
|
|
|
111
113
|
export const directedShots: Recipe = async (ctx) => {
|
|
112
114
|
const src = ctx.state.shot_sources as Record<string, string> | undefined;
|
|
113
115
|
if (!src) return need('shot_sources');
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
+
const prompts = ctx.state.shot_prompts as Record<string, string> | undefined;
|
|
117
|
+
const existingShots = Object.entries(src).filter(([, path]) => existsSync(path));
|
|
118
|
+
const shot_paths = existingShots.map(([, path]) => path);
|
|
119
|
+
const promptedShots = existingShots.filter(([shot]) => prompts?.[shot] !== undefined);
|
|
120
|
+
const shot_references: Record<string, { url: string; videoUrl: string | null; model: string; name: string; author: string | null; authorUrl: string | null; camera: string[] }[]> = {};
|
|
121
|
+
let referenceNote = '';
|
|
122
|
+
if (prompts && Object.keys(prompts).length && shot_paths.length) {
|
|
123
|
+
const file = (ctx.state.vflow_file as string | undefined) ?? join(homedir(), 'docs', 'ref', 'vflow', 'prompts.ndjson');
|
|
124
|
+
const taxonomy = readFileSync(join(import.meta.dir, '../../../graphs/video/reference/vflow-taxonomy.yaml'), 'utf8');
|
|
125
|
+
const cameraAxis = taxonomy.match(/^ camera_movement:.*\n((?:^ .*\n)*)/m)?.[1] ?? '';
|
|
126
|
+
const cameraTerms = [...cameraAxis.matchAll(/term:\s*([^,}]+)/g)].map((match) => match[1]!.trim());
|
|
127
|
+
// These shot-prompt camera terms supplement the site's taxonomy axis.
|
|
128
|
+
cameraTerms.push('crash zoom', 'dolly', 'static');
|
|
129
|
+
const cameraPatterns = cameraTerms.map((term) => {
|
|
130
|
+
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
131
|
+
return { term, pattern: new RegExp(`(?<![\\p{L}\\p{N}])${escaped}(?![\\p{L}\\p{N}])`, 'iu') };
|
|
132
|
+
});
|
|
133
|
+
let found = 0;
|
|
134
|
+
for (const [shot] of promptedShots) {
|
|
135
|
+
const prompt = prompts[shot]!;
|
|
136
|
+
const camera = cameraPatterns.filter(({ pattern }) => pattern.test(prompt)).map(({ term }) => term);
|
|
137
|
+
const result = searchVflowReferences(file, { camera, model: ctx.state.shot_model as string | undefined, limit: camera.length ? 3 : 0 });
|
|
138
|
+
if (!result.available) {
|
|
139
|
+
referenceNote = `vflow DB 없음(${result.reason})`;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
shot_references[shot] = result.rows.map((row) => ({
|
|
143
|
+
url: row.url, videoUrl: row.video?.url ?? null, model: row.model, name: row.name,
|
|
144
|
+
author: row.author, authorUrl: row.authorUrl, camera: row.spec?.camera ?? [],
|
|
145
|
+
}));
|
|
146
|
+
if (shot_references[shot]!.length) found++;
|
|
147
|
+
}
|
|
148
|
+
if (!referenceNote) referenceNote = `vflow 참고 ${found}샷/${shot_paths.length}샷`;
|
|
149
|
+
}
|
|
150
|
+
const note = (text: string) => referenceNote ? `${text}\n${referenceNote}` : text;
|
|
151
|
+
if (shot_paths.length === 0) return { outcome: 'error', produced: prompts ? { shot_references } : undefined, note: note('샷 0 — ⛔ 이 러너는 크레딧을 안 쓴다(Seedance·Kling 생성은 스킬 세션의 몫)') };
|
|
152
|
+
const produced = { shot_paths, shot_count: shot_paths.length, ...(prompts ? { shot_references } : {}) };
|
|
116
153
|
// ⛔⭐ 되돌이 수렴(🩸 2026-09-23 실물: fullbleed → shots → «같은» 샷 → fullbleed … 예산 소진).
|
|
117
154
|
// 리프레임 자가 「그 비율로 다시 렌더하라」고 돌려보냈는데 이 러너는 다시 그릴 수 없다(크레딧 무사용)
|
|
118
155
|
// ⇒ 같은 샷을 또 내면 같은 판정이 난다. 「못 다시 그린다」를 error 로 말해 `rendered-unedited` 로 끝낸다.
|
|
119
156
|
const pending = (ctx.state.fullbleed_cuts as string[] | undefined) ?? [];
|
|
120
|
-
if (pending.length) return { outcome: 'error', produced
|
|
121
|
-
return { outcome: 'ok', produced
|
|
157
|
+
if (pending.length) return { outcome: 'error', produced, note: note(`전용 비율 재렌더가 필요한 샷 ${pending.join(', ')} — ⛔ 이 러너는 다시 그리지 않는다(크레딧 무사용) · 그 비율 렌더를 스킬 세션에서 만든 뒤 native 로 넘겨라`) };
|
|
158
|
+
return { outcome: 'ok', produced, note: note(`샷 ${shot_paths.length}개 · ⚠️ 이미 생성된 것을 받았다`) };
|
|
122
159
|
};
|
|
123
160
|
|
|
124
161
|
/** `08_shot_ruler.py` 의 `shot_variation` 한 칸만 읽는다(그 자가 «살아남은 유일한 칸»이라 스스로 적었다). */
|