elanous 0.2.9 → 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 (694) 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/5845-e6c003ce8d5fd36a.js +1 -0
  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-f972fc1c00a62e88.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-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
  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 -0
  152. package/apps/pwa/out/ops/seats/index.txt +30 -0
  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 -0
  178. package/apps/pwa/out/today/index.txt +33 -0
  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/field/field-feed.yaml +2 -0
  194. package/graphs/implement-loop.yaml +1 -1
  195. package/graphs/intake/intake-daily.yaml +2 -1
  196. package/graphs/ops/recipes.yaml +3 -0
  197. package/graphs/ops/secret-exposure.yaml +24 -0
  198. package/graphs/release/recipes.yaml +3 -0
  199. package/graphs/release/release-loop.yaml +4 -1
  200. package/graphs/video/explainer-line.yaml +2 -2
  201. package/package.json +2 -1
  202. package/plugins/card-followup/graphs/run-step.ts +48 -13
  203. package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
  204. package/plugins/doc-draft/graphs/run-step.ts +13 -6
  205. package/plugins/elanous-hwp/README.md +25 -0
  206. package/plugins/elanous-hwp/cli.ts +22 -0
  207. package/plugins/elanous-hwp/converter.ts +237 -0
  208. package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
  209. package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
  210. package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
  211. package/plugins/elanous-hwp/plugin.json +16 -0
  212. package/plugins/elanous-hwp/plugin.ts +40 -0
  213. package/scripts/ci-public-export-leak-gate.ts +75 -14
  214. package/scripts/ci-public-leak-gate.ts +44 -9
  215. package/scripts/ci-pwa-build-gate.ts +160 -0
  216. package/scripts/context-hooks/claude-stop.sh +4 -0
  217. package/scripts/context-hooks/emit.ts +24 -0
  218. package/scripts/context-hooks/post-tool-use.sh +4 -0
  219. package/scripts/coord-channel-watch.sh +54 -8
  220. package/scripts/coord-digest.ts +199 -0
  221. package/scripts/coord-post.sh +60 -3
  222. package/scripts/coord-requests-bridge.ts +143 -0
  223. package/scripts/field-feed/lib.ts +4 -0
  224. package/scripts/fleet/node-setup.sh +20 -3
  225. package/scripts/homebrew-formula-bump.ts +69 -0
  226. package/scripts/install.ps1 +68 -9
  227. package/scripts/install.sh +39 -12
  228. package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
  229. package/scripts/lib/tui-regress-checks.ts +146 -0
  230. package/scripts/marketing/measure-site-numbers.ts +169 -0
  231. package/scripts/measure-gate-shards.ts +309 -0
  232. package/scripts/memory-lifecycle-cycle.ts +2 -2
  233. package/scripts/mission-request-judge.ts +31 -1
  234. package/scripts/morning-report.ts +2 -2
  235. package/scripts/opportunity-scan.ts +1 -1
  236. package/scripts/ops-now-probe.ts +327 -0
  237. package/scripts/publish-internal-dist.ts +11 -1
  238. package/scripts/release-loop/auto-approve-node.ts +21 -4
  239. package/scripts/release-loop/cut-branch.ts +84 -0
  240. package/scripts/release-loop/cutoff.ts +19 -8
  241. package/scripts/release-loop/gate-node.ts +14 -13
  242. package/scripts/release-loop/mac-smoke-node.ts +229 -0
  243. package/scripts/release-loop/node-verdict.ts +3 -3
  244. package/scripts/release-loop/ops-upgrade-node.ts +72 -16
  245. package/scripts/release-loop/release-readiness.ts +9 -0
  246. package/scripts/release-loop/tui-node-checks.ts +42 -0
  247. package/scripts/release-loop/tui-sim-node.ts +32 -8
  248. package/scripts/release-loop/unattended-release.ts +5 -3
  249. package/scripts/release-loop/version-node.ts +112 -13
  250. package/scripts/repo-watch-cycle.ts +1 -1
  251. package/scripts/retro-cycle.ts +2 -2
  252. package/scripts/schedule-health-report.ts +1 -1
  253. package/scripts/signal-digest-cycle.ts +2 -7
  254. package/scripts/signal-digest-photo.ts +11 -0
  255. package/scripts/storyboard/storyboard.ts +5 -161
  256. package/scripts/tech1-public-measure.ts +94 -0
  257. package/scripts/test-diet/lib.ts +30 -1
  258. package/scripts/test-diet/node.ts +83 -8
  259. package/scripts/test-timeout-audit.ts +114 -0
  260. package/scripts/tree-sync-alert.ts +1 -1
  261. package/scripts/tui-regress.ts +71 -0
  262. package/scripts/ux/demo-rehearsal.ts +243 -0
  263. package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
  264. package/scripts/waitlist-daily-digest.ts +1 -1
  265. package/skills/diagram-master/SKILL.md +366 -0
  266. package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
  267. package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
  268. package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
  269. package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
  270. package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
  271. package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
  272. package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
  273. package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
  274. package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
  275. package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
  276. package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
  277. package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
  278. package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
  279. package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
  280. package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
  281. package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
  282. package/skills/diagram-master/references/examples/README.md +69 -0
  283. package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
  284. package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
  285. package/skills/diagram-master/references/pyproject.toml +16 -0
  286. package/skills/diagram-master/references/quality-checklist.md +33 -0
  287. package/skills/diagram-master/references/routing-guide.md +164 -0
  288. package/skills/diagram-master/references/uv.lock +1356 -0
  289. package/skills/explainer-video/SKILL.md +4 -0
  290. package/skills/explainer-video/engine/reel.mjs +18 -13
  291. package/skills/explainer-video/engine/reel.sh +24 -5
  292. package/skills/explainer-video/engine/stitch.mjs +145 -0
  293. package/skills/google-workspace/SKILL.md +33 -0
  294. package/skills/google-workspace/scripts/gws-safe.sh +177 -0
  295. package/skills/grill-me/SKILL.md +1 -1
  296. package/skills/lecture-note-digitizer/SKILL.md +926 -0
  297. package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
  298. package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
  299. package/skills/lecture-note-digitizer/references/html-template.md +167 -0
  300. package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
  301. package/skills/omni-crawl/SKILL.md +21 -11
  302. package/skills/omni-crawl/scripts/main.ts +6 -6
  303. package/skills/omni-crawl/src/router.ts +3 -3
  304. package/skills/omni-digest/SKILL.md +17 -9
  305. package/skills/omni-digest/digest.md +2 -2
  306. package/skills/omni-digest/src/fetch.ts +30 -3
  307. package/skills/pitch-deck/SKILL.md +36 -0
  308. package/skills/pitch-deck/template.html +80 -0
  309. package/skills/youtube-master/SKILL.md +163 -0
  310. package/skills/youtube-master/package-lock.json +558 -0
  311. package/skills/youtube-master/package.json +13 -0
  312. package/skills/youtube-master/references/study-note-template.md +124 -0
  313. package/skills/youtube-master/scripts/main.ts +435 -0
  314. package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
  315. package/skills/youtube-master/src/audio.ts +63 -0
  316. package/skills/youtube-master/src/domain-staging.ts +50 -0
  317. package/skills/youtube-master/src/env.ts +36 -0
  318. package/skills/youtube-master/src/obsidian.ts +155 -0
  319. package/skills/youtube-master/src/router.ts +110 -0
  320. package/skills/youtube-master/src/stt.ts +199 -0
  321. package/skills/youtube-master/src/study-note.ts +175 -0
  322. package/skills/youtube-master/src/summarize.ts +358 -0
  323. package/skills/youtube-master/src/transcript.ts +76 -0
  324. package/skills/youtube-master/src/types.ts +91 -0
  325. package/skills/youtube-master/src/util.ts +93 -0
  326. package/skills/youtube-master/src/youtube.ts +70 -0
  327. package/skills/youtube-master/tsconfig.json +13 -0
  328. package/src/acp/codex-approval-adapter.ts +9 -3
  329. package/src/acp/core-turn-bridge.ts +117 -18
  330. package/src/acp/fact-question.ts +11 -0
  331. package/src/acp/server.ts +53 -9
  332. package/src/acp/tool-approval.ts +126 -0
  333. package/src/acp/turn-runner.ts +36 -0
  334. package/src/agent/monad-agent-turn.ts +8 -0
  335. package/src/agent-mission/driver.ts +80 -10
  336. package/src/agent-mission/pty-decision.ts +71 -0
  337. package/src/agent-mission/review-loop.ts +30 -0
  338. package/src/ask-user-question/pending-questions.ts +25 -10
  339. package/src/ask-user-question/types.ts +9 -0
  340. package/src/auth/setup-link-tokens.ts +16 -5
  341. package/src/autopilot/build/integrity-gate.ts +12 -0
  342. package/src/autopilot/build/llm-conflict-merge.ts +16 -3
  343. package/src/autopilot/tool-registry.ts +2 -0
  344. package/src/boot/daemon-prompt-turn.ts +8 -0
  345. package/src/boot/daemon-runtime.ts +9 -3
  346. package/src/boot/daemon-tools/index.ts +8 -0
  347. package/src/boot/daemon-tools/types.ts +2 -0
  348. package/src/boot/daemon-tools/web-search.ts +4 -0
  349. package/src/card-followup/core.ts +109 -0
  350. package/src/chat/ctrl-c-in-input.ts +14 -0
  351. package/src/chat/index.ts +53 -0
  352. package/src/chat/pickers/state.ts +6 -2
  353. package/src/cli/agent-cli.ts +7 -0
  354. package/src/cli/decisions-cli.ts +25 -3
  355. package/src/cli/doctor-bundle-upload.ts +68 -0
  356. package/src/cli/doctor-cli.ts +38 -4
  357. package/src/cli/drive-input-jail.ts +101 -0
  358. package/src/cli/hooks-cli.ts +17 -3
  359. package/src/cli/make-cli.ts +43 -0
  360. package/src/cli/ops-cli.ts +20 -0
  361. package/src/cli/persona-cli.ts +90 -4
  362. package/src/cli/plugin-cli.ts +31 -22
  363. package/src/cli/pod-cli.ts +61 -2
  364. package/src/cli/pr-cli.ts +82 -17
  365. package/src/cli/pty-drive-cli.ts +41 -7
  366. package/src/cli/pty-drive-verdict.ts +40 -0
  367. package/src/cli/pwa-stop.ts +163 -13
  368. package/src/cli/pwa-test.ts +3 -0
  369. package/src/cli/release-cli.ts +80 -24
  370. package/src/cli/self-update.ts +14 -0
  371. package/src/cli/setup-cli.ts +43 -1
  372. package/src/cli/skills-cli.ts +17 -1
  373. package/src/cli/storyboard-cli.ts +37 -0
  374. package/src/cli/test-state-dir-flag.ts +11 -4
  375. package/src/connectors/linear.ts +146 -0
  376. package/src/context-bus/claude-hooks-install.ts +10 -0
  377. package/src/context-bus/context-now-surfaces.ts +48 -0
  378. package/src/context-bus/context-now.ts +104 -0
  379. package/src/context-bus/coord-events.ts +115 -0
  380. package/src/context-bus/external-events.ts +52 -0
  381. package/src/context-bus/long-term-memory.ts +108 -0
  382. package/src/dashboard/dashboard-boot-fixture.ts +23 -0
  383. package/src/dashboard/index.ts +63 -21
  384. package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
  385. package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
  386. package/src/decisions/decision-cards.ts +58 -3
  387. package/src/decisions/decision-ledger.ts +85 -6
  388. package/src/decisions/decision-linear-projection.ts +157 -0
  389. package/src/decisions/web-push-decision-cards.ts +50 -0
  390. package/src/directive/interpretation-card.ts +36 -0
  391. package/src/discord/sprint21-runtime.ts +5 -1
  392. package/src/discord-self-message.ts +32 -0
  393. package/src/discord-slash-wire.ts +5 -1
  394. package/src/discord.ts +19 -2
  395. package/src/domains/coo-admin-tool.ts +62 -0
  396. package/src/domains/core-tools.ts +13 -4
  397. package/src/domains/elanous-card.ts +29 -0
  398. package/src/domains/ops-facts-tool.ts +76 -0
  399. package/src/domains/outbound-alert.ts +46 -13
  400. package/src/domains/release-tool.ts +168 -0
  401. package/src/domains/telegram-kind-route.ts +65 -9
  402. package/src/exec-requests/default-outputs.ts +25 -0
  403. package/src/exec-requests/planner.ts +106 -28
  404. package/src/exec-requests/runner.ts +123 -12
  405. package/src/exec-requests/store.ts +11 -2
  406. package/src/execution-loop/launch-gate.ts +100 -0
  407. package/src/field/field-media.ts +10 -7
  408. package/src/field/field-reel.ts +19 -5
  409. package/src/field-note/index.ts +201 -0
  410. package/src/field-note/transcribe.ts +248 -0
  411. package/src/git-fs/worktree.ts +45 -6
  412. package/src/graph-kinds/registry.ts +3 -3
  413. package/src/graph-runner/graph-approval-card.ts +113 -0
  414. package/src/graph-runner/graph-cli.ts +189 -4
  415. package/src/graph-runner/graph-grow-llm.ts +37 -0
  416. package/src/graph-runner/graph-grow.ts +47 -0
  417. package/src/graph-runner/graph-notify.ts +25 -3
  418. package/src/graph-runner/runner.ts +453 -35
  419. package/src/grok/agent-search.ts +8 -2
  420. package/src/guardian/secret-exposure-scan.ts +101 -0
  421. package/src/harness/browser-verify.ts +25 -2
  422. package/src/harness/harness-cli-command.ts +478 -42
  423. package/src/harness/harness-incidents-writer.fixture.ts +24 -0
  424. package/src/harness/harness-incidents.ts +129 -0
  425. package/src/harness/harness-pod-dispatch.ts +43 -23
  426. package/src/harness/harness-seams.ts +38 -4
  427. package/src/harness/harness-stop.ts +75 -6
  428. package/src/harness/launch-registry.ts +91 -0
  429. package/src/harness/process-garbage.ts +5 -3
  430. package/src/hitl/clarification-policy.ts +3 -1
  431. package/src/hooks/dispatch.ts +82 -0
  432. package/src/hooks/expose.ts +254 -0
  433. package/src/hooks/github-shadow.ts +108 -0
  434. package/src/hooks/providers.ts +71 -5
  435. package/src/hooks/queue.ts +1 -1
  436. package/src/hooks/receiver.ts +21 -20
  437. package/src/index.ts +206 -49
  438. package/src/intake-plane/author-goals.ts +37 -4
  439. package/src/intake-plane/categorize.ts +18 -46
  440. package/src/intake-plane/check.ts +3 -0
  441. package/src/intake-plane/discord-seat-work.ts +57 -2
  442. package/src/intake-plane/front-route-classifier.ts +33 -39
  443. package/src/intake-plane/persona-answer.ts +30 -0
  444. package/src/intake-plane/runtime-callables.ts +8 -1
  445. package/src/intake-plane/seat-doc-route.ts +170 -6
  446. package/src/intake-plane/telegram-seat-work.ts +80 -4
  447. package/src/intake-plane/telegram-work.ts +1 -0
  448. package/src/intake-plane/wish-folder.ts +67 -0
  449. package/src/intent-gate/gate.ts +30 -10
  450. package/src/live/detail-switch.ts +5 -0
  451. package/src/llm/difficulty.ts +57 -0
  452. package/src/llm/judge-layer.ts +101 -0
  453. package/src/llm/mission-router.ts +33 -19
  454. package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
  455. package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
  456. package/src/loops/contract/examples/steward.loop.yaml +50 -0
  457. package/src/loops/contract/loop-agent.schema.json +138 -0
  458. package/src/loops/contract/validate.ts +64 -0
  459. package/src/loops/registry.ts +20 -6
  460. package/src/market/signed-index.ts +4 -0
  461. package/src/maturity/bot-command-maturity.ts +45 -0
  462. package/src/maturity/cli-maturity.ts +34 -0
  463. package/src/maturity/feature-maturity.ts +120 -1
  464. package/src/maturity/tui-slash-maturity.ts +31 -0
  465. package/src/memory.ts +32 -4
  466. package/src/model-tier/index.ts +2 -2
  467. package/src/model-tier/tier-resolver.ts +20 -20
  468. package/src/model-tier/types.ts +6 -6
  469. package/src/mss/logging/log-store.ts +15 -0
  470. package/src/nexus/api/config-model-tier.ts +5 -4
  471. package/src/nexus/api/exec-requests.ts +33 -3
  472. package/src/nexus/api/fabric-plans.ts +53 -0
  473. package/src/nexus/api/harness-api.ts +5 -1
  474. package/src/nexus/api/health.ts +2 -0
  475. package/src/nexus/api/http-server.ts +89 -1
  476. package/src/nexus/api/inside-events.ts +226 -0
  477. package/src/nexus/api/meta-api.ts +32 -8
  478. package/src/nexus/api/missions.ts +6 -1
  479. package/src/nexus/api/ops-api.ts +10 -1
  480. package/src/nexus/api/ops-seats-sources.ts +37 -7
  481. package/src/nexus/api/ops-seats.ts +49 -6
  482. package/src/nexus/api/outputs-route.ts +44 -0
  483. package/src/nexus/api/seat-requests.ts +132 -10
  484. package/src/nexus/api/sessions-store.ts +42 -0
  485. package/src/nexus/api/setup-codex-login.ts +160 -0
  486. package/src/nexus/api/sub-seat-charters.ts +34 -0
  487. package/src/nexus/api/tabs-mutations.ts +3 -1
  488. package/src/nexus/api/trace.ts +18 -6
  489. package/src/nexus/api/usage-api.ts +102 -0
  490. package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
  491. package/src/nexus/api/workflows.ts +80 -6
  492. package/src/nexus/index.ts +47 -4
  493. package/src/nexus/kinds/webterm.ts +2 -1
  494. package/src/nexus/webterm/pty.ts +6 -2
  495. package/src/onboarding/cli-auth-status.ts +80 -0
  496. package/src/onboarding/first-run.ts +89 -0
  497. package/src/onboarding/lan-address.ts +45 -0
  498. package/src/onboarding/voice-ai.ts +3 -3
  499. package/src/onboarding/web-first.ts +119 -24
  500. package/src/onboarding.ts +4 -0
  501. package/src/ops-now/ops-now-refresh.ts +100 -0
  502. package/src/org/seat-budget.ts +48 -0
  503. package/src/org/stall-escalation.ts +63 -0
  504. package/src/outputs/ledger.ts +120 -0
  505. package/src/persona/persona-todo.ts +79 -0
  506. package/src/persona/presets.ts +116 -2
  507. package/src/persona/team-set.ts +155 -0
  508. package/src/plugins/install/plugin-install.ts +14 -0
  509. package/src/plugins/maker/market-bundle.ts +109 -0
  510. package/src/plugins/maker/plugin-maker.ts +254 -11
  511. package/src/plugins/maker/wizard-generate.ts +103 -0
  512. package/src/pod-lease/admission.ts +150 -0
  513. package/src/pod-lease/dependency-state.ts +85 -0
  514. package/src/pod-lease/host-lease.ts +127 -0
  515. package/src/project/project-store.ts +115 -0
  516. package/src/project/project-suggestion.ts +16 -0
  517. package/src/project/session-context.ts +24 -0
  518. package/src/release-loop/checklist.ts +79 -5
  519. package/src/release-loop/feature-store.ts +159 -24
  520. package/src/release-loop/next-md-merge.ts +58 -0
  521. package/src/release-loop/release-note.ts +59 -4
  522. package/src/release-loop/release-schedule.ts +53 -0
  523. package/src/repl/index.ts +7 -0
  524. package/src/seat-dispatch/ceo-commands.ts +41 -8
  525. package/src/seat-dispatch/ceo-intent.ts +38 -0
  526. package/src/seat-dispatch/seat-ask.ts +130 -0
  527. package/src/seat-dispatch/seat-questions.ts +100 -0
  528. package/src/seat-loop/seat-loop.ts +750 -0
  529. package/src/seat-loop/seat-report.ts +99 -0
  530. package/src/self-dev/decompose.ts +66 -11
  531. package/src/self-dev/dev-cli.ts +4 -1
  532. package/src/self-dev/dev-pipeline.ts +37 -1
  533. package/src/self-dev/draft-sweep.ts +38 -33
  534. package/src/self-dev/draft-triage-rules.ts +8 -5
  535. package/src/self-dev/fabric-plan-core.ts +297 -0
  536. package/src/self-dev/orchestrate.ts +36 -4
  537. package/src/self-dev/release-path-guard.ts +62 -0
  538. package/src/self-dev/run-store.ts +10 -1
  539. package/src/self-dev/shard-aggregate.ts +230 -0
  540. package/src/self-dev/shard-placement.ts +60 -0
  541. package/src/self-dev/shard-plan.ts +48 -0
  542. package/src/self-dev/shard-pod-run.ts +77 -0
  543. package/src/self-dev/shard-run.ts +105 -0
  544. package/src/self-implement/execution-clarification.ts +115 -0
  545. package/src/self-implement/gate-baseline.ts +1 -1
  546. package/src/self-implement/gate-cli.ts +46 -4
  547. package/src/self-implement/gate-scope.ts +37 -7
  548. package/src/self-implement/graph-variant.ts +171 -0
  549. package/src/self-implement/harness-policy-gates.ts +1 -1
  550. package/src/self-implement/headless-elanous-driver.ts +22 -3
  551. package/src/self-implement/host-regate.ts +22 -1
  552. package/src/self-implement/importer-test-index.ts +2 -1
  553. package/src/self-implement/l8-merge-queue.ts +130 -0
  554. package/src/self-implement/orchestrator.ts +279 -12
  555. package/src/self-implement/pipeline-shape.ts +1 -1
  556. package/src/self-implement/route-consumer-test-index.ts +122 -0
  557. package/src/self-implement/run-status-mapping.ts +5 -3
  558. package/src/self-implement/seams.ts +72 -11
  559. package/src/self-implement/test-seams.ts +1 -0
  560. package/src/self-implement/uncommitted-work.ts +59 -0
  561. package/src/session/chat.ts +2 -0
  562. package/src/session/index.ts +45 -13
  563. package/src/shell-env-bootstrap.ts +17 -0
  564. package/src/skills/gift-install.ts +215 -0
  565. package/src/skills/tools/web-search.ts +4 -1
  566. package/src/steward/directive.ts +51 -2
  567. package/src/steward/launch.ts +266 -0
  568. package/src/steward/outcome-notify.ts +115 -0
  569. package/src/steward/steward-cards.ts +25 -11
  570. package/src/steward/triage-plan.ts +32 -4
  571. package/src/steward/triage.ts +129 -13
  572. package/src/steward/working-backwards.ts +64 -0
  573. package/src/storyboard/storyboard.ts +141 -0
  574. package/src/task-cards/card-cli.ts +25 -1
  575. package/src/task-cards/card-store.ts +2 -2
  576. package/src/task-orchestrator/mission.ts +5 -0
  577. package/src/task-orchestrator/store.ts +12 -3
  578. package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
  579. package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
  580. package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
  581. package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
  582. package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
  583. package/src/task-orchestrator/types.ts +2 -0
  584. package/src/telegram-card-followup.ts +153 -0
  585. package/src/telegram-commands.ts +10 -1
  586. package/src/telegram-project-command.ts +71 -0
  587. package/src/telegram-report.ts +29 -19
  588. package/src/telegram-run.ts +7 -0
  589. package/src/telegram.ts +58 -11
  590. package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
  591. package/src/tool-runtime/types.ts +4 -0
  592. package/src/tui-client/dashboard-session.ts +2 -0
  593. package/src/user-config.ts +216 -27
  594. package/src/version/packed-revision.json +1 -1
  595. package/src/web-push/notify-exec-request.ts +32 -0
  596. package/src/web-search/grok.ts +7 -1
  597. package/src/web-search/index.ts +28 -1
  598. package/src/web-search/provider.ts +4 -0
  599. package/src/web-search/x-intent.ts +5 -0
  600. package/src/workflow-runtime/executor.ts +277 -47
  601. package/src/workflow-runtime/index.ts +1 -0
  602. package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
  603. package/src/workflow-runtime/plugin-kind-node.ts +1 -1
  604. package/src/workflow-runtime/schema.ts +79 -4
  605. package/src/workflow-runtime/types.ts +35 -4
  606. package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
  617. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
  618. package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
  622. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
  692. package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
  693. package/src/dashboard/turn-typeahead-echo.ts +0 -23
  694. /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,153 @@
