elanous 0.2.20 → 0.2.22

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 (456) 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/aBi6EyMtLsrl7J8eH4kF7/_buildManifest.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/088d8e8a.8069543d082bec12.js +160 -0
  5. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +148 -0
  6. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +32 -0
  7. package/apps/pwa/out/_next/static/chunks/119fc678.6f591cdb84ca5791.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +309 -0
  9. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +122 -0
  11. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +149 -0
  12. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +79 -0
  13. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +24 -0
  15. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +27 -0
  19. package/apps/pwa/out/_next/static/chunks/1948.5f35b39eef222a94.js +5 -0
  20. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +36 -0
  25. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +286 -0
  26. package/apps/pwa/out/_next/static/chunks/{2489-ff55a35b202c0f94.js → 2489-d238d3e2eb5b2bf5.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
  34. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
  38. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
  41. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
  45. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
  47. package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
  48. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
  50. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
  55. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
  60. package/apps/pwa/out/_next/static/chunks/{6158.af2e93b7adff709b.js → 6158.566c890adc06a459.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
  62. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
  64. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
  65. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
  67. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
  74. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
  75. package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
  76. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
  82. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
  83. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
  85. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
  87. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
  89. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
  90. package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/app/approvals/{page-c855c24de7db74fe.js → page-88459e0903da2803.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-85b316bb4235980b.js → page-d85c43f46f58716b.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/app/board/{page-9b2b26a33cb2cd42.js → page-4e645600579ae952.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-c9955fde67b1bcb5.js → page-87edbfd19117823b.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/app/chat/{page-4ba4abe096b6c2a8.js → page-cbaf66b1e1804adf.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/app/consult/{page-575d4a8b4f7becb2.js → page-80ed511e02c81412.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/app/control/{page-f5d56ff5f45ad164.js → page-9f5610caaa06178c.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/app/decisions/{page-2260e9eef0357421.js → page-ec8f3575e339de74.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/app/exec/{page-466bf0ee16ad1432.js → page-2a19c5cd3b562580.js} +1 -1
  105. package/apps/pwa/out/_next/static/chunks/app/field/{page-a23bc71713bcc08f.js → page-b6a09cde2e07521a.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/app/loops/{page-35bfec2e631d3eae.js → page-abd86cd832aaa011.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-f9ccb1b1adbea14d.js → page-8c3f168fc3f91939.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/app/morning/{page-ec102c9b8b691e37.js → page-786fb4504d0f2fa9.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-db03ae3589a81c9e.js → page-7ec8e289b4c14df6.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-4a6463b97f0ad94f.js → page-8c8ac17d52be2a79.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/app/sessions/{page-75bffecc9aa1004e.js → page-d359ab048d63a9d9.js} +1 -1
  125. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/settings/{page-31d5b875760bb62d.js → page-f151cc10ad026940.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/share/{page-46d5201d2207a511.js → page-bf495a1e284f4e00.js} +1 -1
  130. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/term/{page-cf0a4b4abead71ea.js → page-9abcfac07e02a542.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-0acc8e198f7b0dfb.js → page-69cb93d1a2e57e0e.js} +1 -1
  138. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-34882c84f84021c5.js → page-72ec543928d67c3e.js} +1 -1
  139. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
  141. package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
  143. package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
  144. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +1 -0
  145. package/apps/pwa/out/approvals/index.html +1 -1
  146. package/apps/pwa/out/approvals/index.txt +14 -14
  147. package/apps/pwa/out/autopilot/index.html +1 -1
  148. package/apps/pwa/out/autopilot/index.txt +14 -14
  149. package/apps/pwa/out/board/index.html +1 -1
  150. package/apps/pwa/out/board/index.txt +14 -14
  151. package/apps/pwa/out/botlab/index.html +1 -1
  152. package/apps/pwa/out/botlab/index.txt +14 -14
  153. package/apps/pwa/out/bots/index.html +1 -1
  154. package/apps/pwa/out/bots/index.txt +14 -14
  155. package/apps/pwa/out/ceo/index.html +1 -1
  156. package/apps/pwa/out/ceo/index.txt +14 -14
  157. package/apps/pwa/out/chat/index.html +1 -1
  158. package/apps/pwa/out/chat/index.txt +14 -14
  159. package/apps/pwa/out/consult/index.html +1 -1
  160. package/apps/pwa/out/consult/index.txt +14 -14
  161. package/apps/pwa/out/control/index.html +1 -1
  162. package/apps/pwa/out/control/index.txt +14 -14
  163. package/apps/pwa/out/decisions/index.html +1 -1
  164. package/apps/pwa/out/decisions/index.txt +14 -14
  165. package/apps/pwa/out/design-check/index.html +1 -1
  166. package/apps/pwa/out/design-check/index.txt +14 -14
  167. package/apps/pwa/out/editor/index.html +1 -1
  168. package/apps/pwa/out/editor/index.txt +15 -15
  169. package/apps/pwa/out/exec/index.html +1 -1
  170. package/apps/pwa/out/exec/index.txt +14 -14
  171. package/apps/pwa/out/field/index.html +1 -1
  172. package/apps/pwa/out/field/index.txt +14 -14
  173. package/apps/pwa/out/healthz +1 -1
  174. package/apps/pwa/out/index.html +1 -1
  175. package/apps/pwa/out/index.txt +14 -14
  176. package/apps/pwa/out/inside/index.html +1 -1
  177. package/apps/pwa/out/inside/index.txt +15 -15
  178. package/apps/pwa/out/intake/index.html +1 -1
  179. package/apps/pwa/out/intake/index.txt +14 -14
  180. package/apps/pwa/out/live/index.html +1 -1
  181. package/apps/pwa/out/live/index.txt +14 -14
  182. package/apps/pwa/out/live-run/index.html +1 -0
  183. package/apps/pwa/out/live-run/index.txt +35 -0
  184. package/apps/pwa/out/loops/index.html +1 -1
  185. package/apps/pwa/out/loops/index.txt +14 -14
  186. package/apps/pwa/out/market/index.html +1 -1
  187. package/apps/pwa/out/market/index.txt +14 -14
  188. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  189. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  190. package/apps/pwa/out/morning/index.html +1 -1
  191. package/apps/pwa/out/morning/index.txt +14 -14
  192. package/apps/pwa/out/observatory/index.html +1 -1
  193. package/apps/pwa/out/observatory/index.txt +14 -14
  194. package/apps/pwa/out/ops/checklist/index.html +1 -1
  195. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  196. package/apps/pwa/out/ops/release/index.html +1 -1
  197. package/apps/pwa/out/ops/release/index.txt +14 -14
  198. package/apps/pwa/out/ops/seats/index.html +1 -1
  199. package/apps/pwa/out/ops/seats/index.txt +14 -14
  200. package/apps/pwa/out/outputs/index.html +1 -1
  201. package/apps/pwa/out/outputs/index.txt +14 -14
  202. package/apps/pwa/out/reflection/index.html +1 -1
  203. package/apps/pwa/out/reflection/index.txt +15 -15
  204. package/apps/pwa/out/scheduler/index.html +1 -1
  205. package/apps/pwa/out/scheduler/index.txt +14 -14
  206. package/apps/pwa/out/sessions/index.html +1 -1
  207. package/apps/pwa/out/sessions/index.txt +14 -14
  208. package/apps/pwa/out/settings/devices/index.html +1 -1
  209. package/apps/pwa/out/settings/devices/index.txt +14 -14
  210. package/apps/pwa/out/settings/index.html +1 -1
  211. package/apps/pwa/out/settings/index.txt +14 -14
  212. package/apps/pwa/out/setup/done/index.html +1 -1
  213. package/apps/pwa/out/setup/done/index.txt +14 -14
  214. package/apps/pwa/out/setup/index.html +1 -1
  215. package/apps/pwa/out/setup/index.txt +14 -14
  216. package/apps/pwa/out/share/index.html +1 -1
  217. package/apps/pwa/out/share/index.txt +14 -14
  218. package/apps/pwa/out/showroom/index.html +1 -1
  219. package/apps/pwa/out/showroom/index.txt +14 -14
  220. package/apps/pwa/out/tasks/index.html +1 -1
  221. package/apps/pwa/out/tasks/index.txt +14 -14
  222. package/apps/pwa/out/term/index.html +1 -1
  223. package/apps/pwa/out/term/index.txt +14 -14
  224. package/apps/pwa/out/today/index.html +1 -1
  225. package/apps/pwa/out/today/index.txt +14 -14
  226. package/apps/pwa/out/trace/index.html +1 -1
  227. package/apps/pwa/out/trace/index.txt +14 -14
  228. package/apps/pwa/out/vault/index.html +1 -1
  229. package/apps/pwa/out/vault/index.txt +14 -14
  230. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  231. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  232. package/apps/pwa/out/workflows/index.html +1 -1
  233. package/apps/pwa/out/workflows/index.txt +14 -14
  234. package/apps/pwa/out/workspace/index.html +1 -1
  235. package/apps/pwa/out/workspace/index.txt +14 -14
  236. package/apps/pwa/out/worktrees/index.html +1 -1
  237. package/apps/pwa/out/worktrees/index.txt +14 -14
  238. package/graphs/catalog/catalog.yaml +1 -1
  239. package/graphs/drafts/recipes.yaml +6 -6
  240. package/graphs/implement-loop.yaml +277 -5
  241. package/graphs/test-diet/recipes.yaml +3 -0
  242. package/graphs/test-diet/test-diet.yaml +3 -1
  243. package/package.json +1 -1
  244. package/scripts/coord-channel-watch.sh +31 -4
  245. package/scripts/docs-lint.ts +4 -1
  246. package/scripts/f-session-monitor.ts +69 -0
  247. package/scripts/hq/standby-snapshot.ts +7 -3
  248. package/scripts/knowledge-compress.ts +11 -0
  249. package/scripts/marketing/generate-ax-brief.ts +18 -1
  250. package/scripts/measure-nl-routing-corpus.ts +11 -3
  251. package/scripts/nightly-docops.ts +90 -3
  252. package/scripts/release-loop/gate-node.ts +5 -5
  253. package/scripts/release-loop/shard-plan.ts +50 -5
  254. package/scripts/research-coo-admin-dates.ts +39 -0
  255. package/scripts/rhythm/daily.ts +2 -1
  256. package/scripts/skills/public-check.ts +7 -2
  257. package/scripts/smart-merge/resync-shadow.ts +5 -3
  258. package/scripts/test-diet/lib.ts +81 -1
  259. package/scripts/test-diet/node.ts +48 -2
  260. package/scripts/verify-coo-admin-evidence.ts +83 -0
  261. package/src/acp/client.ts +4 -2
  262. package/src/agent/run-context.ts +4 -0
  263. package/src/agent-env/profile.ts +25 -5
  264. package/src/agent-mission/driver.ts +26 -12
  265. package/src/agent-mission/supervisor-metrics.ts +17 -2
  266. package/src/agent-substrate/acp-reviewer.ts +12 -5
  267. package/src/agent-substrate/pr-reviewer.ts +11 -4
  268. package/src/agent-substrate/review-intent.ts +102 -3
  269. package/src/autopilot/build/llm-conflict-merge.ts +22 -8
  270. package/src/autopilot/pr-manager.ts +18 -8
  271. package/src/away/release-watch.ts +47 -8
  272. package/src/briefing/brief-items.ts +104 -11
  273. package/src/browser-cdp/client.ts +10 -5
  274. package/src/chat/index.ts +1 -0
  275. package/src/cli/brief-cli.ts +20 -2
  276. package/src/cli/config-classify.ts +83 -0
  277. package/src/cli/control-cli.ts +14 -0
  278. package/src/cli/decisions-cli.ts +26 -16
  279. package/src/cli/logs-model-input.ts +1 -1
  280. package/src/cli/ops-cli.ts +11 -0
  281. package/src/cli/ops-overview-cli.ts +50 -0
  282. package/src/cli/pod-cli.ts +1 -0
  283. package/src/cli/pr-cli.ts +65 -8
  284. package/src/cli/release-cli.ts +21 -4
  285. package/src/cli/tasks-cli.ts +214 -1
  286. package/src/connectors/types.ts +6 -6
  287. package/src/context-bus/context-now-surfaces.ts +18 -0
  288. package/src/context-bus/coord-events.ts +32 -4
  289. package/src/context-bus/long-term-memory.ts +23 -6
  290. package/src/context-bus/nightly-condense.ts +169 -21
  291. package/src/control/control-status.ts +87 -0
  292. package/src/control-plane/light-member.ts +5 -3
  293. package/src/control-plane/member.ts +172 -7
  294. package/src/core-turn/run-goal-loop.ts +22 -1
  295. package/src/dashboard/index.ts +40 -4
  296. package/src/dashboard/slash-runtime/dashboard-handlers.ts +9 -0
  297. package/src/decisions/decision-cards.ts +20 -1
  298. package/src/decisions/decision-ledger.ts +11 -8
  299. package/src/decisions/web-push-decision-cards.ts +19 -3
  300. package/src/discord-self-message.ts +2 -2
  301. package/src/domains/coo-admin-dates.evidence.json +876 -0
  302. package/src/domains/coo-admin-tool.ts +48 -14
  303. package/src/domains/ops-status.ts +53 -0
  304. package/src/domains/outbound-alert.ts +24 -1
  305. package/src/esc-abort-gate.ts +3 -1
  306. package/src/exec-requests/planner.ts +6 -0
  307. package/src/graph-kinds/registry.ts +6 -6
  308. package/src/graph-runner/graph-cli.ts +91 -2
  309. package/src/graph-runner/graph-run-api.ts +20 -0
  310. package/src/graph-runner/graph-tick.ts +73 -12
  311. package/src/graph-runner/runner.ts +43 -11
  312. package/src/graph-unify/wf-to-graph.ts +79 -0
  313. package/src/graph-wizard/archetypes.ts +88 -0
  314. package/src/graph-wizard/generate.ts +577 -0
  315. package/src/graph-wizard/saved-steps.ts +120 -0
  316. package/src/graph-wizard/steps.ts +206 -0
  317. package/src/harness/harness-cli-command.ts +186 -32
  318. package/src/harness/harness-queue.ts +58 -14
  319. package/src/harness/launch-advice.ts +23 -0
  320. package/src/index.ts +43 -11
  321. package/src/intake-plane/digest.ts +18 -11
  322. package/src/knowledge/conclusion-compress.ts +93 -0
  323. package/src/knowledge/know-find.ts +9 -2
  324. package/src/knowledge/query.ts +20 -0
  325. package/src/llm.ts +26 -16
  326. package/src/loops/neighbor-runtime.ts +88 -0
  327. package/src/loops/orchestrator/author-depth.ts +29 -11
  328. package/src/loops/orchestrator/overlap.ts +7 -1
  329. package/src/loops/orchestrator/resync-shadow.ts +1 -1
  330. package/src/loops/orchestrator/tick.ts +35 -2
  331. package/src/loops/orchestrator/traffic.ts +2 -0
  332. package/src/loops/registry.ts +5 -0
  333. package/src/market/publish.ts +17 -1
  334. package/src/maturity/feature-maturity.ts +4 -2
  335. package/src/mss/logging/redaction.ts +17 -0
  336. package/src/nexus/api/draft-metrics.ts +128 -0
  337. package/src/nexus/api/graph-peer-edit.ts +77 -0
  338. package/src/nexus/api/graph-wizard-api.ts +61 -0
  339. package/src/nexus/api/graphs-api.ts +193 -17
  340. package/src/nexus/api/harness-traversal.ts +205 -0
  341. package/src/nexus/api/http-server.ts +122 -6
  342. package/src/nexus/api/plugins-market.ts +24 -0
  343. package/src/nexus/index.ts +3 -2
  344. package/src/nexus/outbound/router.ts +28 -8
  345. package/src/oauth/claude-pty-maturity.ts +24 -0
  346. package/src/oauth/fallback-chain.ts +27 -14
  347. package/src/onboarding/first-run.ts +3 -0
  348. package/src/ops/overview-collect.ts +345 -0
  349. package/src/ops/overview-seat-era.ts +90 -0
  350. package/src/ops/overview.ts +223 -0
  351. package/src/plugins/maker/market-bundle.ts +9 -0
  352. package/src/plugins/maker/plugin-maker.ts +9 -3
  353. package/src/plugins/maker/wizard-generate.ts +73 -9
  354. package/src/policy/llm-policy.ts +11 -6
  355. package/src/release-loop/checklist-board.ts +27 -0
  356. package/src/release-loop/checklist.ts +38 -0
  357. package/src/release-loop/gate-shards.ts +7 -2
  358. package/src/seat-address/seat-address.ts +1 -0
  359. package/src/seat-loop/seat-loop.ts +174 -20
  360. package/src/seat-loop/seat-report.ts +29 -1
  361. package/src/self-dev/ask-launch-flow.ts +4 -2
  362. package/src/self-dev/ask-launch-io.ts +3 -1
  363. package/src/self-dev/dev-cli.ts +90 -8
  364. package/src/self-dev/dev-pipeline.ts +20 -1
  365. package/src/self-dev/draft-sweep.ts +45 -8
  366. package/src/self-dev/graph-journey-nodes.ts +157 -0
  367. package/src/self-dev/graph-journey-route.ts +105 -0
  368. package/src/self-dev/launch-preflight.ts +43 -3
  369. package/src/self-dev/orchestrate.ts +3 -0
  370. package/src/self-dev/release-path-guard.ts +7 -4
  371. package/src/self-dev/review-provider-fallback.ts +83 -0
  372. package/src/self-dev/run-supervisor.ts +5 -1
  373. package/src/self-implement/frozen-merges.ts +23 -0
  374. package/src/self-implement/goal-author.ts +14 -0
  375. package/src/self-implement/harness-policy-gates.ts +7 -5
  376. package/src/self-implement/heal-intake.ts +3 -0
  377. package/src/self-implement/host-regate.ts +28 -14
  378. package/src/self-implement/l8-merge-queue.ts +80 -8
  379. package/src/self-implement/orchestrator.ts +84 -28
  380. package/src/self-implement/seams.ts +8 -3
  381. package/src/self-implement/self-implement-cli.ts +4 -0
  382. package/src/self-implement/self-implement-runtime.ts +12 -0
  383. package/src/session-runtime/index.ts +5 -3
  384. package/src/shell-env-bootstrap.ts +35 -6
  385. package/src/steward/triage.ts +25 -8
  386. package/src/storage/file-lock.ts +33 -4
  387. package/src/task-agent/card-evidence.ts +6 -0
  388. package/src/task-agent/completion-evidence.ts +31 -3
  389. package/src/task-agent/cover.ts +61 -0
  390. package/src/task-agent/live-moves.ts +126 -3
  391. package/src/task-agent/parent-host.ts +315 -0
  392. package/src/task-agent/shadow.ts +19 -4
  393. package/src/task-agent/task-hand.ts +11 -2
  394. package/src/task-orchestrator/surfaces/pod-command-job.ts +41 -6
  395. package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
  396. package/src/task-orchestrator/surfaces/pod-pool.ts +138 -15
  397. package/src/task-orchestrator/surfaces/self-implement-pod.ts +39 -6
  398. package/src/task-orchestrator/surfaces/self-implement.ts +7 -0
  399. package/src/telegram-commands.ts +8 -0
  400. package/src/telegram-project-command.ts +6 -0
  401. package/src/telegram.ts +2 -2
  402. package/src/tool-runtime/browser-runtime.ts +87 -3
  403. package/src/tool-runtime/index.ts +1 -0
  404. package/src/typecheck-ratchet.ts +2 -1
  405. package/src/user-config.ts +55 -8
  406. package/src/version/packed-revision.json +1 -1
  407. package/src/workflow-runtime/executor.ts +24 -2
  408. package/src/workflow-runtime/triggers/registry.ts +27 -0
  409. package/src/workflow-runtime/triggers/schedule-source.ts +30 -3
  410. package/apps/pwa/out/_next/static/Bam1YziK2iH9bN4K0utGk/_buildManifest.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1307-77fad80cf54477c6.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
  416. package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +0 -1
  417. package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +0 -1
  419. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +0 -25
  425. package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +0 -1
  426. package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/app/bots/page-7a852956c74015a3.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/app/design-check/page-7c058069c5e7fa63.js +0 -1
  430. package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/app/intake/page-9cd565005b93aca6.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/app/live/page-474cb5888ea0e8f3.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/app/market/page-9ca21f9ad3208a61.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/app/not-found-a9c2cfa8dda922a5.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-f6055495e9ed7ea8.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +0 -1
  442. package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c26fa10aac6c21c4.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/app/setup/page-68793c6e10331d66.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/app/showroom/page-d81c07a7b4f618ae.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/app/tasks/page-be1c4e8697f22360.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/app/trace/page-0fd895fab9b62c1b.js +0 -1
  450. package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c6e4364d9de8f717.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/webpack-c260571513bf43c2.js +0 -1
  454. package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +0 -1
  455. /package/apps/pwa/out/_next/static/{Bam1YziK2iH9bN4K0utGk → aBi6EyMtLsrl7J8eH4kF7}/_ssgManifest.js +0 -0
  456. /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
@@ -11,6 +11,7 @@ import { getUserConfig } from '../user-config.js';
11
11
  import { projectDecisionsToLinear } from '../decisions/decision-linear-projection.js';
12
12
  import { DecisionLedger, importDecisionMarkdown, type DecisionCategory, type DecisionLedgerOptions, type DecisionOption, type DecisionTrack, type DecisionEntry, type Seat, type SeatDecisionRecord } from '../decisions/decision-ledger.js';
13
13
  import { formatProactMeter, readProactMeter } from '../decisions/proact-meter.js';
14
+ import { writeStdoutFully } from './stdout-flush.js';
14
15
 
15
16
  const repeat = (value: string, values: string[]) => [...values, value];
16
17
  function date(raw?: string): string | undefined {
@@ -75,14 +76,24 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
75
76
  return hqCliWriteAllowed(`decisions ${command}`, Boolean(override || root.opts().hqOverride),
76
77
  (getElanousConfigDirOverride() || config.stateDir) && !hqDeps.store && !getUserConfig().hq?.arbiter ? { ...hqDeps, store: fileLeaseStore(join(config.stateDir ?? effectiveInstanceRoot(), 'hq', 'lease.json')), seenPath: join(config.stateDir ?? effectiveInstanceRoot(), 'hq', 'seen-generation'), localPath: join(config.stateDir ?? effectiveInstanceRoot(), 'hq', 'local.json') } : hqDeps);
77
78
  };
78
- const emit = (value: unknown, json?: boolean, text?: string) => out.log(json ? JSON.stringify(value) : text ?? JSON.stringify(value));
79
- const fail = (action: () => void) => { try { action(); } catch (e) { throw new Error(`decisions: ${e instanceof Error ? e.message : String(e)}`); } };
79
+ const emit = (value: unknown, json?: boolean, text?: string): void | Promise<void> => {
80
+ const line = json ? JSON.stringify(value) : text ?? JSON.stringify(value);
81
+ if (json && out === console) return writeStdoutFully(line);
82
+ out.log(line);
83
+ };
84
+ const fail = (action: () => void | Promise<void>): void | Promise<void> => {
85
+ const wrap = (e: unknown) => new Error(`decisions: ${e instanceof Error ? e.message : String(e)}`);
86
+ try {
87
+ const result = action();
88
+ return result instanceof Promise ? result.catch(e => { throw wrap(e); }) : result;
89
+ } catch (e) { throw wrap(e); }
90
+ };
80
91
  root.command('linear-sync').description('열린 결정을 COO Linear 프로젝트에 투영하고 닫힌 결정을 동기화한다')
81
92
  .option('--dry-run').option('--json').option('--hq-override')
82
93
  .action(async (o: { dryRun?: boolean; json?: boolean; hqOverride?: boolean }) => {
83
94
  if (!o.dryRun && !mayWrite('linear-sync', o.hqOverride)) return;
84
95
  const result = await projectDecisionsToLinear({ stateDir: config.stateDir, dryRun: o.dryRun });
85
- emit(result, o.json, result.reason ?? `생성 ${result.created} · 닫음 ${result.closed} · 건너뜀 ${result.skipped} · 실패 ${result.failed}${result.plan?.length ? `\n${result.plan.map(p => `${p.action} ${p.decisionId}${p.issue ? ` ${p.issue}` : ''}`).join('\n')}` : ''}`);
96
+ await emit(result, o.json, result.reason ?? `생성 ${result.created} · 닫음 ${result.closed} · 건너뜀 ${result.skipped} · 실패 ${result.failed}${result.plan?.length ? `\n${result.plan.map(p => `${p.action} ${p.decisionId}${p.issue ? ` ${p.issue}` : ''}`).join('\n')}` : ''}`);
86
97
  });
87
98
  root.command('raise').description('SCQA·선택지와 권고로 결정 항목을 올린다')
88
99
  .requiredOption('--title <text>').requiredOption('--category <category>')
@@ -121,7 +132,7 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
121
132
  ...(o.resumeQuestion !== undefined ? { resume: { questionId: o.resumeQuestion, ...(o.run !== undefined ? { runId: o.run } : {}) } } : {}),
122
133
  ...(o.due ? { dueAt: dueAt(o.due) } : {}) });
123
134
  if (entry.crossCheckSkipped === 'missing') console.error('교차 확인 없음 — --xcheck SEAT:메모 또는 --no-xcheck 이유');
124
- emit(entry, o.json, `올림: ${formatDecisionRow(entry)}`);
135
+ return emit(entry, o.json, `올림: ${formatDecisionRow(entry)}`);
125
136
  }));
126
137
  root.command('record-seat').description('위임 범위에서 이미 내린 자리 결정을 사후 보고로 원장에 기록 (대표 카드 아님)')
127
138
  .requiredOption('--seat <OP|MK|TC|UX>').requiredOption('--title <text>')
@@ -133,13 +144,13 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
133
144
  if (!mayWrite('record-seat', o.hqOverride)) return;
134
145
  const entry = new DecisionLedger(config).recordSeatDecision({ seat: o.seat, title: o.title, decision: o.decision,
135
146
  delegation: o.delegation, ...(o.at ? { decidedAt: o.at } : {}), ...(o.ref.length ? { refs: o.ref } : {}) });
136
- emit(entry, o.json, formatSeatDecisionRow(entry));
147
+ return emit(entry, o.json, formatSeatDecisionRow(entry));
137
148
  }));
138
149
  root.command('seat-report').description('밤사이 자리들의 사후 결정을 한 번에 조회 (기본 최근 24시간)')
139
150
  .option('--since <date>', '조회 시작 UTC ISO 또는 Nd', '1d').option('--seat <OP|MK|TC|UX>').option('--json')
140
151
  .action((o: { since: string; seat?: Seat; json?: boolean }) => fail(() => {
141
152
  const rows = new DecisionLedger(config).seatReport({ since: date(o.since), seat: o.seat });
142
- emit(rows, o.json, rows.length ? rows.map(formatSeatDecisionRow).join('\n') : '자리 결정 0건');
153
+ return emit(rows, o.json, rows.length ? rows.map(formatSeatDecisionRow).join('\n') : '자리 결정 0건');
143
154
  }));
144
155
  root.command('proact').description('선제성 기준선 — 지난 7일, 먼저 낸 수·채택 수·물어서야 드러난 수')
145
156
  .option('--days <n>', 'KST 일수 (기본 7)', '7').option('--json')
@@ -147,17 +158,17 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
147
158
  const days = Number(o.days);
148
159
  if (!Number.isInteger(days) || days < 1) throw new Error('invalid days');
149
160
  const meter = readProactMeter({ ...(config.stateDir ? { stateDir: config.stateDir, instanceRoot: config.stateDir } : {}), ...(config.now ? { now: config.now() } : {}), days });
150
- emit(meter, o.json, formatProactMeter(meter));
161
+ return emit(meter, o.json, formatProactMeter(meter));
151
162
  }));
