elanous 0.2.10 → 0.2.11

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 (584) 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/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
  7. package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
  20. package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
  25. package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-b12b6d2f8d2d1aea.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/morning/page-35414e0a007b4082.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
  105. package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
  106. package/apps/pwa/out/approvals/index.html +1 -1
  107. package/apps/pwa/out/approvals/index.txt +23 -23
  108. package/apps/pwa/out/autopilot/index.html +1 -1
  109. package/apps/pwa/out/autopilot/index.txt +23 -23
  110. package/apps/pwa/out/board/index.html +1 -1
  111. package/apps/pwa/out/board/index.txt +23 -23
  112. package/apps/pwa/out/botlab/index.html +1 -1
  113. package/apps/pwa/out/botlab/index.txt +22 -22
  114. package/apps/pwa/out/bots/index.html +1 -1
  115. package/apps/pwa/out/bots/index.txt +22 -22
  116. package/apps/pwa/out/chat/index.html +1 -1
  117. package/apps/pwa/out/chat/index.txt +22 -22
  118. package/apps/pwa/out/consult/index.html +1 -1
  119. package/apps/pwa/out/consult/index.txt +23 -23
  120. package/apps/pwa/out/control/index.html +1 -1
  121. package/apps/pwa/out/control/index.txt +23 -23
  122. package/apps/pwa/out/design-check/index.html +1 -1
  123. package/apps/pwa/out/design-check/index.txt +23 -23
  124. package/apps/pwa/out/editor/index.html +1 -1
  125. package/apps/pwa/out/editor/index.txt +23 -23
  126. package/apps/pwa/out/exec/index.html +1 -1
  127. package/apps/pwa/out/exec/index.txt +23 -23
  128. package/apps/pwa/out/field/index.html +1 -1
  129. package/apps/pwa/out/field/index.txt +23 -23
  130. package/apps/pwa/out/healthz +1 -1
  131. package/apps/pwa/out/index.html +1 -1
  132. package/apps/pwa/out/index.txt +22 -22
  133. package/apps/pwa/out/inside/index.html +1 -0
  134. package/apps/pwa/out/inside/index.txt +31 -0
  135. package/apps/pwa/out/intake/index.html +1 -1
  136. package/apps/pwa/out/intake/index.txt +23 -23
  137. package/apps/pwa/out/live/index.html +1 -1
  138. package/apps/pwa/out/live/index.txt +23 -23
  139. package/apps/pwa/out/market/index.html +1 -1
  140. package/apps/pwa/out/market/index.txt +22 -22
  141. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  142. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  143. package/apps/pwa/out/morning/index.html +1 -1
  144. package/apps/pwa/out/morning/index.txt +23 -23
  145. package/apps/pwa/out/observatory/index.html +1 -1
  146. package/apps/pwa/out/observatory/index.txt +23 -23
  147. package/apps/pwa/out/ops/checklist/index.html +1 -1
  148. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  149. package/apps/pwa/out/ops/release/index.html +1 -1
  150. package/apps/pwa/out/ops/release/index.txt +22 -22
  151. package/apps/pwa/out/ops/seats/index.html +1 -1
  152. package/apps/pwa/out/ops/seats/index.txt +22 -22
  153. package/apps/pwa/out/outputs/index.html +1 -0
  154. package/apps/pwa/out/outputs/index.txt +30 -0
  155. package/apps/pwa/out/reflection/index.html +1 -1
  156. package/apps/pwa/out/reflection/index.txt +23 -23
  157. package/apps/pwa/out/scheduler/index.html +1 -1
  158. package/apps/pwa/out/scheduler/index.txt +23 -23
  159. package/apps/pwa/out/sessions/index.html +1 -1
  160. package/apps/pwa/out/sessions/index.txt +22 -22
  161. package/apps/pwa/out/settings/devices/index.html +1 -1
  162. package/apps/pwa/out/settings/devices/index.txt +23 -23
  163. package/apps/pwa/out/settings/index.html +1 -1
  164. package/apps/pwa/out/settings/index.txt +23 -23
  165. package/apps/pwa/out/setup/done/index.html +1 -1
  166. package/apps/pwa/out/setup/done/index.txt +23 -23
  167. package/apps/pwa/out/setup/index.html +1 -1
  168. package/apps/pwa/out/setup/index.txt +23 -23
  169. package/apps/pwa/out/share/index.html +1 -1
  170. package/apps/pwa/out/share/index.txt +23 -23
  171. package/apps/pwa/out/showroom/index.html +1 -1
  172. package/apps/pwa/out/showroom/index.txt +22 -22
  173. package/apps/pwa/out/tasks/index.html +1 -1
  174. package/apps/pwa/out/tasks/index.txt +23 -23
  175. package/apps/pwa/out/term/index.html +1 -1
  176. package/apps/pwa/out/term/index.txt +23 -24
  177. package/apps/pwa/out/today/index.html +1 -1
  178. package/apps/pwa/out/today/index.txt +23 -23
  179. package/apps/pwa/out/trace/index.html +1 -1
  180. package/apps/pwa/out/trace/index.txt +23 -23
  181. package/apps/pwa/out/vault/index.html +1 -1
  182. package/apps/pwa/out/vault/index.txt +23 -23
  183. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  184. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  185. package/apps/pwa/out/workflows/index.html +1 -1
  186. package/apps/pwa/out/workflows/index.txt +23 -23
  187. package/apps/pwa/out/workspace/index.html +1 -1
  188. package/apps/pwa/out/workspace/index.txt +23 -24
  189. package/apps/pwa/out/worktrees/index.html +1 -1
  190. package/apps/pwa/out/worktrees/index.txt +23 -23
  191. package/graphs/drafts/draft-cleanup.yaml +19 -0
  192. package/graphs/drafts/recipes.yaml +23 -0
  193. package/graphs/intake/intake-daily.yaml +2 -1
  194. package/graphs/ops/recipes.yaml +3 -0
  195. package/graphs/ops/secret-exposure.yaml +24 -0
  196. package/graphs/release/recipes.yaml +3 -0
  197. package/graphs/release/release-loop.yaml +4 -1
  198. package/graphs/video/explainer-line.yaml +2 -2
  199. package/package.json +2 -1
  200. package/plugins/elanous-hwp/README.md +25 -0
  201. package/plugins/elanous-hwp/cli.ts +22 -0
  202. package/plugins/elanous-hwp/converter.ts +237 -0
  203. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  204. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  205. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  206. package/plugins/elanous-hwp/plugin.json +16 -0
  207. package/plugins/elanous-hwp/plugin.ts +40 -0
  208. package/scripts/ci-public-export-leak-gate.ts +75 -14
  209. package/scripts/ci-public-leak-gate.ts +44 -9
  210. package/scripts/context-hooks/claude-stop.sh +4 -0
  211. package/scripts/context-hooks/emit.ts +24 -0
  212. package/scripts/context-hooks/post-tool-use.sh +4 -0
  213. package/scripts/coord-channel-watch.sh +12 -0
  214. package/scripts/coord-requests-bridge.ts +143 -0
  215. package/scripts/field-feed/lib.ts +4 -0
  216. package/scripts/fleet/node-setup.sh +20 -3
  217. package/scripts/homebrew-formula-bump.ts +69 -0
  218. package/scripts/marketing/measure-site-numbers.ts +169 -0
  219. package/scripts/measure-gate-shards.ts +309 -0
  220. package/scripts/mission-request-judge.ts +31 -1
  221. package/scripts/morning-report.ts +2 -2
  222. package/scripts/opportunity-scan.ts +1 -1
  223. package/scripts/release-loop/auto-approve-node.ts +21 -4
  224. package/scripts/release-loop/cut-branch.ts +84 -0
  225. package/scripts/release-loop/gate-node.ts +14 -13
  226. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  227. package/scripts/release-loop/node-verdict.ts +3 -3
  228. package/scripts/release-loop/tui-node-checks.ts +42 -0
  229. package/scripts/release-loop/tui-sim-node.ts +32 -8
  230. package/scripts/release-loop/unattended-release.ts +5 -3
  231. package/scripts/release-loop/version-node.ts +61 -10
  232. package/scripts/signal-digest-cycle.ts +2 -7
  233. package/scripts/signal-digest-photo.ts +11 -0
  234. package/scripts/tech1-public-measure.ts +94 -0
  235. package/scripts/test-diet/node.ts +1 -1
  236. package/scripts/tui-regress.ts +2 -2
  237. package/scripts/ux/demo-rehearsal.ts +243 -0
  238. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  239. package/skills/diagram-master/SKILL.md +366 -0
  240. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  241. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  242. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  243. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  244. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  245. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  246. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  247. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  248. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  249. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  250. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  251. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  252. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  253. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  254. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  255. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  256. package/skills/diagram-master/references/examples/README.md +69 -0
  257. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  258. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  259. package/skills/diagram-master/references/pyproject.toml +16 -0
  260. package/skills/diagram-master/references/quality-checklist.md +33 -0
  261. package/skills/diagram-master/references/routing-guide.md +164 -0
  262. package/skills/diagram-master/references/uv.lock +1356 -0
  263. package/skills/google-workspace/SKILL.md +33 -0
  264. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  265. package/skills/grill-me/SKILL.md +1 -1
  266. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  267. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  268. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  269. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  270. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  271. package/skills/omni-crawl/SKILL.md +21 -11
  272. package/skills/omni-crawl/scripts/main.ts +6 -6
  273. package/skills/omni-crawl/src/router.ts +3 -3
  274. package/skills/omni-digest/SKILL.md +17 -9
  275. package/skills/omni-digest/digest.md +2 -2
  276. package/skills/omni-digest/src/fetch.ts +30 -3
  277. package/skills/pitch-deck/SKILL.md +2 -2
  278. package/skills/pitch-deck/template.html +2 -2
  279. package/skills/youtube-master/SKILL.md +163 -0
  280. package/skills/youtube-master/package-lock.json +558 -0
  281. package/skills/youtube-master/package.json +13 -0
  282. package/skills/youtube-master/references/study-note-template.md +124 -0
  283. package/skills/youtube-master/scripts/main.ts +435 -0
  284. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  285. package/skills/youtube-master/src/audio.ts +63 -0
  286. package/skills/youtube-master/src/domain-staging.ts +50 -0
  287. package/skills/youtube-master/src/env.ts +36 -0
  288. package/skills/youtube-master/src/obsidian.ts +155 -0
  289. package/skills/youtube-master/src/router.ts +110 -0
  290. package/skills/youtube-master/src/stt.ts +199 -0
  291. package/skills/youtube-master/src/study-note.ts +175 -0
  292. package/skills/youtube-master/src/summarize.ts +358 -0
  293. package/skills/youtube-master/src/transcript.ts +76 -0
  294. package/skills/youtube-master/src/types.ts +91 -0
  295. package/skills/youtube-master/src/util.ts +93 -0
  296. package/skills/youtube-master/src/youtube.ts +70 -0
  297. package/skills/youtube-master/tsconfig.json +13 -0
  298. package/src/acp/server.ts +5 -2
  299. package/src/agent-mission/driver.ts +80 -10
  300. package/src/agent-mission/pty-decision.ts +71 -0
  301. package/src/agent-mission/review-loop.ts +30 -0
  302. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  303. package/src/autopilot/tool-registry.ts +2 -0
  304. package/src/boot/daemon-prompt-turn.ts +5 -0
  305. package/src/boot/daemon-runtime.ts +9 -3
  306. package/src/boot/daemon-tools/web-search.ts +3 -0
  307. package/src/card-followup/core.ts +109 -0
  308. package/src/chat/index.ts +1 -0
  309. package/src/cli/drive-input-jail.ts +101 -0
  310. package/src/cli/hooks-cli.ts +17 -3
  311. package/src/cli/make-cli.ts +43 -0
  312. package/src/cli/persona-cli.ts +90 -4
  313. package/src/cli/plugin-cli.ts +31 -22
  314. package/src/cli/pod-cli.ts +19 -9
  315. package/src/cli/pr-cli.ts +51 -15
  316. package/src/cli/pty-drive-cli.ts +41 -7
  317. package/src/cli/pty-drive-verdict.ts +40 -0
  318. package/src/cli/release-cli.ts +17 -4
  319. package/src/cli/setup-cli.ts +43 -1
  320. package/src/cli/skills-cli.ts +17 -1
  321. package/src/context-bus/claude-hooks-install.ts +10 -0
  322. package/src/context-bus/context-now-surfaces.ts +48 -0
  323. package/src/context-bus/context-now.ts +104 -0
  324. package/src/context-bus/coord-events.ts +2 -2
  325. package/src/context-bus/external-events.ts +52 -0
  326. package/src/context-bus/long-term-memory.ts +108 -0
  327. package/src/dashboard/index.ts +9 -4
  328. package/src/dashboard/slash-runtime/dashboard-handlers.ts +7 -1
  329. package/src/decisions/decision-cards.ts +10 -3
  330. package/src/decisions/decision-ledger.ts +13 -5
  331. package/src/discord/sprint21-runtime.ts +5 -1
  332. package/src/discord-self-message.ts +32 -0
  333. package/src/discord-slash-wire.ts +5 -1
  334. package/src/discord.ts +17 -1
  335. package/src/domains/core-tools.ts +3 -2
  336. package/src/domains/outbound-alert.ts +6 -1
  337. package/src/domains/telegram-kind-route.ts +51 -13
  338. package/src/exec-requests/default-outputs.ts +25 -0
  339. package/src/exec-requests/planner.ts +10 -2
  340. package/src/exec-requests/runner.ts +20 -6
  341. package/src/exec-requests/store.ts +3 -0
  342. package/src/execution-loop/launch-gate.ts +100 -0
  343. package/src/field/field-reel.ts +5 -1
  344. package/src/field-note/index.ts +201 -0
  345. package/src/field-note/transcribe.ts +248 -0
  346. package/src/graph-kinds/registry.ts +3 -3
  347. package/src/graph-runner/graph-cli.ts +61 -1
  348. package/src/graph-runner/graph-grow-llm.ts +37 -0
  349. package/src/graph-runner/graph-grow.ts +47 -0
  350. package/src/graph-runner/runner.ts +317 -25
  351. package/src/grok/agent-search.ts +8 -2
  352. package/src/guardian/secret-exposure-scan.ts +101 -0
  353. package/src/harness/harness-cli-command.ts +247 -7
  354. package/src/harness/harness-pod-dispatch.ts +43 -23
  355. package/src/harness/harness-seams.ts +38 -4
  356. package/src/harness/harness-stop.ts +23 -4
  357. package/src/harness/launch-registry.ts +91 -0
  358. package/src/harness/process-garbage.ts +5 -3
  359. package/src/hooks/dispatch.ts +82 -0
  360. package/src/hooks/expose.ts +254 -0
  361. package/src/hooks/github-shadow.ts +108 -0
  362. package/src/hooks/providers.ts +71 -5
  363. package/src/hooks/queue.ts +1 -1
  364. package/src/hooks/receiver.ts +21 -20
  365. package/src/index.ts +52 -14
  366. package/src/intake-plane/categorize.ts +18 -46
  367. package/src/intake-plane/discord-seat-work.ts +10 -0
  368. package/src/intake-plane/front-route-classifier.ts +33 -39
  369. package/src/intake-plane/persona-answer.ts +30 -0
  370. package/src/intake-plane/runtime-callables.ts +8 -1
  371. package/src/intake-plane/telegram-seat-work.ts +36 -2
  372. package/src/intake-plane/wish-folder.ts +67 -0
  373. package/src/intent-gate/gate.ts +30 -10
  374. package/src/live/detail-switch.ts +5 -0
  375. package/src/llm/difficulty.ts +57 -0
  376. package/src/llm/judge-layer.ts +101 -0
  377. package/src/llm/mission-router.ts +33 -19
  378. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  379. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  380. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  381. package/src/loops/contract/loop-agent.schema.json +138 -0
  382. package/src/loops/contract/validate.ts +64 -0
  383. package/src/loops/registry.ts +20 -6
  384. package/src/market/signed-index.ts +4 -0
  385. package/src/maturity/bot-command-maturity.ts +45 -0
  386. package/src/maturity/feature-maturity.ts +26 -4
  387. package/src/model-tier/index.ts +2 -2
  388. package/src/model-tier/tier-resolver.ts +20 -20
  389. package/src/model-tier/types.ts +6 -6
  390. package/src/mss/logging/log-store.ts +15 -0
  391. package/src/nexus/api/config-model-tier.ts +5 -4
  392. package/src/nexus/api/fabric-plans.ts +53 -0
  393. package/src/nexus/api/harness-api.ts +5 -1
  394. package/src/nexus/api/health.ts +2 -0
  395. package/src/nexus/api/http-server.ts +36 -0
  396. package/src/nexus/api/inside-events.ts +226 -0
  397. package/src/nexus/api/meta-api.ts +21 -8
  398. package/src/nexus/api/missions.ts +6 -1
  399. package/src/nexus/api/ops-seats.ts +33 -0
  400. package/src/nexus/api/outputs-route.ts +44 -0
  401. package/src/nexus/api/seat-requests.ts +44 -2
  402. package/src/nexus/api/sessions-store.ts +17 -38
  403. package/src/nexus/api/sub-seat-charters.ts +34 -0
  404. package/src/nexus/api/tabs-mutations.ts +3 -1
  405. package/src/nexus/api/trace.ts +18 -6
  406. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  407. package/src/nexus/api/workflows.ts +80 -6
  408. package/src/nexus/index.ts +2 -0
  409. package/src/nexus/kinds/webterm.ts +2 -1
  410. package/src/nexus/webterm/pty.ts +6 -2
  411. package/src/onboarding/cli-auth-status.ts +80 -0
  412. package/src/onboarding/voice-ai.ts +3 -3
  413. package/src/org/seat-budget.ts +48 -0
  414. package/src/org/stall-escalation.ts +63 -0
  415. package/src/outputs/ledger.ts +120 -0
  416. package/src/persona/persona-todo.ts +79 -0
  417. package/src/persona/presets.ts +116 -2
  418. package/src/persona/team-set.ts +155 -0
  419. package/src/plugins/install/plugin-install.ts +14 -0
  420. package/src/plugins/maker/market-bundle.ts +109 -0
  421. package/src/plugins/maker/plugin-maker.ts +254 -11
  422. package/src/plugins/maker/wizard-generate.ts +103 -0
  423. package/src/pod-lease/admission.ts +150 -0
  424. package/src/pod-lease/dependency-state.ts +85 -0
  425. package/src/pod-lease/host-lease.ts +127 -0
  426. package/src/project/project-suggestion.ts +16 -0
  427. package/src/project/session-context.ts +24 -0
  428. package/src/release-loop/checklist.ts +2 -2
  429. package/src/release-loop/feature-store.ts +5 -3
  430. package/src/release-loop/next-md-merge.ts +58 -0
  431. package/src/release-loop/release-note.ts +59 -4
  432. package/src/seat-dispatch/seat-ask.ts +130 -0
  433. package/src/seat-dispatch/seat-questions.ts +100 -0
  434. package/src/seat-loop/seat-loop.ts +548 -29
  435. package/src/seat-loop/seat-report.ts +37 -2
  436. package/src/self-dev/dev-cli.ts +4 -1
  437. package/src/self-dev/dev-pipeline.ts +37 -1
  438. package/src/self-dev/draft-sweep.ts +38 -33
  439. package/src/self-dev/draft-triage-rules.ts +8 -5
  440. package/src/self-dev/fabric-plan-core.ts +297 -0
  441. package/src/self-dev/orchestrate.ts +36 -4
  442. package/src/self-dev/release-path-guard.ts +62 -0
  443. package/src/self-dev/shard-aggregate.ts +230 -0
  444. package/src/self-dev/shard-placement.ts +60 -0
  445. package/src/self-dev/shard-plan.ts +48 -0
  446. package/src/self-dev/shard-pod-run.ts +77 -0
  447. package/src/self-dev/shard-run.ts +105 -0
  448. package/src/self-implement/gate-baseline.ts +1 -1
  449. package/src/self-implement/gate-cli.ts +40 -1
  450. package/src/self-implement/gate-scope.ts +37 -7
  451. package/src/self-implement/graph-variant.ts +171 -0
  452. package/src/self-implement/harness-policy-gates.ts +1 -1
  453. package/src/self-implement/headless-elanous-driver.ts +22 -3
  454. package/src/self-implement/host-regate.ts +22 -1
  455. package/src/self-implement/importer-test-index.ts +2 -1
  456. package/src/self-implement/l8-merge-queue.ts +130 -0
  457. package/src/self-implement/orchestrator.ts +242 -9
  458. package/src/self-implement/route-consumer-test-index.ts +122 -0
  459. package/src/self-implement/seams.ts +72 -11
  460. package/src/self-implement/test-seams.ts +1 -0
  461. package/src/self-implement/uncommitted-work.ts +59 -0
  462. package/src/session/index.ts +36 -13
  463. package/src/skills/gift-install.ts +215 -0
  464. package/src/skills/tools/web-search.ts +4 -1
  465. package/src/steward/launch.ts +42 -26
  466. package/src/steward/steward-cards.ts +17 -9
  467. package/src/steward/triage.ts +46 -14
  468. package/src/task-cards/card-cli.ts +25 -1
  469. package/src/task-orchestrator/mission.ts +5 -0
  470. package/src/task-orchestrator/store.ts +12 -3
  471. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  472. package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
  473. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  474. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  475. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  476. package/src/task-orchestrator/types.ts +2 -0
  477. package/src/telegram-card-followup.ts +16 -96
  478. package/src/telegram-commands.ts +10 -1
  479. package/src/telegram-project-command.ts +71 -0
  480. package/src/telegram-report.ts +21 -17
  481. package/src/telegram.ts +29 -3
  482. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  483. package/src/user-config.ts +102 -20
  484. package/src/version/packed-revision.json +1 -1
  485. package/src/web-search/grok.ts +7 -1
  486. package/src/web-search/index.ts +28 -1
  487. package/src/web-search/provider.ts +4 -0
  488. package/src/web-search/x-intent.ts +5 -0
  489. package/src/workflow-runtime/executor.ts +277 -47
  490. package/src/workflow-runtime/index.ts +1 -0
  491. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  492. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  493. package/src/workflow-runtime/schema.ts +79 -4
  494. package/src/workflow-runtime/types.ts +35 -4
  495. package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  505. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  506. package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
  525. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  583. package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
  584. /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -1,13 +1,13 @@
