elanous 0.2.17 → 0.2.19

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 (491) 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/J5H7BvqgSI8DUjtRRcA_S/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1157-cba0e8553d35a980.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/{726.83532d69452ee24b.js → 1470.98a6ab61ccb4131c.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/171-23a877ed11720de9.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/2336-e830c777eb6bce04.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{9247-269e4464cc4b491c.js → 2375-e061bb24cd2b5cde.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/{211-9c9090c59e2c5907.js → 2977-e38442e86289f1d3.js} +1 -1
  14. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → 2ea96958.e8c7e112de50b067.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/3094.67339318c7f72a3a.js +2 -0
  16. package/apps/pwa/out/_next/static/chunks/338-ceb956612dcfaa86.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/3395-835e4ceaa6335ba4.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +5 -0
  19. package/apps/pwa/out/_next/static/chunks/3441-be82e3595aef3a20.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/3689-89905039bf3e7257.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/3822-6f268bc26c6a84ac.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 4323.c5dfb6f503304775.js} +1 -1
  25. package/apps/pwa/out/_next/static/chunks/4457-d7df81c90f9d0268.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/4551-77dadae76f6cbace.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 4847.56f5bc454fbcc827.js} +2 -2
  28. package/apps/pwa/out/_next/static/chunks/4978.6fd93b974441e87f.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/5012-f746f6549b869f91.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 6062-73e68343a9814f6a.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/62-5bfed1e23790b745.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/6320-9bc8561fde416e07.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/649-ca96d1c5d09e02b8.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/6726-85a7db59b288c53f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/6735-33267c4630d0d963.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/7633-141682015873beb6.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{935.4ddaa99fc1d1126c.js → 7647.2fcd30d894d5ee30.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/{f6231284-45726550aba08fca.js → 8046cadf-211ca3c0e00f2b72.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/8067-143791231c99bd02.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/8430-a10cfba8ef282d4e.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/8870-9614a213b990b10b.js +25 -0
  49. package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/9454-12c2f30dea62291c.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/976-4a9b4ebdca7c739a.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/9989-15cdf568bafa9fc8.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/ae787e4c-e5b1ef00b2dbceca.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/app/approvals/page-deef5ee191830f14.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-b193da485f9a14b2.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/app/board/page-b6e1a79df0e214f4.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/app/botlab/page-e84df4d907f703c7.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/app/bots/page-a5fb9a5db89ae4ea.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/app/ceo/page-1499f481d7fc52d6.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/app/chat/page-c7cf753aeb648790.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/app/consult/page-4118469e514e10fd.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/app/control/page-e968f7630654332a.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/app/decisions/page-505915052f947022.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c2f962fb4a3b06c6.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/app/editor/page-7b5ed0bd8a589ec4.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/app/exec/page-cf8193250dd42dd4.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/app/field/page-cf3f5dfa35dea8e9.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/app/inside/page-5b29d9b06ceadade.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/app/intake/page-a15e7fcc283e9ca7.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/app/layout-d2915e7b70ff3d0e.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/app/live/page-b70cd005d9169e25.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/app/loops/page-2595f0eba29f57e1.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/app/market/page-c776322454156e36.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-77bbd17f4435aa10.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/app/morning/page-049689e611ecc936.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/app/not-found-85954a4fb09c44eb.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/app/observatory/page-e773e552e1068ee6.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5633c4bfa7684b4a.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-d829b92bd01b4994.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-061c317fc771becf.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a45ece8865ed4b6.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/app/page-0be990618c0d56bd.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/app/reflection/page-bfea4865dc244b73.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d6ba8e337741484.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/app/sessions/page-76a88b55d816482e.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-bba1542df59f61ce.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/app/settings/page-4185c95689bb372e.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b699e1a8d5d34b8b.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/setup/page-c225e338c31bf274.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/app/share/page-449353f70507ca1f.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/app/showroom/page-90b889714102476d.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f1ee7fbeb7f96ddc.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/term/page-d59a95e1434dfaa0.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/today/page-71491a23414d1a47.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/app/trace/page-de7112bdb65fa4fe.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/app/vault/page-feb4d0d88079660d.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-f17d887b40dd6b1d.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/app/workflows/page-8da77be2192bcd5d.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72c3b9a5e9582b29.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3afe4c8d0c48c39.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/main-app-b9308f2d8a931531.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/webpack-6f35f9d892fa630b.js +1 -0
  110. package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
  111. package/apps/pwa/out/_next/static/css/85f53c6f35d11382.css +1 -0
  112. package/apps/pwa/out/_next/static/css/d3427996da11e480.css +1 -0
  113. package/apps/pwa/out/approvals/index.html +1 -1
  114. package/apps/pwa/out/approvals/index.txt +23 -23
  115. package/apps/pwa/out/autopilot/index.html +1 -1
  116. package/apps/pwa/out/autopilot/index.txt +23 -23
  117. package/apps/pwa/out/board/index.html +1 -1
  118. package/apps/pwa/out/board/index.txt +23 -23
  119. package/apps/pwa/out/botlab/index.html +1 -1
  120. package/apps/pwa/out/botlab/index.txt +22 -22
  121. package/apps/pwa/out/bots/index.html +1 -1
  122. package/apps/pwa/out/bots/index.txt +22 -22
  123. package/apps/pwa/out/ceo/index.html +1 -1
  124. package/apps/pwa/out/ceo/index.txt +23 -23
  125. package/apps/pwa/out/chat/index.html +1 -1
  126. package/apps/pwa/out/chat/index.txt +22 -22
  127. package/apps/pwa/out/consult/index.html +1 -1
  128. package/apps/pwa/out/consult/index.txt +23 -23
  129. package/apps/pwa/out/control/index.html +1 -1
  130. package/apps/pwa/out/control/index.txt +23 -23
  131. package/apps/pwa/out/decisions/index.html +1 -0
  132. package/apps/pwa/out/decisions/index.txt +30 -0
  133. package/apps/pwa/out/design-check/index.html +1 -1
  134. package/apps/pwa/out/design-check/index.txt +23 -23
  135. package/apps/pwa/out/editor/index.html +1 -1
  136. package/apps/pwa/out/editor/index.txt +25 -24
  137. package/apps/pwa/out/exec/index.html +1 -1
  138. package/apps/pwa/out/exec/index.txt +23 -23
  139. package/apps/pwa/out/field/index.html +1 -1
  140. package/apps/pwa/out/field/index.txt +23 -23
  141. package/apps/pwa/out/healthz +1 -1
  142. package/apps/pwa/out/index.html +1 -1
  143. package/apps/pwa/out/index.txt +22 -22
  144. package/apps/pwa/out/inside/index.html +1 -1
  145. package/apps/pwa/out/inside/index.txt +24 -23
  146. package/apps/pwa/out/intake/index.html +1 -1
  147. package/apps/pwa/out/intake/index.txt +23 -23
  148. package/apps/pwa/out/live/index.html +1 -1
  149. package/apps/pwa/out/live/index.txt +23 -23
  150. package/apps/pwa/out/loops/index.html +1 -1
  151. package/apps/pwa/out/loops/index.txt +28 -27
  152. package/apps/pwa/out/market/index.html +1 -1
  153. package/apps/pwa/out/market/index.txt +22 -22
  154. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  155. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  156. package/apps/pwa/out/morning/index.html +1 -1
  157. package/apps/pwa/out/morning/index.txt +23 -23
  158. package/apps/pwa/out/observatory/index.html +1 -1
  159. package/apps/pwa/out/observatory/index.txt +23 -23
  160. package/apps/pwa/out/ops/checklist/index.html +1 -1
  161. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  162. package/apps/pwa/out/ops/release/index.html +1 -1
  163. package/apps/pwa/out/ops/release/index.txt +22 -22
  164. package/apps/pwa/out/ops/seats/index.html +1 -1
  165. package/apps/pwa/out/ops/seats/index.txt +22 -22
  166. package/apps/pwa/out/outputs/index.html +1 -1
  167. package/apps/pwa/out/outputs/index.txt +22 -22
  168. package/apps/pwa/out/reflection/index.html +1 -1
  169. package/apps/pwa/out/reflection/index.txt +23 -23
  170. package/apps/pwa/out/scheduler/index.html +1 -1
  171. package/apps/pwa/out/scheduler/index.txt +23 -23
  172. package/apps/pwa/out/sessions/index.html +1 -1
  173. package/apps/pwa/out/sessions/index.txt +22 -22
  174. package/apps/pwa/out/settings/devices/index.html +1 -1
  175. package/apps/pwa/out/settings/devices/index.txt +23 -23
  176. package/apps/pwa/out/settings/index.html +1 -1
  177. package/apps/pwa/out/settings/index.txt +23 -23
  178. package/apps/pwa/out/setup/done/index.html +1 -1
  179. package/apps/pwa/out/setup/done/index.txt +23 -23
  180. package/apps/pwa/out/setup/index.html +1 -1
  181. package/apps/pwa/out/setup/index.txt +23 -23
  182. package/apps/pwa/out/share/index.html +1 -1
  183. package/apps/pwa/out/share/index.txt +23 -23
  184. package/apps/pwa/out/showroom/index.html +1 -1
  185. package/apps/pwa/out/showroom/index.txt +22 -22
  186. package/apps/pwa/out/tasks/index.html +1 -1
  187. package/apps/pwa/out/tasks/index.txt +23 -23
  188. package/apps/pwa/out/term/index.html +1 -1
  189. package/apps/pwa/out/term/index.txt +23 -23
  190. package/apps/pwa/out/today/index.html +1 -1
  191. package/apps/pwa/out/today/index.txt +23 -23
  192. package/apps/pwa/out/trace/index.html +1 -1
  193. package/apps/pwa/out/trace/index.txt +23 -23
  194. package/apps/pwa/out/vault/index.html +1 -1
  195. package/apps/pwa/out/vault/index.txt +23 -23
  196. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  197. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  198. package/apps/pwa/out/workflows/index.html +1 -1
  199. package/apps/pwa/out/workflows/index.txt +23 -23
  200. package/apps/pwa/out/workspace/index.html +1 -1
  201. package/apps/pwa/out/workspace/index.txt +23 -23
  202. package/apps/pwa/out/worktrees/index.html +1 -1
  203. package/apps/pwa/out/worktrees/index.txt +23 -23
  204. package/graphs/ops/guardian.yaml +26 -0
  205. package/graphs/ops/recipes.yaml +3 -0
  206. package/package.json +2 -1
  207. package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
  208. package/samples/workflows/templates/chat-driven-research.yaml +35 -0
  209. package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
  210. package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
  211. package/samples/workflows/templates/manual-quickstart.yaml +21 -0
  212. package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
  213. package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
  214. package/scripts/ci-public-export-import-gate.ts +7 -2
  215. package/scripts/ci-typecheck-changed.ts +21 -6
  216. package/scripts/coord-channel-watch.sh +2 -2
  217. package/scripts/discord-seat-probe.ts +6 -3
  218. package/scripts/docs/generate-cli-anatomy.ts +162 -0
  219. package/scripts/goals/authoring-metrics.ts +73 -0
  220. package/scripts/landing-heal/must-fix-match.ts +7 -7
  221. package/scripts/landing-heal/run-mission.ts +3 -2
  222. package/scripts/lib/pch-regress-map.ts +23 -0
  223. package/scripts/morning-report.ts +18 -4
  224. package/scripts/pch-regress.ts +88 -0
  225. package/scripts/public-export-test-run.ts +37 -2
  226. package/scripts/release-loop/checklist-gate-node.ts +13 -11
  227. package/scripts/release-loop/cut-branch.ts +2 -1
  228. package/scripts/release-loop/cutoff.ts +4 -2
  229. package/scripts/release-loop/docs-land-node.ts +8 -1
  230. package/scripts/release-loop/docs-node.ts +1 -1
  231. package/scripts/release-loop/gate-diff.ts +18 -0
  232. package/scripts/release-loop/gate-node.ts +436 -59
  233. package/scripts/release-loop/gate-partial.ts +106 -0
  234. package/scripts/release-loop/gate-timing.ts +120 -0
  235. package/scripts/release-loop/node-verdict.ts +2 -1
  236. package/scripts/release-loop/npm-publish-node.ts +11 -7
  237. package/scripts/release-loop/ops-upgrade-node.ts +8 -1
  238. package/scripts/release-loop/preflight.ts +246 -0
  239. package/scripts/release-loop/publish-node.ts +8 -1
  240. package/scripts/release-loop/release-readiness.ts +11 -6
  241. package/scripts/release-loop/release-version.ts +48 -0
  242. package/scripts/release-loop/resume-release.ts +174 -0
  243. package/scripts/release-loop/shard-plan.ts +65 -0
  244. package/scripts/release-loop/unattended-release.ts +45 -7
  245. package/scripts/release-loop/version-node.ts +145 -40
  246. package/scripts/rhythm/daily.ts +25 -4
  247. package/scripts/skills/public-check.ts +62 -12
  248. package/scripts/test-deterministic.ts +51 -33
  249. package/scripts/test-diet/effectiveness.ts +62 -1
  250. package/scripts/test-diet/lib.ts +1 -1
  251. package/scripts/test-diet/node.ts +8 -1
  252. package/scripts/video/scene-table.ts +159 -0
  253. package/src/acp/core-turn-bridge.ts +39 -2
  254. package/src/agent-mission/review-loop.ts +4 -3
  255. package/src/agent-substrate/pr-comment-meta.ts +20 -0
  256. package/src/autopilot/build/llm-conflict-merge.ts +28 -8
  257. package/src/away/presence.ts +40 -0
  258. package/src/away/release-watch.ts +255 -0
  259. package/src/briefing/brief-items.ts +86 -17
  260. package/src/chat/index.ts +2 -1
  261. package/src/chat/short-question.ts +3 -40
  262. package/src/cli/autopilot-cli.ts +30 -11
  263. package/src/cli/away-cli.ts +68 -0
  264. package/src/cli/brief-cli.ts +36 -2
  265. package/src/cli/freeze-cli.ts +3 -2
  266. package/src/cli/guardian-cli.ts +49 -0
  267. package/src/cli/intake-cli.ts +85 -7
  268. package/src/cli/log-event-names.ts +1 -0
  269. package/src/cli/notify-cli.ts +75 -0
  270. package/src/cli/pod-cli.ts +5 -1
  271. package/src/cli/provider-cli.ts +12 -2
  272. package/src/cli/pty-drive-cli.ts +14 -3
  273. package/src/cli/release-cli.ts +128 -19
  274. package/src/cli/setup-cli.ts +31 -1
  275. package/src/cli/tasks-cli.ts +403 -4
  276. package/src/context-bus/condense.ts +19 -3
  277. package/src/context-bus/context-day.ts +77 -24
  278. package/src/context-bus/context-first.ts +33 -0
  279. package/src/context-bus/context-now-public.ts +1 -1
  280. package/src/context-bus/context-now-surfaces.ts +16 -6
  281. package/src/context-bus/context-now.ts +97 -3
  282. package/src/core-turn/short-question.ts +100 -0
  283. package/src/dashboard/dashboard-status-lines.ts +24 -4
  284. package/src/dashboard/index.ts +50 -5
  285. package/src/dashboard/input/slash-executor.ts +6 -2
  286. package/src/dashboard/slash-runtime/dashboard-handlers.ts +63 -36
  287. package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
  288. package/src/dashboard/slash-runtime/help-from-registry.ts +21 -8
  289. package/src/dashboard/slash-runtime/help-groups.ts +44 -0
  290. package/src/dashboard/slash-runtime/model-choices.ts +125 -0
  291. package/src/discord-self-message.ts +20 -2
  292. package/src/discord-slash-wire.ts +1 -0
  293. package/src/domains/guardian-tick.ts +138 -0
  294. package/src/domains/outbound-alert.ts +244 -40
  295. package/src/domains/outbound-log-probe.ts +16 -1
  296. package/src/domains/release-tool.ts +2 -2
  297. package/src/domains/schedule-registry.ts +23 -0
  298. package/src/domains/telegram-kind-route.ts +39 -0
  299. package/src/domains/watch-default-scheduler.ts +95 -0
  300. package/src/esc-abort-gate.ts +44 -0
  301. package/src/execution-loop/gates.ts +11 -2
  302. package/src/flow-loop/split.ts +8 -4
  303. package/src/git-fs/worktree.ts +23 -3
  304. package/src/graph-runner/runner.ts +25 -5
  305. package/src/harness/harness-cli-command.ts +12 -2
  306. package/src/harness/harness-queue.ts +388 -33
  307. package/src/harness/harness-salvage-cli.ts +78 -0
  308. package/src/harness/harness-worktree-add.ts +68 -0
  309. package/src/harness/helper-scan.ts +10 -3
  310. package/src/harness/ledger-write-guard.ts +6 -16
  311. package/src/hq/hq.ts +6 -1
  312. package/src/hq/seats.ts +369 -0
  313. package/src/index.ts +185 -18
  314. package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
  315. package/src/instance/test-write-guard.ts +200 -0
  316. package/src/intake-plane/adopt-gate.ts +49 -0
  317. package/src/intake-plane/check.ts +3 -0
  318. package/src/intake-plane/collect-github.ts +57 -25
  319. package/src/intake-plane/digest.ts +39 -15
  320. package/src/intake-plane/discord-seat-work.ts +8 -2
  321. package/src/intake-plane/harness-target.ts +4 -3
  322. package/src/intake-plane/intake-sources.ts +1 -0
  323. package/src/intake-plane/items.ts +1 -0
  324. package/src/intake-plane/requirement-funnel.ts +316 -0
  325. package/src/knowledge/know-find.ts +10 -1
  326. package/src/loops/budget.ts +36 -0
  327. package/src/loops/orchestrator/degradation.ts +57 -0
  328. package/src/loops/orchestrator/finish-rate.ts +106 -4
  329. package/src/loops/orchestrator/grid-place.ts +11 -0
  330. package/src/loops/orchestrator/tick.ts +450 -54
  331. package/src/maturity/feature-maturity.ts +8 -5
  332. package/src/maturity/tui-slash-maturity.ts +1 -0
  333. package/src/mss/logging/log-store.ts +3 -0
  334. package/src/nexus/api/decisions-route.ts +11 -1
  335. package/src/nexus/api/http-server.ts +16 -5
  336. package/src/nexus/api/loop-edges.ts +352 -23
  337. package/src/nexus/api/ops-api.ts +96 -28
  338. package/src/nexus/api/ops-seats-sources.ts +2 -2
  339. package/src/nexus/api/workflow-templates.ts +3 -0
  340. package/src/nexus/index.ts +7 -0
  341. package/src/oauth/codex.ts +38 -0
  342. package/src/onboarding/first-chat-gate.ts +29 -0
  343. package/src/release-loop/checklist.ts +106 -6
  344. package/src/release-loop/feature-store.ts +64 -16
  345. package/src/release-loop/landing-freeze.ts +6 -4
  346. package/src/release-loop/light-rc.ts +173 -0
  347. package/src/release-loop/placement.ts +64 -20
  348. package/src/release-loop/rubric.ts +136 -0
  349. package/src/seat-dispatch/seat-ask.ts +79 -16
  350. package/src/seat-loop/seat-loop.ts +12 -6
  351. package/src/self-dev/ask-launch-flow.ts +24 -3
  352. package/src/self-dev/ask-path-candidates.ts +68 -0
  353. package/src/self-dev/dev-cli.ts +36 -0
  354. package/src/self-dev/dev-pipeline.ts +4 -0
  355. package/src/self-dev/draft-triage-rules.ts +1 -1
  356. package/src/self-dev/orchestrate-cli.ts +22 -0
  357. package/src/self-dev/orchestrate.ts +1 -0
  358. package/src/self-dev/pr-preview.ts +179 -0
  359. package/src/self-dev/round-pr-supersede.ts +244 -0
  360. package/src/self-dev/run-supervisor.ts +14 -0
  361. package/src/self-dev/shard-run.ts +23 -7
  362. package/src/self-implement/follow-up-goals.ts +2 -2
  363. package/src/self-implement/gate-cli.ts +29 -8
  364. package/src/self-implement/gate-remote.ts +427 -0
  365. package/src/self-implement/goal-author-clarification.ts +88 -13
  366. package/src/self-implement/goal-author.ts +8 -3
  367. package/src/self-implement/goal-clarification-escalation.ts +2 -0
  368. package/src/self-implement/l8-merge-queue.ts +29 -5
  369. package/src/self-implement/orchestrator.ts +61 -13
  370. package/src/self-implement/prior-draft-findings.ts +4 -3
  371. package/src/self-implement/salvage-branches.ts +254 -0
  372. package/src/skills/skill-feedback.ts +76 -0
  373. package/src/task-agent/actions.ts +101 -7
  374. package/src/task-agent/board.ts +132 -0
  375. package/src/task-agent/card-evidence.ts +203 -0
  376. package/src/task-agent/completion-evidence.ts +126 -0
  377. package/src/task-agent/judge.ts +49 -5
  378. package/src/task-agent/live-moves.ts +176 -0
  379. package/src/task-agent/mission.ts +449 -0
  380. package/src/task-agent/shadow.ts +258 -0
  381. package/src/task-agent/task-hand.ts +337 -0
  382. package/src/task-orchestrator/surfaces/pod-command-job.ts +64 -4
  383. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +10 -0
  384. package/src/task-orchestrator/surfaces/pod-lease.ts +142 -13
  385. package/src/task-orchestrator/surfaces/pod-pool.ts +13 -5
  386. package/src/task-orchestrator/surfaces/self-implement-pod.ts +88 -20
  387. package/src/telegram-away-command.ts +38 -0
  388. package/src/telegram-commands.ts +11 -0
  389. package/src/telegram-loops-command.ts +1 -1
  390. package/src/telegram-report-log-probe.ts +21 -0
  391. package/src/telegram-report.ts +27 -3
  392. package/src/telegram.ts +5 -20
  393. package/src/tui-client/dashboard-session.ts +1 -0
  394. package/src/user-config.ts +196 -4
  395. package/src/version/packed-revision.json +1 -1
  396. package/apps/pwa/out/_next/static/chunks/1307-aac7332576c4d6fc.js +0 -1
  397. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  398. package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
  399. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
  400. package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
  401. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
  403. package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
  405. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  406. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
  416. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
  419. package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +0 -2
  420. package/apps/pwa/out/_next/static/chunks/6877-fe94e76a5841ee9b.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/8401-4ce1c42c8d89903f.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
  429. package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/899-f41be85e8a680651.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3143b07a817d1da9.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-17ba086ef82d339b.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/app/board/page-7eb661ff23af7da2.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/app/botlab/page-6b8444914da74ca6.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/app/bots/page-6e5c3a867557298b.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/app/ceo/page-7110f732f45bf944.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/app/chat/page-9a41d65355fc25b9.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/app/consult/page-5e77cd1802567c89.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/app/control/page-41afec0b255ed2bb.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/app/design-check/page-4187666132fc98c4.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/app/editor/page-09328d499162bae4.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/app/exec/page-29ff3a8f84f03b6a.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/app/field/page-80ec7401bc83f511.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/app/inside/page-ab93b240f687d69a.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/app/intake/page-fc7d86467291ae38.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/app/layout-de43a186e5ba5683.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/live/page-8b08cafad27759c9.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/app/loops/page-0e2d6985fb42cd2f.js +0 -1
  454. package/apps/pwa/out/_next/static/chunks/app/market/page-13e4108999f58d13.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e8296ee284aa1293.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/app/morning/page-043a9111e74f6b24.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/app/not-found-23a4601ceb7f452e.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1ed1324b1dc36754.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-10d958605a77b3bd.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-166745e51ac0c7b0.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a04260b8ccc968d4.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/app/outputs/page-7a1d85e121065cc8.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/app/page-1f50e3d4e13435f4.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/app/reflection/page-12916918988ac97e.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d8a3347a9d0c3f4a.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a9117d2cd3093d36.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-5a64cb5208c6a8fd.js +0 -1
  468. package/apps/pwa/out/_next/static/chunks/app/settings/page-1407ec83ea64c1f9.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-1d824510df025d18.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/app/setup/page-6e878ebbe1737d00.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/app/share/page-7f49fe645d5132f7.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/app/showroom/page-81a4e7f8dbfe74cb.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/app/tasks/page-27d71f131acd9320.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/app/term/page-3ab59d19913b200e.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/app/today/page-bf85b2f5bf077925.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/app/trace/page-424659bacfb8cdd7.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/app/vault/page-ab32a8f522a60371.js +0 -1
  479. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-fc2df261f8a2c7df.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/app/workflows/page-09461366af82ef13.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/app/workspace/page-5d4fef9ccd7d406b.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ea90a8ac73ce2749.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +0 -1
  489. package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
  490. package/apps/pwa/out/_next/static/yRA5ur6DcPl0YHSRheH2O/_buildManifest.js +0 -1
  491. /package/apps/pwa/out/_next/static/{yRA5ur6DcPl0YHSRheH2O → J5H7BvqgSI8DUjtRRcA_S}/_ssgManifest.js +0 -0
@@ -0,0 +1,35 @@
1
+ name: chat-driven-research
2
+ description: |
3
+ Chat-trigger workflow. POST a question to the daemon's chat endpoint
4
+ and the workflow plans → crawls → summarizes → returns. Streaming
5
+ response is opt-in (v2 daemon wire).
6
+
7
+ _meta:
8
+ template:
9
+ title: Chat-driven research
10
+ description: POST /chat → plan → crawl → summarize
11
+ tags: [chat, research, streaming]
12
+
13
+ nodes:
14
+ - id: chat
15
+ chatTrigger:
16
+ path: /research/chat
17
+ sessionMode: stateless
18
+ streaming: true
19
+
20
+ - id: plan
21
+ prompt: |
22
+ The user asked: "$ARGUMENTS". Break this into 3 sub-questions
23
+ we should research, one per line.
24
+ depends_on: [chat]
25
+
26
+ - id: crawl
27
+ skill: omni-crawl
28
+ arguments: $plan.output
29
+ depends_on: [plan]
30
+
31
+ - id: summarize
32
+ prompt: |
33
+ Synthesize these findings into a concise answer:
34
+ $crawl.output
35
+ depends_on: [crawl]
@@ -0,0 +1,29 @@
1
+ name: discord-listen-and-respond
2
+ description: |
3
+ Listens for messages on a specific Discord channel matching a regex
4
+ pattern, runs a small script, and posts a reply. Daemon-side AXON
5
+ bridge tap (BACKLOG FU-1) is required for production fire — until
6
+ then this works in dry-run via PWA "Run now".
7
+
8
+ _meta:
9
+ template:
10
+ title: Discord listen & respond
11
+ description: Discord #ops message → script → reply
12
+ tags: [discord, listen, respond]
13
+
14
+ nodes:
15
+ - id: listen
16
+ discordTrigger:
17
+ kind: message
18
+ channel: ops
19
+ pattern: "^deploy"
20
+
21
+ - id: handle
22
+ bash: |
23
+ echo "received: $listen.output"
24
+ depends_on: [listen]
25
+
26
+ - id: reply
27
+ bash: |
28
+ echo "replying with: $handle.output"
29
+ depends_on: [handle]
@@ -0,0 +1,30 @@
1
+ name: http-poll-then-alert
2
+ description: |
3
+ Hourly HTTP poll of an upstream API. When the response diverges from
4
+ the last seen value, fires the notify step. Useful for status pages /
5
+ feature flag dashboards / blog feeds.
6
+
7
+ _meta:
8
+ template:
9
+ title: HTTP poll + alert
10
+ description: Cron hourly → HTTP fetch → diff → notify
11
+ tags: [schedule, http, monitor]
12
+
13
+ nodes:
14
+ - id: tick
15
+ scheduleTrigger:
16
+ type: interval
17
+ interval: 3600000
18
+ enabled: true
19
+
20
+ - id: probe
21
+ http:
22
+ method: GET
23
+ url: https://status.example.com/api/status
24
+ timeout: 15000
25
+ depends_on: [tick]
26
+
27
+ - id: alert
28
+ bash: |
29
+ echo "status: $probe.output"
30
+ depends_on: [probe]
@@ -0,0 +1,21 @@
1
+ name: manual-quickstart
2
+ description: |
3
+ Two-node smoke for the very first PWA user — click ▶ "Run now" and
4
+ see the graph light up. Echoes the arguments and exits. Modify to
5
+ taste once you've confirmed the editor works.
6
+
7
+ _meta:
8
+ template:
9
+ title: Manual quickstart
10
+ description: Manual ▶ → echo → done (first-touch smoke)
11
+ tags: [manual, starter]
12
+
13
+ nodes:
14
+ - id: start
15
+ manualTrigger:
16
+ description: Click ▶ Run now to fire this workflow
17
+
18
+ - id: echo
19
+ bash: |
20
+ echo "hello from monad-agent: $ARGUMENTS"
21
+ depends_on: [start]
@@ -0,0 +1,30 @@
1
+ name: scheduled-daily-digest
2
+ description: |
3
+ Daily 9am Seoul-time digest workflow.
4
+ Triggers: schedule cron 0 9 * * * Asia/Seoul.
5
+ Does: crawls a fixed search term → omni-digest summary → saves to Obsidian.
6
+ Edit this template to swap the search term / Obsidian target.
7
+
8
+ _meta:
9
+ template:
10
+ title: Daily digest
11
+ description: Cron 9am → crawl → summarize → save
12
+ tags: [schedule, daily, digest]
13
+
14
+ nodes:
15
+ - id: tick
16
+ scheduleTrigger:
17
+ type: cron
18
+ cron: 0 9 * * *
19
+ timezone: Asia/Seoul
20
+ enabled: true
21
+
22
+ - id: crawl
23
+ skill: omni-crawl
24
+ arguments: "latest AI agent news"
25
+ depends_on: [tick]
26
+
27
+ - id: save
28
+ skill: omni-digest
29
+ arguments: $crawl.output
30
+ depends_on: [crawl]
@@ -0,0 +1,27 @@
1
+ name: webhook-deploy-hook
2
+ description: |
3
+ Production deploy webhook receiver. CI posts to /hooks/deploy with
4
+ the build artifact id; the workflow builds, runs tests, and notifies
5
+ on Slack/Discord depending on result.
6
+
7
+ _meta:
8
+ template:
9
+ title: Webhook deploy hook
10
+ description: POST /hooks/deploy → build → notify
11
+ tags: [webhook, deploy, ci]
12
+
13
+ nodes:
14
+ - id: receive
15
+ webhookTrigger:
16
+ method: POST
17
+ path: /hooks/deploy
18
+
19
+ - id: build
20
+ bash: |
21
+ echo "building $ARGUMENTS" && sleep 1 && echo ok
22
+ depends_on: [receive]
23
+
24
+ - id: notify
25
+ bash: |
26
+ echo "deploy result: $build.output"
27
+ depends_on: [build]
@@ -88,9 +88,14 @@ export async function exportImportCheck(changedFiles: readonly string[], root: s
88
88
  const tracked = trackedFiles(root);
89
89
  if (!tracked) return { measured: false, hits: [], unseen: 0, detail: 'git ls-files 실패' };
90
90
  let included: Set<string>;
91
+ let present: Set<string>;
91
92
  try {
92
93
  const { loadExportConfig, selectExportFiles } = await exportSelectors();
93
- included = new Set(selectExportFiles(tracked, loadExportConfig(root)));
94
+ const config = loadExportConfig(root);
95
+ included = new Set(selectExportFiles(tracked, config));
96
+ // An import target also exists in the export when `replace` writes a public file at that path. Only targets use
97
+ // this — a replaced private original is not shipped, so it is not scanned as an importer.
98
+ present = new Set([...included, ...Object.keys(config.replace ?? {})]);
94
99
  } catch (error) {
95
100
  return { measured: false, hits: [], unseen: 0, detail: error instanceof Error ? error.message : '매니페스트를 못 읽었다' };
96
101
  }
@@ -108,7 +113,7 @@ export async function exportImportCheck(changedFiles: readonly string[], root: s
108
113
  const resolvedSpec = resolveSpecifier(file, specifier);
109
114
  if (!resolvedSpec) return;
110
115
  const target = candidatePaths(resolvedSpec).find((candidate) => trackedSet.has(candidate));
111
- if (!target || included.has(target)) return;
116
+ if (!target || present.has(target)) return;
112
117
  const key = `${index}\0${target}`;
113
118
  if (seen.has(key)) return;
114
119
  seen.add(key);
@@ -1032,14 +1032,29 @@ export function runGate(io: Partial<GateIo> = {}): void {
1032
1032
  // ⭐ 그래서 막는 자리는 «여기»뿐이다 — 인-프로세스 호출자(`pr-cli.ts`·`seams.ts`)는
1033
1033
  // argv 를 안 넘기고, 만약 여기서 `process.argv` 를 «읽으면» 형제 게이트가 경고한 그 사고가 난다
1034
1034
  // (`elanous pr land` 의 인자를 자기 인자로 읽는다 — `src/cli/pr-cli.ts` 의 `args: []` 주석).
1035
- if (import.meta.main) {
1036
- const cliArgs = process.argv.slice(2);
1037
- if (cliArgs.length > 0) {
1038
- console.error(`[tsc-gate] ⛔ 이 게이트는 인자를 받지 않는다 — 준 인자 ${cliArgs.length}개를 «조용히 삼키지 않고» 막는다: ${cliArgs.join(' ')}`);
1035
+ if (import.meta.main) void (async () => {
1036
+ // GATE-REMOTE (10-06): the only accepted arguments are the dispatch flags `--remote [host]` / `--local` — they choose
1037
+ // «where» the same commit is measured, never «what» (the base stays merge-base(origin/main) on both sides).
1038
+ const { extractGateRemoteFlags, dispatchHeavyCheck } = await import('../src/self-implement/gate-remote.js');
1039
+ const flags = extractGateRemoteFlags(process.argv.slice(2));
1040
+ const cliArgs = flags.rest;
1041
+ if (cliArgs.length > 0 || flags.error) {
1042
+ if (flags.error) console.error(`[tsc-gate] ⛔ ${flags.error}`);
1043
+ if (cliArgs.length > 0) console.error(`[tsc-gate] ⛔ 이 게이트는 인자를 받지 않는다(--remote/--local 제외) — 준 인자 ${cliArgs.length}개를 «조용히 삼키지 않고» 막는다: ${cliArgs.join(' ')}`);
1039
1044
  console.error('[tsc-gate] 기준은 언제나 merge-base(origin/main) 다. 다른 기준으로 재려면 «그 트리에 서서» 돌려라:');
1040
1045
  console.error('[tsc-gate] git worktree add --detach <경로> <커밋> && cd <경로> && bun run scripts/ci-typecheck-changed.ts');
1041
1046
  console.error('[tsc-gate] ⇒ 그러면 merge-base 가 그때와 «같아진다». 이것이 재현의 유일한 길이다.');
1042
1047
  process.exit(2);
1043
1048
  }
1044
- runGate();
1045
- }
1049
+ const repo = sh('git rev-parse --show-toplevel').trim();
1050
+ const baseRef = process.env.TSC_BASE_REF;
1051
+ const passEnv = (sha: (ref: string) => string) => (['NODE_OPTIONS', 'TSC_BASE_REF', 'TSC_HEAP_MB'] as const).filter((key) => process.env[key])
1052
+ .map((key) => `${key}=${key === 'TSC_BASE_REF' && baseRef !== 'origin/main' ? sha(baseRef!) : process.env[key]}`);
1053
+ // exitCode, not exit(): piped stdout/stderr drain before the process ends.
1054
+ process.exitCode = await dispatchHeavyCheck({
1055
+ tool: 'ci-typecheck-changed', repo, flags,
1056
+ remoteArgv: (sha) => { const vars = passEnv(sha); return [...(vars.length ? ['env', ...vars] : []), 'bun', 'run', 'scripts/ci-typecheck-changed.ts', '--local']; },
1057
+ refs: baseRef ? [baseRef] : [],
1058
+ runLocal: () => { runGate(); return 0; },
1059
+ });
1060
+ })();
@@ -49,8 +49,8 @@
49
49
  set -u
50
50
  set -o pipefail
51
51
 
52
- PR_NUM="${CH_PR:-23032}" # ⛔ 2026-10-03: #20798 가 2,500 상한 → 채널 «6»(OP) # ⛔ 2026-09-27: #16815 가 2,500 상한에 닿아 채널 «5» 로 옮김(🅞 · 벽에 «닿은 뒤» — 미리 못 옮겼다)
53
- # 📏 이력: #5730(07-28~08-12) → #8328(08-11~08-25) → #12577(08-25~09-10) → #16815(09-10~09-27) → #20798(09-27~10-03) → #23032.
52
+ PR_NUM="${CH_PR:-24694}" # ⛔ 2026-10-07: #23032 가 2,500 상한 → 채널 «7»(OP) # ⛔ 2026-10-03: #20798 가 2,500 상한 → 채널 «6»(OP) # ⛔ 2026-09-27: #16815 가 2,500 상한에 닿아 채널 «5» 로 옮김(🅞 · 벽에 «닿은 뒤» — 미리 못 옮겼다)
53
+ # 📏 이력: #5730(07-28~08-12) → #8328(08-11~08-25) → #12577(08-25~09-10) → #16815(09-10~09-27) → #20798(09-27~10-03) → #23032(10-03~10-07) → #24694.
54
54
  # ***수명이 «2주 안팎»이다 — 세 판이 전부 그랬다.*** 다음 벽은 09-24 언저리.
55
55
  # 🩹 발신이 rc=1 이면 먼저 세라: gh api repos/ElanvitalAI/elanous/issues/<n> --jq .comments
56
56
  REPO="${CH_REPO:-ElanvitalAI/elanous}"
@@ -56,7 +56,8 @@ export async function probeDiscordSeatWork(text: string, options: ProbeOptions =
56
56
  open: () => { const db = new Database(':memory:'); return { db, close: () => db.close() } as unknown as MsgStore; },
57
57
  dispatch: async (seatId, forwarded) => {
58
58
  capture('ask', seatId, forwarded);
59
- return { channel: 'unknown', reply: '마른 실행 — 질문을 맡기지 않았습니다.' };
59
+ // Since #24523 a seat *task* also travels this ask path (so the answer can come back) — the wording covers both.
60
+ return { channel: 'unknown', reply: `마른 실행 — ${seatId}에 맡길 예정 (실제 맡김 없음).` };
60
61
  },
61
62
  send: async () => { throw new Error('dry Discord delivery unavailable'); },
62
63
  },
@@ -76,14 +77,16 @@ export async function probeDiscordSeatWork(text: string, options: ProbeOptions =
76
77
  ...options.liveDeps?.askDeps,
77
78
  dispatch: async (seatId, forwarded, deps, extra) => {
78
79
  capture('ask', seatId, forwarded);
79
- return (options.liveDeps?.askDeps?.dispatch ?? dispatchCeoTask)(seatId, forwarded, deps, extra);
80
+ return (options.liveDeps?.askDeps?.dispatch ?? options.liveDeps?.dispatch ?? dispatchCeoTask)(seatId, forwarded, deps, extra);
80
81
  },
81
82
  // This CLI has no Discord transport: even live mode must not post to Discord.
82
83
  send: async () => { throw new Error('probe does not send Discord messages'); },
83
84
  },
84
85
  };
85
86
  const start = performance.now();
86
- const reply = await handleDiscordSeatWork(text, msg, options.live ? live : dry);
87
+ let reply = await handleDiscordSeatWork(text, msg, options.live ? live : dry);
88
+ // The ask path answers with its real acceptance text («…에게 맡겼습니다»); a dry run must still say nothing was assigned.
89
+ if (!options.live && (route as ProbeResult['route']) === 'ask' && reply !== null) reply = `마른 실행 (실제 맡김 없음) — ${reply}`;
87
90
  return { text: Array.from(text).slice(0, 80).join(''), ms: Math.round((performance.now() - start) * 100) / 100,
88
91
  route, seat, body, reply: reply === null ? null : Array.from(reply).slice(0, 120).join('') };
89
92
  }
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env bun
2
+ /** DOC-GEN — src/cli/ 의 정적 Commander 명령을 실행 없이 TypeScript AST 로 읽는다. */
3
+ import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { dirname, join, relative } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import ts from 'typescript';
7
+ import { readCommit } from './generate-graph-anatomy.js';
8
+
9
+ export interface RenderCliAnatomyInput {
10
+ readonly cliRoot: string;
11
+ readonly repoRoot: string;
12
+ readonly commit: string;
13
+ readonly generatedAt: string;
14
+ }
15
+
16
+ interface CommandRow {
17
+ readonly name: string;
18
+ readonly description: string;
19
+ readonly file: string;
20
+ }
21
+
22
+ function propertyCall(expression: ts.Expression, method: string): expression is ts.CallExpression & { expression: ts.PropertyAccessExpression } {
23
+ return ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression)
24
+ && expression.expression.name.text === method;
25
+ }
26
+
27
+ function literal(expression: ts.Expression | undefined): string | undefined {
28
+ return expression && (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression))
29
+ ? expression.text : undefined;
30
+ }
31
+
32
+ function descriptionOf(command: ts.CallExpression): string {
33
+ let current: ts.Expression = command;
34
+ while (ts.isPropertyAccessExpression(current.parent) && current.parent.expression === current
35
+ && ts.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
36
+ const property = current.parent;
37
+ const call = current.parent.parent;
38
+ if (property.name.text === 'description') return literal(call.arguments[0]) ?? '';
39
+ if (property.name.text === 'command') break;
40
+ current = call;
41
+ }
42
+ return '';
43
+ }
44
+
45
+ function rowsInFile(source: string, file: string): CommandRow[] {
46
+ const ast = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
47
+ interface Scope {
48
+ readonly owner: ts.Node;
49
+ readonly parent?: Scope;
50
+ readonly bindings: Map<string, ts.VariableDeclaration | null>;
51
+ }
52
+ const scopes = new Map<ts.Node, Scope>();
53
+ const gather = (node: ts.Node, outer?: Scope): void => {
54
+ const createsScope = ts.isSourceFile(node) || ts.isBlock(node) || ts.isModuleBlock(node)
55
+ || ts.isCaseBlock(node) || ts.isCatchClause(node) || ts.isFunctionLike(node)
56
+ || ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node);
57
+ const scope: Scope = createsScope ? { owner: node, parent: outer, bindings: new Map() } : outer!;
58
+ scopes.set(node, scope);
59
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
60
+ const list = node.parent;
61
+ const isVar = ts.isVariableDeclarationList(list) && (list.flags & ts.NodeFlags.BlockScoped) === 0;
62
+ let target = scope;
63
+ if (isVar) {
64
+ while (target.parent && !ts.isSourceFile(target.owner) && !ts.isFunctionLike(target.owner)) {
65
+ target = target.parent;
66
+ }
67
+ }
68
+ target.bindings.set(node.name.text, node);
69
+ }
70
+ if (ts.isFunctionLike(node)) {
71
+ for (const parameter of node.parameters) {
72
+ if (ts.isIdentifier(parameter.name)) scope.bindings.set(parameter.name.text, null);
73
+ }
74
+ }
75
+ if (ts.isCatchClause(node) && node.variableDeclaration && ts.isIdentifier(node.variableDeclaration.name)) {
76
+ scope.bindings.set(node.variableDeclaration.name.text, null);
77
+ }
78
+ ts.forEachChild(node, (child) => gather(child, scope));
79
+ };
80
+ gather(ast);
81
+
82
+ const commandName = (expression: ts.Expression, seen: ReadonlySet<ts.VariableDeclaration> = new Set()): string => {
83
+ if (ts.isParenthesizedExpression(expression)) return commandName(expression.expression, seen);
84
+ if (ts.isIdentifier(expression)) {
85
+ let scope = scopes.get(expression);
86
+ while (scope && !scope.bindings.has(expression.text)) scope = scope.parent;
87
+ const declaration = scope?.bindings.get(expression.text);
88
+ if (!declaration || !declaration.initializer || seen.has(declaration)) return '';
89
+ return commandName(declaration.initializer, new Set([...seen, declaration]));
90
+ }
91
+ if (propertyCall(expression, 'command')) {
92
+ const name = literal(expression.arguments[0]);
93
+ if (name === undefined) return '';
94
+ const parent = commandName(expression.expression.expression, seen);
95
+ return parent ? `${parent} ${name}` : name;
96
+ }
97
+ if (ts.isCallExpression(expression) && ts.isPropertyAccessExpression(expression.expression)) {
98
+ return commandName(expression.expression.expression, seen);
99
+ }
100
+ return '';
101
+ };
102
+
103
+ const rows: CommandRow[] = [];
104
+ const visit = (node: ts.Node): void => {
105
+ if (ts.isCallExpression(node) && propertyCall(node, 'command')) {
106
+ const name = literal(node.arguments[0]);
107
+ if (name !== undefined) rows.push({ name: commandName(node), description: descriptionOf(node), file });
108
+ }
109
+ ts.forEachChild(node, visit);
110
+ };
111
+ visit(ast);
112
+ return rows;
113
+ }
114
+
115
+ function cell(value: string): string {
116
+ return value.replace(/\|/g, '\\|').replace(/\r?\n/g, ' ');
117
+ }
118
+
119
+ /** 지정된 src/cli/ 바로 아래 .ts 만 읽으며 import/명령을 실행하지 않는다. */
120
+ export function renderCliAnatomy(input: RenderCliAnatomyInput): string {
121
+ const rows = readdirSync(input.cliRoot, { withFileTypes: true })
122
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.ts')
123
+ && !entry.name.endsWith('.test.ts') && !entry.name.endsWith('.spec.ts'))
124
+ .flatMap((entry) => {
125
+ const abs = join(input.cliRoot, entry.name);
126
+ return rowsInFile(readFileSync(abs, 'utf8'), relative(input.repoRoot, abs).replace(/\\/g, '/'));
127
+ })
128
+ .sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.file < b.file ? -1 : a.file > b.file ? 1 : 0);
129
+ return [
130
+ '# CLI anatomy',
131
+ '',
132
+ '> 이 문서는 생성물이다 — 손으로 고치지 마라',
133
+ '',
134
+ `- generatedAt: ${input.generatedAt}`,
135
+ `- commit: ${input.commit}`,
136
+ '',
137
+ '| 명령 | 설명 | 정의 파일 |',
138
+ '| --- | --- | --- |',
139
+ ...rows.map((row) => `| ${cell(row.name)} | ${cell(row.description)} | ${cell(row.file)} |`),
140
+ '',
141
+ ].join('\n');
142
+ }
143
+
144
+ export function defaultOutputPath(repoRoot: string): string {
145
+ return join(repoRoot, 'docs', 'generated', 'cli-anatomy.md');
146
+ }
147
+
148
+ function main(): void {
149
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
150
+ const argv = process.argv.slice(2);
151
+ const index = argv.indexOf('--out');
152
+ const outArg = index < 0 ? undefined : argv[index + 1];
153
+ if (index >= 0 && (!outArg || outArg.startsWith('--'))) throw new Error('--out 에는 경로가 필요하다');
154
+ const out = outArg ?? defaultOutputPath(repoRoot);
155
+ const markdown = renderCliAnatomy({ cliRoot: join(repoRoot, 'src', 'cli'), repoRoot,
156
+ commit: readCommit(repoRoot), generatedAt: new Date().toISOString() });
157
+ mkdirSync(dirname(out), { recursive: true });
158
+ writeFileSync(out, markdown);
159
+ process.stdout.write(`${out}\n`);
160
+ }
161
+
162
+ if (import.meta.main) main();
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bun
2
+ import { readFileSync } from 'node:fs';
3
+ import { inspectAskMarkers } from '../ask-marker-check.js';
4
+
5
+ export interface AuthoringMeasurement {
6
+ readonly path: string;
7
+ readonly chars: number;
8
+ readonly bytes: number;
9
+ readonly sections: number;
10
+ readonly markerAxes: number;
11
+ readonly markerFailed: number;
12
+ }
13
+
14
+ type UnreadableMeasurement = { readonly path: string; readonly error: 'unreadable' };
15
+ type AuthoringRow = AuthoringMeasurement | UnreadableMeasurement;
16
+
17
+ export function measureAuthoring(path: string, text: string): AuthoringMeasurement {
18
+ const axes = inspectAskMarkers(text);
19
+ return {
20
+ path,
21
+ chars: text.length,
22
+ bytes: Buffer.byteLength(text, 'utf8'),
23
+ sections: text.split(/\r?\n/).filter((line) => /^#{1,6}\s/u.test(line)).length,
24
+ markerAxes: axes.length,
25
+ markerFailed: axes.filter((axis) => !(axis.marker && axis.extracted)).length,
26
+ };
27
+ }
28
+
29
+ export function median(numbers: readonly number[]): number | null {
30
+ if (numbers.length === 0) return null;
31
+ const sorted = [...numbers].sort((a, b) => a - b);
32
+ const middle = Math.floor(sorted.length / 2);
33
+ return sorted.length % 2 === 1
34
+ ? sorted[middle]!
35
+ : (sorted[middle - 1]! + sorted[middle]!) / 2;
36
+ }
37
+
38
+ function main(argv: readonly string[]): number {
39
+ const json = argv.includes('--json');
40
+ const paths = argv.filter((argument) => argument !== '--json');
41
+ const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
42
+ const rows: AuthoringRow[] = paths.map((path) => {
43
+ let text: string;
44
+ try {
45
+ text = decoder.decode(readFileSync(path));
46
+ } catch {
47
+ return { path, error: 'unreadable' };
48
+ }
49
+ return measureAuthoring(path, text);
50
+ });
51
+ const measured = rows.filter((row): row is AuthoringMeasurement => !('error' in row));
52
+ const summary = {
53
+ files: measured.length,
54
+ medianChars: median(measured.map((row) => row.chars)),
55
+ medianBytes: median(measured.map((row) => row.bytes)),
56
+ };
57
+
58
+ if (json) {
59
+ for (const row of rows) console.log(JSON.stringify(row));
60
+ console.log(JSON.stringify(summary));
61
+ } else {
62
+ console.log('path\tchars\tbytes\tsections\tmarkerAxes\tmarkerFailed\terror');
63
+ for (const row of rows) {
64
+ console.log('error' in row
65
+ ? `${row.path}\t\t\t\t\t\t${row.error}`
66
+ : `${row.path}\t${row.chars}\t${row.bytes}\t${row.sections}\t${row.markerAxes}\t${row.markerFailed}\t`);
67
+ }
68
+ console.log(`files\t${summary.files}\tmedianChars\t${summary.medianChars ?? '—'}\tmedianBytes\t${summary.medianBytes ?? '—'}`);
69
+ }
70
+ return rows.some((row) => 'error' in row) ? 1 : 0;
71
+ }
72
+
73
+ if (import.meta.main) process.exitCode = main(process.argv.slice(2));
@@ -1,4 +1,4 @@
1
- import { parse } from '../../src/agent-substrate/pr-comment-meta.js';
1
+ import { expandRecords, parse } from '../../src/agent-substrate/pr-comment-meta.js';
2
2
 
3
3
  export type MustFixVerdict = 'resolved' | 'unresolved' | 'unknown';
4
4
  export interface ReviewRoundMatch {
@@ -12,12 +12,12 @@ export interface ReviewRoundMatch {
12
12
  const MUST_FIX_ROUND = /^Round \d+: reviewer requested \d+ must-fix change\(s\)\.$/m;
13
13
 
14
14
  export function classifyReviewRounds(comments: Array<{ body?: string }>): ReviewRoundMatch[] {
15
- const reviews = comments.flatMap(({ body }) => {
16
- if (!body) return [];
17
- const meta = parse(body);
18
- return meta?.role === 'reviewer' && meta.run && meta.round !== undefined
19
- ? [{ body, run: meta.run, round: meta.round }] : [];
20
- });
15
+ const reviews = comments.flatMap(({ body }) =>
16
+ body ? expandRecords(body).flatMap((record) => {
17
+ const meta = parse(record);
18
+ return meta?.role === 'reviewer' && meta.run && meta.round !== undefined
19
+ ? [{ body: record, run: meta.run, round: meta.round }] : [];
20
+ }) : []);
21
21
  // 항목은 «must-fix 요청» 라운드에서만 센다 — «review completed (warn)» 의 요약 본문에도 «- » 글머리가 들어 있다(#21983 실물).
22
22
  return reviews.flatMap(({ body, run, round }) => !MUST_FIX_ROUND.test(body) ? [] :
23
23
  [...body.matchAll(/^- (.+)$/gm)].map((item) => ({
@@ -5,7 +5,7 @@ import { dirname, join, resolve } from 'node:path';
5
5
  import { githubAutomationToken } from '../../src/auth/github-app-token.js';
6
6
  import { debug } from '../../src/debug/log.js';
7
7
  import { emitDecision } from '../../src/live/detail-switch.js';
8
- import { parse } from '../../src/agent-substrate/pr-comment-meta.js';
8
+ import { expandRecords, parse } from '../../src/agent-substrate/pr-comment-meta.js';
9
9
  import { classifyReviewRounds, matchMustFix, type MustFixVerdict } from './must-fix-match.js';
10
10
  import { verifyCleanCheckout, type CheckoutResult } from './clean-checkout.js';
11
11
 
@@ -116,7 +116,8 @@ export function runMission(mission: string, ctx: GraphContext, run: RunCommand =
116
116
  const pages = JSON.parse(run(['api', `repos/{owner}/{repo}/pulls/${pr.number}/comments`, '--paginate', '--slurp'])) as Array<Array<{ body?: string }>>;
117
117
  if (!Array.isArray(pages) || !pages.every(Array.isArray)) throw new Error(`invalid review comments for PR #${pr.number}`);
118
118
  const inline = pages.flat();
119
- const comments = [...(details.reviews ?? []), ...(details.comments ?? []), ...inline];
119
+ const comments = [...(details.reviews ?? []), ...(details.comments ?? []), ...inline]
120
+ .flatMap((comment) => comment.body ? expandRecords(comment.body).map((body) => ({ ...comment, body })) : [comment]);
120
121
  const reviewRounds = comments.filter(({ body }) => {
121
122
  const meta = body ? parse(body) : null;
122
123
  return meta?.role === 'reviewer' && !!meta.run && meta.round !== undefined;
@@ -0,0 +1,23 @@
1
+ // Paths are relative to apps/pwa, the cwd of each bun test invocation.
2
+ // Empty lists mean no existing PWA test was identified for that document slot.
3
+ export const PCH_REGRESS_MAP: Record<string, readonly string[]> = {
4
+ 'PCH-1': ['src/components/chat/ChatLayout.test.tsx', 'src/lib/chat-runtime.meta.test.ts'],
5
+ 'PCH-2': [], // Parent slot: PCH-2a (live observation) and PCH-2b (approval UI) are distinct.
6
+ 'PCH-2a': [], // Live write/approval observation is not a PWA unit test.
7
+ 'PCH-2b': ['src/components/tool-approval/use-tool-approval.test.ts', 'src/components/chat/ChatApprovalsChip.test.tsx'],
8
+ 'PCH-3': ['src/lib/chat-model-commands.test.ts'],
9
+ 'PCH-4': [], // Parent slot: daemon usage endpoint is outside apps/pwa.
10
+ 'PCH-4a': [], // Daemon usage endpoint, not a PWA test.
11
+ 'PCH-4b': ['src/lib/chat-status.test.ts', 'src/lib/chat-runtime.meta.test.ts'],
12
+ 'PCH-5': ['src/lib/chat-paste-drop.test.ts', 'src/components/chat/ChatLayout.test.tsx'],
13
+ 'PCH-6': ['src/lib/chat-queue.test.ts', 'src/components/chat/ChatLayout.test.tsx'],
14
+ 'PCH-7': ['src/lib/chat-session-commands.test.ts'],
15
+ 'PCH-8': ['src/lib/chat-harness-ask.test.ts', 'src/components/chat/HarnessAskCard.test.tsx'],
16
+ 'PCH-9': ['src/components/chat/ChatPendingDecision.test.tsx', 'src/components/chat/ChatDecisionsChip.test.tsx'],
17
+ 'PCH-10': ['src/lib/chat-runtime.meta.test.ts'], // /rewind · /undo meta commands.
18
+ 'PCH-11': ['src/lib/chat-fork.test.ts'],
19
+ 'PCH-12': ['src/lib/chat-runtime.run-skill.test.ts'],
20
+ 'PCH-13': ['src/components/chat/ChatConversationList.test.tsx'], // Chat search; export has no identified PWA test.
21
+ 'PCH-14': ['src/lib/compact-mode.test.ts'], // Compact; plan toggle has no identified PWA test.
22
+ 'PCH-15': ['src/components/terminal/TerminalChatDock.test.tsx'],
23
+ };
@@ -6,11 +6,16 @@
6
6
  // bun run scripts/morning-report.ts --no-upload # skip S3 상세 업로드(로컬 미리보기)
7
7
 
8
8
  import { composeMorningReport } from '../src/domains/morning-report.js';
9
- import { sendTelegramReport, sendReportPhoto } from '../src/telegram-report.js';
9
+ import { explainReportRoute, sendTelegramReport, sendReportPhoto } from '../src/telegram-report.js';
10
10
  import { getUserConfig } from '../src/user-config.js';
11
11
  import { getFirecrawlConfig } from '../src/registry/discovery/config.js';
12
12
  import { captureFinvizMapImageUrl } from '../src/domains/finviz-image.js';
13
13
 
14
+ import { registerStandaloneLogSink } from '../src/domains/standalone-log-sink.js';
15
+
16
+ // cron runs this outside the daemon — attach logs.db so `elanous logs --category telegram.report` sees the send.
17
+ await registerStandaloneLogSink('morning-report');
18
+
14
19
  const dry = process.argv.includes('--dry');
15
20
  const cfg = getUserConfig();
16
21
  const narrate = cfg.finance.morningNarrative !== false && !process.argv.includes('--no-narrate');
@@ -32,9 +37,18 @@ if (dry) {
32
37
  console.log(report);
33
38
  } else {
34
39
  const sent = await sendTelegramReport(cfg, report, { markdown: true, kind: 'report' });
35
- console.error(sent
36
- ? '[morning-report] sent to report channel ✓'
37
- : '[morning-report] no report channel configured — skipped');
40
+ if (sent) console.error('[morning-report] sent to report channel ✓');
41
+ else {
42
+ // ⛔ «no report channel configured» was printed for four days while reportChannel was set
43
+ // (BRIEF-DELIVERY-1007) — say which routing rule closed it, and fail the cron run.
44
+ const why = explainReportRoute(cfg, 'report');
45
+ console.error(!report
46
+ ? '[morning-report] ⛔ 못 보냄(report) — empty-report: 본문이 비었다(composeMorningReport 산출 확인)'
47
+ : why.reason === 'routed'
48
+ ? '[morning-report] ⛔ 못 보냄(report) — unconfirmed: 텔레그램이 message_id 를 돌려주지 않았다(elanous logs --category telegram.report)'
49
+ : `[morning-report] ⛔ 못 보냄(report) — ${why.reason}: ${why.hint}`);
50
+ process.exitCode = 1;
51
+ }
38
52
 
39
53
  // 히트맵 이미지 첨부(위에서 캡처한 URL 재사용). fail-soft.
40
54
  if (heatmapImageUrl) {