elanous 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (524) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/LZcstaO9_NXypPFmujolv/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/1307-33ffcc49ab45123b.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
  10. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
  31. package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
  42. package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0e2c57fe6add4b2a.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e05a77df7e005b04.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/board/page-f544338193a9a762.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/botlab/page-5491c115b1f9a923.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/bots/page-b8c49f6b4fa2df91.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/ceo/page-96398e364fbd4548.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/chat/page-976813c91d7394ea.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/consult/page-28b9448091776c06.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/control/page-1d4901eb7c2d8822.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/design-check/page-72d3e7ff35a8c954.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/editor/page-60c7a8e1a4fe62ce.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a52b316cb143d9c.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/field/page-c3ce483c8d5db370.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/inside/page-13c7b53e0c2519a9.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/intake/page-96f074f6538e8a2c.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/layout-e97be5334d83a9f5.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/live/page-65e484302921a932.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/loops/page-34d08facaf08f556.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-955ec2da3be4c560.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-9f88fbc15d9058d1.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-c1343f9499d86f3f.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-8739a2e0ae793130.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-c9fc5706b8abaa11.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-d23b12bb92242558.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8d47f45a0dc044ac.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c7fea475488201a8.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e2ee2896811e98d0.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-83b19dae8619de05.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-5efbf81124c474ae.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f1a1fc0a82738c.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-da6c08aae0f92768.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-06ee266953d9c879.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-153c2b3bcc89e8de.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-87a11e6a05f15199.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-7d4182964407c09c.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-0d6d23b40263a7ea.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-7e8c39241f8eb6d0.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-008c1a96618a4887.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-f5597e894c02cd33.js} +1 -1
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-0337fdf7fb5e37b6.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-73735b64bfe1ae67.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-8fcec4c9ea2e7f70.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f7e631e9b4daf66e.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-4881b8f9f63694b4.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9817c7f9007466cc.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-97f9f43172a3a90e.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
  106. package/apps/pwa/out/_next/static/css/1f7c958c41ffa3b9.css +1 -0
  107. package/apps/pwa/out/approvals/index.html +1 -1
  108. package/apps/pwa/out/approvals/index.txt +23 -23
  109. package/apps/pwa/out/autopilot/index.html +1 -1
  110. package/apps/pwa/out/autopilot/index.txt +23 -23
  111. package/apps/pwa/out/board/index.html +1 -1
  112. package/apps/pwa/out/board/index.txt +23 -23
  113. package/apps/pwa/out/botlab/index.html +1 -1
  114. package/apps/pwa/out/botlab/index.txt +22 -22
  115. package/apps/pwa/out/bots/index.html +1 -1
  116. package/apps/pwa/out/bots/index.txt +22 -22
  117. package/apps/pwa/out/ceo/index.html +1 -0
  118. package/apps/pwa/out/ceo/index.txt +33 -0
  119. package/apps/pwa/out/chat/index.html +1 -1
  120. package/apps/pwa/out/chat/index.txt +22 -22
  121. package/apps/pwa/out/consult/index.html +1 -1
  122. package/apps/pwa/out/consult/index.txt +23 -23
  123. package/apps/pwa/out/control/index.html +1 -1
  124. package/apps/pwa/out/control/index.txt +23 -23
  125. package/apps/pwa/out/design-check/index.html +1 -1
  126. package/apps/pwa/out/design-check/index.txt +23 -23
  127. package/apps/pwa/out/editor/index.html +1 -1
  128. package/apps/pwa/out/editor/index.txt +23 -23
  129. package/apps/pwa/out/exec/index.html +1 -1
  130. package/apps/pwa/out/exec/index.txt +23 -23
  131. package/apps/pwa/out/field/index.html +1 -1
  132. package/apps/pwa/out/field/index.txt +23 -23
  133. package/apps/pwa/out/healthz +1 -1
  134. package/apps/pwa/out/index.html +1 -1
  135. package/apps/pwa/out/index.txt +22 -22
  136. package/apps/pwa/out/inside/index.html +1 -1
  137. package/apps/pwa/out/inside/index.txt +22 -22
  138. package/apps/pwa/out/intake/index.html +1 -1
  139. package/apps/pwa/out/intake/index.txt +23 -23
  140. package/apps/pwa/out/live/index.html +1 -1
  141. package/apps/pwa/out/live/index.txt +23 -23
  142. package/apps/pwa/out/loops/index.html +1 -0
  143. package/apps/pwa/out/loops/index.txt +30 -0
  144. package/apps/pwa/out/market/index.html +1 -1
  145. package/apps/pwa/out/market/index.txt +22 -22
  146. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  147. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  148. package/apps/pwa/out/morning/index.html +1 -1
  149. package/apps/pwa/out/morning/index.txt +23 -23
  150. package/apps/pwa/out/observatory/index.html +1 -1
  151. package/apps/pwa/out/observatory/index.txt +23 -23
  152. package/apps/pwa/out/ops/checklist/index.html +1 -1
  153. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  154. package/apps/pwa/out/ops/release/index.html +1 -1
  155. package/apps/pwa/out/ops/release/index.txt +22 -22
  156. package/apps/pwa/out/ops/seats/index.html +1 -1
  157. package/apps/pwa/out/ops/seats/index.txt +22 -22
  158. package/apps/pwa/out/outputs/index.html +1 -1
  159. package/apps/pwa/out/outputs/index.txt +22 -22
  160. package/apps/pwa/out/reflection/index.html +1 -1
  161. package/apps/pwa/out/reflection/index.txt +23 -23
  162. package/apps/pwa/out/scheduler/index.html +1 -1
  163. package/apps/pwa/out/scheduler/index.txt +23 -23
  164. package/apps/pwa/out/sessions/index.html +1 -1
  165. package/apps/pwa/out/sessions/index.txt +22 -22
  166. package/apps/pwa/out/settings/devices/index.html +1 -1
  167. package/apps/pwa/out/settings/devices/index.txt +23 -23
  168. package/apps/pwa/out/settings/index.html +1 -1
  169. package/apps/pwa/out/settings/index.txt +23 -23
  170. package/apps/pwa/out/setup/done/index.html +1 -1
  171. package/apps/pwa/out/setup/done/index.txt +23 -23
  172. package/apps/pwa/out/setup/index.html +1 -1
  173. package/apps/pwa/out/setup/index.txt +23 -23
  174. package/apps/pwa/out/share/index.html +1 -1
  175. package/apps/pwa/out/share/index.txt +23 -23
  176. package/apps/pwa/out/showroom/index.html +1 -1
  177. package/apps/pwa/out/showroom/index.txt +22 -22
  178. package/apps/pwa/out/tasks/index.html +1 -1
  179. package/apps/pwa/out/tasks/index.txt +23 -23
  180. package/apps/pwa/out/term/index.html +1 -1
  181. package/apps/pwa/out/term/index.txt +23 -23
  182. package/apps/pwa/out/today/index.html +1 -1
  183. package/apps/pwa/out/today/index.txt +23 -23
  184. package/apps/pwa/out/trace/index.html +1 -1
  185. package/apps/pwa/out/trace/index.txt +23 -23
  186. package/apps/pwa/out/vault/index.html +1 -1
  187. package/apps/pwa/out/vault/index.txt +23 -23
  188. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  189. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  190. package/apps/pwa/out/workflows/index.html +1 -1
  191. package/apps/pwa/out/workflows/index.txt +23 -23
  192. package/apps/pwa/out/workspace/index.html +1 -1
  193. package/apps/pwa/out/workspace/index.txt +23 -23
  194. package/apps/pwa/out/worktrees/index.html +1 -1
  195. package/apps/pwa/out/worktrees/index.txt +23 -23
  196. package/graphs/heal/heal-loop.yaml +1 -1
  197. package/graphs/implement-loop.yaml +1 -1
  198. package/graphs/orchestrator/orchestrator.yaml +59 -0
  199. package/graphs/orchestrator/recipes.yaml +18 -0
  200. package/graphs/release/recipes.yaml +6 -0
  201. package/graphs/release/release-loop.yaml +6 -1
  202. package/graphs/rhythm/daily.yaml +38 -0
  203. package/graphs/rhythm/recipes.yaml +18 -0
  204. package/graphs/rhythm/weekly.yaml +39 -0
  205. package/graphs/video/recipes.yaml +3 -0
  206. package/graphs/video/youtube-summary.yaml +17 -0
  207. package/package.json +1 -1
  208. package/scripts/audit-test-state-writes.ts +72 -17
  209. package/scripts/brand/check.ts +188 -0
  210. package/scripts/ci-typecheck-changed.ts +50 -18
  211. package/scripts/coord-post.sh +11 -1
  212. package/scripts/docs/generate-graph-anatomy.ts +315 -0
  213. package/scripts/docs-cli-check.ts +23 -6
  214. package/scripts/expose-rubric-check.ts +118 -0
  215. package/scripts/expose-rubric-suggest.ts +169 -0
  216. package/scripts/heal/run-role.ts +14 -0
  217. package/scripts/hq/standby-verify.ts +11 -7
  218. package/scripts/lecture-note/node.ts +31 -11
  219. package/scripts/lessons/handbook-page.ts +112 -0
  220. package/scripts/marketing/generate-ax-brief.ts +140 -0
  221. package/scripts/marketing/generate-feature-map.ts +118 -0
  222. package/scripts/release-loop/checklist-gate-node.ts +53 -14
  223. package/scripts/release-loop/gate-node.ts +89 -14
  224. package/scripts/release-loop/publish-node.ts +14 -1
  225. package/scripts/release-loop/unattended-release.ts +23 -1
  226. package/scripts/release-loop/vault-note-node.ts +428 -0
  227. package/scripts/release-story/draft.ts +220 -0
  228. package/scripts/rhythm/daily.ts +570 -0
  229. package/scripts/rhythm/weekly.ts +315 -0
  230. package/scripts/skills/public-check.ts +169 -0
  231. package/scripts/smart-merge/resync-shadow.ts +147 -0
  232. package/scripts/test-deterministic.ts +4 -8
  233. package/scripts/test-diet/effectiveness.ts +195 -0
  234. package/scripts/test-diet/lib.ts +16 -8
  235. package/scripts/test-diet/node.ts +77 -9
  236. package/scripts/ux/demo-rehearsal.ts +2 -2
  237. package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
  238. package/scripts/video/youtube-summary.ts +133 -0
  239. package/skills/diagram-master/SKILL.md +42 -49
  240. package/skills/diagram-master/references/pyproject.toml +4 -1
  241. package/skills/diagram-master/references/routing-guide.md +4 -2
  242. package/skills/grill-me/SKILL.md +1 -0
  243. package/skills/youtube-master/SKILL.md +13 -13
  244. package/skills/youtube-master/package-lock.json +0 -545
  245. package/skills/youtube-master/package.json +2 -5
  246. package/skills/youtube-master/scripts/main.ts +2 -2
  247. package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
  248. package/skills/youtube-master/src/util.ts +30 -7
  249. package/src/agent-env/profile.ts +161 -0
  250. package/src/agent-mission/driver.ts +3 -3
  251. package/src/agent-substrate/pr-reviewer.ts +2 -0
  252. package/src/ask-user-question/pending-questions.ts +5 -0
  253. package/src/auth/github-app-token.ts +112 -13
  254. package/src/autopilot/build/llm-conflict-merge.ts +73 -10
  255. package/src/autopilot/build/merge-intent.ts +53 -0
  256. package/src/briefing/brief-items.ts +121 -0
  257. package/src/chat/index.ts +2 -0
  258. package/src/claims/claims-ledger.ts +232 -0
  259. package/src/claims/claims-render.ts +166 -0
  260. package/src/cli/agent-env-cli.ts +21 -0
  261. package/src/cli/claims-cli.ts +94 -0
  262. package/src/cli/decisions-cli.ts +44 -3
  263. package/src/cli/docs-cli.ts +2 -0
  264. package/src/cli/doctor-cli.ts +23 -1
  265. package/src/cli/doctor-node-modules.ts +147 -0
  266. package/src/cli/flow-cli.ts +11 -0
  267. package/src/cli/freeze-cli.ts +45 -0
  268. package/src/cli/intake-cli.ts +46 -17
  269. package/src/cli/lesson-cli.ts +108 -0
  270. package/src/cli/logs-cli.ts +104 -2
  271. package/src/cli/logs-model-input.ts +131 -0
  272. package/src/cli/pod-cli.ts +2 -0
  273. package/src/cli/pr-cli.ts +29 -1
  274. package/src/cli/private-ledger-commands.ts +54 -4
  275. package/src/cli/pty-drive-verdict.ts +11 -2
  276. package/src/cli/release-cli.ts +190 -33
  277. package/src/cli/rfc-status.ts +91 -0
  278. package/src/cli/seat-requests-cli.ts +52 -0
  279. package/src/connectors/linear.ts +5 -3
  280. package/src/context-bus/condense.ts +15 -20
  281. package/src/context-bus/context-now-public.ts +96 -0
  282. package/src/context-bus/context-now-surfaces.ts +55 -2
  283. package/src/context-bus/context-now.ts +6 -3
  284. package/src/context-bus/coord-events.ts +6 -4
  285. package/src/context-bus/long-term-memory.ts +92 -11
  286. package/src/dashboard/index.ts +75 -22
  287. package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
  288. package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
  289. package/src/dashboard/slash-runtime/loops-table.ts +77 -0
  290. package/src/decisions/decision-cards.ts +33 -7
  291. package/src/decisions/decision-ledger.ts +40 -1
  292. package/src/decisions/proact-meter.ts +286 -0
  293. package/src/decisions/proact1-lite.ts +86 -0
  294. package/src/decisions/web-push-decision-cards.ts +1 -1
  295. package/src/discord/sprint21-runtime.ts +16 -0
  296. package/src/discord-self-message.ts +8 -0
  297. package/src/discord-slash-wire.ts +31 -2
  298. package/src/domains/alert-audit.ts +271 -0
  299. package/src/domains/core-tools.ts +4 -3
  300. package/src/domains/ops-facts-tool.ts +31 -1
  301. package/src/domains/outbound-alert.ts +1 -1
  302. package/src/elanous-config-dir.ts +29 -4
  303. package/src/execution-loop/launch-gate.ts +29 -14
  304. package/src/flow/cards.ts +239 -0
  305. package/src/graph-runner/graph-tick.ts +4 -0
  306. package/src/graph-runner/runner.ts +30 -5
  307. package/src/harness/harness-cli-command.ts +259 -38
  308. package/src/harness/harness-incidents.ts +45 -12
  309. package/src/harness/harness-pod-dispatch.ts +102 -11
  310. package/src/harness/harness-queue-child.ts +3 -3
  311. package/src/harness/harness-queue.ts +583 -65
  312. package/src/harness/helper-repair.ts +87 -0
  313. package/src/harness/helper-scan.ts +151 -0
  314. package/src/harness/launch-stamp.ts +236 -0
  315. package/src/harness/ledger-write-guard-child.fixture.ts +12 -0
  316. package/src/harness/ledger-write-guard.ts +35 -0
  317. package/src/harness/model-input-observation.ts +37 -0
  318. package/src/harness/pod-memory-policy.ts +15 -0
  319. package/src/harness/repository-name.ts +55 -0
  320. package/src/hq/fence-audit.ts +90 -0
  321. package/src/hq/hq.ts +63 -5
  322. package/src/hq/lease.ts +4 -4
  323. package/src/hq/move-plan.ts +126 -0
  324. package/src/hq/promote.ts +332 -0
  325. package/src/index.ts +159 -27
  326. package/src/intake-plane/check.ts +63 -0
  327. package/src/intake-plane/digest.ts +37 -15
  328. package/src/intake-plane/front-classifier.ts +6 -0
  329. package/src/intake-plane/items.ts +3 -2
  330. package/src/intake-plane/lens.ts +177 -0
  331. package/src/intake-plane/linear-wish.ts +39 -11
  332. package/src/intake-plane/route.ts +145 -1
  333. package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
  334. package/src/intake-plane/wish-card.ts +53 -2
  335. package/src/intake-plane/wish-folder.ts +5 -2
  336. package/src/intake-plane/wish-reply.ts +72 -0
  337. package/src/launch-head/seat-goal-queue-lock.fixture.ts +15 -0
  338. package/src/launch-head/seat-goal-queue.ts +198 -0
  339. package/src/lessons/lesson-import.ts +106 -0
  340. package/src/lessons/lesson-ledger.ts +206 -0
  341. package/src/loops/activity.ts +203 -0
  342. package/src/loops/budget.ts +63 -0
  343. package/src/loops/checker.ts +5 -3
  344. package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
  345. package/src/loops/loop-cli.ts +36 -4
  346. package/src/loops/neighbors.ts +40 -0
  347. package/src/loops/observe.ts +10 -0
  348. package/src/loops/orchestrator/author-depth.ts +220 -0
  349. package/src/loops/orchestrator/author-input-check.ts +82 -0
  350. package/src/loops/orchestrator/author-ledger.ts +232 -0
  351. package/src/loops/orchestrator/finish-rate.ts +175 -0
  352. package/src/loops/orchestrator/overlap.ts +51 -12
  353. package/src/loops/orchestrator/resync-shadow.ts +227 -0
  354. package/src/loops/orchestrator/seat-share.ts +56 -0
  355. package/src/loops/orchestrator/tick.ts +309 -0
  356. package/src/loops/orchestrator/traffic.ts +134 -13
  357. package/src/loops/registry.ts +535 -9
  358. package/src/loops/status-rows.ts +118 -0
  359. package/src/loops/verdict.ts +17 -5
  360. package/src/maturity/bot-slash-catalog.ts +66 -0
  361. package/src/maturity/feature-maturity.ts +9 -5
  362. package/src/maturity/tui-slash-availability.ts +31 -0
  363. package/src/mss/logging/log-store.ts +35 -4
  364. package/src/nexus/api/dashboard.ts +6 -1
  365. package/src/nexus/api/http-server.ts +33 -3
  366. package/src/nexus/api/loop-edges.ts +173 -0
  367. package/src/nexus/api/merge-approvals-gate.ts +1 -1
  368. package/src/nexus/api/schedules-read.ts +18 -1
  369. package/src/nexus/api/seat-requests.ts +79 -56
  370. package/src/nexus/api/task-cards-api.ts +44 -5
  371. package/src/nexus/api/workflows.ts +2 -1
  372. package/src/prompt-enhance/enhance.ts +6 -1
  373. package/src/release-loop/auto-start.ts +51 -0
  374. package/src/release-loop/checklist.ts +22 -4
  375. package/src/release-loop/feature-store.ts +71 -32
  376. package/src/release-loop/landing-freeze.ts +121 -0
  377. package/src/release-loop/merged-pr-checklist.ts +125 -0
  378. package/src/release-loop/placement.ts +302 -0
  379. package/src/release-loop/release-schedule.ts +3 -1
  380. package/src/seat-dispatch/ceo-commands.ts +2 -2
  381. package/src/seat-dispatch/seat-ask.ts +16 -3
  382. package/src/seat-dispatch/seat-questions.ts +58 -0
  383. package/src/seat-dispatch/seat-request-eligibility.ts +19 -0
  384. package/src/seat-dispatch/seat-request-ledger.ts +133 -0
  385. package/src/seat-loop/seat-loop.ts +531 -40
  386. package/src/self-dev/dev-pipeline.ts +14 -6
  387. package/src/self-dev/draft-sweep.ts +162 -6
  388. package/src/self-dev/draft-triage-rules.ts +25 -8
  389. package/src/self-dev/orchestrate.ts +15 -1
  390. package/src/self-dev/review-provider-fallback.ts +6 -1
  391. package/src/self-dev/run-store.ts +73 -1
  392. package/src/self-dev/run-supervisor.ts +57 -2
  393. package/src/self-dev/self-orchestrate-runtime.ts +5 -1
  394. package/src/self-implement/budget-gate.ts +29 -0
  395. package/src/self-implement/expose-gate.ts +47 -0
  396. package/src/self-implement/frozen-merges.ts +295 -0
  397. package/src/self-implement/gate-cli.ts +10 -4
  398. package/src/self-implement/gate-scope.ts +46 -9
  399. package/src/self-implement/goal-archive.ts +222 -0
  400. package/src/self-implement/goal-author.ts +43 -5
  401. package/src/self-implement/goal-clarification-escalation.ts +5 -0
  402. package/src/self-implement/goal-lookup.ts +147 -0
  403. package/src/self-implement/heal-intake.ts +197 -0
  404. package/src/self-implement/host-regate.ts +32 -2
  405. package/src/self-implement/l8-merge-queue.ts +132 -0
  406. package/src/self-implement/orchestrator.ts +299 -48
  407. package/src/self-implement/pipeline-shape.ts +1 -1
  408. package/src/self-implement/revert-guard.ts +97 -0
  409. package/src/self-implement/run-ledger.ts +3 -1
  410. package/src/self-implement/run-status-mapping.ts +2 -0
  411. package/src/self-implement/seams.ts +29 -9
  412. package/src/self-implement/self-implement-cli.ts +1 -0
  413. package/src/self-implement/speed-claims.ts +338 -0
  414. package/src/session/index.ts +2 -0
  415. package/src/steward/triage.ts +74 -3
  416. package/src/steward/working-backwards.ts +4 -1
  417. package/src/task-cards/card-cli.ts +10 -2
  418. package/src/task-cards/card-store.ts +10 -6
  419. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +63 -48
  420. package/src/task-orchestrator/surfaces/pod-command-job.ts +84 -9
  421. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +48 -0
  422. package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
  423. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
  424. package/src/task-orchestrator/surfaces/pod-pool.ts +60 -8
  425. package/src/task-orchestrator/surfaces/self-implement-pod.ts +224 -49
  426. package/src/task-orchestrator/surfaces/self-implement.ts +5 -1
  427. package/src/telegram-commands.ts +27 -3
  428. package/src/telegram-loops-command.ts +44 -0
  429. package/src/telegram.ts +25 -4
  430. package/src/user-config.ts +146 -18
  431. package/src/version/packed-revision.json +1 -1
  432. package/src/workflow-runtime/nodes/bash.ts +9 -1
  433. package/src/workflow-runtime/storage.ts +31 -13
  434. package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
  445. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
  449. package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f14987d5850a31e0.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66c27608f651b866.js +0 -1
  491. package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-78b40a344ed22f24.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
  523. package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
  524. /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → LZcstaO9_NXypPFmujolv}/_ssgManifest.js +0 -0