1
- import { chmodSync, mkdirSync, readFileSync, readdirSync, rmSync } from 'node:fs';
1
+ import { chmodSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
2
2
  import { spawn } from 'node:child_process';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { randomUUID } from 'node:crypto';
5
5
  import { debug } from './debug/log.js';
6
6
  import { effectiveInstanceRoot } from './instance/resolve.js';
7
- import { lastJsonObject, runGraph, type GraphRunState } from './graph-runner/runner.js';
7
+ import { runGraph } from './graph-runner/runner.js';
8
+ import { cardShape, detectCard, runCardFollowup, NotACardError, type CardDetectDecision } from './card-followup/core.js';
8
9
  import type { TgIncoming } from './telegram.js';
9
10
 
10
- const GRAPH = resolve(import.meta.dir, '../plugins/card-followup/graphs/card-followup.yaml');
11
11
  // Latin keywords are whole words only — «postcard» or «cardinal» is not a card request (review round 3).
12
12
  const KEYWORD = /명함|전략|메일\s*초안|초안|팔로업|\bcard\b|\bCRM\b/i;
13
13
  /** Untagged albums start one graph run, not one per photo (chatId:mediaGroupId → first seen at). */
@@ -22,30 +22,7 @@ function firstOfAlbum(chatId: number, mediaGroupId: string | undefined, now: num
22
22
  return true;
23
23
  }
24
24
 
25
- // Captionless photos start a run only when they look like a business card (OP 10-02 18:54 · cheap signals first, ambiguous → nothing).
26
- export type CardDetectDecision = 'card' | 'skip' | 'ambiguous';
27
- export function cardShape(width?: number, height?: number): { decision: 'skip' | 'pass'; signal: string } {
28
- if (!width || !height) return { decision: 'pass', signal: 'ratio:unknown' };
29
- const ratio = Math.max(width, height) / Math.min(width, height);
30
- if (ratio < 1.15) return { decision: 'skip', signal: 'ratio:square' };
31
- if (ratio > 2.0) return { decision: 'skip', signal: 'ratio:screenshot' };
32
- return { decision: 'pass', signal: `ratio:${ratio.toFixed(2)}` };
33
- }
34
- const EMAIL = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i;
35
- const PHONE = /(?:\+?\d{1,3}[\s.-]?)?\(?\d{2,4}\)?[\s.-]?\d{3,4}[\s.-]?\d{4}/;
36
- const WEB = /\b(?:https?:\/\/|www\.)\S+|\b[a-z0-9-]+\.(?:com|co\.kr|kr|io|ai|net|org)\b/i;
37
- const TITLE = /대표|이사|팀장|부장|과장|실장|매니저|주식회사|\(주\)|\b(?:CEO|CTO|COO|CFO|Director|Manager|Founder|Inc|Ltd|Corp)\b/i;
38
- /** Card text is short and carries contact patterns; long text is a document. Returns signal names only, never the text. */
39
- export function cardText(ocr: string | null): { decision: CardDetectDecision; signal: string } {
40
- if (ocr === null) return { decision: 'ambiguous', signal: 'ocr:unavailable' };
41
- const chars = ocr.replace(/\s+/g, '').length;
42
- if (chars < 15) return { decision: 'ambiguous', signal: `ocr:chars<15` };
43
- if (chars > 700) return { decision: 'skip', signal: 'ocr:document' };
44
- const hits = ([['email', EMAIL], ['phone', PHONE], ['web', WEB], ['title', TITLE]] as const).filter(([, re]) => re.test(ocr)).map(([name]) => name);
45
- const signal = `ocr:${hits.join(',') || 'none'}`;
46
- if (hits.length >= 2) return { decision: 'card', signal };
47
- return { decision: hits.length === 0 ? 'skip' : 'ambiguous', signal };
48
- }
25
+ export { cardShape, cardText } from './card-followup/core.js';
49
26
  const OCR_SCRIPT = resolve(import.meta.dir, '../scripts/ocr-text-regions.swift');
50
27
  /** Local macOS Vision OCR (no network · no new dependency); null where it cannot run. */
51
28
  export function localOcrText(path: string, timeoutMs = 30_000): Promise<string | null> {
@@ -78,36 +55,6 @@ export interface CardPhotoDeps {
78
55
  ocrText?: (path: string) => Promise<string | null>;
79
56
  }
80
57
 
81
- const obj = (value: unknown): Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {};
82
- const text = (value: unknown): string => typeof value === 'string' ? value.trim() : '';
83
- const line = (value: unknown): string => (typeof value === 'number' && Number.isFinite(value) ? String(value) : text(value)).replace(/[\r\n]+/g, ' ') || '—';
84
-
85
- function isNotACard(state: GraphRunState): boolean {
86
- if (state.status !== 'failed') return false;
87
- const read = state.nodes.find((node) => node.nodeId === 'read-card');
88
- if (!read || !read.ok) return false;
89
- const output = lastJsonObject(read.output);
90
- if (output?.outcome === 'ok' && output.card && typeof output.card === 'object') {
91
- const card = obj(output.card);
92
- return !['name', 'company', 'title', 'email', 'phone', 'url', 'linkedin'].some((field) => text(card[field]));
93
- }
94
- return output?.outcome === 'fail' && typeof output.reason === 'string'
95
- && /\bnot a (?:business )?card\b|명함이?\s*아님|명함이?\s*아닙니다/i.test(output.reason);
96
- }
97
-
98
- function validateReport(report: Record<string, unknown>): void {
99
- const card = obj(report.card), fit = obj(report.fit), approach = obj(report.approach);
100
- const next = obj(report.nextAction), draft = obj(report.draft);
101
- const score = fit.score;
102
- if (report.sent !== false || !text(card.name) || !text(card.company)
103
- || !(score === null || (typeof score === 'number' && Number.isFinite(score)))
104
- || !text(fit.label) || !text(approach.problem) || !text(approach.proposal)
105
- || !text(approach.channel) || !text(next.what) || !text(next.due)
106
- || !text(draft.subject) || !text(draft.body)) {
107
- throw new Error('incomplete or sent card report');
108
- }
109
- }
110
-
111
58
  function pick(caption: string): Picked {
112
59
  if (/\bCRM\b/i.test(caption)) return 'crm';
113
60
  if (/메일\s*초안|초안/i.test(caption)) return 'draft';
@@ -149,7 +96,7 @@ export async function maybeHandleCardPhoto(ctx: TgIncoming, deps: CardPhotoDeps)
149
96
  const { localPath } = await deps.downloadFile(photo.fileId, dir);
150
97
  chmodSync(localPath, 0o600);
151
98
  if (!caption) {
152
- const verdict = cardText(await (deps.ocrText ?? localOcrText)(localPath));
99
+ const verdict = detectCard({ width: photo.width, height: photo.height, ocrText: await (deps.ocrText ?? localOcrText)(localPath) });
153
100
  detect(verdict.decision, verdict.signal);
154
101
  if (verdict.decision !== 'card') { rmSync(dir, { recursive: true, force: true }); return null; }
155
102
  }
@@ -166,38 +113,22 @@ export async function maybeHandleCardPhoto(ctx: TgIncoming, deps: CardPhotoDeps)
166
113
  try { localPath = await prepare(); } catch { log('failed'); return; }
167
114
  if (!localPath) return;
168
115
  }
169
- const state = await (deps.runGraph ?? runGraph)(GRAPH, { runId, deps: { root }, input: {
170
- image: localPath!, outDir: dir, ...(caption ? { context: caption } : {}),
171
- } });
172
- if (!deps.runGraph) {
173
- const statePath = join(base, `${runId}.json`);
174
- chmodSync(statePath, 0o600);
175
- const contexts = `${statePath}.contexts`;
176
- try {
177
- chmodSync(contexts, 0o700);
178
- for (const file of readdirSync(contexts)) chmodSync(join(contexts, file), 0o600);
179
- } catch (error) {
180
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
181
- }
182
- }
183
- if (isNotACard(state)) {
184
- log('not-a-card');
185
- return;
116
+ let result;
117
+ try {
118
+ result = await runCardFollowup({ imagePath: localPath!, ocrText: null,
119
+ runGraph: deps.runGraph ?? runGraph, rootDir: root, outDir: dir, runId,
120
+ ...(caption ? { context: caption } : {}),
121
+ });
122
+ } catch (error) {
123
+ if (error instanceof NotACardError) { log('not-a-card'); return; }
124
+ throw error;
186
125
  }
187
- if (state.status !== 'done') throw new Error('graph did not finish');
188
- const report = obj(JSON.parse(readFileSync(join(dir, 'followup.json'), 'utf8')));
189
- validateReport(report);
190
- const card = obj(report.card), fit = obj(report.fit), approach = obj(report.approach);
191
- const next = obj(report.nextAction), draft = obj(report.draft);
192
- const summary = `① 요약\n${line(card.name)} · ${line(card.company)} · ${line(card.title)}\n타겟 판정: ${line(fit.score)} · ${line(fit.label)}`;
193
- const strategy = `② 전략\n${[approach.problem, approach.proposal, approach.channel].map(line).join('\n')}\n다음 행동: ${line(next.what)} · ${line(next.due)}`;
194
- const mail = `③ 팔로업 초안 (보내지 않았습니다)\n제목: ${line(draft.subject)}\n${text(draft.body)}`;
195
- const markdown = readFileSync(join(dir, 'followup.md'));
126
+ const markdown = readFileSync(result.followupPath!);
196
127
  const crmLine = picked === 'crm'
197
128
  ? /^## ② CRM 한 줄\r?\n파일: [^\r\n]*\r?\n([^\r\n]+)/m.exec(markdown.toString('utf8'))?.[1]
198
129
  : undefined;
199
130
  if (picked === 'crm' && !crmLine) throw new Error('CRM row missing from report');
200
- const messages = picked === 'strategy' ? [strategy] : picked === 'draft' ? [mail] : picked === 'crm' ? [`CRM 한 줄\n${crmLine}`] : [summary, strategy, mail];
131
+ const messages = picked === 'strategy' ? [result.replies[1]] : picked === 'draft' ? [result.replies[2]] : picked === 'crm' ? [`CRM 한 줄\n${crmLine}`] : result.replies;
201
132
  for (const message of messages) await deps.sendMessage(ctx.chatId, message, reply);
202
133
  const sent = await deps.sendDocument(ctx.chatId, markdown, 'followup.md', { ...reply, mimeType: 'text/markdown' });
203
134
  if (sent === undefined) throw new Error('document delivery failed');
@@ -207,17 +138,6 @@ export async function maybeHandleCardPhoto(ctx: TgIncoming, deps: CardPhotoDeps)
207
138
  try {
208
139
  await deps.sendMessage(ctx.chatId, '명함 정리에 실패했습니다. 다시 시도해 주세요.', reply);
209
140
  } catch { /* Telegram delivery itself failed; the failure is already observed. */ }
210
- } finally {
211
- if (!deps.runGraph) {
212
- // The runner may throw before returning its state; seal any partial state and contexts too.
213
- const statePath = join(base, `${runId}.json`);
214
- try { chmodSync(statePath, 0o600); } catch { /* no state yet */ }
215
- const contexts = `${statePath}.contexts`;
216
- try {
217
- chmodSync(contexts, 0o700);
218
- for (const file of readdirSync(contexts)) chmodSync(join(contexts, file), 0o600);
219
- } catch { /* no contexts yet */ }
220
- }
221
141
  }
222
142
  })();