152
163
  root.command('list').description('결정 목록 (기본 열린 것)')
153
164
  .option('--status <open|decided|all>', '기본 open', 'open').option('--since <date>').option('--version <version>')
154
165
  .option('--decided-by <human|auto>').option('--category <category>').option('--json')
155
166
  .action((o: { status: 'open' | 'decided' | 'all'; since?: string; version?: string; decidedBy?: 'human' | 'auto'; category?: DecisionCategory; json?: boolean }) => fail(() => {
156
167
  const rows = new DecisionLedger(config).list({ status: o.status, since: date(o.since), version: o.version, decidedBy: o.decidedBy, category: o.category });
157
- emit(rows, o.json, rows.length ? rows.map(formatDecisionRow).join('\n') : '결정 0건');
168
+ return emit(rows, o.json, rows.length ? rows.map(formatDecisionRow).join('\n') : '결정 0건');
158
169
  }));
159
170
  root.command('show <id>').description('SCQA · 선택지 · 권고 · 이력 · 판').option('--json')
160
- .action((id: string, o: { json?: boolean }) => fail(() => { const entry = new DecisionLedger(config).show(id); emit(entry, o.json, formatDecisionDetail(entry)); }));
171
+ .action((id: string, o: { json?: boolean }) => fail(() => { const entry = new DecisionLedger(config).show(id); return emit(entry, o.json, formatDecisionDetail(entry)); }));
161
172
  root.command('decide <id> <option>').description('사람 또는 AUTO 위임 결정 기록')