@@ -0,0 +1,286 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { DecisionLedger, type DecisionEntry, type SeatDecisionRecord } from './decision-ledger.js';
4
+ import { createRequire } from 'node:module';
5
+ import { listCoordEvents, type CoordEvent } from '../context-bus/coord-events.js';
6
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
7
+ import { elanousStateRoot } from '../autopilot/state-paths.js';
8
+
9
+ /** Directive row fields this meter reads — kept local because `src/directives/directive-index` is excluded from the public export. */
10
+ export interface DirectiveRow { ts: string; text: string; source_file: string; line_no: number }
11
+
12
+ /** Loads the private directive index at run time only, so public builds (no index) bundle cleanly and report `directivesError`. */
13
+ function openDirectiveIndex(stateDir?: string): { search(q: string, f: { since?: string; until?: string; limit?: number }): DirectiveRow[]; close(): void } {
14
+ const spec = ['..', 'directives', 'directive-index.js'].join('/');
15
+ const mod = createRequire(import.meta.url)(spec) as { DirectiveIndex: new (o: { stateDir?: string }) => ReturnType<typeof openDirectiveIndex> };
16
+ return new mod.DirectiveIndex(stateDir ? { stateDir } : {});
17
+ }
18
+
19
+ /** KST calendar day, matching the seat-loop ledger file name. */
20
+ export function proactKstDay(at: Date | string): string {
21
+ const date = typeof at === 'string' ? new Date(at) : at;
22
+ if (!Number.isFinite(date.getTime())) throw new Error('valid timestamp required');
23
+ return new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Seoul', year: 'numeric', month: '2-digit', day: '2-digit' }).format(date);
24
+ }
25
+
26
+ export function proactWindow(now: Date, days = 7): { since: string; until: string; days: string[] } {
27
+ if (!Number.isFinite(now.getTime()) || !Number.isInteger(days) || days < 1) throw new Error('valid window required');
28
+ const today = proactKstDay(now);
29
+ const todayStart = Date.parse(`${today}T00:00:00+09:00`);
30
+ const list: string[] = [];
31
+ for (let i = days - 1; i >= 0; i--) list.push(proactKstDay(new Date(todayStart - i * 86_400_000)));
32
+ return { since: new Date(todayStart - (days - 1) * 86_400_000).toISOString(), until: now.toISOString(), days: list };
33
+ }
34
+
35
+ export type ProactKind = 'proposal' | 'alert' | 'action';
36
+ export type ProactSource = 'decision' | 'directive' | 'coord' | 'loop';
37
+ export interface ProactSample {
38
+ readonly day: string;
39
+ readonly bucket: 'offered' | 'adopted' | 'asked';
40
+ readonly source: ProactSource;
41
+ readonly id: string;
42
+ readonly at: string;
43
+ readonly title: string;
44
+ /** Where the original row lives, so a count can be opened again. */
45
+ readonly link: string;
46
+ }
47
+ export interface ProactDay {
48
+ readonly day: string;
49
+ /** System offered a proposal, alert, or action before the owner asked. */
50
+ readonly offered: number;
51
+ /** Of those, the ones the owner (or a delegated seat) adopted. */
52
+ readonly adopted: number;
53
+ /** Problems that stayed invisible until the owner asked first. */
54
+ readonly asked: number;
55
+ }
56
+ export interface ProactSourceStatus { readonly read: boolean; readonly reason?: string }
57
+ export interface ProactMeter {
58
+ readonly since: string;
59
+ readonly until: string;
60
+ readonly days: readonly ProactDay[];
61
+ readonly samples: readonly ProactSample[];
62
+ readonly sources: Readonly<Record<ProactSource, ProactSourceStatus>>;
63
+ }
64
+
65
+ export interface ProactMeterInput {
66
+ decisions?: readonly DecisionEntry[];
67
+ seatDecisions?: readonly SeatDecisionRecord[];
68
+ directives?: readonly DirectiveRow[];
69
+ coord?: readonly CoordEvent[];
70
+ loops?: readonly ProactLoopRow[];
71
+ decisionsError?: string;
72
+ directivesError?: string;
73
+ coordError?: string;
74
+ loopsError?: string;
75
+ }
76
+ export interface ProactLoopRow {
77
+ readonly seat: string;
78
+ readonly at: string;
79
+ readonly status: string;
80
+ readonly action?: string;
81
+ readonly id?: string;
82
+ readonly title?: string;
83
+ readonly file: string;
84
+ }
85
+
86
+ const ALERT = /경보|경고|장애|실패|막힘|alert|fail|blocked|stall/i;
87
+ const ACTION = /조치|실행|발사|launch|queued|launched/i;
88
+ const ASKED = /왜|문제|안 되|안돼|고장|버그|실패|막혀|뭐가|무슨 일|확인해/;
89
+
90
+ export function proactKind(text: string, action?: string): ProactKind {
91
+ if (action === 'decision' || action === 'harness' || action === 'seat-question' || ACTION.test(text)) return 'action';
92
+ if (ALERT.test(text)) return 'alert';
93
+ return 'proposal';
94
+ }
95
+
96
+ function sample(day: string, bucket: ProactSample['bucket'], source: ProactSource, id: string, at: string, title: string, link: string): ProactSample {
97
+ return { day, bucket, source, id, at, title: title.replace(/\s+/g, ' ').trim().slice(0, 160), link };
98
+ }
99
+
100
+ /** Count one row once. Adoption is a property of an offered row, never a second offered row. */
101
+ export function measureProact(input: ProactMeterInput, now: Date, days = 7): ProactMeter {
102
+ const window = proactWindow(now, days);
103
+ const inWindow = (at: string | undefined): at is string => !!at && at >= window.since && at <= window.until;
104
+ const offered: ProactSample[] = [];
105
+ const adopted: ProactSample[] = [];
106
+ const asked: ProactSample[] = [];
107
+
108
+ if (!input.decisionsError) {
109
+ for (const card of input.decisions ?? []) {
110
+ const at = card.raisedAt ?? card.importedAt;
111
+ if (!inWindow(at)) continue;
112
+ const day = proactKstDay(at);
113
+ const link = `decisions://${card.id}`;
114
+ const system = card.raisedBy.agent !== 'human' && card.raisedBy.agent !== 'owner';
115
+ if (system) {
116
+ offered.push(sample(day, 'offered', 'decision', card.id, at, card.title, link));
117
+ const decidedAt = card.decidedAt;
118
+ const adoptedDay = decidedAt ? proactKstDay(decidedAt) : '';
119
+ if (card.status === 'decided' && decidedAt && decidedAt <= window.until) {
120
+ adopted.push(sample(adoptedDay, 'adopted', 'decision', card.id, decidedAt, card.title, link));
121
+ }
122
+ } else if (ASKED.test(`${card.title} ${card.scqa.c}`)) {
123
+ asked.push(sample(day, 'asked', 'decision', card.id, at, card.title, link));
124
+ }
125
+ }
126
+ for (const seat of input.seatDecisions ?? []) {
127
+ if (!inWindow(seat.recordedAt)) continue;
128
+ const at = seat.decidedAt && seat.decidedAt <= window.until ? seat.decidedAt : seat.recordedAt;
129
+ const adoptedDay = proactKstDay(at);
130
+ const link = `decisions://${seat.id}`;
131
+ offered.push(sample(proactKstDay(seat.recordedAt), 'offered', 'decision', seat.id, seat.recordedAt, seat.title, link));
132
+ if (window.days.includes(adoptedDay)) adopted.push(sample(adoptedDay, 'adopted', 'decision', seat.id, at, seat.title, link));
133
+ }
134
+ }
135
+
136
+ if (!input.directivesError) {
137
+ for (const row of input.directives ?? []) {
138
+ if (!inWindow(row.ts) || !ASKED.test(row.text)) continue;
139
+ asked.push(sample(proactKstDay(row.ts), 'asked', 'directive', `${row.source_file}:${row.line_no}`, row.ts, row.text, `directives://${row.source_file}#L${row.line_no}`));
140
+ }
141
+ }
142
+
143
+ if (!input.coordError) {
144
+ for (const event of input.coord ?? []) {
145
+ if (!inWindow(event.at)) continue;
146
+ const day = proactKstDay(event.at);
147
+ const link = event.refs.url ?? `coord://${event.id}`;
148
+ const text = `${event.summary} ${event.kind}`;
149
+ const systemOffered = event.refs.seat && event.refs.seat !== 'CEO' && (event.kind === '제안' || event.kind === '보고' || event.kind === '사고' || ALERT.test(text) || ACTION.test(text));
150
+ if (systemOffered) {
151
+ offered.push(sample(day, 'offered', 'coord', event.id, event.at, event.summary, link));
152
+ } else if (event.refs.seat === 'CEO' && (event.kind === '요청' || ASKED.test(text))) {
153
+ asked.push(sample(day, 'asked', 'coord', event.id, event.at, event.summary, link));
154
+ }
155
+ }
156
+ }
157
+
158
+ if (!input.loopsError) {
159
+ const proactive = new Set(['queued', 'launched', 'asked', 'hitl', 'shadow', 'attempting']);
160
+ for (const row of input.loops ?? []) {
161
+ if (!inWindow(row.at)) continue;
162
+ const day = proactKstDay(row.at);
163
+ const id = row.id ?? `${row.seat}:${row.at}`;
164
+ const link = `loop://${row.file}#${id}`;
165
+ const title = row.title ?? `${row.seat} ${row.status}`;
166
+ if (proactive.has(row.status) || row.action === 'decision' || row.action === 'harness') {
167
+ offered.push(sample(day, 'offered', 'loop', id, row.at, `${proactKind(title, row.action)}:${title}`, link));
168
+ if (row.status === 'launched' || row.status === 'queued' || row.action === 'decision') {
169
+ adopted.push(sample(day, 'adopted', 'loop', id, row.at, title, link));
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ const tally = new Map<string, { day: string; offered: number; adopted: number; asked: number }>(window.days.map(day => [day, { day, offered: 0, adopted: 0, asked: 0 }]));
176
+ for (const row of offered) tally.get(row.day)!.offered += 1;
177
+ for (const row of adopted) {
178
+ const cell = tally.get(row.day);
179
+ if (cell) cell.adopted += 1;
180
+ }
181
+ for (const row of asked) tally.get(row.day)!.asked += 1;
182
+ const pick = (rows: ProactSample[]) => {
183
+ const seen = new Set<string>();
184
+ const out: ProactSample[] = [];
185
+ for (const source of ['decision', 'directive', 'coord', 'loop'] as const) {
186
+ for (const row of rows.filter(item => item.source === source).sort((a, b) => b.at.localeCompare(a.at) || a.id.localeCompare(b.id))) {
187
+ if (seen.has(row.link)) continue;
188
+ seen.add(row.link);
189
+ out.push(row);
190
+ if (out.length === 2) break;
191
+ }
192
+ }
193
+ return out;
194
+ };
195
+ const status = (error: string | undefined, read: boolean): ProactSourceStatus => error ? { read: false, reason: error } : { read };
196
+ return {
197
+ since: window.since, until: window.until,
198
+ days: window.days.map(day => tally.get(day)!),
199
+ samples: [...pick(offered), ...pick(adopted), ...pick(asked)],
200
+ sources: {
201
+ decision: status(input.decisionsError, !input.decisionsError),
202
+ directive: status(input.directivesError, !input.directivesError),
203
+ coord: status(input.coordError, !input.coordError),
204
+ loop: status(input.loopsError, !input.loopsError),
205
+ },
206
+ };
207
+ }
208
+
209
+ function readLoopRows(root: string, days: readonly string[]): ProactLoopRow[] {
210
+ const base = join(root, 'seat-loop');
211
+ const seats = readdirSync(base, { withFileTypes: true }).filter(entry => entry.isDirectory()).map(entry => entry.name);
212
+ const rows: ProactLoopRow[] = [];
213
+ for (const seat of seats) {
214
+ for (const day of days) {
215
+ const file = join(base, seat, `${day}.jsonl`);
216
+ let text = '';
217
+ try { text = readFileSync(file, 'utf8'); } catch (error) {
218
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;
219
+ throw error;
220
+ }
221
+ for (const line of text.split('\n')) {
222
+ if (!line.trim()) continue;
223
+ const parsed = JSON.parse(line) as { at?: string; ts?: string; status?: string; action?: string; item?: { id?: string; title?: string } };
224
+ const at = parsed.at ?? parsed.ts;
225
+ if (!at || !parsed.status) continue;
226
+ rows.push({ seat, at, status: parsed.status, action: parsed.action, id: parsed.item?.id, title: parsed.item?.title, file });
227
+ }
228
+ }
229
+ }
230
+ return rows;
231
+ }
232
+
233
+ export interface ProactMeterDeps {
234
+ readonly now?: Date;
235
+ readonly days?: number;
236
+ readonly stateDir?: string;
237
+ readonly instanceRoot?: string;
238
+ readonly readDecisions?: () => { decisions: DecisionEntry[]; seatDecisions: SeatDecisionRecord[] };
239
+ readonly readDirectives?: (since: string, until: string) => DirectiveRow[];
240
+ readonly readCoord?: (since: string) => CoordEvent[];
241
+ readonly readLoops?: (days: readonly string[]) => ProactLoopRow[];
242
+ }
243
+
244
+ /** Read the four ledgers. A source that cannot be opened is reported, never counted as zero evidence. */
245
+ export function readProactMeter(deps: ProactMeterDeps = {}): ProactMeter {
246
+ const now = deps.now ?? new Date();
247
+ const window = proactWindow(now, deps.days ?? 7);
248
+ const input: ProactMeterInput = {};
249
+ const stateDir = deps.stateDir;
250
+ try {
251
+ const read = deps.readDecisions ?? (() => {
252
+ const ledger = new DecisionLedger(stateDir ? { stateDir } : {});
253
+ return { decisions: ledger.list({ status: 'all', since: window.since }), seatDecisions: ledger.seatReport({ since: window.since }) };
254
+ });
255
+ const got = read();
256
+ input.decisions = got.decisions;
257
+ input.seatDecisions = got.seatDecisions;
258
+ } catch (error) { input.decisionsError = error instanceof Error ? error.message : String(error); }
259
+ try {
260
+ input.directives = (deps.readDirectives ?? ((since, until) => {
261
+ const index = openDirectiveIndex(stateDir);
262
+ try { return index.search('', { since, until, limit: 1000 }); }
263
+ finally { index.close(); }
264
+ }))(window.since, window.until);
265
+ } catch (error) { input.directivesError = error instanceof Error ? error.message : String(error); }
266
+ try {
267
+ input.coord = (deps.readCoord ?? ((since) => listCoordEvents({ since, channelOnly: true })))(window.since);
268
+ } catch (error) { input.coordError = error instanceof Error ? error.message : String(error); }
269
+ try {
270
+ const loopRoot = deps.instanceRoot ?? stateDir ?? effectiveInstanceRoot() ?? elanousStateRoot();
271
+ input.loops = (deps.readLoops ?? ((days) => readLoopRows(loopRoot, days)))(window.days);
272
+ } catch (error) { input.loopsError = error instanceof Error ? error.message : String(error); }
273
+ return measureProact(input, now, deps.days ?? 7);
274
+ }
275
+
276
+ export function formatProactMeter(meter: ProactMeter): string {
277
+ const lines = [`선제성 ${meter.since} ~ ${meter.until}`, '날짜 · 먼저 냄 · 채택 · 물어서야'];
278
+ for (const day of meter.days) lines.push(`${day.day} · ${day.offered} · ${day.adopted} · ${day.asked}`);
279
+ const unread = (Object.entries(meter.sources) as Array<[ProactSource, ProactSourceStatus]>).filter(([, status]) => !status.read);
280
+ if (unread.length) lines.push(`못 읽음: ${unread.map(([name, status]) => `${name}(${status.reason})`).join(' · ')}`);
281
+ if (meter.samples.length) {
282
+ lines.push('표본:');
283
+ for (const row of meter.samples) lines.push(` ${row.bucket} · ${row.source} · ${row.id} · ${row.link}`);
284
+ }
285
+ return lines.join('\n');
286
+ }
@@ -0,0 +1,86 @@
1
+ import type { DecisionEntry } from './decision-ledger.js';
2
+ import type { ChecklistItem } from '../release-loop/checklist.js';
3
+ import type { ReleaseSchedule } from '../release-loop/release-schedule.js';
4
+ import type { DraftSweepResult, SweepDraft } from '../self-dev/draft-sweep.js';
5
+
6
+ type ProactLoop = { readonly name: string; readonly state: 'alive' | 'late' | 'failing' | 'off' | 'unknown'; readonly scope?: string };
7
+ type ProactYellow = { readonly version: string; readonly item: Pick<ChecklistItem, 'id' | 'title' | 'status'> };
8
+ type ProactDrafts = { readonly drafts: readonly Pick<SweepDraft, 'number' | 'title'>[]; readonly sweep: Pick<DraftSweepResult, 'complete' | 'entries'> };
9
+ export interface ProactSignals {
10
+ /** A suspended run (resume) or an explicitly observed blocker, not merely an old open card. */
11
+ readonly decisions?: readonly (Pick<DecisionEntry, 'id' | 'title' | 'status' | 'raisedAt' | 'importedAt' | 'resume'> & { readonly blocked?: boolean })[];
12
+ readonly yellow?: readonly ProactYellow[];
13
+ readonly schedules?: readonly Pick<ReleaseSchedule, 'version' | 'landBy'>[];
14
+ readonly loops?: readonly ProactLoop[];
15
+ /** Only a complete, read-only runDraftSweep({ apply: false }) assessment proves draft staleness. */
16
+ readonly draftAssessment?: ProactDrafts;
17
+ }
18
+ type ProactSuggestion = {
19
+ readonly key: string;
20
+ readonly kind: 'decision' | 'yellow' | 'loop' | 'draft';
21
+ readonly title: string;
22
+ readonly reason: string;
23
+ readonly source: string;
24
+ readonly score: number;
25
+ };
26
+
27
+ const HOUR = 3_600_000;
28
+ const DECISION_AGE_HOURS = 24;
29
+ const LANDING_WINDOW_HOURS = 24;
30
+ const MAX_SUGGESTIONS = 3;
31
+
32
+ /** Rules-only, read-only selection. Missing/invalid observations are unknown, never evidence of urgency. */
33
+ export function selectProact1Lite(signals: ProactSignals, options: { now: Date; previouslySuggested?: ReadonlySet<string> }): ProactSuggestion[] {
34
+ const now = options.now.getTime();
35
+ if (!Number.isFinite(now)) throw new Error('valid now required');
36
+ const candidates: ProactSuggestion[] = [];
37
+ const elapsedHours = (iso: string | undefined): number => iso ? (now - Date.parse(iso)) / HOUR : NaN;
38
+ const valid = (text: string): boolean => text.trim().length > 0;
39
+
40
+ for (const card of signals.decisions ?? []) {
41
+ if (card.status !== 'open' || (card.blocked !== true && !card.resume) || !valid(card.id) || !valid(card.title)) continue;
42
+ // Imported historical cards have no known raise time; their import time is a lower bound on age.
43
+ const age = elapsedHours(card.raisedAt ?? card.importedAt);
44
+ if (!Number.isFinite(age) || age < DECISION_AGE_HOURS) continue;
45
+ candidates.push({ key: `decision:${card.id}`, kind: 'decision', title: card.title,
46
+ reason: `열린 결정 ${Math.floor(age)}시간 대기${card.raisedAt ? '' : ' (가져온 시각 기준)'}`,
47
+ source: card.id, score: 400 + Math.min(100, Math.floor(age / 24)) });
48
+ }
49
+
50
+ const deadlines = new Map((signals.schedules ?? []).map(schedule => [schedule.version, schedule.landBy]));
51
+ for (const { version, item } of signals.yellow ?? []) {
52
+ if (item.status !== 'yellow' || !valid(item.id) || !valid(item.title) || !valid(version)) continue;
53
+ const landBy = deadlines.get(version);
54
+ const remaining = landBy ? (Date.parse(landBy) - now) / HOUR : NaN;
55
+ if (!Number.isFinite(remaining) || remaining > LANDING_WINDOW_HOURS) continue;
56
+ candidates.push({ key: `yellow:${version}:${item.id}`, kind: 'yellow', title: item.title,
57
+ reason: remaining < 0 ? `착지 마감 ${Math.ceil(-remaining)}시간 경과` : `착지 마감 ${Math.ceil(remaining)}시간 전`,
58
+ source: `${version}/${item.id} · ${landBy}`, score: 500 + Math.min(100, Math.max(0, Math.ceil(-remaining))) });
59
+ }
60
+
61
+ for (const loop of signals.loops ?? []) {
62
+ if (loop.state !== 'late' || !valid(loop.name)) continue;
63
+ candidates.push({ key: `loop:${loop.scope ?? ''}:${loop.name}`, kind: 'loop', title: loop.name,
64
+ reason: '루프 실행 지연 관측', source: `${loop.scope ?? 'loop'}/${loop.name}`, score: 300 });
65
+ }
66
+
67
+ const assessment = signals.draftAssessment;
68
+ if (assessment?.sweep.complete) {
69
+ const drafts = new Map(assessment.drafts.map(draft => [draft.number, draft]));
70
+ for (const entry of assessment.sweep.entries) {
71
+ // A stale assessment is not a request to close: only surface the already-verified signal.
72
+ if (entry.action !== 'close' || entry.applied || !['stale-unobserved', 'claim-expired', 'claim-expired (self-implement.result final; worktree is not live)'].includes(entry.reason)) continue;
73
+ const draft = drafts.get(entry.number);
74
+ if (!draft || !valid(draft.title)) continue;
75
+ candidates.push({ key: `draft:${entry.number}`, kind: 'draft', title: draft.title,
76
+ reason: `draft PR 정체 (${entry.reason})`, source: `#${entry.number}`, score: 200 });
77
+ }
78
+ }
79
+
80
+ const selected = new Map<string, ProactSuggestion>();
81
+ for (const candidate of candidates) {
82
+ if (options.previouslySuggested?.has(candidate.key)) continue;
83
+ if (!selected.has(candidate.key) || selected.get(candidate.key)!.score < candidate.score) selected.set(candidate.key, candidate);
84
+ }
85
+ return [...selected.values()].sort((a, b) => b.score - a.score || a.key.localeCompare(b.key)).slice(0, MAX_SUGGESTIONS);
86
+ }
@@ -28,7 +28,7 @@ export function webPushDecisionTransport(
28
28
  const recommendation = 'skipped' in entry.recommendation ? '추천안 없음' : `추천안: ${entry.recommendation.option.toUpperCase()}`;
29
29
  const body = `${recommendation}${entry.dueAt ? ` · 기한: ${new Intl.DateTimeFormat('ko-KR', { timeZone: 'Asia/Seoul', month: 'numeric', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date(entry.dueAt))}` : ''}`;
30
30
  const result = await push({ title: title('대표 결정 · ', entry.title), body, url: url(id), tag: tag(id) });
31
- debug.log('decisions.webpush', 'card-sent', { id, delivered: result.delivered });
31
+ if (result.attempted) debug.log('decisions.webpush', 'card-sent', { id, delivered: result.delivered });
32
32
  return result.delivered ? { chat: 'webpush', message: id } : null;
33
33
  },
34
34
  edit: async (ref, _view) => {
@@ -22,6 +22,9 @@
22
22
 
23
23
  import { debug } from '../debug/log.js';
24
24
  import { botAudienceFor, gateDiscordSchemas } from '../maturity/bot-command-maturity.js';
25
+ import { buildBotSlashCatalog } from '../maturity/bot-slash-catalog.js';
26
+ import { FEATURE_MATURITY } from '../maturity/feature-maturity.js';
27
+ import { SLASH_COMMANDS } from '../chat/index.js';
25
28
  import type { DiscordBot } from '../discord.js';
26
29
  import {
27
30
  loadLayeredPersonaDirs,
@@ -195,6 +198,19 @@ export async function wireSprint21Runtime(opts: WireSprint21Opts): Promise<Sprin
195
198
  router.bind(statusCommand);
196
199
  router.bind(pollCommand);
197
200
  for (const command of botCommands) router.bind(command);
201
+ const catalog = buildBotSlashCatalog({
202
+ surface: 'discord', coreCommands: SLASH_COMMANDS, maturity: FEATURE_MATURITY,
203
+ handledCommands: router.schemas(),
204
+ });
205
+ for (const entry of catalog.commands) {
206
+ if (entry.supported) continue;
207
+ const { name, description } = entry;
208
+ router.bind({ schema: { name, description }, handler: async () => ({
209
+ type: RESPONSE_CHANNEL_MESSAGE_WITH_SOURCE,
210
+ content: catalog.unsupportedReply(entry.name)!,
211
+ ephemeral: true,
212
+ }) });
213
+ }
198
214
 
199
215
  // 5. Wire bot callbacks — INTERACTION_CREATE + reactions
200
216
  // (Bot must be created with onInteraction/onReaction in opts;
@@ -64,6 +64,8 @@ import { getUserConfig } from './user-config.js';
64
64
  import { detectCard, runCardFollowup, NotACardError } from './card-followup/core.js';
65
65
  import { localOcrText } from './telegram-card-followup.js';
66
66
  import type { runGraph } from './graph-runner/runner.js';
67
+ import { readSlashContextNow, renderTelegramNow } from './context-bus/context-now-surfaces.js';
68
+ import type { ContextNowDeps } from './context-bus/context-now.js';
67
69
 
68
70
  const SLASH_FOCUS_TURNS_DEFAULT = 8;
69
71
 
@@ -139,6 +141,7 @@ export interface DiscordSelfMessageDeps {
139
141
  questionChannelFor?: (channelId: string) => import('./hitl/question.js').QuestionChannel;
140
142
  log?: (msg: string) => void;
141
143
  cardFollowupDeps?: { ocrText?: (path: string) => Promise<string | null>; runGraph?: typeof runGraph; rootDir?: () => string };
144
+ nowDeps?: ContextNowDeps;
142
145
  }
143
146
 
144
147
  /** Compose the full discord self+interweave onMessage handler. */
@@ -356,6 +359,11 @@ export function buildDiscordSelfOnMessage(deps: DiscordSelfMessageDeps): DcMessa
356
359
  // Voice text commands pass the guild gate for the voice adapter's
357
360
  // sake — never route them into the LLM turn (legacy behavior).
358
361
  if (/^\/voice-(join|leave|status)\b/.test(ctx.text.trim())) return undefined;
362
+ const nowCommand = /^[/!]now(?:\s+([\s\S]*))?$/.exec(ctx.text.trim());
363
+ if (nowCommand) {
364
+ const args = nowCommand[1]?.trim().split(/\s+/).filter(Boolean) ?? [];
365
+ return renderTelegramNow(readSlashContextNow(args, deps.nowDeps));
366
+ }
359
367
  if (!ctx.text.trim() && ctx.attachments.length === 1 && ctx.attachments[0]!.contentType?.startsWith('image/')) {
360
368
  const photo = ctx.attachments[0]!;
361
369
  if (detectCard({ width: photo.width, height: photo.height, ocrText: null }).decision !== 'skip') {
@@ -16,12 +16,15 @@
16
16
  // 우회해 도착하므로 여기서 allowlist를 직접 강제한다.
17
17
 
18
18
  import type { UserConfig } from './user-config.js';
19
+ import { SLASH_COMMANDS } from './chat/index.js';
19
20
  import type { DiscordBot, DcIncoming, DcMessageStreamer } from './discord.js';
20
21
  import { makeCommandRest } from './discord/slash-registry.js';
21
22
  import { normalizeInteractionPayload } from './discord/slash-router.js';
22
23
  import type { SlashCommandSchema } from './discord/slash-types.js';
23
24
  import { debug } from './debug/log.js';
24
25
  import { gateDiscordSchemas, readBotAudience } from './maturity/bot-command-maturity.js';
26
+ import { buildBotSlashCatalog } from './maturity/bot-slash-catalog.js';
27
+ import { FEATURE_MATURITY } from './maturity/feature-maturity.js';
25
28
  import { resolveChannelBotToken } from './channel-bot-token.js';
26
29
 
27
30
  const REST_BASE = 'https://discord.com/api/v10';
@@ -42,6 +45,9 @@ export const ELANOUS_SLASH_COMMANDS: readonly SlashCommandSchema[] = [
42
45
  { name: 'file', description: '첨부 (이미지/문서 — 백엔드가 봄)', type: 11, required: false },
43
46
  ] },
44
47
  { name: 'brain', description: '브레인 모드로 복귀 (위임 해제)' },
48
+ { name: 'now', description: '지금 판·칸·결정·자리·최근 맥락 보기', options: [
49
+ { name: 'topic', description: '좁혀 볼 주제 (선택)', type: 3, required: false },
50
+ ] },
45
51
  { name: 'sessions', description: '바인딩된 세션 목록' },
46
52
  { name: 'new', description: '새 세션으로 시작 (이전 대화 보존)' },
47
53
  { name: 'attach', description: '이 채널을 다른 세션에 연결', options: [
@@ -58,6 +64,15 @@ export const ELANOUS_SLASH_COMMANDS: readonly SlashCommandSchema[] = [
58
64
  { name: 'voice-status', description: '보이스 연결 상태' },
59
65
  ] as const;
60
66
 
67
+ /** The native wire keeps its original schemas (including options); only new catalog
68
+ * entries use the core registry's description and the unsupported response. */
69
+ export function discordWireCatalog() {
70
+ return buildBotSlashCatalog({
71
+ surface: 'discord', coreCommands: SLASH_COMMANDS, maturity: FEATURE_MATURITY,
72
+ handledCommands: ELANOUS_SLASH_COMMANDS,
73
+ });
74
+ }
75
+
61
76
  /** SlashInteraction → 기존 텍스트 명령 문장 합성. */
62
77
  export function synthesizeCommandText(
63
78
  commandName: string,
@@ -79,6 +94,10 @@ export function synthesizeCommandText(
79
94
  case 'voice-leave': return '!voice-leave';
80
95
  case 'voice-status': return '!voice-status';
81
96
  case 'sessions': return '!sessions';
97
+ case 'now': {
98
+ const topic = options.get('topic');
99
+ return typeof topic === 'string' && topic.trim() ? `!now ${topic.trim()}` : '!now';
100
+ }
82
101
  case 'new': return '!new';
83
102
  case 'attach': return `!attach ${String(options.get('prefix') ?? '').trim()}`;
84
103
  case 'brain': return '!brain';
@@ -123,8 +142,16 @@ export function buildDiscordSlashWire(deps: DiscordSlashWireDeps): DiscordSlashW
123
142
  const guilds = await (await fetchImpl(`${REST_BASE}/users/@me/guilds`, auth)).json() as Array<{ id: string }>;
124
143
  const rest = makeCommandRest({ token, ...(deps.__fetchImpl ? { fetchImpl: deps.__fetchImpl } : {}) });
125
144
  const audience = readBotAudience((deps.userConfig.raw?.discord as { commandAudience?: unknown } | undefined)?.commandAudience);
126
- const { schemas, hidden } = gateDiscordSchemas(ELANOUS_SLASH_COMMANDS, audience);
127
- debug.log('discord.command', 'menu-filtered', { total: ELANOUS_SLASH_COMMANDS.length, shown: schemas.length - hidden, ...audience });
145
+ const catalog = discordWireCatalog();
146
+ const handled = new Map(ELANOUS_SLASH_COMMANDS.map((schema) => [schema.name, schema]));
147
+ const allSchemas: SlashCommandSchema[] = catalog.commands.map((entry) => {
148
+ const original = handled.get(entry.name);
149
+ if (original) return original;
150
+ const { name, description } = entry;
151
+ return { name, description };
152
+ });
153
+ const { schemas, hidden } = gateDiscordSchemas(allSchemas, audience);
154
+ debug.log('discord.command', 'menu-filtered', { total: allSchemas.length, shown: schemas.length - hidden, ...audience });
128
155
  for (const g of Array.isArray(guilds) ? guilds : []) {
129
156
  const registered = await rest.bulkOverwriteGuild(app.id, g.id, schemas);
130
157
  log(`[slash] registered ${registered.length} commands in guild ${g.id}`);
@@ -180,6 +207,8 @@ export function buildDiscordSlashWire(deps: DiscordSlashWireDeps): DiscordSlashW
180
207
  await ack(it.id, it.token, `이 봇은 <#${deps.channelScope}> 채널 전용입니다.`);
181
208
  return;
182
209
  }
210
+ const unsupported = discordWireCatalog().unsupportedReply(it.commandName);
211
+ if (unsupported) { await ack(it.id, it.token, unsupported); return; }
183
212
  const text = synthesizeCommandText(it.commandName, it.options);
184
213
  const attachments = resolvedAttachments(raw);
185
214
  await ack(it.id, it.token, `▶ \`${text}\`${attachments.length ? ` (+첨부 ${attachments.length})` : ''}`);