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
@@ -57,6 +57,8 @@ export interface StewardDeps {
57
57
  cardStore?: StewardCardDeps['store'];
58
58
  warn?: (message: string) => void;
59
59
  ask?: StewardAsk;
60
+ /** Maximum time for each working-backwards wish draft in schedule (milliseconds). */
61
+ draftItemMs?: number;
60
62
  launchSettings?: Pick<StewardSettings, 'mode' | 'launch' | 'maxParallel' | 'podPool'>;
61
63
  launchCommand?: LaunchDeps['command'];
62
64
  spawnLaunch?: LaunchDeps['spawn'];
@@ -413,20 +415,35 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
413
415
  const wishes = rows.filter(row => present.has(row.issue) && row.capability === 'new-capability' && row.rung !== 'hitl');
414
416
  const store = wishes.length ? deps.cardStore ?? new CardStore(root) : undefined;
415
417
  const invalid = new Set<string>();
418
+ const carried = new Set<string>();
416
419
  if (store) try {
417
420
  recordTriageOnCards(wishes, issues, { root, store, now: deps.now });
418
421
  for (const wish of wishes) {
419
- try { await recordWorkingBackwardsOnCards([wish], issues, store, deps.ask ?? askSteward); }
420
- catch (error) {
421
- if (!(error instanceof InvalidWorkingBackwardsDraft)) throw error;
422
- invalid.add(wish.issue);
423
- debug.log('steward.stage', 'draft-invalid', { issue: wish.issue });
424
- }
422
+ const timedOut = Symbol('draft-timeout');
423
+ let timer: ReturnType<typeof setTimeout> | undefined;
424
+ const timeout = new Promise<never>((_, reject) => {
425
+ timer = setTimeout(() => reject(timedOut), deps.draftItemMs ?? 120_000);
426
+ });
427
+ // The draft may finish without ever racing this promise (no ask needed) — never leave its rejection unhandled.
428
+ timeout.catch(() => undefined);
429
+ try {
430
+ // Bound the ask itself so a late answer cannot write to a store closed after this tick.
431
+ const ask: StewardAsk = (prompt, role) => Promise.race([(deps.ask ?? askSteward)(prompt, role), timeout]);
432
+ await recordWorkingBackwardsOnCards([wish], issues, store, ask);
433
+ } catch (error) {
434
+ if (error instanceof InvalidWorkingBackwardsDraft) {
435
+ invalid.add(wish.issue);
436
+ debug.log('steward.stage', 'draft-invalid', { issue: wish.issue });
437
+ } else {
438
+ carried.add(wish.issue);
439
+ debug.log('steward.schedule', 'draft-carried', { issue: wish.issue, reason: error === timedOut ? 'timeout' : 'error' });
440
+ }
441
+ } finally { if (timer) clearTimeout(timer); }
425
442
  }
426
443
  } finally { if (!deps.cardStore) store.close(); }
427
- if (invalid.size) rows = rows.map(row => invalid.has(row.issue)
444
+ if (invalid.size || carried.size) rows = rows.map(row => invalid.has(row.issue)
428
445
  ? { ...row, rung: 'hitl' as const, disposition: 'hitl' as const, hitlReason: 'other' as const, why: 'working-backwards draft invalid' }
429
- : row);
446
+ : carried.has(row.issue) ? { ...row, deferred: true as const, disposition: 'wait' as const } : row);
430
447
  }