162
173
  .option('--note <text>').option('--auto').option('--delegation <reason>').option('--track <track>').option('--agent <agent>').option('--json').option('--hq-override')
163
174
  .action((id: string, choice: string, o: { note?: string; auto?: boolean; delegation?: string; track?: DecisionTrack; agent?: string; json?: boolean; hqOverride?: boolean }) => fail(() => {
@@ -169,17 +180,16 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
169
180
  if (delivery && !delivery.ok) {
170
181
  // The decision is recorded; only the answer to the waiting run failed — say so and how to retry, never «success».
171
182
  const hint = `⚠ 답 전달 실패(${delivery.questionId} · ${delivery.reason}) — 결정은 기록됐다 · 다시: elanous decisions retry-answer ${entry.id}`;
172
- emit({ ...entry, delivery }, o.json, `결정: ${formatDecisionDetail(entry)}\n${hint}`);
173
183
  process.exitCode = 3;
174
- return;
184
+ return emit({ ...entry, delivery }, o.json, `결정: ${formatDecisionDetail(entry)}\n${hint}`);
175
185
  }
176
- emit(delivery ? { ...entry, delivery } : entry, o.json, `결정: ${formatDecisionDetail(entry)}`);
186
+ return emit(delivery ? { ...entry, delivery } : entry, o.json, `결정: ${formatDecisionDetail(entry)}`);
177
187
  }));