1
+ import { chmodSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
2
+ import { spawn } from 'node:child_process';
3
+ import { join, resolve } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { debug } from './debug/log.js';
6
+ import { effectiveInstanceRoot } from './instance/resolve.js';
7
+ import { runGraph } from './graph-runner/runner.js';
8
+ import { cardShape, detectCard, runCardFollowup, NotACardError, type CardDetectDecision } from './card-followup/core.js';
9
+ import type { TgIncoming } from './telegram.js';
10
+
11
+ // Latin keywords are whole words only — «postcard» or «cardinal» is not a card request (review round 3).
12
+ const KEYWORD = /명함|전략|메일\s*초안|초안|팔로업|\bcard\b|\bCRM\b/i;
13
+ /** Untagged albums start one graph run, not one per photo (chatId:mediaGroupId → first seen at). */
14
+ const startedAlbums = new Map<string, number>();
15
+ const ALBUM_TTL_MS = 10 * 60_000;
16
+ function firstOfAlbum(chatId: number, mediaGroupId: string | undefined, now: number): boolean {
17
+ if (!mediaGroupId) return true;
18
+ for (const [key, at] of startedAlbums) if (now - at > ALBUM_TTL_MS) startedAlbums.delete(key);
19
+ const key = `${chatId}:${mediaGroupId}`;
20
+ if (startedAlbums.has(key)) return false;
21
+ startedAlbums.set(key, now);
22
+ return true;
23
+ }
24
+
25
+ export { cardShape, cardText } from './card-followup/core.js';
26
+ const OCR_SCRIPT = resolve(import.meta.dir, '../scripts/ocr-text-regions.swift');
27
+ /** Local macOS Vision OCR (no network · no new dependency); null where it cannot run. */
28
+ export function localOcrText(path: string, timeoutMs = 30_000): Promise<string | null> {
29
+ if (process.platform !== 'darwin') return Promise.resolve(null);
30
+ return new Promise((done) => {
31
+ let out = '';
32
+ let child: ReturnType<typeof spawn>;
33
+ try { child = spawn('swift', [OCR_SCRIPT, path], { stdio: ['ignore', 'pipe', 'ignore'] }); } catch { done(null); return; }
34
+ const timer = setTimeout(() => { child.kill('SIGKILL'); done(null); }, timeoutMs);
35
+ child.stdout?.on('data', (chunk) => { out += String(chunk); });
36
+ child.once('error', () => { clearTimeout(timer); done(null); });
37
+ child.once('close', (code) => {
38
+ clearTimeout(timer);
39
+ if (code !== 0) { done(null); return; }
40
+ done(out.split('\n').map((l) => /^\s+[\d.]+\s+(.*?)\s+box=/.exec(l)?.[1]).filter(Boolean).join('\n'));
41
+ });
42
+ });
43
+ }
44
+
45
+ type Picked = 'all' | 'strategy' | 'draft' | 'crm';
46
+ export interface CardPhotoDeps {
47
+ isOwner: (userId: number) => boolean;
48
+ isFieldAlbum?: (id: string) => boolean;
49
+ downloadFile: (fileId: string, destDir: string) => Promise<{ localPath: string }>;
50
+ sendMessage: (chatId: number, text: string, opts: { replyTo: number; threadId?: number }) => Promise<unknown>;
51
+ sendDocument: (chatId: number, body: string | Buffer, filename: string, opts: { replyTo: number; threadId?: number; mimeType?: string }) => Promise<unknown>;
52
+ runGraph?: typeof runGraph;
53
+ rootDir?: () => string;
54
+ /** OCR text of a downloaded photo, or null when unavailable (default: local macOS Vision). */
55
+ ocrText?: (path: string) => Promise<string | null>;
56
+ }
57
+
58
+ function pick(caption: string): Picked {
59
+ if (/\bCRM\b/i.test(caption)) return 'crm';
60
+ if (/메일\s*초안|초안/i.test(caption)) return 'draft';
61
+ if (/전략/.test(caption)) return 'strategy';
62
+ return 'all';
63
+ }
64
+
65
+ /** Starts a private graph run without blocking the Telegram message turn. */
66
+ export async function maybeHandleCardPhoto(ctx: TgIncoming, deps: CardPhotoDeps): Promise<boolean> {
67
+ const photo = ctx.attachments.find((att) => att.kind === 'photo');
68
+ const caption = ctx.text.trim();
69
+ if (!ctx.isDm || ctx.isGroup || !deps.isOwner(ctx.userId) || !photo
70
+ || (ctx.mediaGroupId && deps.isFieldAlbum?.(ctx.mediaGroupId))
71
+ || /#현장/.test(caption) || (caption && !KEYWORD.test(caption))) return false;
72
+ const detect = (decision: CardDetectDecision, signal: string) =>
73
+ debug.log('telegram.card-followup', 'detect', { chatId: ctx.chatId, decision, signal });
74
+ if (!caption) {
75
+ const shape = cardShape(photo.width, photo.height);
76
+ if (shape.decision === 'skip') { detect('skip', shape.signal); return false; }
77
+ }
78
+ // Album items after the first: a keyword caption sits on one item only, so later items follow the normal flow.
79
+ if (!firstOfAlbum(ctx.chatId, ctx.mediaGroupId, Date.now())) return false;
80
+
81
+ const picked = pick(caption);
82
+ const started = Date.now();
83
+ const reply = { replyTo: ctx.messageId, ...(ctx.threadId === undefined ? {} : { threadId: ctx.threadId }) };
84
+ const log = (event: 'started' | 'not-a-card' | 'replied' | 'failed') =>
85
+ debug.log('card.followup', event, { chatId: ctx.chatId, picked, ms: Date.now() - started });
86
+
87
+ try {
88
+ const root = (deps.rootDir ?? effectiveInstanceRoot)();
89
+ const base = join(root, 'graph-runs', 'card-followup');
90
+ const runId = randomUUID();
91
+ const dir = join(base, runId);
92
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
93
+ chmodSync(base, 0o700);
94
+ chmodSync(dir, 0o700);
95
+ const prepare = async (): Promise<string | null> => {
96
+ const { localPath } = await deps.downloadFile(photo.fileId, dir);
97
+ chmodSync(localPath, 0o600);
98
+ if (!caption) {
99
+ const verdict = detectCard({ width: photo.width, height: photo.height, ocrText: await (deps.ocrText ?? localOcrText)(localPath) });
100
+ detect(verdict.decision, verdict.signal);
101
+ if (verdict.decision !== 'card') { rmSync(dir, { recursive: true, force: true }); return null; }
102
+ }
103
+ log('started');
104
+ await deps.sendMessage(ctx.chatId, '명함으로 보고 정리하는 중입니다(1~3분)', reply);
105
+ return localPath;
106
+ };
107
+ // A keyword caption is an explicit request: download before returning. A bare photo is judged in the background.
108
+ const prepared = caption ? await prepare() : null;
109
+ void (async () => {
110
+ let localPath = prepared;
111
+ try {
112
+ if (!caption) {
113
+ try { localPath = await prepare(); } catch { log('failed'); return; }
114
+ if (!localPath) return;
115
+ }
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;
125
+ }
126
+ const markdown = readFileSync(result.followupPath!);
127
+ const crmLine = picked === 'crm'
128
+ ? /^## ② CRM 한 줄\r?\n파일: [^\r\n]*\r?\n([^\r\n]+)/m.exec(markdown.toString('utf8'))?.[1]
129
+ : undefined;
130
+ if (picked === 'crm' && !crmLine) throw new Error('CRM row missing from report');
131
+ const messages = picked === 'strategy' ? [result.replies[1]] : picked === 'draft' ? [result.replies[2]] : picked === 'crm' ? [`CRM 한 줄\n${crmLine}`] : result.replies;
132
+ for (const message of messages) await deps.sendMessage(ctx.chatId, message, reply);
133
+ const sent = await deps.sendDocument(ctx.chatId, markdown, 'followup.md', { ...reply, mimeType: 'text/markdown' });
134
+ if (sent === undefined) throw new Error('document delivery failed');
135
+ log('replied');
136
+ } catch {
137
+ log('failed');
138
+ try {
139
+ await deps.sendMessage(ctx.chatId, '명함 정리에 실패했습니다. 다시 시도해 주세요.', reply);
140
+ } catch { /* Telegram delivery itself failed; the failure is already observed. */ }
141
+ }
142
+ })();
143
+ } catch {
144
+ log('failed');
145
+ // A bare photo was never claimed as a card — failing to prepare it stays silent.
146
+ if (caption) {
147
+ try {
148
+ await deps.sendMessage(ctx.chatId, '명함 정리에 실패했습니다. 다시 시도해 주세요.', reply);
149
+ } catch { /* Telegram delivery itself failed; the failure is already observed. */ }
150
+ }
151
+ }
152
+ return !!caption;
153
+ }
@@ -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 { kindRouteTarget } 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,18 +51,29 @@ export interface ReportTarget {
51
51
  chatId: number;
52
52
  }
53
53
 
54
- /** Resolve the send target. With a purpose `kind` that maps to a role and explicit `telegram.channels`,
55
- * the channel holding that role wins (fallback: the `default` channel). Otherwise the legacy report
56
- * channel: `botToken` falls back to the main Q&A bot token when the report channel is served by the
57
- * same bot. Returns null when nothing 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. */
58
57
  export function resolveReportTarget(cfg: UserConfig, kind?: string): ReportTarget | null {
59
- const routed = kindRouteTarget(cfg, kind);
60
- 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
+ }
61
64
  const rc = cfg.telegram.reportChannel;
62
- if (!rc || !Number.isFinite(rc.chatId)) return null;
63
- const botToken = rc.botToken ?? resolveChannelBotToken('telegram', cfg)?.token;
64
- if (!botToken) return null;
65
- return { botToken, chatId: rc.chatId };
65
+ const mainToken = resolveChannelBotToken('telegram', cfg).token;
66
+ const sameBot = !!mainToken && !!rc && (rc.botToken ?? mainToken) === mainToken;
67
+ if (!isTradingKind(kind)) {
68
+ const home = mainHomeTarget(cfg);
69
+ logKindRouteFallback(kind, home ? 'main-home' : 'none', sameBot);
70
+ return home;
71
+ }
72
+ const botToken = rc?.botToken;
73
+ const target = rc && Number.isFinite(rc.chatId) && botToken && botToken !== mainToken
74
+ ? { botToken, chatId: rc.chatId } : null;
75
+ logKindRouteFallback(kind, target ? 'report-channel' : 'none', sameBot);
76
+ return target;
66
77
  }
