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.
Files changed (479) hide show
  1. package/.env.example +10 -7
  2. package/README.md +9 -4
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{5391-8793f88b03b30161.js → 2375-cb6debea56cce4fb.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/{1751.50b96ea9c37b49b6.js → 2415.ed6428ff334c7ce2.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +25 -0
  16. package/apps/pwa/out/_next/static/chunks/{4daa2798-1363d725c79f3593.js → 2ea96958-e8c7e112de50b067.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
  18. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{8617.465ca22a319c95b3.js → 4323.c5dfb6f503304775.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/4836-2eba6079f31b88d4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{8918-482b30ce2a8ebf4c.js → 5080-1613752891fcadb4.js} +3 -3
  24. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{5348-bbf838e119661eee.js → 5791-bb82743fa6299562.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/{9704-3221c102623c8d73.js → 6062-73e68343a9814f6a.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/{4440-18bb160d95819f4e.js → 6090-85a3f05f954e5697.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{f6f3850d-7f324c6566002113.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/8067-f74bf14d67ad98f1.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8519-f6b5d8a5833a7603.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8894-e92491a164192cc1.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/9454-a3e0953307216c58.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9740-67051141115ce775.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5ebde04844689e6.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-f89e9a303515a033.js → page-10ed24f413ed66e9.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/app/board/{page-4f403cd060442c95.js → page-211810b6c93ab66a.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-0ac5d053f0444d21.js → page-624f7a2f89b60c8f.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/app/bots/page-5a5fb385a4df0ffe.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/chat/page-80497e93a878ddc5.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/consult/page-7457f52683562161.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/control/page-cee86394de407aa6.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/design-check/page-4ff8edab44196b8c.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/editor/page-92e4f44428d5e290.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/exec/page-b7dcf5d48a854b76.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/field/page-51480757e7d68b92.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/intake/page-2a05dfe80c8bdf16.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/layout-d9979633aa82f8e6.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/live/page-30533117beb53625.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/market/page-f7857826c2f97ad7.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-07267f1391b96aba.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/morning/{page-bccce0babceae30f.js → page-55d50e9b0006a91d.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/app/not-found-9699b1786be6171d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/observatory/page-43dd772aee8af75f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/page-a7e37af7d0399cb8.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/reflection/page-973ab7af59c718b7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a9f8d3865b91e436.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/sessions/page-15e5a15db84c56aa.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a2e572e4511f2a16.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/settings/page-dd107bf1c7d52a90.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d42b99cdfb9f27c6.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/setup/page-2764ff40dad5a995.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/share/page-c5f1152db116ff96.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/showroom/page-f933bca81ea38a6f.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/tasks/page-c1c95739c0bff3b8.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/term/page-a7aaffcf771662d8.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/trace/page-71d18eec33b9c667.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/vault/page-56adbe1a1f1379bd.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-2c4e59079ee357ac.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a81f113f3ef89d72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d422f38c052967e.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fc27b00e20733146.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{webpack-2bf59c720fe9542c.js → webpack-e5bea36f183b25e6.js} +1 -1
  95. package/apps/pwa/out/_next/static/css/f537bdb19c69306a.css +1 -0
  96. package/apps/pwa/out/_next/static/keajW7DDyghEs1y8oJe6T/_buildManifest.js +1 -0
  97. package/apps/pwa/out/approvals/index.html +1 -1
  98. package/apps/pwa/out/approvals/index.txt +22 -22
  99. package/apps/pwa/out/autopilot/index.html +1 -1
  100. package/apps/pwa/out/autopilot/index.txt +22 -22
  101. package/apps/pwa/out/board/index.html +1 -1
  102. package/apps/pwa/out/board/index.txt +22 -22
  103. package/apps/pwa/out/botlab/index.html +1 -1
  104. package/apps/pwa/out/botlab/index.txt +21 -21
  105. package/apps/pwa/out/bots/index.html +1 -1
  106. package/apps/pwa/out/bots/index.txt +21 -21
  107. package/apps/pwa/out/chat/index.html +1 -1
  108. package/apps/pwa/out/chat/index.txt +21 -21
  109. package/apps/pwa/out/consult/index.html +1 -0
  110. package/apps/pwa/out/consult/index.txt +32 -0
  111. package/apps/pwa/out/control/index.html +1 -1
  112. package/apps/pwa/out/control/index.txt +22 -22
  113. package/apps/pwa/out/design-check/index.html +1 -1
  114. package/apps/pwa/out/design-check/index.txt +22 -22
  115. package/apps/pwa/out/editor/index.html +1 -1
  116. package/apps/pwa/out/editor/index.txt +22 -22
  117. package/apps/pwa/out/exec/index.html +1 -0
  118. package/apps/pwa/out/exec/index.txt +32 -0
  119. package/apps/pwa/out/field/index.html +1 -0
  120. package/apps/pwa/out/field/index.txt +32 -0
  121. package/apps/pwa/out/healthz +1 -1
  122. package/apps/pwa/out/icons/elanous-16.png +0 -0
  123. package/apps/pwa/out/icons/elanous-180.png +0 -0
  124. package/apps/pwa/out/icons/elanous-192.png +0 -0
  125. package/apps/pwa/out/icons/elanous-32.png +0 -0
  126. package/apps/pwa/out/icons/elanous-512.png +0 -0
  127. package/apps/pwa/out/index.html +1 -1
  128. package/apps/pwa/out/index.txt +21 -21
  129. package/apps/pwa/out/intake/index.html +1 -1
  130. package/apps/pwa/out/intake/index.txt +22 -22
  131. package/apps/pwa/out/live/index.html +1 -1
  132. package/apps/pwa/out/live/index.txt +22 -22
  133. package/apps/pwa/out/market/index.html +1 -1
  134. package/apps/pwa/out/market/index.txt +21 -21
  135. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  136. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  137. package/apps/pwa/out/morning/index.html +1 -1
  138. package/apps/pwa/out/morning/index.txt +22 -22
  139. package/apps/pwa/out/observatory/index.html +1 -1
  140. package/apps/pwa/out/observatory/index.txt +22 -22
  141. package/apps/pwa/out/reflection/index.html +1 -1
  142. package/apps/pwa/out/reflection/index.txt +22 -22
  143. package/apps/pwa/out/scheduler/index.html +1 -1
  144. package/apps/pwa/out/scheduler/index.txt +22 -22
  145. package/apps/pwa/out/sessions/index.html +1 -1
  146. package/apps/pwa/out/sessions/index.txt +21 -21
  147. package/apps/pwa/out/settings/devices/index.html +1 -1
  148. package/apps/pwa/out/settings/devices/index.txt +22 -22
  149. package/apps/pwa/out/settings/index.html +1 -1
  150. package/apps/pwa/out/settings/index.txt +22 -22
  151. package/apps/pwa/out/setup/done/index.html +1 -1
  152. package/apps/pwa/out/setup/done/index.txt +22 -22
  153. package/apps/pwa/out/setup/index.html +1 -1
  154. package/apps/pwa/out/setup/index.txt +22 -22
  155. package/apps/pwa/out/share/index.html +1 -1
  156. package/apps/pwa/out/share/index.txt +22 -22
  157. package/apps/pwa/out/showroom/index.html +1 -1
  158. package/apps/pwa/out/showroom/index.txt +21 -21
  159. package/apps/pwa/out/tasks/index.html +1 -1
  160. package/apps/pwa/out/tasks/index.txt +22 -22
  161. package/apps/pwa/out/term/index.html +1 -1
  162. package/apps/pwa/out/term/index.txt +22 -22
  163. package/apps/pwa/out/trace/index.html +1 -1
  164. package/apps/pwa/out/trace/index.txt +22 -22
  165. package/apps/pwa/out/vault/index.html +1 -1
  166. package/apps/pwa/out/vault/index.txt +22 -22
  167. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  168. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  169. package/apps/pwa/out/workflows/index.html +1 -1
  170. package/apps/pwa/out/workflows/index.txt +22 -22
  171. package/apps/pwa/out/workspace/index.html +1 -1
  172. package/apps/pwa/out/workspace/index.txt +22 -22
  173. package/apps/pwa/out/worktrees/index.html +1 -1
  174. package/apps/pwa/out/worktrees/index.txt +22 -22
  175. package/bin/elanous.cjs +107 -0
  176. package/graphs/field/field-feed.yaml +24 -0
  177. package/graphs/field/recipes.yaml +12 -0
  178. package/graphs/landing/landing-heal.yaml +3 -1
  179. package/graphs/landing/recipes.yaml +3 -0
  180. package/graphs/release/recipes.yaml +13 -0
  181. package/graphs/release/release-loop.yaml +13 -4
  182. package/package.json +5 -5
  183. package/plugins/card-followup/README.md +42 -0
  184. package/plugins/card-followup/examples/card-sample.json +7 -0
  185. package/plugins/card-followup/graphs/card-followup.yaml +18 -0
  186. package/plugins/card-followup/graphs/recipes.yaml +16 -0
  187. package/plugins/card-followup/graphs/run-step.ts +276 -0
  188. package/plugins/card-followup/graphs/sales-strategy.ts +173 -0
  189. package/plugins/card-followup/plugin.json +25 -0
  190. package/plugins/doc-draft/README.md +13 -0
  191. package/plugins/doc-draft/examples/brief-sample.json +8 -0
  192. package/plugins/doc-draft/graphs/doc-draft.yaml +14 -0
  193. package/plugins/doc-draft/graphs/recipes.yaml +9 -0
  194. package/plugins/doc-draft/graphs/run-step.ts +113 -0
  195. package/plugins/doc-draft/plugin.json +24 -0
  196. package/plugins/geo-check/README.md +15 -0
  197. package/plugins/geo-check/examples/brand-sample.json +8 -0
  198. package/plugins/geo-check/graphs/geo-check.yaml +20 -0
  199. package/plugins/geo-check/graphs/recipes.yaml +18 -0
  200. package/plugins/geo-check/graphs/run-step.ts +198 -0
  201. package/plugins/geo-check/plugin.json +24 -0
  202. package/plugins/job-coach/.codex-plugin/plugin.json +1 -1
  203. package/plugins/job-coach/README.md +31 -1
  204. package/plugins/job-coach/graphs/run-step.ts +2 -2
  205. package/plugins/job-coach/plugin.json +1 -1
  206. package/plugins/job-coach/plugin.ts +1 -1
  207. package/scripts/affinity/endcard.sh +3 -2
  208. package/scripts/affinity/reframe.sh +3 -1
  209. package/scripts/ci-public-export-leak-gate.ts +48 -0
  210. package/scripts/codex-quota-alert.ts +122 -258
  211. package/scripts/coord-tracks.json +4 -4
  212. package/scripts/daemon-port-baseline.txt +1 -2
  213. package/scripts/field-feed/deliver-node.ts +52 -0
  214. package/scripts/field-feed/feed-node.ts +67 -0
  215. package/scripts/field-feed/lib.ts +162 -0
  216. package/scripts/field-feed/reel-node.ts +24 -0
  217. package/scripts/field-feed/start.ts +62 -0
  218. package/scripts/fixtures/vflow-sample.ndjson +6 -0
  219. package/scripts/install.sh +92 -13
  220. package/scripts/landing-heal/clean-checkout.ts +114 -0
  221. package/scripts/landing-heal/run-mission.ts +38 -3
  222. package/scripts/lib/android-test-device.ts +32 -0
  223. package/scripts/lib/pwa-scenarios/scenarios.ts +2 -1
  224. package/scripts/public-export.ts +8 -4
  225. package/scripts/release-loop/baseline-from-logs.ts +92 -0
  226. package/scripts/release-loop/checklist-gate-node.ts +35 -0
  227. package/scripts/release-loop/env-known-failures.ts +31 -0
  228. package/scripts/release-loop/gate-diff.ts +29 -0
  229. package/scripts/release-loop/gate-node.ts +124 -29
  230. package/scripts/release-loop/known-issues-node.ts +159 -0
  231. package/scripts/release-loop/npm-publish-node.ts +118 -0
  232. package/scripts/release-loop/ops-upgrade-node.ts +87 -0
  233. package/scripts/release-loop/release-readiness.ts +58 -0
  234. package/scripts/release-loop/shard-plan.ts +47 -0
  235. package/scripts/release-loop/unattended-release.ts +93 -0
  236. package/scripts/ux/measure-first-text.ts +102 -0
  237. package/scripts/ux/record-page.ts +4 -1
  238. package/scripts/vflow-collect.ts +20 -7
  239. package/scripts/vflow-search.ts +73 -0
  240. package/scripts/video-free-line-test-walker.ts +36 -0
  241. package/scripts/video-pipeline.ts +2 -2
  242. package/skills/explainer-video/SKILL.md +24 -3
  243. package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -1
  244. package/skills/explainer-video/engine/build.mjs +2 -2
  245. package/skills/explainer-video/engine/reel.mjs +235 -0
  246. package/skills/explainer-video/engine/reel.sh +9 -0
  247. package/skills/explainer-video/engine/vo.ts +58 -16
  248. package/skills/explainer-video/examples/elanous-0.2.5/script.json +1 -1
  249. package/skills/grill-me/SKILL.md +1 -1
  250. package/skills/omni-digest/docs/diagrams/noncode-terminal-promotion-path-2026-08-13.mmd +1 -1
  251. package/src/a2a/server.ts +2 -0
  252. package/src/acp/elanous-aware-peers.ts +30 -0
  253. package/src/acp/server.ts +91 -15
  254. package/src/agent/monad-agent-turn.ts +25 -6
  255. package/src/agent/shared-app-tools.ts +5 -3
  256. package/src/agent-substrate/review-intent.ts +6 -2
  257. package/src/agent-substrate/shard-boundary-intent.ts +70 -0
  258. package/src/auth/github-app-token.ts +4 -1
  259. package/src/autopilot/mission-origin.ts +20 -4
  260. package/src/autopilot/mission-phase-track.ts +11 -1
  261. package/src/autopilot/track-agent-shadow.ts +151 -0
  262. package/src/autopilot/track-agent.ts +26 -6
  263. package/src/autopilot/track-courier.ts +2 -2
  264. package/src/boot/acp-server-help.ts +16 -0
  265. package/src/boot/daemon-prompt-turn.ts +31 -10
  266. package/src/boot/daemon-tools/index.ts +7 -1
  267. package/src/budget/codex-credit-pace.ts +84 -0
  268. package/src/budget/codex-credit-plan.ts +154 -0
  269. package/src/budget/codex-reset-credit-state.ts +2 -0
  270. package/src/chat/chat-cli.ts +4 -1
  271. package/src/chat/short-question.ts +40 -0
  272. package/src/cli/agent-cli.ts +24 -15
  273. package/src/cli/ask-bare.ts +42 -0
  274. package/src/cli/cli-user-error.ts +25 -0
  275. package/src/cli/codex-credit-plan-view.ts +25 -0
  276. package/src/cli/dependence-gauge.ts +237 -0
  277. package/src/cli/doctor-cli.ts +5 -0
  278. package/src/cli/doctor-modes.ts +48 -0
  279. package/src/cli/intake-cli.ts +12 -2
  280. package/src/cli/intake-source-cli.ts +58 -0
  281. package/src/cli/machine-cli.ts +23 -0
  282. package/src/cli/msg-cli.ts +137 -0
  283. package/src/cli/nexus-ios-bind.ts +25 -8
  284. package/src/cli/phone-link.ts +117 -0
  285. package/src/cli/plugin-cli.ts +52 -0
  286. package/src/cli/pr-cli.ts +36 -0
  287. package/src/cli/private-ledger-commands.ts +31 -0
  288. package/src/cli/provider-cli.ts +5 -0
  289. package/src/cli/release-cli.ts +56 -12
  290. package/src/cli/release-run-if-ready.ts +48 -0
  291. package/src/cli/setup-cli.ts +27 -6
  292. package/src/cli/setup-recommend.ts +8 -0
  293. package/src/cli/usage-cli.ts +11 -1
  294. package/src/codex/setup.ts +27 -8
  295. package/src/dashboard/index.ts +1 -1
  296. package/src/discord.ts +56 -6
  297. package/src/domains/core-tools.ts +37 -14
  298. package/src/domains/outbound-alert.ts +55 -16
  299. package/src/exec-requests/planner.ts +140 -0
  300. package/src/exec-requests/runner.ts +338 -0
  301. package/src/exec-requests/store.ts +76 -0
  302. package/src/field/field-media.ts +250 -0
  303. package/src/field/field-reel.ts +196 -0
  304. package/src/grok/credential.ts +7 -5
  305. package/src/harness/aside-run-status.ts +33 -0
  306. package/src/harness/browser-verify.ts +48 -17
  307. package/src/harness/harness-cli-command.ts +25 -3
  308. package/src/harness/image-load-state.ts +21 -0
  309. package/src/harness/process-garbage.ts +45 -0
  310. package/src/index.ts +104 -38
  311. package/src/instance/leader.ts +13 -1
  312. package/src/intake-plane/collect-github.ts +5 -3
  313. package/src/intake-plane/collect-telegram-saved.ts +15 -3
  314. package/src/intake-plane/discord-seat-work.ts +56 -0
  315. package/src/intake-plane/intake-sources.ts +202 -0
  316. package/src/intake-plane/items.ts +28 -12
  317. package/src/intake-plane/seat-doc-route.ts +207 -0
  318. package/src/intake-plane/submit-intake-work.ts +9 -1
  319. package/src/intake-plane/telegram-seat-work.ts +72 -0
  320. package/src/llm/model-defaults.ts +24 -1
  321. package/src/llm.ts +5 -4
  322. package/src/machines/machine-ledger.ts +127 -0
  323. package/src/market/pack-internal-refs.ts +28 -0
  324. package/src/market/publish.ts +31 -4
  325. package/src/maturity/feature-maturity.ts +65 -0
  326. package/src/model-tier/turn-tier.ts +24 -0
  327. package/src/msg/msg-store.ts +149 -0
  328. package/src/native-tool-catalog.ts +2 -1
  329. package/src/nexus/api/chat-fast-path-config.ts +28 -0
  330. package/src/nexus/api/consult-requests.ts +117 -0
  331. package/src/nexus/api/discord-trigger-bot.ts +3 -0
  332. package/src/nexus/api/exec-requests.ts +51 -0
  333. package/src/nexus/api/field-uploads.ts +180 -0
  334. package/src/nexus/api/graph-approvals-feed.ts +140 -0
  335. package/src/nexus/api/graph-approvals.ts +120 -4
  336. package/src/nexus/api/harness-api.ts +219 -5
  337. package/src/nexus/api/http-server.ts +68 -5
  338. package/src/nexus/api/seat-requests.ts +254 -0
  339. package/src/nexus/api/trace-run-scan.ts +37 -0
  340. package/src/nexus/api/trace.ts +19 -3
  341. package/src/nexus/index.ts +3 -0
  342. package/src/nexus/setup-status.ts +4 -5
  343. package/src/notify/llm-budget-alert.ts +125 -0
  344. package/src/oauth/codex-account-rotation.ts +26 -4
  345. package/src/oauth/codex-account-store.ts +20 -2
  346. package/src/oauth/codex-browser-login.ts +173 -0
  347. package/src/oauth/codex.ts +4 -1
  348. package/src/oauth/fallback-chain.ts +5 -5
  349. package/src/oauth/store.ts +42 -5
  350. package/src/onboarding/continue-here.ts +29 -0
  351. package/src/onboarding/entry-hints.ts +8 -0
  352. package/src/onboarding/full-screen-io.ts +35 -3
  353. package/src/onboarding/help/skills.md +1 -1
  354. package/src/onboarding/non-interactive.ts +1 -0
  355. package/src/onboarding/subscription-hint.ts +27 -0
  356. package/src/onboarding/web-first.ts +83 -0
  357. package/src/onboarding.ts +230 -23
  358. package/src/plugins/maker/node-install.ts +92 -0
  359. package/src/plugins/maker/node-maker.ts +139 -0
  360. package/src/plugins/maker/plugin-maker.ts +220 -0
  361. package/src/policy/llm-policy.ts +268 -0
  362. package/src/prompt-library/session-guidance.ts +7 -1
  363. package/src/prompt-library/universal-preamble.ts +2 -2
  364. package/src/relay/channel.ts +184 -0
  365. package/src/relay/mux.ts +182 -0
  366. package/src/relay/relay-cli.ts +20 -0
  367. package/src/relay/relay-server.ts +220 -0
  368. package/src/relay/test-vectors.json +29 -0
  369. package/src/release-loop/checklist.ts +36 -9
  370. package/src/seat-address/seat-address.ts +34 -0
  371. package/src/self-dev/decompose.ts +1 -0
  372. package/src/self-dev/dev-pipeline.ts +6 -3
  373. package/src/self-dev/run-record-mirror.ts +44 -0
  374. package/src/self-dev/run-store.ts +12 -3
  375. package/src/self-implement/harness-policy-gates.ts +4 -1
  376. package/src/self-implement/report-origin.ts +12 -1
  377. package/src/self-implement/run-ledger-compact.ts +1 -1
  378. package/src/session/chat.ts +17 -5
  379. package/src/session/index.ts +23 -10
  380. package/src/skills/shared-agent-skill-roots.ts +25 -0
  381. package/src/steward/failure-streak.ts +78 -0
  382. package/src/steward/steward-cards.ts +24 -0
  383. package/src/steward/triage-budget.ts +127 -0
  384. package/src/steward/triage-plan.ts +75 -0
  385. package/src/steward/triage.ts +244 -42
  386. package/src/task-cards/card-store.ts +1 -1
  387. package/src/task-orchestrator/surfaces/pod-bun-cache.ts +18 -0
  388. package/src/task-orchestrator/surfaces/pod-command-job.ts +12 -3
  389. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  390. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +68 -0
  391. package/src/task-orchestrator/surfaces/self-implement-pod.ts +78 -4
  392. package/src/telegram.ts +145 -2
  393. package/src/tool-runtime/elanous-skills-list-runtime.ts +3 -3
  394. package/src/tool-runtime/self-cognition-runtimes.ts +160 -2
  395. package/src/user-config.ts +84 -4
  396. package/src/version/packed-revision.json +1 -1
  397. package/src/video-pipeline/recipes/character.ts +42 -5
  398. package/src/video-pipeline/recipes/explainer.ts +213 -0
  399. package/src/video-pipeline/recipes/ffmpeg.ts +1 -1
  400. package/src/video-pipeline/recipes/free-line.ts +16 -3
  401. package/src/video-pipeline/recipes/remote.ts +7 -1
  402. package/src/video-pipeline/vflow-reference.ts +109 -0
  403. package/src/video-pipeline/walk-line.ts +3 -2
  404. package/apps/pwa/out/_next/static/chunks/06ef2eba-d1b99ac6d2ea663c.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/1413-7179a49332db5a80.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/150-25c277137a9638ab.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/1640-bc99ec23bbe29d12.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/2300-de059d0ab2a16630.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/2684-05b0a81e75298c16.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/3026-2ed7e317d9b02102.js +0 -25
  411. package/apps/pwa/out/_next/static/chunks/3611-77496ada38cd6358.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/3717-68957c4dc9ceec90.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/3929-46ba9af6f9d895cc.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/4015-62c5a3744698a8da.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/4217-3c4317a7905f9eeb.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/4240-3230f230fae2d7d5.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/4271-e53e075ebd48593b.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/4377.3b125fef79576dfd.js +0 -5
  419. package/apps/pwa/out/_next/static/chunks/4853-35fdbe6bdbcdc0fc.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/5007-6a3b30e23ff68a6e.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/5244-12b424c42070f5ff.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/5611-df00af3e4e4a61bb.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/5890-dca2321773be829a.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/6123-37c9dc57ddaa7ab0.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/6588-b7975304a302ab91.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/6604-c03961962b6273b6.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/7109-cf8c87e968e83a65.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/7178-30f77877525a2efb.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/7262-871563fc9663730b.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/7294-f0eeebb92aa93459.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/7429-881af44deed6958f.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/7527.943753b6ed829f09.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/764-a01e858525a190c0.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/7868-e35d5f7985ecd3f1.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/8320-51484af7b01fdfa5.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/9131-52f5fad51cceca04.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/9238.2cd5f47f4bf7a2c3.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-70c404c7bb6d7f0f.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3ffd80166b1050aa.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/app/bots/page-4bcc63e272ae8205.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/app/chat/page-880734bd07d62882.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/app/control/page-72bd384898d88955.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1018bbc9586ecae5.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/app/editor/page-de86f8c38076dd7b.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/app/healthz/route-70c404c7bb6d7f0f.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/app/intake/page-cd6447196d8bafe6.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/app/layout-e733630c47fa102b.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/app/live/page-d1c1a8357b161875.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/app/market/page-60c514128e81d787.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8b637b7e325e13c1.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/app/not-found-63301d11dbe73836.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/observatory/page-a8cf0dc472060db2.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/page-02fba54881ccfa49.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d5e8e90f0038f8de.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-b1ef6824f494466a.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d589bb0f233b1009.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c9bbaebef4cda059.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/settings/page-3639ce7916b92fed.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7450ae7478955653.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/setup/layout-70c404c7bb6d7f0f.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/setup/page-b41ca4abfd618452.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/share/page-b333dd79ebee3fa9.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/showroom/page-8be1227492793655.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6e03e9371b552e0d.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/term/page-911411e9fca18d03.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/trace/page-792170e649b37088.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/vault/page-c40463466937bc91.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-509c798b80384536.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/workflows/page-1cac2aa21d77c417.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9626799d9b4a2cd1.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-84cd419494e16b0f.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/framework-361487d2da603917.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/main-app-607f5beb94cb2e07.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/main-d0222d219e29dddf.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/pages/_app-a26980a31126decc.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/pages/_error-edb2b37decf23e4d.js +0 -1
  477. package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +0 -1
  478. package/apps/pwa/out/_next/static/ktMqfrBbf8BMGac0jqLrb/_buildManifest.js +0 -1
  479. /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) => toToolRunResult(await coreTools().buildCoreTools().dispatch(name, 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. */
@@ -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 loop: observe-only until an independently approved act implementation exists. */
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 ? { loops: 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":"e491ebfd1661520b780aff439e71baa26895ab53"}
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 shot_paths = Object.values(src).filter(existsSync);
115
- if (shot_paths.length === 0) return { outcome: 'error', note: '샷 0 — ⛔ 이 러너는 크레딧을 안 쓴다(Seedance·Kling 생성은 스킬 세션의 몫)' };
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: { shot_paths, shot_count: shot_paths.length }, note: `전용 비율 재렌더가 필요한 샷 ${pending.join(', ')} — ⛔ 이 러너는 다시 그리지 않는다(크레딧 무사용) · 그 비율 렌더를 스킬 세션에서 만든 뒤 native 로 넘겨라` };
121
- return { outcome: 'ok', produced: { shot_paths, shot_count: shot_paths.length }, note: `샷 ${shot_paths.length}개 · ⚠️ 이미 생성된 것을 받았다` };
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` 한 칸만 읽는다(그 자가 «살아남은 유일한 칸»이라 스스로 적었다). */