178
188
  root.command('retry-answer <id>').description('기록된 결정의 대기 질문 답 전달만 재시도한다').option('--json').option('--hq-override')
179
189
  .action((id: string, o: { json?: boolean; hqOverride?: boolean }) => fail(() => {
180
190
  if (!mayWrite('retry-answer', o.hqOverride)) return;
181
191
  const entry = new DecisionLedger(config).retryAnswer(id);
182
- emit(entry, o.json, `답 전달: ${entry.id} → ${entry.resume?.questionId}`);
192
+ return emit(entry, o.json, `답 전달: ${entry.id} → ${entry.resume?.questionId}`);
183
193
  }));
184
194
  root.command('add-options <id>').description('선택지가 미기재된 과거 항목에 확인된 선택지를 추가')
185
195
  .requiredOption('--option <key=label:consequence>', '선택지 (두 번 이상)', repeat, [] as string[])
@@ -188,15 +198,15 @@ export function registerDecisionsCommands(program: Command, config: DecisionLedg
188
198
  const who = agent(o.agent);
189
199
  if (!mayWrite('add-options', o.hqOverride)) return;
190
200
  const entry = new DecisionLedger(config).addOptions(id, o.option.map(parseOption), who);
191
- emit(entry, o.json, formatDecisionDetail(entry));
201
+ return emit(entry, o.json, formatDecisionDetail(entry));
192
202
  }));