67
78
 
68
79
  export interface SendReportOpts {
@@ -75,10 +86,9 @@ export interface SendReportOpts {
75
86
  kind?: string;
76
87
  }
77
88
 
78
- /** Send a report to the configured report channel. Returns false (a
79
- * no-op, never throws) when no report channel is configured, so callers
80
- * can fire-and-forget without gating on config. Throws only on an actual
81
- * 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. */
82
92
  export async function sendTelegramReport(
83
93
  cfg: UserConfig,
84
94
  text: string,
@@ -104,9 +114,9 @@ export async function sendTelegramReport(
104
114
  export async function sendReportPhoto(
105
115
  cfg: UserConfig,
106
116
  photoUrl: string,
107
- opts: { caption?: string; fetchImpl?: typeof fetch } = {},
117
+ opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
108
118
  ): Promise<boolean> {
109
- const target = resolveReportTarget(cfg);
119
+ const target = resolveReportTarget(cfg, opts.kind);
110
120
  if (!target || !photoUrl) return false;
111
121
  const bot = new TelegramBot({
112
122
  token: target.botToken,
@@ -125,9 +135,9 @@ export async function sendReportPhoto(
125
135
  export async function sendReportPhotoBuffer(
126
136
  cfg: UserConfig,
127
137
  png: Buffer,
128
- opts: { caption?: string; fetchImpl?: typeof fetch } = {},
138
+ opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
129
139
  ): Promise<boolean> {
130
- const target = resolveReportTarget(cfg);
140
+ const target = resolveReportTarget(cfg, opts.kind);
131
141
  if (!target || !png) return false;
132
142
  const bot = new TelegramBot({
133
143
  token: target.botToken,
@@ -18,6 +18,7 @@ import { effectiveInstanceRoot } from './instance/resolve.js';
18
18
  import { getUserConfig } from './user-config.js';
19
19
  import { resolveChannelBotToken } from './channel-bot-token.js';
20
20
  import { forwardTelegramDispatch } from './telegram-dispatch-forward.js';
21
+ import { mergeCapturedPath, warmCapturedEnv } from './shell-env-bootstrap.js';
21
22
  import type { NexusTelegramQaPollerWireHandle } from './nexus/index.js';
22
23
 
23
24
  export interface TelegramRunResult {
@@ -138,7 +139,13 @@ export async function runTelegramPoller(deps: {
138
139
  alert?: (text: string, kind: string) => boolean;
139
140
  wait?: () => Promise<void>;
140
141
  registerLogSink?: () => Promise<void>;
142
+ warm?: () => Promise<boolean>;
141
143
  } = {}): Promise<void> {
144
+ void (deps.warm ?? warmCapturedEnv)().then((ok) => {
145
+ if (ok) mergeCapturedPath();
146
+ }).catch((error) => {
147
+ debug.log('shell.envbootstrap.capture', 'warm-failed', { error: String(error) });
148
+ });
142
149
  try {
143
150
  if (deps.registerLogSink) await deps.registerLogSink();
144
151
  else {
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,10 +68,12 @@ 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';
73
75
  import { scheduleFieldReel, type FieldReelOptions } from './field/field-reel.js';
76
+ import { maybeHandleCardPhoto, type CardPhotoDeps } from './telegram-card-followup.js';
74
77
 
75
78
  export type TgAttachmentKind = 'photo' | 'voice' | 'audio' | 'document';
76
79
 
@@ -216,6 +219,8 @@ export interface TelegramBotOpts {
216
219
  fieldRootDir?: () => string;
217
220
  /** 시험에서는 실제 렌더 대신 가짜 실행기를 주입한다. */
218
221
  fieldReel?: FieldReelOptions;
222
+ /** Test seam for the business-card graph and its private run root. */
223
+ cardFollowupDeps?: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
219
224
  }
220
225
 
221
226
  /** Surface-unification v2 (FU-2) — Telegram trigger event passed to
@@ -333,10 +338,12 @@ export class TelegramBot {
333
338
  private readonly fieldDefaultEventOpt?: string;
334
339
  private readonly fieldRootDir: () => string;
335
340
  private readonly fieldReel?: FieldReelOptions;
341
+ private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
336
342
  private readonly seatWorkDeps: TelegramSeatWorkDeps;
343
+ private seatAskTimer: ReturnType<typeof setInterval> | null = null;
337
344
  /** 앨범 id → `#현장` 행사 · 답장 디바운스. 태그된 앨범만 들어온다. */
338
345
  private readonly fieldGroups = new Map<string, {
339
- event: string; at: number; chatId: number; threadId?: number; replyTo: number; count: number;
346
+ event: string; mode?: 'instant'; at: number; chatId: number; threadId?: number; replyTo: number; count: number;
340
347
  timer?: ReturnType<typeof setTimeout>;
341
348
  }>();
342
349
 
@@ -368,7 +375,16 @@ export class TelegramBot {
368
375
  this.fieldDefaultEventOpt = opts.fieldDefaultEvent;
369
376
  this.fieldRootDir = opts.fieldRootDir ?? getElanousConfigDir;
370
377
  this.fieldReel = opts.fieldReel;
371
- this.seatWorkDeps = opts.seatWorkDeps ?? {};
378
+ this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
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
+
372
388
  if (opts.onTriggerTap) {
373
389
  // Assign through `as unknown` to bypass `readonly` + private —
374
390
  // the tap is set once at construction and never reassigned.
@@ -376,7 +392,7 @@ export class TelegramBot {
376
392
  }
377
393
  }
378
394
 
379
- private isOwnerAllowed(userId: number): boolean {
395
+ isOwnerAllowed(userId: number): boolean {
380
396
  return this.allowedUsers.size > 0 && this.allowedUsers.has(userId);
381
397
  }
382
398
 
@@ -1115,6 +1131,9 @@ export class TelegramBot {
1115
1131
  async start(): Promise<void> {
1116
1132
  this.running = true;
1117
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);
1118
1137
  if (this.allowedUsers.size === 0) this.log('telegram.owner-gate empty-allowlist');
1119
1138
 
1120
1139
  // Publish the slash-command menu to Telegram. Clients pick up the
@@ -1123,9 +1142,16 @@ export class TelegramBot {
1123
1142
  // still processes `/commands` via the incoming-message dispatch
1124
1143
  // path, users just don't get the autocomplete.
1125
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
+ });
1126
1152
  try {
1127
1153
  const result = await this.apiCall<unknown>('setMyCommands', {
1128
- commands: toTelegramBotCommands(this.slashCommands),
1154
+ commands: toTelegramBotCommands(commands),
1129
1155
  });
1130
1156
  debug.log('telegram.command', 'published', { success: true, result });
1131
1157
  this.log(`telegram: setMyCommands published (${String(result)})`);
@@ -1146,6 +1172,7 @@ export class TelegramBot {
1146
1172
  const CONFLICT_BACKOFF_CAP = 60_000;
1147
1173
  while (this.running) {
1148
1174
  try {
1175
+ await deliverSeatAnswers(this.seatWorkDeps.askDeps!);
1149
1176
  const wantCallbackQuery = this.callbackHandlers.size > 0;
1150
1177
  const wantReaction = this.reactionHandlers.size > 0;
1151
1178
  // allowed_updates 는 명시한 것만 받으므로 등록된 핸들러 종류만 추가(비파괴 — 핸들러
@@ -1287,7 +1314,11 @@ export class TelegramBot {
1287
1314
  this.log('telegram bot stopped');
1288
1315
  }
1289
1316
 
1290
- stop(): void { this.running = false; }
1317
+ stop(): void {
1318
+ this.running = false;
1319
+ if (this.seatAskTimer) clearInterval(this.seatAskTimer);
1320
+ this.seatAskTimer = null;
1321
+ }
1291
1322
 
1292
1323
  /** Download + normalize this message's attachments into the shape
1293
1324
  * the ACP content-blocks module consumes. Called lazily by slash
@@ -1415,6 +1446,10 @@ export class TelegramBot {
1415
1446
  ? tag.event ?? defaultFieldEvent(
1416
1447
  this.fieldDefaultEventOpt ?? this.slashContext?.userConfig?.telegram?.fieldDefaultEvent, new Date(now))
1417
1448
  : group!.event;
1449
+ const captionMode = tag?.mode ?? group?.mode;
1450
+ const configMode = this.slashContext?.userConfig?.telegram?.fieldReelMode;
1451
+ const mode = captionMode ?? configMode ?? 'standard';
1452
+ const source = captionMode ? 'caption' : configMode ? 'config' : 'default';
1418
1453
 
1419
1454
  let count: number | null = null;
1420
1455
  let failure: string | null = null;
@@ -1435,14 +1470,16 @@ export class TelegramBot {
1435
1470
  // 글(자막)은 캡션이 달린 항목에만 있다 — 앨범이면 첫 장에만 붙는다(MK 2026-09-30).
1436
1471
  const saved = saveFieldMedia(inputs, { rootDir: this.fieldRootDir(), event, device: 'telegram', ...(tag?.text ? { caption: tag.text } : {}) });
1437
1472
  count = saved.count;
1473
+ debug.log('telegram.field', 'reel-mode', { event, mode, source });
1438
1474
  scheduleFieldReel(saved.dir, {
1439
1475
  ...this.fieldReel,
1476
+ mode,
1440
1477
  notificationKey: `telegram:${this.botId}:${ctx.chatId}:${ctx.threadId ?? ''}:${ctx.mediaGroupId ?? ctx.messageId}`,
1441
1478
  onDone: async (result) => {
1442
1479
  const reply = { replyTo: ctx.messageId, threadId: ctx.threadId };
1443
1480
  if (result.ok && result.file) {
1444
1481
  const sent = await this.sendDocument(ctx.chatId, readFileSync(result.file), 'reel-9x16.mp4', {
1445
- ...reply, mimeType: 'video/mp4', caption: `현장 영상 · ${event} · ${result.seconds}초`,
1482
+ ...reply, mimeType: 'video/mp4', caption: `현장 영상 · ${event} · ${result.seconds}초${mode === 'instant' ? ' (즉석판)' : ''}`,
1446
1483
  });
1447
1484
  if (!sent) throw new Error('sendDocument failed');
1448
1485
  if (result.feed?.started) {
@@ -1469,7 +1506,8 @@ export class TelegramBot {
1469
1506
  return true;
1470
1507
  }
1471
1508
  // 앨범은 항목마다 답하지 않는다 — 마지막 항목 뒤 한 번(디바운스)만 최신 수로 답한다.
1472
- const entry = group ?? { event, at: now, chatId: ctx.chatId, threadId: ctx.threadId, replyTo: ctx.messageId, count: 0 };
1509
+ const entry = group ?? { event, mode: tag?.mode, at: now, chatId: ctx.chatId, threadId: ctx.threadId, replyTo: ctx.messageId, count: 0 };
1510
+ if (group && tag?.mode) group.mode = tag.mode;
1473
1511
  entry.at = now;
1474
1512
  entry.count = count!;
1475
1513
  if (entry.timer) clearTimeout(entry.timer);
@@ -1490,10 +1528,18 @@ export class TelegramBot {
1490
1528
  }
1491
1529
  // 현장 업로드 — `#현장` 캡션(또는 태그된 앨범의 나머지)의 사진·영상은 LLM 대신 현장 폴더로.
1492
1530
  if (await this.tryHandleFieldUpload(ctx)) return;
1493
- if (ctx.text.startsWith('@')) {
1531
+ if (await maybeHandleCardPhoto(ctx, {
1532
+ isOwner: (userId) => this.isOwnerAllowed(userId),
1533
+ isFieldAlbum: (id) => this.fieldGroups.has(id),
1534
+ downloadFile: (fileId, dir) => this.downloadFile(fileId, dir),
1535
+ sendMessage: (chatId, text, opts) => this.sendMessage(chatId, text, opts),
1536
+ sendDocument: (chatId, body, filename, opts) => this.sendDocument(chatId, body, filename, opts),
1537
+ ...this.cardFollowupDeps,
1538
+ })) return;
1539
+ if (ctx.text.startsWith('@') || (ctx.isDm && ctx.text && !ctx.text.startsWith('/'))) {
1494
1540
  const reply = await handleTelegramSeatWork(ctx.text, {
1495
- chatId: ctx.chatId, messageId: ctx.messageId, threadId: ctx.threadId, botId: ctx.botId,
1496
- }, this.seatWorkDeps);
1541
+ chatId: ctx.chatId, userId: ctx.userId, messageId: ctx.messageId, threadId: ctx.threadId, botId: ctx.botId,
1542
+ }, { ...this.seatWorkDeps, config: this.seatWorkDeps.config ?? this.slashContext?.userConfig });
1497
1543
  if (reply !== null) {
1498
1544
  await this.sendMessage(ctx.chatId, reply, { replyTo: ctx.messageId, threadId: ctx.threadId });
1499
1545
  return;
@@ -1529,7 +1575,7 @@ export class TelegramBot {
1529
1575
  try {
1530
1576
  const { addDirective } = await import('./steward/directive.js');
1531
1577
  const text = ctx.text.startsWith('지시:') ? ctx.text.slice('지시:'.length) : ctx.text.slice('/directive '.length);
1532
- const result = await addDirective(text, { source: 'telegram' });
1578
+ const result = await addDirective(text, { source: 'telegram', origin: { chatId: ctx.chatId, botId: ctx.botId, threadId: ctx.threadId } });
1533
1579
  await this.sendMessage(ctx.chatId, `${result.issue}: ${result.status}`, { replyTo: ctx.messageId, threadId: ctx.threadId });
1534
1580
  } catch {
1535
1581
  await this.sendMessage(ctx.chatId, '지시 등록 실패 — Linear 연결과 자격을 확인하세요.', { replyTo: ctx.messageId, threadId: ctx.threadId });
@@ -2746,6 +2792,7 @@ export function botFromConfig(opts: BotFromConfigOpts): TelegramBot {
2746
2792
  // (makeTelegramAgentRunTurn) threads it into `delegate_code_agent`
2747
2793
  // so a delegated sub-agent's approval prompt lands back here.
2748
2794
  hitlConfirmChannel: botRef.hitlConfirmChannelForChat(ctx.chatId, ctx.threadId),
2795
+ ...(botRef.isOwnerAllowed(ctx.userId) ? { verifiedOwner: { id: `telegram:${ctx.userId}` } } : {}),
2749
2796
  hitlQuestionChannel: botRef.hitlQuestionChannelForChat(ctx.chatId, ctx.threadId),
2750
2797
  // P1.4 — surface file spill bound to THIS chat so the NL
2751
2798
  // `delegate_code_agent` path spills big diffs/stdout back here.
@@ -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. */
@@ -91,8 +91,12 @@ export interface ToolRuntimeContext {
91
91
  sessionId?: string;
92
92
  /** Session that originated this execution when it was delegated through another runtime session. */
93
93
  originSessionId?: string;
94
+ /** Server-verified owner principal. Never derive this from session source, tool args, or a client-declared origin. */
95
+ verifiedOwner?: { id: string };
94
96
  /** Server-assigned provenance; omitted on existing owner tool paths. */
95
97
  requestOrigin?: RequestOrigin;
98
+ /** Confirm through the originating chat's channels, not another user's global channel. */
99
+ confirmChannels?: import('../hitl/confirm.js').ConfirmChannel[];
96
100
  }
97
101
 
98
102
  /** Output shape the LLM layer expects back. Most tools produce
@@ -210,6 +210,8 @@ export class DashboardSession {
210
210
  transportFactory: pair.transportFactory,
211
211
  shutdownSignal: shutdownCtrl.signal,
212
212
  runTurn,
213
+ // PCH-2b — the in-process TUI dispatcher carries its own approval modals.
214
+ toolApproval: 'off',
213
215
  ...(opts.agentName ? { agentName: opts.agentName } : {}),
214
216
  ...(opts.agentVersion ? { agentVersion: opts.agentVersion } : {}),
215
217
  ...(opts.serverOptions ?? {}),