223
143
  } catch {
@@ -44,6 +44,9 @@ import { readDaemonSessionHistory } from './telegram/daemon-history-reader.js';
44
44
  import { renderTelegramReplayPreviewHtml } from './telegram/replay-preview.js';
45
45
  import { classifyIntake } from './ad-pipeline/intake.js';
46
46
  import { createAdPipelineDeps, runAdPipeline } from './ad-pipeline/run.js';
47
+ import { projectCommand } from './telegram-project-command.js';
48
+ import { telegramNowSlash } from './context-bus/context-now-surfaces.js';
49
+ import type { ContextNowDeps } from './context-bus/context-now.js';
47
50
 
48
51
  /** How many prior user/assistant turns to pass into `executeSkill` as
49
52
  * the `## Recent conversation` block. Mirrors the dashboard default
@@ -291,7 +294,7 @@ function dropChatSessionReply(ctx: TgIncoming): string {
291
294
  /** Build the default command set for a Telegram bot wired via
292
295
  * botFromConfig. Returns the array rather than mutating globals so
293
296
  * tests can construct a variant set with stubbed handlers. */
294
- export function defaultTelegramCommands(): TgSlashCommand[] {
297
+ export function defaultTelegramCommands(nowDeps?: ContextNowDeps): TgSlashCommand[] {
295
298
  return [
296
299
  {
297
300
  name: 'help',
@@ -304,6 +307,11 @@ export function defaultTelegramCommands(): TgSlashCommand[] {
304
307
  return lines.join('\n');
305
308
  },
306
309
  },
310
+ {
311
+ name: 'now',
312
+ description: 'Show current release, decisions, seats and context: /now [topic]',
313
+ handler: async (args) => telegramNowSlash(args, nowDeps),
314
+ },
307
315
  {
308
316
  name: 'status',
309
317
  description: 'Show bot identity, current session, provider + model',
@@ -581,6 +589,7 @@ export function defaultTelegramCommands(): TgSlashCommand[] {
581
589
  return lines.join('\n');
582
590
  },
583
591
  },
592
+ projectCommand(),
584
593
  {
585
594
  name: 'fork',
586
595
  description: 'Fork the current chat session (or /fork <prefix>) and continue HERE on the fork · time-travel: /fork before:N',
@@ -0,0 +1,71 @@
1
+ import { debug } from './debug/log.js';
2
+ import { getProject, listProjects, type Project } from './project/project-store.js';
3
+ import { findSessionByTelegramChat, updateSessionMeta } from './session/index.js';
4
+ import type { TgSlashCommand } from './telegram-commands.js';
5
+
6
+ export interface TelegramProjectCommandDeps {
7
+ list: () => Project[];
8
+ find: (id: string) => Project | null;
9
+ update: typeof updateSessionMeta;
10
+ findSession: typeof findSessionByTelegramChat;
11
+ }
12
+
13
+ export function projectCommand(deps: TelegramProjectCommandDeps = {
14
+ list: listProjects,
15
+ find: getProject,
16
+ update: updateSessionMeta,
17
+ findSession: findSessionByTelegramChat,
18
+ }): TgSlashCommand {
19
+ return {
20
+ name: 'project',
21
+ description: '이 대화의 프로젝트 보기·옮기기',
22
+ handler: async (args, ctx) => {
23
+ const session = deps.findSession(ctx.chatId, ctx.threadId, ctx.botId);
24
+ if (!session) {
25
+ debug.log('telegram.project', 'rejected', { projects: [], reason: 'no-session' });
26
+ return '아직 이 채팅에 대화가 없습니다 — 한 마디 보낸 뒤 다시';
27
+ }
28
+
29
+ if (args.length === 0) {
30
+ const current = session.projectId ? deps.find(session.projectId) : null;
31
+ const projects = deps.list().sort((a, b) => a.name.localeCompare(b.name)).slice(0, 20);
32
+ debug.log('telegram.project', 'listed', { projects: projects.map(p => ({ id: p.id, name: p.name })) });
33
+ return [
34
+ `지금 대화의 프로젝트: ${current?.name ?? '받은 대화(프로젝트 없음)'}`,
35
+ '',
36
+ '프로젝트 목록:',
37
+ ...projects.map(p => `• ${p.name}`),
38
+ '',
39
+ '옮기려면 /project <이름>',
40
+ ].join('\n');
41
+ }
42
+
43
+ const name = args.join(' ').trim();
44
+ if (name === '-') {
45
+ deps.update(session.id, m => { delete m.projectId; });
46
+ debug.log('telegram.project', 'cleared', { projects: [] });
47
+ return '받은 대화로 옮겼습니다';
48
+ }
49
+
50
+ const projects = deps.list();
51
+ const normalized = name.toLocaleLowerCase();
52
+ const exact = projects.filter(p => p.name.toLocaleLowerCase() === normalized);
53
+ const matches = exact.length ? exact : projects.filter(p => p.name.toLocaleLowerCase().startsWith(normalized));
54
+ if (matches.length === 0) {
55
+ debug.log('telegram.project', 'rejected', { projects: [], reason: 'not-found' });
56
+ return '그 이름의 프로젝트가 없습니다 — /project 로 목록 보기';
57
+ }
58
+ if (matches.length > 1) {
59
+ debug.log('telegram.project', 'rejected', {
60
+ projects: matches.map(p => ({ id: p.id, name: p.name })), reason: 'ambiguous',
61
+ });
62
+ return `여러 프로젝트가 맞습니다 — 이름을 골라 주세요:\n${matches.map(p => `• ${p.name}`).join('\n')}`;
63
+ }
64
+
65
+ const project = matches[0]!;
66
+ deps.update(session.id, m => { m.projectId = project.id; });
67
+ debug.log('telegram.project', 'moved', { projects: [{ id: project.id, name: project.name }] });
68
+ return `이 대화를 ${project.name} 프로젝트로 옮겼습니다`;
69
+ },
70
+ };
71
+ }
@@ -11,7 +11,7 @@
11
11
  // the report channel while interactive Q&A stays on the main bot.
12
12
 
13
13
  import { TelegramBot } from './telegram.js';
14
- import { isOperationalKind, kindRouteTarget, logKindRouteFallback, mainHomeTarget } from './domains/telegram-kind-route.js';
14
+ import { isTradingKind, kindRouteTarget, logKindRouteFallback, mainHomeTarget } from './domains/telegram-kind-route.js';
15
15
  export { DEFAULT_KIND_ROLES, roleForKind } from './domains/telegram-kind-route.js';
16
16
  import { resolveChannelBotToken } from './channel-bot-token.js';
17
17
  import type { UserConfig } from './user-config.js';
@@ -51,22 +51,27 @@ export interface ReportTarget {
51
51
  chatId: number;
52
52
  }
53
53
 
54
- /** Explicit role channels win. Without a role channel, operational kinds use the main bot's
55
- * home when the legacy report channel uses another bot; same-bot reports and trading kinds
56
- * keep the legacy report destination. Returns null when no safe target is configured. */
54
+ /** An exact role channel wins. A configured channels table cannot silently fall through
55
+ * to the legacy report bot or a channel with a different role. Without that table, only
56
+ * named finance kinds can use the legacy trading report channel. */
57
57
  export function resolveReportTarget(cfg: UserConfig, kind?: string): ReportTarget | null {
58
- const routed = kindRouteTarget(cfg, kind);
59
- if (routed) return routed;
58
+ if (cfg.telegram.channels?.length) {
59
+ const routed = kindRouteTarget(cfg, kind);
60
+ if (routed) return routed;
61
+ logKindRouteFallback(kind, 'none', false);
62
+ return null;
63
+ }
60
64
  const rc = cfg.telegram.reportChannel;
61
65
  const mainToken = resolveChannelBotToken('telegram', cfg).token;
62
66
  const sameBot = !!mainToken && !!rc && (rc.botToken ?? mainToken) === mainToken;
63
- if (isOperationalKind(kind) && !sameBot) {
67
+ if (!isTradingKind(kind)) {
64
68
  const home = mainHomeTarget(cfg);
65
69
  logKindRouteFallback(kind, home ? 'main-home' : 'none', sameBot);
66
70
  return home;
67
71
  }
68
- const botToken = rc?.botToken ?? mainToken;
69
- const target = rc && Number.isFinite(rc.chatId) && botToken ? { botToken, chatId: rc.chatId } : null;
72
+ const botToken = rc?.botToken;
73
+ const target = rc && Number.isFinite(rc.chatId) && botToken && botToken !== mainToken
74
+ ? { botToken, chatId: rc.chatId } : null;
70
75
  logKindRouteFallback(kind, target ? 'report-channel' : 'none', sameBot);
71
76
  return target;
72
77
  }
@@ -81,10 +86,9 @@ export interface SendReportOpts {
81
86
  kind?: string;
82
87
  }
83
88
 
84
- /** Send a report to the configured report channel. Returns false (a
85
- * no-op, never throws) when no report channel is configured, so callers
86
- * can fire-and-forget without gating on config. Throws only on an actual
87
- * Telegram API failure once a target exists. */
89
+ /** Send a report to its kind's exact-role channel (or the safe legacy target).
90
+ * Returns false when no safe target exists; throws only on an actual
91
+ * Telegram API failure after a target has been selected. */
88
92
  export async function sendTelegramReport(
89
93
  cfg: UserConfig,
90
94
  text: string,
@@ -110,9 +114,9 @@ export async function sendTelegramReport(
110
114
  export async function sendReportPhoto(
111
115
  cfg: UserConfig,
112
116
  photoUrl: string,
113
- opts: { caption?: string; fetchImpl?: typeof fetch } = {},
117
+ opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
114
118
  ): Promise<boolean> {
115
- const target = resolveReportTarget(cfg);
119
+ const target = resolveReportTarget(cfg, opts.kind);
116
120
  if (!target || !photoUrl) return false;
117
121
  const bot = new TelegramBot({
118
122
  token: target.botToken,
@@ -131,9 +135,9 @@ export async function sendReportPhoto(
131
135
  export async function sendReportPhotoBuffer(
132
136
  cfg: UserConfig,
133
137
  png: Buffer,
134
- opts: { caption?: string; fetchImpl?: typeof fetch } = {},
138
+ opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
135
139
  ): Promise<boolean> {
136
- const target = resolveReportTarget(cfg);
140
+ const target = resolveReportTarget(cfg, opts.kind);
137
141
  if (!target || !png) return false;
138
142
  const bot = new TelegramBot({
139
143
  token: target.botToken,
package/src/telegram.ts CHANGED
@@ -25,6 +25,7 @@ import { randomUUID } from 'node:crypto';
25
25
  import { buildTurnOutputTextBlocks } from './input/turn-output-block.js';
26
26
  import { selectTurnOutputTextForSink } from './input/turn-output-sink-registry.js';
27
27
  import { debug } from './debug/log.js';
28
+ import { botAudienceFor, filterBotCommands, readBotAudience } from './maturity/bot-command-maturity.js';
28
29
  import { resolveChannelBotToken } from './channel-bot-token.js';
29
30
  import type { TelegramVoiceAdapter } from './voice/channel-adapters/telegram-voice-adapter.js';
30
31
  import { createTelegramSurfaceHitl, type TelegramSurfaceHitl } from './hitl/telegram-surface-hitl.js';
@@ -67,6 +68,7 @@ import { runUrlRoute } from './skills/url-route-exec.js';
67
68
  import { recordRoutedLinkAbsorbed } from './intake-plane/link-ledger.js';
68
69
  import { classifyFrontInput } from './intake-plane/front-classifier.js';
69
70
  import { handleTelegramSeatWork, type TelegramSeatWorkDeps } from './intake-plane/telegram-seat-work.js';
71
+ import { deliverSeatAnswers } from './seat-dispatch/seat-ask.js';
70
72
  import { effectiveInstanceRoot } from './instance/resolve.js';
71
73
  import { getElanousConfigDir } from './elanous-config-dir.js';
72
74
  import { defaultFieldEvent, FieldUploadError, parseFieldCaption, resolveFieldMime, saveFieldMedia } from './field/field-media.js';
@@ -338,6 +340,7 @@ export class TelegramBot {
338
340
  private readonly fieldReel?: FieldReelOptions;
339
341
  private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
340
342
  private readonly seatWorkDeps: TelegramSeatWorkDeps;
343
+ private seatAskTimer: ReturnType<typeof setInterval> | null = null;
341
344
  /** 앨범 id → `#현장` 행사 · 답장 디바운스. 태그된 앨범만 들어온다. */
342
345
  private readonly fieldGroups = new Map<string, {
343
346
  event: string; mode?: 'instant'; at: number; chatId: number; threadId?: number; replyTo: number; count: number;
@@ -373,7 +376,15 @@ export class TelegramBot {
373
376
  this.fieldRootDir = opts.fieldRootDir ?? getElanousConfigDir;
374
377
  this.fieldReel = opts.fieldReel;
375
378
  this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
376
- this.seatWorkDeps = opts.seatWorkDeps ?? {};
379
+ this.seatWorkDeps = { ...opts.seatWorkDeps, askDeps: { ...opts.seatWorkDeps?.askDeps,
380
+ channel: 'telegram', botId: this.botId,
381
+ send: opts.seatWorkDeps?.askDeps?.send ?? (async (origin, text) => {
382
+ if (origin.channel !== 'telegram') throw new Error('seat ask belongs to another surface');
383
+ const posted = await this.sendMessage(Number(origin.chatId), text, { replyTo: origin.messageId, threadId: origin.threadId });
384
+ if (!posted) throw new Error('Telegram seat ask reply was not posted');
385
+ }),
386
+ } };
387
+
377
388
  if (opts.onTriggerTap) {
378
389
  // Assign through `as unknown` to bypass `readonly` + private —
379
390
  // the tap is set once at construction and never reassigned.
@@ -1120,6 +1131,9 @@ export class TelegramBot {
1120
1131
  async start(): Promise<void> {
1121
1132
  this.running = true;
1122
1133
  this.log(`telegram bot starting (allowlist size ${this.allowedUsers.size})`);
1134
+ this.seatAskTimer = setInterval(() => {
1135
+ void deliverSeatAnswers(this.seatWorkDeps.askDeps!).catch((error) => this.log(`seat ask delivery failed: ${String(error)}`));
1136
+ }, 10_000);
1123
1137
  if (this.allowedUsers.size === 0) this.log('telegram.owner-gate empty-allowlist');
1124
1138
 
1125
1139
  // Publish the slash-command menu to Telegram. Clients pick up the
@@ -1128,9 +1142,16 @@ export class TelegramBot {
1128
1142
  // still processes `/commands` via the incoming-message dispatch
1129
1143
  // path, users just don't get the autocomplete.
1130
1144
  if (this.slashCommands.length > 0) {
1145
+ const audience = this.slashContext
1146
+ ? readBotAudience((this.slashContext.userConfig.raw?.telegram as { commandAudience?: unknown } | undefined)?.commandAudience)
1147
+ : botAudienceFor('telegram');
1148
+ const commands = filterBotCommands('telegram', this.slashCommands, audience);
1149
+ debug.log('telegram.command', 'menu-filtered', {
1150
+ total: this.slashCommands.length, shown: commands.length, ...audience,
1151
+ });
1131
1152
  try {
1132
1153
  const result = await this.apiCall<unknown>('setMyCommands', {
1133
- commands: toTelegramBotCommands(this.slashCommands),
1154
+ commands: toTelegramBotCommands(commands),
1134
1155
  });
1135
1156
  debug.log('telegram.command', 'published', { success: true, result });
1136
1157
  this.log(`telegram: setMyCommands published (${String(result)})`);
@@ -1151,6 +1172,7 @@ export class TelegramBot {
1151
1172
  const CONFLICT_BACKOFF_CAP = 60_000;
1152
1173
  while (this.running) {
1153
1174
  try {
1175
+ await deliverSeatAnswers(this.seatWorkDeps.askDeps!);
1154
1176
  const wantCallbackQuery = this.callbackHandlers.size > 0;
1155
1177
  const wantReaction = this.reactionHandlers.size > 0;
1156
1178
  // allowed_updates 는 명시한 것만 받으므로 등록된 핸들러 종류만 추가(비파괴 — 핸들러
@@ -1292,7 +1314,11 @@ export class TelegramBot {
1292
1314
  this.log('telegram bot stopped');
1293
1315
  }
1294
1316
 
1295
- stop(): void { this.running = false; }
1317
+ stop(): void {
1318
+ this.running = false;
1319
+ if (this.seatAskTimer) clearInterval(this.seatAskTimer);
1320
+ this.seatAskTimer = null;
1321
+ }
1296
1322
 
1297
1323
  /** Download + normalize this message's attachments into the shape
1298
1324
  * the ACP content-blocks module consumes. Called lazily by slash
@@ -11,6 +11,7 @@ export const SELF_COGNITION_TOOL_NAMES = [
11
11
  'logs_query',
12
12
  'ops_status',
13
13
  'memory_recall',
14
+ 'context_now',
14
15
  ] as const;
15
16
 
16
17
  type SelfCognitionToolName = (typeof SELF_COGNITION_TOOL_NAMES)[number];
@@ -23,7 +24,14 @@ function coreTools(): CoreToolsModule {
23
24
  return require('../domains/core-tools.js') as CoreToolsModule;
24
25
  }
25
26
 
27
+ export const CONTEXT_NOW_SPEC: LLMToolSpec = {
28
+ name: 'context_now',
29
+ description: '지금 무엇이 돌고 있는지 릴리스 칸·열린 결정·자리 원장·최근 맥락 이벤트의 출처 있는 요약을 읽는다. 원문 대화는 반환하지 않는다.',
30
+ parameters: { type: 'object', properties: { topic: { type: 'string', description: '칸 id·제목 또는 이벤트 요약에 들어 있는 낱말(선택).' } }, required: [] },
31
+ };
32
+
26
33
  function coreSpec(name: SelfCognitionToolName): LLMToolSpec {
34
+ if (name === 'context_now') return CONTEXT_NOW_SPEC;
27
35
  const spec = coreTools().CORE_TOOL_SPECS.find(candidate => candidate.name === name);
28
36
  if (!spec) throw new Error(`Missing core tool spec for self-cognition runtime '${name}'`);
29
37
  return spec;
@@ -193,9 +201,11 @@ export const SELF_COGNITION_RUNTIMES: readonly ToolRuntime[] = SELF_COGNITION_TO
193
201
  get spec() {
194
202
  return coreSpec(name);
195
203
  },
196
- run: async (args, ctx) => name === 'memory_recall' || name === 'self_recall'
197
- ? runRecall(name, args, ctx)
198
- : toToolRunResult(await coreTools().buildCoreTools().dispatch(name, args)),
204
+ run: async (args, ctx) => name === 'context_now'
205
+ ? (await import('../context-bus/context-now.js')).contextNow({ ...(typeof args.topic === 'string' ? { topic: args.topic } : {}) })
206
+ : name === 'memory_recall' || name === 'self_recall'
207
+ ? runRecall(name, args, ctx)
208
+ : toToolRunResult(await coreTools().buildCoreTools().dispatch(name, args)),
199
209
  }));
200
210
 
201
211
  /** MCP catalog metadata derived from the same name ledger as the runtimes. */