193
203
  root.command('withdraw <id>').description('결정 철회도 원장에 남긴다').requiredOption('--reason <reason>').option('--json').option('--hq-override')
194
- .action((id: string, o: { reason: string; json?: boolean; hqOverride?: boolean }) => fail(() => { if (!mayWrite('withdraw', o.hqOverride)) return; const entry = new DecisionLedger(config).withdraw(id, o.reason); emit(entry, o.json, `철회: ${formatDecisionDetail(entry)}`); }));
204
+ .action((id: string, o: { reason: string; json?: boolean; hqOverride?: boolean }) => fail(() => { if (!mayWrite('withdraw', o.hqOverride)) return; const entry = new DecisionLedger(config).withdraw(id, o.reason); return emit(entry, o.json, `철회: ${formatDecisionDetail(entry)}`); }));
195
205
  root.command('import-markdown <file>').description('기존 대표 결정 문서 씨앗을 가져온다 (재실행 안전)').option('--json').option('--hq-override')
196
206
  .action((file: string, o: { json?: boolean; hqOverride?: boolean }) => fail(() => {
197
207
  if (!mayWrite('import-markdown', o.hqOverride)) return;
198
208
  const result = importDecisionMarkdown(new DecisionLedger(config), file);
199
- emit(result, o.json, `가져옴 ${result.imported.length} · 기존 ${result.existing.length} · 불완전 ${result.incomplete.length} · 못 읽음 ${result.unread.length}${result.incomplete.length ? `\n${result.incomplete.join('\n')}` : ''}${result.unread.length ? `\n${result.unread.join('\n')}` : ''}`);
200
209
  if (result.unread.length) process.exitCode = 1;
210
+ return emit(result, o.json, `가져옴 ${result.imported.length} · 기존 ${result.existing.length} · 불완전 ${result.incomplete.length} · 못 읽음 ${result.unread.length}${result.incomplete.length ? `\n${result.incomplete.join('\n')}` : ''}${result.unread.length ? `\n${result.unread.join('\n')}` : ''}`);
201
211
  }));
202
212
  }
@@ -79,7 +79,7 @@ export function renderModelInput(report: ModelInputReport): string {
79
79
  `model input tokens · ${report.since} ~ ${report.until} · stores=${report.stores.join(', ') || '(없음)'} · records=${report.records}`,
80
80
  'scope\tnodeKind\tmeasured\tmedian\tp90\t못 잼',
81
81
  ...(report.baselines.length === 0 ? ['(관측 표본 없음)'] : report.baselines.map((item) =>
82
- `${item.scope}\t${item.nodeKind}\t${item.measured}\t${item.median ?? '—'}\t${item.p90 ?? '—'}\t${item.unmeasured}`)),
82
+ `${item.scope}\t${item.nodeKind}\t${item.measured}\t${item.median ?? '못 잼'}\t${item.p90 ?? '못 잼'}\t${item.unmeasured}`)),
83
83
  ].join('\n');
84
84
  }
85
85
 
@@ -213,6 +213,17 @@ opsCmd.command('status').description('현재 상태 종합(미션·태스크·
213
213
  }