431
448
  for (const row of rows) try { debug.log('steward.schedule', 'decision', {
432
449
  kind: row.disposition, target: row.issue, wouldAct: row.disposition === 'now' && liveLike(settings.mode),
@@ -27,9 +27,13 @@ const STALE_MS = 30_000;
27
27
  const RETRY_BUSY_MS = 25;
28
28
  const MAX_TRIES = 240; // ~6s upper bound
29
29
 
30
+ const SLEEP_CELL = new Int32Array(new SharedArrayBuffer(4));
31
+
30
32
  function busyWaitMs(ms: number): void {
33
+ // ⭐ A real sleep, not a CPU spin — a waiter may wait minutes (pod image ship lock, 10-08 flood).
34
+ try { Atomics.wait(SLEEP_CELL, 0, 0, ms); return; }
35
+ catch { /* Atomics.wait unavailable on this thread · fall back to the spin */ }
31
36
  const target = Date.now() + ms;
32
- // Trivial busy-loop. Nothing else to do synchronously.
33
37
  while (Date.now() < target) { /* spin */ }
34
38
  }
35
39
 
@@ -37,6 +41,22 @@ export interface LockOpts {
37
41
  staleMs?: number;
38
42
  retryBusyMs?: number;
39
43
  maxTries?: number;
44
+ /**
45
+ * Sync lock only: also break the lock when the pid on its first line is a dead process
46
+ * (a holder killed with -9 must not wedge waiters for `staleMs`).
47
+ */
48
+ breakDeadHolder?: boolean;
49
+ /** Sync lock only: called once, the first time the lock is found held by someone else. */
50
+ onWait?: (holder: string) => void;
51
+ }
52
+
53
+ function holderIsDead(lockPath: string): boolean {
54
+ let pid: number;
55
+ try { pid = Number.parseInt(readFileSync(lockPath, 'utf8').split(/[\n:]/)[0] ?? '', 10); }
56
+ catch { return false; }
57
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
58
+ try { process.kill(pid, 0); return false; }
59
+ catch (err) { return (err as NodeJS.ErrnoException).code === 'ESRCH'; }
40
60
  }
41
61
 
42
62
  export type ReleaseLock = () => void;
@@ -45,6 +65,7 @@ export function acquireLockSync(lockPath: string, opts: LockOpts = {}): ReleaseL
45
65
  const staleMs = opts.staleMs ?? STALE_MS;
46
66
  const retryBusyMs = opts.retryBusyMs ?? RETRY_BUSY_MS;
47
67
  const maxTries = opts.maxTries ?? MAX_TRIES;
68
+ let waited = false;
48
69
 
49
70
  for (let attempt = 0; attempt < maxTries; attempt += 1) {
50
71
  try {
@@ -63,15 +84,23 @@ export function acquireLockSync(lockPath: string, opts: LockOpts = {}): ReleaseL
63
84
  if (code !== 'EEXIST') throw err;
64
85
  // Lock exists · check for staleness.
65
86
  try {
66
- const age = Date.now() - statSync(lockPath).mtimeMs;
67
- if (age > staleMs) {
68
- try { unlinkSync(lockPath); } catch { /* race · retry */ }
87
+ const seen = statSync(lockPath);
88
+ const age = Date.now() - seen.mtimeMs;
89
+ if (age > staleMs || (opts.breakDeadHolder && holderIsDead(lockPath))) {
90
+ // Narrow the race: only unlink the file we judged (a fresh holder may have replaced it meanwhile).
91
+ try { if (statSync(lockPath).ino === seen.ino) unlinkSync(lockPath); } catch { /* race · retry */ }
69
92
  continue;
70
93
  }
71
94
  } catch {
72
95
  // Race: lock disappeared between EEXIST and stat → retry.
73
96
  continue;
74
97
  }
98
+ if (!waited && opts.onWait) {
99
+ waited = true;
100
+ let holder = '';
101
+ try { holder = readFileSync(lockPath, 'utf8').trim(); } catch { /* gone */ }
102
+ try { opts.onWait(holder); } catch { /* observer only */ }
103
+ }
75
104
  busyWaitMs(retryBusyMs);
76
105
  }
77
106
  }
@@ -139,6 +139,12 @@ async function defaultLoadLedger(): Promise<(runId: string) => RunLedgerEntry[]
139
139
  // 연합 목록을 못 읽으면 이 우주만 읽되, 여기서 못 찾으면 «없음»이 아니라 실패로 올린다(card-bind-failed).
140
140
  let federationFailure: unknown;
141
141
  try { dirs = [...new Set([...dirs, ...resolveFederatedRunLedgerDirectories({})])]; } catch (error) { federationFailure = new Error(`federated run-ledger lookup failed: ${error instanceof Error ? error.message : String(error)}`); }
142
+ // HARNESS-PARENT-ON-MSB1: 원격 부모 런의 원장 거울(`tasks show` 가 ssh 로 당긴다) — 이 우주 ⊕ 연합 «뒤»에만 붙는다.
143
+ try {
144
+ const { remoteLedgerMirrorDirs } = await import('./parent-host.js');
145
+ const { prodInstanceRoot } = await import('../instance/resolve.js');
146
+ dirs = [...new Set([...dirs, ...remoteLedgerMirrorDirs(prodInstanceRoot())])];
147
+ } catch { /* 거울이 없으면 종전 그대로 */ }
142
148
  return ledgerLoader(dirs, (runId, dir) => loadRunLedger(runId, dir), federationFailure);
143
149
  }
144
150
 
@@ -1,10 +1,10 @@
1
- import { readFileSync, statSync } from 'node:fs';
1
+ import { readFileSync, realpathSync, statSync } from 'node:fs';
2
2
  import { extname, isAbsolute, relative, resolve, sep } from 'node:path';
3
3
  import type { Database } from 'bun:sqlite';
4
4
  import type { DecisionLedger } from '../decisions/decision-ledger.js';
5
5
  import { getLastStatus } from '../domains/schedule-registry.js';
6
6
 
7
- export type CompletionEvidenceKind = 'research-report' | 'artifact' | 'content' | 'ops-action' | 'watch-brief' | 'decision-support';
7
+ export type CompletionEvidenceKind = 'research-report' | 'artifact' | 'content' | 'ops-action' | 'watch-brief' | 'decision-support' | 'deliverable';
8
8
  export interface CompletionEvidenceDeps {
9
9
  ledger?: Pick<DecisionLedger, 'list'>;
10
10
  schedulesDb?: Database;
@@ -13,7 +13,7 @@ export interface CompletionEvidenceDeps {
13
13
  /** A missing record is negative evidence; a failed read is explicitly unmeasured. No store is opened or mutated here. */
14
14
  export function checkCompletionEvidence(
15
15
  kind: CompletionEvidenceKind,
16
- input: { dir: string; ref: string },
16
+ input: { dir: string; ref: string; receipt?: boolean },
17
17
  deps: CompletionEvidenceDeps = {},
18
18
  ): { ok: boolean; ref: string; missing: string[] } {
19
19
  const missing: string[] = [];
@@ -38,6 +38,34 @@ export function checkCompletionEvidence(
38
38
  };
39
39
 
40
40
  switch (kind) {
41
+ case 'deliverable': {
42
+ const ref = input.ref.trim();
43
+ if (/^https?:\/\//i.test(ref)) {
44
+ try {
45
+ const url = new URL(ref);
46
+ if (!url.hostname || !['http:', 'https:'].includes(url.protocol)) add('산출물 링크');
47
+ } catch { add('산출물 링크'); }
48
+ } else if (!ref || /^[a-z][a-z\d+.-]*:/i.test(ref)) {
49
+ add('산출물 경로 또는 링크');
50
+ } else {
51
+ const path = pathFor(ref);
52
+ if (!path) add('못 쟀다: 경로');
53
+ else {
54
+ try {
55
+ const root = realpathSync(input.dir);
56
+ const actual = realpathSync(path);
57
+ const rel = relative(root, actual);
58
+ if (rel === '..' || rel.startsWith(`..${sep}`)) add('못 쟀다: 경로');
59
+ else {
60
+ const stat = statSync(actual);
61
+ if (!stat.isFile() || stat.size === 0) add('산출물 파일');
62
+ }
63
+ } catch (error) { add((error as NodeJS.ErrnoException).code === 'ENOENT' ? '산출물 파일' : '못 쟀다: 산출물 파일 읽기'); }
64
+ }
65
+ }
66
+ if (input.receipt !== true) add('수신 확인');
67
+ break;
68
+ }
41
69
  case 'research-report': {
42
70
  const path = file();
43
71
  if (!path) break;
@@ -0,0 +1,61 @@
1
+ import type { NextActionKind } from './actions.js';
2
+
3
+ type CoverVerb = 'land' | 'review' | 'retry' | 'green';
4
+ export interface CoverRow {
5
+ verb: CoverVerb;
6
+ /** null means the TASK-AGENT action source could not be fully read. */
7
+ byTaskAgent: number | null;
8
+ /** Total work by all seats; null when no independent denominator is available. */
9
+ total: number | null;
10
+ /** TASK-AGENT events observed for this verb, including non-done outcomes; null if unreadable. */
11
+ observedActions: number | null;
12
+ ratio: number | null;
13
+ state: 'measured' | 'no-denominator' | 'unreadable';
14
+ /** Non-shadow action events, including failures; null if the action source is incomplete. */
15
+ liveActions: number | null;
16
+ /** Shadow action events; null if the action source is incomplete. */
17
+ shadowActions: number | null;
18
+ /** A transition is observable only with an independent denominator and a completed TA action. */
19
+ stewardTransition: 'observed' | 'not-observed' | 'unmeasured';
20
+ }
21
+
22
+ /** null means the source could not be read; [] means it was read and had no matching events. */
23
+ export interface TaskAgentCoverInput {
24
+ taskAgentActions: readonly { kind: NextActionKind; result: string }[] | null;
25
+ allLands: readonly { step: string; ok: boolean }[] | null;
26
+ /** A source reached the query safety limit; its aggregate is not known to be complete. */
27
+ truncated?: { taskAgentActions: boolean; allLands: boolean };
28
+ }
29
+
30
+ /** Only land has an independent denominator. The other three verbs have no hand-work source yet. */
31
+ export function measureTaskAgentCover(input: TaskAgentCoverInput): CoverRow[] {
32
+ const verbs: CoverVerb[] = ['land', 'review', 'retry', 'green'];
33
+ return verbs.map((verb) => {
34
+ const actions = input.taskAgentActions?.filter((action) => action.kind === verb);
35
+ const actionsUnreadable = actions === undefined || input.truncated?.taskAgentActions === true;
36
+ const byTaskAgent = actionsUnreadable ? null : actions.filter((action) => action.result === 'done').length;
37
+ const observedActions = actionsUnreadable ? null : actions.length;
38
+ const liveActions = actionsUnreadable ? null : actions.filter((action) => action.result !== 'shadow').length;
39
+ const shadowActions = actionsUnreadable ? null : actions.filter((action) => action.result === 'shadow').length;
40
+ const counts = { liveActions, shadowActions };
41
+ if (verb !== 'land') return {
42
+ verb, byTaskAgent, total: null, observedActions, ratio: null,
43
+ state: actionsUnreadable ? 'unreadable' : 'no-denominator',
44
+ ...counts, stewardTransition: 'unmeasured' as const,
45
+ };
46
+ const total = input.allLands === null || input.truncated?.allLands
47
+ ? null : input.allLands.filter((land) => land.step === 'merge' && land.ok === true).length;
48
+ const state = actionsUnreadable || total === null ? 'unreadable'
49
+ : total === 0 ? 'no-denominator' : 'measured';
50
+ const ratio = state === 'measured' && byTaskAgent !== null && total !== null ? byTaskAgent / total : null;
51
+ return { verb, byTaskAgent, total, observedActions, ratio, state, ...counts,
52
+ stewardTransition: ratio === null ? 'unmeasured' : byTaskAgent !== null && byTaskAgent > 0 ? 'observed' : 'not-observed',
53
+ };
54
+ });
55
+ }
56
+
57
+ /** A single human-readable line per verb; unknown numbers are never rendered as zero. */
58
+ export function formatTaskAgentCover(row: CoverRow): string {
59
+ const value = (count: number | null): string => count === null ? '-' : String(count);
60
+ return `${row.verb}: TA ${value(row.byTaskAgent)}/${value(row.total)} (${row.ratio === null ? '-' : `${(row.ratio * 100).toFixed(1)}%`}) · live ${value(row.liveActions)} · shadow ${value(row.shadowActions)} · steward-transition ${row.stewardTransition}`;
61
+ }
@@ -1,9 +1,10 @@
1
1
  /**
2
- * TA-JUDGE-LIVE-SAFE — 판단부의 «안전한 수» 둘만 실제로 한다(10-07 승인 · 그 밖의 수는 그림자 그대로).
2
+ * TA-JUDGE-LIVE-SAFE — 설정에서 명시한 review · propose-green · propose-land 만 실제로 한다.
3
3
  *
4
4
  * - `review`: 수확 가능 런의 PR 에 elanous 리뷰를 «한 번» 요청한다 — PR 머리(sha)마다 한 번(카드 `reviewRequests` 이력).
5
5
  * 요청만 한다: 결과로 착지·재발사로 잇지 않는다(실행부 `executeNextAction` 의 review→land 사슬을 타지 않는다).
6
6
  * - `propose-green`: 카드에 green «제안»(`greenProposal`)만 적는다 — 체크리스트는 손대지 않는다.
7
+ * - `propose-land`: 카드·현재 머리의 self review pass·non-draft 를 확인하고 기존 `pr land` 를 머리 고정으로 한 번 부른다.
7
8
  * - 설정 `taskAgent.liveMoves`(config > env `ELANOUS_TASK_AGENT_LIVE_MOVES` > 없음). 모르는 항목은 경고하고 버린다.
8
9
  * - 관측: 실행한 수마다 `debug.log('task-agent', 'live-move', {kind, card, ok, detail, live:true})`.
9
10
  */
@@ -16,7 +17,7 @@ import { getUserConfig } from '../user-config.js';
16
17
  import type { DetachedSpawn } from '../cli/tasks-cli.js';
17
18
  import { taskAgentStatePath, updateTaskCard, type TaskCard } from './task-hand.js';
18
19
 
19
- export const TASK_AGENT_LIVE_MOVES = ['review', 'propose-green'] as const;
20
+ export const TASK_AGENT_LIVE_MOVES = ['review', 'propose-green', 'propose-land'] as const;
20
21
  export type TaskAgentLiveMove = typeof TASK_AGENT_LIVE_MOVES[number];
21
22
  export const TASK_AGENT_LIVE_MOVES_ENV = 'ELANOUS_TASK_AGENT_LIVE_MOVES';
22
23
 
@@ -62,12 +63,16 @@ export interface LiveMoveDeps {
62
63
  repoCandidates?: (card: TaskCard) => readonly ReviewRepoCandidate[];
63
64
  /** 리뷰 요청(떼어 띄운다) — 시험은 반드시 주입한다. */
64
65
  requestReview?: (pr: number, intent: string, cwd?: string) => Promise<void>;
66
+ /** Fresh PR head and draft flag for landing; separate from the unchanged review lookup. */
67
+ landPrHead?: (pr: number, cwd: string) => Promise<(PrHeadView & { isDraft: boolean }) | null>;
68
+ /** One existing pr land operation; inject in tests instead of invoking the CLI. */
69
+ land?: (pr: number, head: string, cwd: string) => Promise<{ status: number; stdout: string; stderr?: string }>;
65
70
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
66
71
  }
67
72
 
68
73
  /** `executed` = 부작용을 실제로 냈다(리뷰를 띄웠다 · 제안을 적었다). ok 이지만 이미 한 수(같은 머리·이미 제안)면 false. */
69
74
  export interface LiveMoveResult {
70
- kind: TaskAgentLiveMove; card: string | null; ok: boolean; executed: boolean; detail: string;
75
+ kind: TaskAgentLiveMove | 'land'; card: string | null; ok: boolean; executed: boolean; detail: string;
71
76
  /** TA-LIVE-REVIEW-POD — 작업 트리 없이 리뷰 저장소를 찾았을 때(또는 못 찾았을 때)의 근거 한 줄. */
72
77
  reviewRepo?: { resolved: boolean; source?: ReviewRepoCandidate['source']; cwd?: string; proof?: 'head-sha' | 'branch'; reason: string };
73
78
  }
@@ -183,6 +188,52 @@ export async function defaultRequestReview(pr: number, intent: string, cwd?: str
183
188
  await spawnDetachedConfirmed(opts.spawn ?? (spawn as unknown as DetachedSpawn), process.execPath, liveReviewArgs(opts.entry ?? ELANOUS_CLI_ENTRY, configDir, pr, intent), undefined, cwd);
184
189
  }
185
190
 
191
+ export function liveLandArgs(entry: string, configDir: string, pr: number, head: string, cwd: string): string[] {
192
+ return [resolve(entry), '--config-dir', configDir, 'pr', 'land', '--cwd', cwd, '--pr', String(pr), '--expected-head', head];
193
+ }
194
+
195
+ /** The CLI owns the freeze, gate and merge checks; no direct gh merge or bypass flags. */
196
+ export async function defaultLand(pr: number, head: string, cwd: string): Promise<{ status: number; stdout: string; stderr?: string }> {
197
+ const { ELANOUS_CLI_ENTRY } = await import('../cli/tasks-cli.js');
198
+ const { getElanousConfigDirOverride } = await import('../elanous-config-dir.js');
199
+ const { effectiveInstanceRoot } = await import('../instance/resolve.js');
200
+ const args = liveLandArgs(ELANOUS_CLI_ENTRY, getElanousConfigDirOverride() ?? effectiveInstanceRoot(), pr, head, cwd);
201
+ return new Promise((resolveResult, reject) => {
202
+ const child = spawn(process.execPath, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
203
+ let stdout = '';
204
+ let stderr = '';
205
+ child.stdout.on('data', (chunk: Buffer) => { stdout = (stdout + chunk.toString()).slice(-300); });
206
+ child.stderr.on('data', (chunk: Buffer) => { stderr = (stderr + chunk.toString()).slice(-300); });
207
+ child.once('error', reject);
208
+ child.once('close', (code) => {
209
+ if (code !== 0) { resolveResult({ status: code ?? 1, stdout, stderr }); return; }
210
+ void defaultLandPrHead(pr, cwd).then((view) => {
211
+ resolveResult(view?.state === 'MERGED'
212
+ ? { status: 0, stdout, stderr }
213
+ : { status: 1, stdout, stderr: (stderr || stdout || 'landing completed without confirmed merge').slice(-300) });
214
+ }).catch((error) => resolveResult({ status: 1, stdout, stderr: String(error).slice(-300) }));
215
+ });
216
+ });
217
+ }
218
+
219
+ export async function defaultLandPrHead(pr: number, cwd: string): Promise<(PrHeadView & { isDraft: boolean }) | null> {
220
+ const view = (env: NodeJS.ProcessEnv) => runGh(['pr', 'view', String(pr), '--json', 'headRefOid,headRefName,state,url,isDraft'], { env, cwd });
221
+ let out = view(process.env);
222
+ if (out.status !== 0) {
223
+ const noProxy = { ...process.env };
224
+ for (const key of ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy']) delete noProxy[key];
225
+ out = view(noProxy);
226
+ }
227
+ if (out.status !== 0) return null;
228
+ try {
229
+ const value = JSON.parse(out.stdout) as { headRefOid?: unknown; headRefName?: unknown; state?: unknown; url?: unknown; isDraft?: unknown };
230
+ if (typeof value.headRefOid !== 'string' || !/^[a-f0-9]{40}$/i.test(value.headRefOid) || typeof value.state !== 'string' || typeof value.isDraft !== 'boolean') return null;
231
+ return { head: value.headRefOid, state: value.state, isDraft: value.isDraft,
232
+ ...(typeof value.headRefName === 'string' ? { branch: value.headRefName } : {}),
233
+ ...(typeof value.url === 'string' ? { url: value.url } : {}) };
234
+ } catch { return null; }
235
+ }
236
+
186
237
  export function liveReviewIntent(card: TaskCard, runId: string | null, stopReason: string): string {
187
238
  const goal = card.text.split('\n')[0]!.trim().slice(0, 300);
188
239
  return [
@@ -255,6 +306,78 @@ export async function executeLiveReview(
255
306
  return observe(deps, withRepo({ kind, executed: true, card: card.id, ok: true, detail: `review requested for #${pr} head ${head.head.slice(0, 12)}` }));
256
307
  }
257
308
 
309
+ const landedCycles = new Set<string>();
310
+
311
+ /** `propose-land` — only a passing self review of this exact OPEN, non-draft head may invoke pr land. */
312
+ export async function executeLiveLand(
313
+ card: TaskCard | undefined, pr: number | undefined,
314
+ ctx: { runId?: string | null; cycleId?: string; cwd?: string; produced?: { headCommit?: string; branch?: string; prUrl?: string }; review?: { verdict: 'pass' | 'fail'; head: string } },
315
+ deps: LiveMoveDeps = {},
316
+ ): Promise<LiveMoveResult> {
317
+ const kind = 'land' as const;
318
+ const reject = (cardId: string | null, detail: string, reviewRepo?: LiveMoveResult['reviewRepo']) =>
319
+ observe(deps, { kind, card: cardId, ok: false, executed: false, detail, ...(reviewRepo ? { reviewRepo } : {}) });
320
+ if (!card) return reject(null, 'no task card — stays shadow');
321
+ if (!pr || !Number.isSafeInteger(pr) || pr < 1) return reject(card.id, 'no PR — stays shadow');
322
+ let cwd = ctx.cwd;
323
+ let reviewRepo: LiveMoveResult['reviewRepo'];
324
+ if (!cwd) {
325
+ const found = await resolveReviewRepo(card, pr, ctx.produced, deps);
326
+ if (!found.resolved) return reject(card.id, `PR #${pr} worktree unknown — stays shadow`, { resolved: false, reason: found.reason });
327
+ cwd = found.cwd;
328
+ reviewRepo = { resolved: true, source: found.source, cwd, proof: found.proof, reason: found.reason };
329
+ }
330
+ const withRepo = (result: LiveMoveResult): LiveMoveResult => reviewRepo ? { ...result, reviewRepo } : result;
331
+ let view: (PrHeadView & { isDraft: boolean }) | null;
332
+ try { view = await (deps.landPrHead ?? defaultLandPrHead)(pr, cwd); } catch { view = null; }
333
+ if (!view || !/^[0-9a-f]{40}$/i.test(view.head)) return reject(card.id, `PR #${pr} head unknown`, reviewRepo);
334
+ if (view.state !== 'OPEN') return reject(card.id, `PR #${pr} is ${view.state}`, reviewRepo);
335
+ if (view.isDraft !== false) return reject(card.id, `PR #${pr} is draft or draft status unknown`, reviewRepo);
336
+ if (ctx.produced?.prUrl && (!view.url || view.url.trim().replace(/\/+$/, '').toLowerCase() !== ctx.produced.prUrl.trim().replace(/\/+$/, '').toLowerCase())) {
337
+ return reject(card.id, `PR #${pr} URL mismatches run evidence`, reviewRepo);
338
+ }
339
+ if (ctx.review?.verdict !== 'pass') return reject(card.id, `PR #${pr} self review pass missing`, reviewRepo);
340
+ if (!/^[0-9a-f]{40}$/i.test(ctx.review.head) || ctx.review.head.toLowerCase() !== view.head.toLowerCase()) {
341
+ return reject(card.id, `PR #${pr} review head mismatch: ${ctx.review.head.slice(0, 12)} ≠ ${view.head.slice(0, 12)}`, reviewRepo);
342
+ }
343
+ const cycle = ctx.cycleId ?? ctx.runId;
344
+ if (cycle && landedCycles.has(cycle)) return reject(card.id, `cycle ${cycle} already landed — stays shadow`, reviewRepo);
345
+ const path = deps.statePath ?? taskAgentStatePath();
346
+ const at = (deps.now ?? (() => new Date()))().toISOString();
347
+ let claimed = false;
348
+ let missing = false;
349
+ try {
350
+ updateTaskCard(path, card.id, (current) => {
351
+ if (!current) { missing = true; return undefined; }
352
+ if ((current.landAttempts ?? []).some(entry => entry.pr === pr && entry.head.toLowerCase() === view!.head.toLowerCase())) return undefined;
353
+ claimed = true;
354
+ return { ...current, landAttempts: [...(current.landAttempts ?? []), { pr, head: view!.head, at }] };
355
+ });
356
+ } catch (error) {
357
+ return reject(card.id, `land attempt could not be recorded: ${String(error).slice(-250)}`, reviewRepo);
358
+ }
359
+ if (missing) return reject(card.id, 'task card not in state file', reviewRepo);
360
+ if (!claimed) return observe(deps, withRepo({ kind, card: card.id, ok: true, executed: false, detail: `already attempted land for #${pr} head ${view.head.slice(0, 12)}` }));
361
+ if (cycle) landedCycles.add(cycle);
362
+ let ok = false;
363
+ let detail: string;
364
+ try {
365
+ // The CLI rechecks the pinned PR/head immediately before merge, after its own gates and freeze admission.
366
+ const outcome = await (deps.land ?? defaultLand)(pr, view.head, cwd);
367
+ ok = outcome.status === 0;
368
+ detail = (ok ? outcome.stdout || `land merged #${pr} head ${view.head.slice(0, 12)}` : outcome.stderr || outcome.stdout || `exit ${outcome.status}`).slice(-300);
369
+ } catch (error) { detail = (error instanceof Error ? error.message : String(error)).slice(-300); }
370
+ try {
371
+ updateTaskCard(path, card.id, (current) => current?.landAttempts?.some(entry => entry.pr === pr && entry.head === view!.head && entry.at === at)
372
+ ? { ...current, landAttempts: current.landAttempts.map(entry => entry.pr === pr && entry.head === view!.head && entry.at === at ? { ...entry, ok, detail } : entry) }
373
+ : undefined);
374
+ } catch (error) {
375
+ return observe(deps, withRepo({ kind, card: card.id, ok: false, executed: true,
376
+ detail: `land ${ok ? 'succeeded' : 'failed'} but card update failed: ${String(error).slice(-230)}` }));
377
+ }
378
+ return observe(deps, withRepo({ kind, card: card.id, ok, executed: true, detail }));
379
+ }
380
+
258
381
  /** `propose-green` — 비지 않은 근거가 있을 때만 카드에 제안을 적는다(한 번). 체크리스트는 쓰지 않는다. */
259
382
  export function executeLiveGreenProposal(card: TaskCard | undefined, evidence: Record<string, string>, deps: LiveMoveDeps = {}): LiveMoveResult {
260
383
  const kind = 'propose-green' as const;