214
214
  return o.allInstances ? runOpsFleet(o.json === true, o.includeTest === true) : runOps('snapshot', o);
215
215
  });
216
+ // OPS-OVERVIEW-CLI (RFC-ops-overview-flow-health-cli-2026-10-08) — 판정 먼저 · 이유 사슬 · 절. 못 잼 = null(0 아님).
217
+ opsCmd.command('overview').description('흐름 한 장 — 저작→구현→착지가 흐르나(판정 먼저·이유 사슬) · 판·일꾼·기계·착지·루프 · 못 잼은 null · exit 0=흐름 정상/저하 3=그 밖 1=수집 실패')
218
+ .option('--json', '칸 꼴 그대로 ⊕ 머리 {verdict, reasons, nextActions, meta.elapsedMs}')
219
+ .option('--watch [seconds]', '주기 재조회(기본 30초)')
220
+ .option('--since <window>', '착지 창(<n>m|h|d · 기본 1h)', '1h')
221
+ .option('--owner <owner>', '일꾼 절 거르기 — seat:TC · TC · unassigned · all')
222
+ .option('--version <v>', '판(기본: 다음 컷)')
223
+ .action(async (o: { json?: boolean; watch?: string | boolean; since?: string; owner?: string; version?: string }) => {
224
+ const { runOpsOverview } = await import('./ops-overview-cli.js');
225
+ process.exitCode = await runOpsOverview(o);
226
+ });
216
227
  opsCmd.command('health').description('이상 판정만(blocked·errored·stale)').option('--json')
217
228
  .action((o: OpsOpts) => runOps('health', o));
218
229
  opsCmd.command('timeline').description('상태 전이 최근순 통합')
@@ -0,0 +1,50 @@
1
+ import { debug } from '../debug/log.js';
2
+ import { collectOverview, parseSince } from '../ops/overview-collect.js';
3
+ import { computeVerdict, renderOverview, unmeasuredCells, verdictExitCode, VERDICT_LABEL } from '../ops/overview.js';
4
+ import { writeStdoutJson } from './stdout-json.js';
5
+
6
+ export interface OpsOverviewOptions { json?: boolean; watch?: string | boolean; since?: string; owner?: string; version?: string }
7
+
8
+ /** 한 번 모아서 내고 exit code 를 돌려준다(RFC §A4: flowing·degraded 0 · 그 밖 3 · 수집 실패 1). */
9
+ async function once(o: OpsOverviewOptions, previous: string | null): Promise<{ code: number; verdict: string | null }> {
10
+ const started = performance.now();
11
+ let since: { ms: number; label: string };
12
+ try { since = parseSince(o.since); } catch (error) { console.error(String((error as Error).message)); return { code: 1, verdict: null }; }
13
+ try {
14
+ const snapshot = await collectOverview({ sinceMs: since.ms, sinceLabel: since.label, ...(o.owner ? { owner: o.owner } : {}), ...(o.version ? { version: o.version } : {}) });
15
+ const result = computeVerdict(snapshot);
16
+ const elapsedMs = Math.round(performance.now() - started);
17
+ const unmeasured = unmeasuredCells(snapshot);
18
+ debug.log('ops.overview', 'computed', { verdict: result.verdict, elapsedMs, unmeasured });
19
+ debug.flush();
20
+ if (o.json) {
21
+ await writeStdoutJson(JSON.stringify({ verdict: result.verdict, verdictLabel: VERDICT_LABEL[result.verdict], reasons: result.reasons, nextActions: result.nextActions,
22
+ meta: { elapsedMs, source: 'local', unmeasured }, ...snapshot }, null, 2) + '\n');
23
+ } else {
24
+ const text = renderOverview(snapshot, result, { elapsedMs });
25
+ if (previous !== null && previous !== result.verdict) console.log(`🔔 판정 바뀜: ${previous} → ${result.verdict}`);
26
+ console.log(text);
27
+ }
28
+ return { code: verdictExitCode(result.verdict), verdict: result.verdict };
29
+ } catch (error) {
30
+ debug.log('ops.overview', 'failed', { reason: String(error) });
31
+ debug.flush();
32
+ console.error(`ops overview 수집 실패: ${String(error)}`);
33
+ return { code: 1, verdict: null };
34
+ }
35
+ }
36
+
37
+ export async function runOpsOverview(o: OpsOverviewOptions): Promise<number> {
38
+ // 독립 CLI 프로세스는 데몬 StoreSink 를 물려받지 않는다 — 등록 없이는 debug.log 가 logs.db 에 안 닿는다(관측 안 한 것).
39
+ try { await (await import('../domains/standalone-log-sink.js')).registerStandaloneLogSink('cli'); } catch { /* fail-open */ }
40
+ if (o.watch === undefined || o.watch === false) return (await once(o, null)).code;
41
+ const seconds = o.watch === true ? 30 : Number(o.watch);
42
+ if (!Number.isFinite(seconds) || seconds < 5) { console.error('--watch 는 5초 이상'); return 1; }
43
+ let previous: string | null = null;
44
+ for (;;) {
45
+ if (!o.json) process.stdout.write('\x1b[2J\x1b[H');
46
+ const r = await once(o, previous);
47
+ previous = r.verdict ?? previous;
48
+ await new Promise((res) => setTimeout(res, seconds * 1000));
49
+ }
50
+ }
@@ -151,6 +151,7 @@ export function registerPodCommands(program: Command, deps: PodCliDeps = {}): vo
151
151
  try {
152
152
  const result = await run({
153
153
  command: commandArgs,
154
+ returnLogs: true,
154
155
  ...(opts.pool ? { pool: opts.pool } : {}),
155
156
  ...(skills.length ? { skills } : {}),
156
157
  ...(opts.llm === 'grok' ? { llm: 'grok' as const } : {}),
package/src/cli/pr-cli.ts CHANGED
@@ -62,6 +62,9 @@ import { enqueueL8ShadowQueue, runL8ShadowQueue, shadowPrNumber, statusL8ShadowQ
62
62
  export { branchLineageSlug, findSiblingPrs };
63
63
 
64
64
  export interface PrLandOpts {
65
+ /** Pin an existing PR and its reviewed head; both must be supplied together. */
66
+ pr?: string;
67
+ expectedHead?: string;
65
68
  base?: string;
66
69
  cwd?: string;
67
70
  dryRun?: boolean;
@@ -1180,10 +1183,33 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1180
1183
 
1181
1184
  const cwd = opts.cwd ?? process.cwd();
1182
1185
  const run = deps.run ?? defaultCmdRunner;
1186
+ const pinned = opts.pr !== undefined || opts.expectedHead !== undefined;
1187
+ let pinnedBranch: string | undefined;
1188
+ let pinnedUrl: string | undefined;
1189
+ if (pinned) {
1190
+ const pr = Number(opts.pr);
1191
+ if (!/^[1-9]\d*$/.test(opts.pr ?? '') || !Number.isSafeInteger(pr) || !/^[a-f0-9]{40}$/i.test(opts.expectedHead ?? '') || opts.hold || opts.dryRun) {
1192
+ out.error('✗ expected-head: --pr and --expected-head (full SHA) are required together without --hold/--dry-run');
1193
+ return 1;
1194
+ }
1195
+ const viewed = run('gh', ['pr', 'view', String(pr), '--json', 'headRefOid,headRefName,state,isDraft,url'], { cwd });
1196
+ let value: { headRefOid?: string; headRefName?: string; state?: string; isDraft?: boolean; url?: string } = {};
1197
+ try { if (viewed.ok) value = JSON.parse(viewed.out) as typeof value; } catch { /* unreadable is not approval */ }
1198
+ const local = run('git', ['rev-parse', 'HEAD'], { cwd });
1199
+ const dirty = run('git', ['status', '--porcelain'], { cwd });
1200
+ if (value.state !== 'OPEN' || value.isDraft !== false || value.headRefOid?.toLowerCase() !== opts.expectedHead!.toLowerCase()
1201
+ || !value.url?.endsWith(`/pull/${pr}`) || !value.headRefName || !local.ok || local.out.trim().toLowerCase() !== opts.expectedHead!.toLowerCase()
1202
+ || !dirty.ok || dirty.out.trim()) {
1203
+ out.error('✗ expected-head: PR OPEN non-draft, matching local HEAD and clean worktree required');
1204
+ return 1;
1205
+ }
1206
+ pinnedBranch = value.headRefName;
1207
+ pinnedUrl = value.url;
1208
+ }
1183
1209
  const resolveBase = deps.resolveBase ?? resolveDeliverableBase;
1184
1210
  const branch = (deps.currentBranch ?? liveCurrentBranch)(cwd);
1185
- if (!branch) {
1186
- const detail = '현재 브랜치를 해석하지 못했습니다.';
1211
+ if (!branch || (pinned && branch !== pinnedBranch)) {
1212
+ const detail = pinned ? 'PR head branch와 현재 브랜치가 다릅니다.' : '현재 브랜치를 해석하지 못했습니다.';
1187
1213
  record('branch', false);
1188
1214
  out.error(`✗ branch: ${detail}`);
1189
1215
  return 1;
@@ -1567,6 +1593,10 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1567
1593
  });
1568
1594
  }
1569
1595
  const hold = !!opts.hold || overlapDecision?.outcome === 'user-hold';
1596
+ if (pinned && overlapDecision && overlapDecision.outcome !== 'user-merge') {
1597
+ out.error('✗ expected-head: overlap merge approval unavailable for the reviewed head');
1598
+ return 1;
1599
+ }
1570
1600
 
1571
1601
  const manager = deps.manager ?? makePrManager(run);
1572
1602
  const existing = manager.findPrForBranchOutcome(branch, cwd);
@@ -1638,7 +1668,12 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1638
1668
  }
1639
1669
  }
1640
1670
 
1641
- const upsert = manager.upsertPr({
1671
+ // A pinned, already-reviewed commit must not go through upsertPr (git add/commit/force-push/PR edit).
1672
+ const upsert = pinned
1673
+ ? existing.status === 'ok OUTPUT' && existing.url === pinnedUrl
1674
+ ? { ok: true as const, url: pinnedUrl!, reused: true }
1675
+ : { ok: false as const, reason: 'gh' as const, detail: 'pinned PR is not the branch open PR' }
1676
+ : manager.upsertPr({
1642
1677
  branch,
1643
1678
  worktreePath: cwd,
1644
1679
  base,
@@ -1654,7 +1689,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1654
1689
  ...(excludingActiveRunFiles ? { excludePaths } : {}),
1655
1690
  });
1656
1691
  if (!upsert.ok) {
1657
- if (upsert.reason === 'noop' && excludingActiveRunFiles) {
1692
+ if (upsert.reason === 'noop' && excludingActiveRunFiles && !pinned) {
1658
1693
  record('upsert-ready-noop', true, { excludePaths, detail: upsert.detail });
1659
1694
  out.log(`✓ upsert-ready: 제외 후 올릴 것이 없습니다 — ${upsert.detail}`);
1660
1695
  return 0;
@@ -1664,6 +1699,13 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1664
1699
  return 1;
1665
1700
  }
1666
1701
  record('upsert-ready', true);
1702
+ if (pinned) {
1703
+ const upsertHead = run('git', ['rev-parse', 'HEAD'], { cwd });
1704
+ if (!upsert.reused || upsert.url !== pinnedUrl || !upsertHead.ok || upsertHead.out.trim().toLowerCase() !== opts.expectedHead!.toLowerCase()) {
1705
+ out.error('✗ expected-head: pinned PR identity or reviewed HEAD changed');
1706
+ return 1;
1707
+ }
1708
+ }
1667
1709
  out.log(`✓ upsert-ready: ${upsert.url}${upsert.reused ? ' (기존 PR)' : ' (새 PR)'}`);
1668
1710
 
1669
1711
  if (hold) {
@@ -1688,21 +1730,34 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1688
1730
  debug.log('harness.merge', 'frozen', { prUrl: upsert.url, reason: frozen.reason, until: frozen.until });
1689
1731
  record('freeze', true, { url: upsert.url, reason: frozen.reason, until: frozen.until });
1690
1732
  out.log(`✓ ready: ${upsert.url} — ${landingFreezeMessage(frozen)} · 병합 연기`);
1691
- return 0;
1733
+ return pinned ? 1 : 0;
1692
1734
  }
1693
1735
  if (admission.kind === 'taken') {
1694
1736
  record('freeze', true, { url: upsert.url, resumedElsewhere: true });
1695
1737
  out.log(`✓ ready: ${upsert.url} — 동결이 막 풀려 보류 병합 재개가 이 PR 을 맡았습니다`);
1696
- return 0;
1738
+ return pinned ? 1 : 0;
1697
1739
  }
1698
1740
  const landing = admission;
1741
+ if (pinned) {
1742
+ const view = run('gh', ['pr', 'view', String(opts.pr), '--json', 'headRefOid,state,isDraft'], { cwd });
1743
+ let current: { headRefOid?: string; state?: string; isDraft?: boolean } = {};
1744
+ try { if (view.ok) current = JSON.parse(view.out) as typeof current; } catch { /* fail closed */ }
1745
+ const finalHead = run('git', ['rev-parse', 'HEAD'], { cwd });
1746
+ if (current.headRefOid?.toLowerCase() !== opts.expectedHead!.toLowerCase() || current.state !== 'OPEN' || current.isDraft !== false
1747
+ || !finalHead.ok || finalHead.out.trim().toLowerCase() !== opts.expectedHead!.toLowerCase()) {
1748
+ landing.end(false);
1749
+ out.error('✗ expected-head: PR head/state changed before merge');
1750
+ return 1;
1751
+ }
1752
+ }
1699
1753
  let merged: ReturnType<typeof manager.mergePrOutcome>;
1700
1754
  try {
1701
- merged = manager.mergePrOutcome(upsert.url);
1755
+ merged = manager.mergePrOutcome(upsert.url, pinned ? opts.expectedHead : undefined, pinned ? cwd : undefined);
1702
1756
  // `GIT-S14` — 병합이 «미완료(OPEN)»로 끝났고 GitHub 가 아직 `mergeable=UNKNOWN`(병합 가능 여부 계산 중)이면
1703
1757
  // 짧게 기다렸다 다시 병합한다. 표본 셋(08-25 · 09-24 🅢 #20233 등)이 모두 «같은 명령 재시도에 병합»이었다.
1704
1758
  // ⛔ UNKNOWN 일 때만 재시도한다 — CONFLICTING 등 다른 값은 기다려도 안 풀린다(그대로 실패를 낸다).
1705
1759
  const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));
1760
+ // pinned 도 재시도한다 — mergePrOutcome 이 머리를 다시 확인하고 --match-head-commit 으로 병합하므로 바뀐 머리로는 안 들어간다.
1706
1761
  for (let attempt = 1; !merged.ok && merged.kind === 'not-merged' && merged.state === 'OPEN' && attempt <= PR_LAND_MERGEABLE_UNKNOWN_RETRIES; attempt += 1) {
1707
1762
  const mergeable = run('gh', ['pr', 'view', upsert.url, '--json', 'mergeable', '--jq', '.mergeable'], { cwd });
1708
1763
  const value = mergeable.ok ? mergeable.out.trim() : '';
@@ -1710,7 +1765,7 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
1710
1765
  record('merge-retry', true, { attempt, mergeable: value, waitMs: PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS });
1711
1766
  out.log(`⏳ merge: mergeable=UNKNOWN — GitHub 가 병합 가능 여부를 아직 계산 중입니다 · ${PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS / 1000}초 뒤 다시 병합 (${attempt}/${PR_LAND_MERGEABLE_UNKNOWN_RETRIES})`);
1712
1767
  await sleep(PR_LAND_MERGEABLE_UNKNOWN_WAIT_MS);
1713
- merged = manager.mergePrOutcome(upsert.url);
1768
+ merged = manager.mergePrOutcome(upsert.url, pinned ? opts.expectedHead : undefined, pinned ? cwd : undefined);
1714
1769
  }
1715
1770
  } finally { landing.end(merged!?.ok === true); }
1716
1771
  if (!merged.ok) {
@@ -1781,6 +1836,8 @@ export function registerPrCommands(program: Command, deps: PrLandDeps = {}, queu
1781
1836
  .description('현재 브랜치 PR을 생성 또는 갱신해 ready 상태로 만들고 squash merge')
1782
1837
  .option('--base <branch>', 'PR base branch')
1783
1838
  .option('--cwd <path>', '작업 트리 경로')
1839
+ .option('--pr <number>', '기존 PR 번호 고정 (--expected-head 와 함께)')
1840
+ .option('--expected-head <sha>', '리뷰된 PR 머리 SHA 고정 (--pr 와 함께)')
1784
1841
  .option('--dry-run', '변경 없이 landing 계획만 출력')
1785
1842
  .option('--hold', 'PR을 생성 또는 갱신한 뒤 병합하지 않고 쌓아 둔다')
1786
1843
  .option('--title <title>', 'PR title')
@@ -18,7 +18,7 @@
18
18
  // ⛔ 공개본은 «원본 매니페스트»(`release/public-export.yaml`)대로만 만든다 — 매매 실행 코드는 그 매니페스트가 이미 뺀다(🅢 #20529).
19
19
  import { spawnSync } from 'node:child_process';
20
20
  import { createHash } from 'node:crypto';
21
- import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
21
+ import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
22
22
  import { tmpdir } from 'node:os';
23
23
  import { dirname, join, resolve } from 'node:path';
24
24
  import type { Command } from 'commander';
@@ -27,7 +27,7 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../instance/resolve.js
27
27
  import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
28
28
  import { envLiteral } from '../platform/env-literal.js';
29
29
  import { getUserConfig, userConfigPath } from '../user-config.js';
30
- import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, listChecklist, ownerMatches, parseOwner, parityGap, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
30
+ import { addItem, cellsReferencingDoc, claimItem, decodeClaimHistoryEntry, devVersion, lintDocRefs, listChecklist, normalizeRefs, ownerMatches, parseOwner, parityGap, refRoots, removeItem, renderRefsStatus, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
31
31
  import * as features from '../release-loop/feature-store.js';
32
32
  import { evidencePlan, landedButYellow, type MergedChecklistPr } from '../release-loop/landed-but-yellow.js';
33
33
  import { formatSchedule, getSchedule, listSchedules, setSchedule } from '../release-loop/release-schedule.js';
@@ -705,11 +705,28 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
705
705
  console.log(`루브릭 없는 칸 ${missing}`);
706
706
  });
707
707
  withContext(checklist.command('refs <doc>').description('문서를 인용하는 칸 — 모든 판의 구현 현황(읽기 전용)'))
708
- .action(async (doc: string, _opts: unknown, cmd: Command) => {
708
+ .option('--lint', '문서 절과 칸 인용을 양방향 대조(읽기 전용)')
709
+ .action(async (doc: string, opts: { lint?: boolean }, cmd: Command) => {
709
710
  if (!doc.trim() || doc.trim().startsWith('#')) throw new CliUserError(`잘못된 문서: ${doc}`, '저장소 상대 경로[#절] — 예: docs/RFC-x.md#§3');
710
711
  const { json } = context(cmd);
711
712
  const ledgerRoot = releaseLedgerRoot();
712
- const rows = cellsReferencingDoc(doc, features.assignedVersions(ledgerRoot).map((version) => listChecklist(version, ledgerRoot)));
713
+ const checklists = features.assignedVersions(ledgerRoot).map((version) => listChecklist(version, ledgerRoot));
714
+ if (opts.lint) {
715
+ const path = doc.trim().split('#')[0]!.replace(/^\.\//, '');
716
+ const roots = refRoots();
717
+ normalizeRefs([path], roots);
718
+ const file = roots.map((root) => join(root, path)).find((candidate) => {
719
+ try { return statSync(candidate).isFile(); } catch { return false; }
720
+ })!;
721
+ const result = lintDocRefs(path, readFileSync(file, 'utf8'), checklists);
722
+ debug.log('release.checklist', 'refs-lint', { doc, sections: result.sections.length, uncovered: result.uncoveredSections.length, dangling: result.danglingRefs.length });
723
+ if (json) { await writeStdoutJson(`${JSON.stringify({ doc, ...result })}\n`); return; }
724
+ console.log(`칸 없는 절: ${result.uncoveredSections.join(', ') || '없음'}`);
725
+ console.log(`없는 절을 가리키는 칸: ${result.danglingRefs.map(({ version, id, ref }) => `${version} ${id} ${ref}`).join(' · ') || '없음'}`);
726
+ console.log(`절 ${result.sections.length} · 칸 없는 절 ${result.uncoveredSections.length} · 없는 절을 가리키는 칸 ${result.danglingRefs.length}`);
727
+ return;
728
+ }
729
+ const rows = cellsReferencingDoc(doc, checklists);
713
730
  const byStatus = { green: 0, yellow: 0, red: 0, done: 0 } as Record<ChecklistStatus, number>;
714
731
  for (const row of rows) byStatus[row.status] += 1;
715
732
  debug.log('release.checklist', 'refs-read', { doc, rows: rows.length });