elanous 0.2.20 → 0.2.21

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 (339) 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/MObU8ujkMciAKr6ljAV05/_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-77fad80cf54477c6.js → 1307-c97eba9fb72a9a5e.js} +1 -1
  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/2549-a8515c86f9e8cb96.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +94 -0
  33. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3522-1de1319d028ac89c.js +25 -0
  37. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +74 -0
  39. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +34 -0
  43. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +115 -0
  45. package/apps/pwa/out/_next/static/chunks/4588.ad3364cb7fb97ada.js +86 -0
  46. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +77 -0
  48. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +90 -0
  52. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5977-59fedea50d13c762.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +8 -0
  57. package/apps/pwa/out/_next/static/chunks/{6158.af2e93b7adff709b.js → 6158.566c890adc06a459.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +64 -0
  59. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +287 -0
  61. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +226 -0
  62. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/6767.8e6c5f6e744fcd9f.js +38 -0
  64. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/7175-350f4ce2873bc038.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +41 -0
  71. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +24 -0
  72. package/apps/pwa/out/_next/static/chunks/7630.2b9a68659053ff4e.js +193 -0
  73. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/7899.597af4a9996c907f.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/79b78388.663188133449d707.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/8194.484f51e273d9abd2.js +217 -0
  79. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +104 -0
  80. package/apps/pwa/out/_next/static/chunks/8857-f1762140ef9a96b1.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/88729267.9c6c000157c83f2f.js +62 -0
  82. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +93 -0
  84. package/apps/pwa/out/_next/static/chunks/9247-7581825d511a64c0.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +23 -0
  86. package/apps/pwa/out/_next/static/chunks/9497-b0e758d1cd4ae8d7.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +62 -0
  88. package/apps/pwa/out/_next/static/chunks/9832.2ab2e818013574c7.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/a9f2b54d-40c16bd0efdb04b8.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/app/approvals/page-937c92292a4ab4f0.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-85b316bb4235980b.js → page-d781be3e3a9cfd74.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/app/board/{page-9b2b26a33cb2cd42.js → page-b0a80997903852d8.js} +1 -1
  93. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-c9955fde67b1bcb5.js → page-2b1263165630d9c8.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/app/bots/{page-7a852956c74015a3.js → page-ea998f7f5d156bea.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/app/ceo/page-33c328b64ca508f8.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/app/chat/{page-4ba4abe096b6c2a8.js → page-e2d6bed48ac20120.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/app/consult/{page-575d4a8b4f7becb2.js → page-111cabe4d1fd69ae.js} +1 -1
  98. package/apps/pwa/out/_next/static/chunks/app/control/{page-f5d56ff5f45ad164.js → page-544dd4bd4847eeb7.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/app/decisions/{page-2260e9eef0357421.js → page-3ee191319bf97d87.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e4bcb2c503dab04b.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/app/editor/page-300897dcbbd5ed76.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/app/exec/{page-466bf0ee16ad1432.js → page-a449f1ed472b81c2.js} +1 -1
  103. package/apps/pwa/out/_next/static/chunks/app/field/{page-a23bc71713bcc08f.js → page-9045094d6d3b5cd0.js} +1 -1
  104. package/apps/pwa/out/_next/static/chunks/app/inside/page-c06673596849ef45.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/app/intake/page-103fa3191c1b2e08.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/app/layout-9f81233f29dcd409.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/app/live/page-be8b4615c919e36c.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/app/live-run/page-c685b104e0dfa609.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/app/loops/page-8d693331cfbb6add.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/app/market/page-cef4f30a4c22fae1.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66ea1b54fc83fa15.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/app/morning/{page-ec102c9b8b691e37.js → page-7a12f61be4a579d1.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/app/not-found-c85b0589591a99c9.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/app/observatory/page-725a4da02dd129eb.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-f6055495e9ed7ea8.js → page-8cc707bd09a497d9.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-90b55be1f15ce0e8.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cb16606e08be65db.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/app/outputs/page-16dc64b74ed6a40a.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/app/page-21bec4afeb2f0917.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/app/reflection/{page-db03ae3589a81c9e.js → page-dc39ee7a36d26385.js} +1 -1
  121. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-4a6463b97f0ad94f.js → page-84ae759f76053672.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/sessions/{page-75bffecc9aa1004e.js → page-3db58ddb61fe2be9.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-c5315e30f3528dc4.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/settings/{page-31d5b875760bb62d.js → page-2fe368efb6de3b6a.js} +1 -1
  125. package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-c26fa10aac6c21c4.js → page-8d04132dd0ac5e10.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/app/setup/{page-68793c6e10331d66.js → page-f23484de467c9ea3.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/share/{page-46d5201d2207a511.js → page-c69762987b751174.js} +1 -1
  128. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5456692bda39aafb.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/tasks/{page-be1c4e8697f22360.js → page-d75f7cd65845ce98.js} +1 -1
  130. package/apps/pwa/out/_next/static/chunks/app/term/page-5603f5e568b25ce3.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/today/page-d2cc0f4e89f42028.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/trace/{page-0fd895fab9b62c1b.js → page-a6eb73b8a4840f1c.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/vault/page-c0a3f4d10edb83fa.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-c6e4364d9de8f717.js → page-6c0b88068c143f15.js} +1 -1
  135. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-0acc8e198f7b0dfb.js → page-7f8d7fcdf058a845.js} +1 -1
  136. package/apps/pwa/out/_next/static/chunks/app/workspace/{page-34882c84f84021c5.js → page-22163556cd38bc88.js} +1 -1
  137. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-141436fd26dd56fc.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/d70879db.c66c56a95a91efc6.js +66 -0
  139. package/apps/pwa/out/_next/static/chunks/f8626309.a4e5d362b1d55e59.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +1 -0
  141. package/apps/pwa/out/_next/static/css/{d3427996da11e480.css → b9d8151e48998417.css} +1 -1
  142. package/apps/pwa/out/_next/static/css/e81df11490b4413b.css +1 -0
  143. package/apps/pwa/out/approvals/index.html +1 -1
  144. package/apps/pwa/out/approvals/index.txt +14 -14
  145. package/apps/pwa/out/autopilot/index.html +1 -1
  146. package/apps/pwa/out/autopilot/index.txt +14 -14
  147. package/apps/pwa/out/board/index.html +1 -1
  148. package/apps/pwa/out/board/index.txt +14 -14
  149. package/apps/pwa/out/botlab/index.html +1 -1
  150. package/apps/pwa/out/botlab/index.txt +14 -14
  151. package/apps/pwa/out/bots/index.html +1 -1
  152. package/apps/pwa/out/bots/index.txt +14 -14
  153. package/apps/pwa/out/ceo/index.html +1 -1
  154. package/apps/pwa/out/ceo/index.txt +14 -14
  155. package/apps/pwa/out/chat/index.html +1 -1
  156. package/apps/pwa/out/chat/index.txt +14 -14
  157. package/apps/pwa/out/consult/index.html +1 -1
  158. package/apps/pwa/out/consult/index.txt +14 -14
  159. package/apps/pwa/out/control/index.html +1 -1
  160. package/apps/pwa/out/control/index.txt +14 -14
  161. package/apps/pwa/out/decisions/index.html +1 -1
  162. package/apps/pwa/out/decisions/index.txt +14 -14
  163. package/apps/pwa/out/design-check/index.html +1 -1
  164. package/apps/pwa/out/design-check/index.txt +14 -14
  165. package/apps/pwa/out/editor/index.html +1 -1
  166. package/apps/pwa/out/editor/index.txt +15 -15
  167. package/apps/pwa/out/exec/index.html +1 -1
  168. package/apps/pwa/out/exec/index.txt +14 -14
  169. package/apps/pwa/out/field/index.html +1 -1
  170. package/apps/pwa/out/field/index.txt +14 -14
  171. package/apps/pwa/out/healthz +1 -1
  172. package/apps/pwa/out/index.html +1 -1
  173. package/apps/pwa/out/index.txt +14 -14
  174. package/apps/pwa/out/inside/index.html +1 -1
  175. package/apps/pwa/out/inside/index.txt +15 -15
  176. package/apps/pwa/out/intake/index.html +1 -1
  177. package/apps/pwa/out/intake/index.txt +14 -14
  178. package/apps/pwa/out/live/index.html +1 -1
  179. package/apps/pwa/out/live/index.txt +14 -14
  180. package/apps/pwa/out/live-run/index.html +1 -0
  181. package/apps/pwa/out/live-run/index.txt +35 -0
  182. package/apps/pwa/out/loops/index.html +1 -1
  183. package/apps/pwa/out/loops/index.txt +14 -14
  184. package/apps/pwa/out/market/index.html +1 -1
  185. package/apps/pwa/out/market/index.txt +14 -14
  186. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  187. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  188. package/apps/pwa/out/morning/index.html +1 -1
  189. package/apps/pwa/out/morning/index.txt +14 -14
  190. package/apps/pwa/out/observatory/index.html +1 -1
  191. package/apps/pwa/out/observatory/index.txt +14 -14
  192. package/apps/pwa/out/ops/checklist/index.html +1 -1
  193. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  194. package/apps/pwa/out/ops/release/index.html +1 -1
  195. package/apps/pwa/out/ops/release/index.txt +14 -14
  196. package/apps/pwa/out/ops/seats/index.html +1 -1
  197. package/apps/pwa/out/ops/seats/index.txt +14 -14
  198. package/apps/pwa/out/outputs/index.html +1 -1
  199. package/apps/pwa/out/outputs/index.txt +14 -14
  200. package/apps/pwa/out/reflection/index.html +1 -1
  201. package/apps/pwa/out/reflection/index.txt +15 -15
  202. package/apps/pwa/out/scheduler/index.html +1 -1
  203. package/apps/pwa/out/scheduler/index.txt +14 -14
  204. package/apps/pwa/out/sessions/index.html +1 -1
  205. package/apps/pwa/out/sessions/index.txt +14 -14
  206. package/apps/pwa/out/settings/devices/index.html +1 -1
  207. package/apps/pwa/out/settings/devices/index.txt +14 -14
  208. package/apps/pwa/out/settings/index.html +1 -1
  209. package/apps/pwa/out/settings/index.txt +14 -14
  210. package/apps/pwa/out/setup/done/index.html +1 -1
  211. package/apps/pwa/out/setup/done/index.txt +14 -14
  212. package/apps/pwa/out/setup/index.html +1 -1
  213. package/apps/pwa/out/setup/index.txt +14 -14
  214. package/apps/pwa/out/share/index.html +1 -1
  215. package/apps/pwa/out/share/index.txt +14 -14
  216. package/apps/pwa/out/showroom/index.html +1 -1
  217. package/apps/pwa/out/showroom/index.txt +14 -14
  218. package/apps/pwa/out/tasks/index.html +1 -1
  219. package/apps/pwa/out/tasks/index.txt +14 -14
  220. package/apps/pwa/out/term/index.html +1 -1
  221. package/apps/pwa/out/term/index.txt +14 -14
  222. package/apps/pwa/out/today/index.html +1 -1
  223. package/apps/pwa/out/today/index.txt +14 -14
  224. package/apps/pwa/out/trace/index.html +1 -1
  225. package/apps/pwa/out/trace/index.txt +14 -14
  226. package/apps/pwa/out/vault/index.html +1 -1
  227. package/apps/pwa/out/vault/index.txt +14 -14
  228. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  229. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  230. package/apps/pwa/out/workflows/index.html +1 -1
  231. package/apps/pwa/out/workflows/index.txt +14 -14
  232. package/apps/pwa/out/workspace/index.html +1 -1
  233. package/apps/pwa/out/workspace/index.txt +14 -14
  234. package/apps/pwa/out/worktrees/index.html +1 -1
  235. package/apps/pwa/out/worktrees/index.txt +14 -14
  236. package/graphs/drafts/recipes.yaml +4 -4
  237. package/graphs/implement-loop.yaml +277 -5
  238. package/package.json +1 -1
  239. package/scripts/coord-channel-watch.sh +31 -4
  240. package/scripts/docs-lint.ts +4 -1
  241. package/scripts/marketing/generate-ax-brief.ts +18 -1
  242. package/scripts/measure-nl-routing-corpus.ts +11 -3
  243. package/scripts/release-loop/gate-node.ts +5 -5
  244. package/scripts/release-loop/shard-plan.ts +50 -5
  245. package/scripts/rhythm/daily.ts +2 -1
  246. package/src/browser-cdp/client.ts +10 -5
  247. package/src/cli/ops-cli.ts +11 -0
  248. package/src/cli/ops-overview-cli.ts +50 -0
  249. package/src/cli/pod-cli.ts +1 -0
  250. package/src/cli/tasks-cli.ts +106 -0
  251. package/src/dashboard/index.ts +40 -4
  252. package/src/esc-abort-gate.ts +3 -1
  253. package/src/graph-runner/graph-cli.ts +57 -0
  254. package/src/graph-runner/graph-run-api.ts +13 -0
  255. package/src/graph-wizard/archetypes.ts +88 -0
  256. package/src/graph-wizard/generate.ts +545 -0
  257. package/src/graph-wizard/saved-steps.ts +120 -0
  258. package/src/graph-wizard/steps.ts +193 -0
  259. package/src/harness/harness-cli-command.ts +68 -12
  260. package/src/index.ts +7 -4
  261. package/src/intake-plane/digest.ts +18 -11
  262. package/src/maturity/feature-maturity.ts +2 -1
  263. package/src/nexus/api/draft-metrics.ts +114 -0
  264. package/src/nexus/api/graph-wizard-api.ts +53 -0
  265. package/src/nexus/api/graphs-api.ts +50 -12
  266. package/src/nexus/api/harness-traversal.ts +205 -0
  267. package/src/nexus/api/http-server.ts +31 -0
  268. package/src/nexus/outbound/router.ts +28 -8
  269. package/src/onboarding/first-run.ts +3 -0
  270. package/src/ops/overview-collect.ts +345 -0
  271. package/src/ops/overview-seat-era.ts +90 -0
  272. package/src/ops/overview.ts +223 -0
  273. package/src/release-loop/gate-shards.ts +7 -2
  274. package/src/self-dev/ask-launch-flow.ts +4 -2
  275. package/src/self-dev/ask-launch-io.ts +3 -1
  276. package/src/self-dev/graph-journey-nodes.ts +157 -0
  277. package/src/self-dev/graph-journey-route.ts +105 -0
  278. package/src/self-dev/launch-preflight.ts +43 -3
  279. package/src/self-dev/release-path-guard.ts +7 -4
  280. package/src/self-implement/frozen-merges.ts +23 -0
  281. package/src/self-implement/goal-author.ts +14 -0
  282. package/src/self-implement/heal-intake.ts +3 -0
  283. package/src/self-implement/orchestrator.ts +16 -1
  284. package/src/self-implement/seams.ts +3 -0
  285. package/src/self-implement/self-implement-runtime.ts +12 -0
  286. package/src/session-runtime/index.ts +5 -3
  287. package/src/shell-env-bootstrap.ts +17 -3
  288. package/src/task-agent/card-evidence.ts +6 -0
  289. package/src/task-agent/parent-host.ts +315 -0
  290. package/src/task-agent/task-hand.ts +9 -2
  291. package/src/task-orchestrator/surfaces/pod-command-job.ts +41 -6
  292. package/src/task-orchestrator/surfaces/pod-gate-deps.ts +123 -0
  293. package/src/task-orchestrator/surfaces/self-implement-pod.ts +39 -6
  294. package/src/tool-runtime/browser-runtime.ts +87 -3
  295. package/src/tool-runtime/index.ts +1 -0
  296. package/src/user-config.ts +20 -4
  297. package/src/version/packed-revision.json +1 -1
  298. package/apps/pwa/out/_next/static/Bam1YziK2iH9bN4K0utGk/_buildManifest.js +0 -1
  299. package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +0 -1
  300. package/apps/pwa/out/_next/static/chunks/1844-9ec4b1d12f6e80eb.js +0 -1
  301. package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +0 -1
  302. package/apps/pwa/out/_next/static/chunks/1948.15f356b15a625597.js +0 -5
  303. package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +0 -1
  304. package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +0 -1
  305. package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +0 -1
  306. package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +0 -1
  307. package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +0 -1
  308. package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +0 -1
  309. package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +0 -1
  310. package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +0 -25
  311. package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +0 -1
  312. package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +0 -1
  313. package/apps/pwa/out/_next/static/chunks/app/approvals/page-c855c24de7db74fe.js +0 -1
  314. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +0 -1
  315. package/apps/pwa/out/_next/static/chunks/app/design-check/page-7c058069c5e7fa63.js +0 -1
  316. package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +0 -1
  317. package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +0 -1
  318. package/apps/pwa/out/_next/static/chunks/app/intake/page-9cd565005b93aca6.js +0 -1
  319. package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +0 -1
  320. package/apps/pwa/out/_next/static/chunks/app/live/page-474cb5888ea0e8f3.js +0 -1
  321. package/apps/pwa/out/_next/static/chunks/app/loops/page-35bfec2e631d3eae.js +0 -1
  322. package/apps/pwa/out/_next/static/chunks/app/market/page-9ca21f9ad3208a61.js +0 -1
  323. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-f9ccb1b1adbea14d.js +0 -1
  324. package/apps/pwa/out/_next/static/chunks/app/not-found-a9c2cfa8dda922a5.js +0 -1
  325. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +0 -1
  326. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +0 -1
  327. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +0 -1
  328. package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +0 -1
  329. package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +0 -1
  330. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +0 -1
  331. package/apps/pwa/out/_next/static/chunks/app/showroom/page-d81c07a7b4f618ae.js +0 -1
  332. package/apps/pwa/out/_next/static/chunks/app/term/page-cf0a4b4abead71ea.js +0 -1
  333. package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +0 -1
  334. package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +0 -1
  335. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +0 -1
  336. package/apps/pwa/out/_next/static/chunks/webpack-c260571513bf43c2.js +0 -1
  337. package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +0 -1
  338. /package/apps/pwa/out/_next/static/{Bam1YziK2iH9bN4K0utGk → MObU8ujkMciAKr6ljAV05}/_ssgManifest.js +0 -0
  339. /package/skills/project-onboarding/{skill.md → SKILL.md} +0 -0
@@ -538,6 +538,9 @@ export interface LaunchPreflightInput {
538
538
  readonly askTargetPaths?: readonly string[];
539
539
  /** 대상 경로 라벨이 «있는데» 거부된 조각. 0건 막음 문면이 그 이유를 말하게 한다(판정은 안 바꾼다). */
540
540
  readonly askTargetPathRejections?: readonly AskTargetPathHintRejection[];
541
+ /** AUTO-TARGET: machine-suggested target paths dropped because the goal is NOT-GROUNDED (no persistent evidence).
542
+ * Non-empty = the goal is a scope card and must not launch an implementation. */
543
+ readonly notGroundedDroppedTargetPaths?: readonly string[];
541
544
  /** ask 원문 경로. 있으면 ask-outside-path 경고만 이 목록과 최종 대상을 비교한다. */
542
545
  readonly askOutsidePathHints?: readonly string[];
543
546
  /** 이번에 쏠 골의 브랜치 이름. 없으면 형제 PR 축의 경고를 내지 않는다. */
@@ -559,19 +562,31 @@ function emitAskMarkerObservation(result: LaunchPreflightResult): void {
559
562
  emittedAskMarkerObservations.add(result);
560
563
  }
561
564
 
565
+ /** AUTO-TARGET: blocker name for a NOT-GROUNDED goal whose only target paths were machine-suggested (a scope card). */
566
+ export const NOT_GROUNDED_SCOPE_CARD_BLOCKER = '(NOT-GROUNDED 범위 카드)';
567
+
562
568
  export function evaluateLaunchPreflight(input: LaunchPreflightInput): LaunchPreflightResult {
563
569
  const paths = [...new Set(input.paths.filter((path) => path.trim().length > 0))];
564
570
  const blockers: LaunchPreflightBlocker[] = [];
565
571
  const warnings: LaunchPreflightBlocker[] = [];
566
572
 
573
+ // AUTO-TARGET (10-08 canary · TSC-HEAP): a NOT-GROUNDED goal whose only target paths came from the
574
+ // harness candidate search is a scope card — refuse it with that reason, not the generic «no label» text.
575
+ const notGroundedDropped = input.notGroundedDroppedTargetPaths ?? [];
576
+ const notGroundedDetail = notGroundedDropped.length > 0
577
+ ? `골이 NOT-GROUNDED(영속 근거 0)라 하니스 후보 검색이 넣은 대상 경로 ${notGroundedDropped.length}개(${notGroundedDropped.slice(0, 3).join(' · ')}${notGroundedDropped.length > 3 ? ' …' : ''})를 대상으로 쓰지 않는다 — 범위 카드: 구현 발사 대상이 아니다 · ask 첫 줄에 사람이 「대상 경로: <파일>」을 적거나 접지 근거를 복구한 뒤 다시 저작`
578
+ : undefined;
579
+ if (notGroundedDetail !== undefined && paths.length > 0) {
580
+ blockers.push({ kind: 'no-target-paths', name: NOT_GROUNDED_SCOPE_CARD_BLOCKER, detail: notGroundedDetail });
581
+ }
567
582
  // ① 모집단이 0이면 «통과»가 아니라 «막는 사유»다(METHOD v32 를 이 코드에도 적용).
568
583
  if (paths.length === 0) {
569
584
  blockers.push({
570
585
  kind: 'no-target-paths',
571
- name: '(대상 경로 0)',
586
+ name: notGroundedDetail !== undefined ? NOT_GROUNDED_SCOPE_CARD_BLOCKER : '(대상 경로 0)',
572
587
  // ⛔ 2026-09-23 — 라벨이 «있는데» 조각이 거부된 경우를 「라벨을 넣어라」로 뭉개면 「거부됐다」를 「없다」로 읽게 된다
573
588
  // (실측: `대상 경로: README.md — 설명…` 한 줄 → has-whitespace 로 통째 거부 · 문면은 「넣어라」뿐이었다).
574
- detail: (input.askTargetPathRejections?.length
589
+ detail: notGroundedDetail !== undefined ? notGroundedDetail : (input.askTargetPathRejections?.length
575
590
  ? `대상 경로 라벨은 있는데 조각 ${input.askTargetPathRejections.length}개가 거부됐다: ${input.askTargetPathRejections.slice(0, 3).map((r) => `「${r.fragment.length > 40 ? `${r.fragment.slice(0, 40)}…` : r.fragment}」(${r.reason})`).join(' · ')} — 그 줄에는 «경로만» 둔다(설명은 다음 줄)`
576
591
  : '골에서 대상 경로를 하나도 못 뽑았다 — ask 첫 줄에 「대상 경로: <파일> · <파일>」을 넣어라')
577
592
  + ' — 이 상태의 「위반 0」은 「검사했다」가 아니다 — elanous self author --inspect-target-paths "<문면>"',
@@ -1192,6 +1207,9 @@ export interface AskPreflightDeps {
1192
1207
  readonly askTargetPaths?: (document: string) => readonly string[];
1193
1208
  /** 대상 경로 라벨 «안»에서 거부된 조각(이유 포함). 0건 막음 문면이 「라벨이 없다」와 「있는데 거부됐다」를 가르게 한다. */
1194
1209
  readonly askTargetPathRejections?: (document: string) => readonly AskTargetPathHintRejection[];
1210
+ /** AUTO-TARGET: true when the authored goal is NOT-GROUNDED with no persistent evidence (a scope card).
1211
+ * Omitted = this distinction is not made (existing behavior). Production wires `isNotGroundedWithoutPersistentEvidence`. */
1212
+ readonly notGroundedWithoutPersistentEvidence?: (document: string) => boolean;
1195
1213
  }
1196
1214
 
1197
1215
  export interface AskPreflightOptions {
@@ -1212,6 +1230,10 @@ export interface AskPreflightOptions {
1212
1230
  readonly plannedBranch?: string;
1213
1231
  /** 저작 전 ask 원문. 주면 기존 ask-marker-check로 형식을 관측하되 발사를 막지 않는다. */
1214
1232
  readonly askText?: string;
1233
+ /** AUTO-TARGET: target paths the harness put into the ask (candidate search), not the human.
1234
+ * If the authored goal is NOT-GROUNDED without persistent evidence, these paths are dropped and the
1235
+ * goal stops before launch (`no-target-paths` blocker naming the reason). */
1236
+ readonly machineSuggestedTargetPaths?: readonly string[];
1215
1237
  }
1216
1238
 
1217
1239
  export type PlannedBranchResolution =
@@ -1539,7 +1561,24 @@ export function decideAskPreflight(
1539
1561
  }
1540
1562
  }
1541
1563
  // ⛔ 저작 전에는 pathsOverride 자체가 ask 대상 힌트다. 저작 뒤에는 골에서 뽑은 대상만 역할로 쓴다.
1542
- const askTargetPaths = opts.pathsOverride ?? (goalDocument && deps.askTargetPaths ? deps.askTargetPaths(goalDocument) : []);
1564
+ const declaredAskTargetPaths = opts.pathsOverride ?? (goalDocument && deps.askTargetPaths ? deps.askTargetPaths(goalDocument) : []);
1565
+ // AUTO-TARGET: a NOT-GROUNDED goal (no persistent evidence) carries no machine-suggested target path.
1566
+ const machineSuggested = new Set((opts.machineSuggestedTargetPaths ?? []).map((path) => path.trim()).filter(Boolean));
1567
+ let notGroundedGoal = false;
1568
+ if (!opts.pathsOverride && goalDocument !== null && machineSuggested.size > 0 && deps.notGroundedWithoutPersistentEvidence) {
1569
+ try { notGroundedGoal = deps.notGroundedWithoutPersistentEvidence(goalDocument); } catch { notGroundedGoal = false; }
1570
+ }
1571
+ const notGroundedDroppedTargetPaths = notGroundedGoal ? declaredAskTargetPaths.filter((path) => machineSuggested.has(path)) : [];
1572
+ const askTargetPaths = notGroundedDroppedTargetPaths.length > 0
1573
+ ? declaredAskTargetPaths.filter((path) => !machineSuggested.has(path))
1574
+ : declaredAskTargetPaths;
1575
+ if (notGroundedDroppedTargetPaths.length > 0) {
1576
+ try {
1577
+ debug.log('harness.preflight', 'not-grounded-target-paths-dropped', { goalFile: opts.goalFile, dropped: notGroundedDroppedTargetPaths });
1578
+ } catch {
1579
+ // Observation never changes the launch decision.
1580
+ }
1581
+ }
1543
1582
  // 저작 뒤에는 접지가 읽은 경로와 선언 대상 경로를 함께 검사한다. 저작 전 pathsOverride는 그대로 쓴다.
1544
1583
  const paths = opts.pathsOverride ?? [...new Set([...tracedPaths, ...askTargetPaths])];
1545
1584
  const askMarkerInspection = opts.askText === undefined
@@ -1677,6 +1716,7 @@ export function decideAskPreflight(
1677
1716
  ...(goalRulersUnknownReason ? { goalRulersUnknownReason } : {}),
1678
1717
  preexistingFailures,
1679
1718
  ...(askTargetPaths.length > 0 ? { askTargetPaths } : {}),
1719
+ ...(notGroundedDroppedTargetPaths.length > 0 ? { notGroundedDroppedTargetPaths } : {}),
1680
1720
  ...(askTargetPaths.length === 0 && goalDocument && deps.askTargetPathRejections
1681
1721
  ? { askTargetPathRejections: deps.askTargetPathRejections(goalDocument) }
1682
1722
  : {}),
@@ -1,6 +1,9 @@
1
- // Release path = what publishing reads directly: the release scripts and graph, plus the manifest, release notes and cut schedule
2
- // in `src/release-loop/`. The checklist store (`checklist.ts`, `feature-store.ts`) is shared ops ledger code — the gate catches its regressions (OP 10-03).
3
- export const RELEASE_PATH_PREFIXES = ['scripts/release-loop/', 'graphs/release/', 'src/release-loop/manifest', 'src/release-loop/release-note', 'src/release-loop/release-schedule'] as const;
1
+ // Release path = release scripts and graph, manifest, notes and cut schedule, plus gate execution modules
2
+ // imported by scripts/release-loop/gate-node.ts (pod-command-job → pod-pool → pod-lease; pod-bun-cache; pod-install-slots; gate-shards).
3
+ // The checklist store (`checklist.ts`, `feature-store.ts`) remains shared ops ledger code (OP 10-03).
4
+ export const RELEASE_PATH_PREFIXES = ['scripts/release-loop/', 'graphs/release/', 'src/release-loop/manifest', 'src/release-loop/release-note', 'src/release-loop/release-schedule',
5
+ 'src/task-orchestrator/surfaces/pod-command-job.ts', 'src/task-orchestrator/surfaces/pod-pool.ts', 'src/task-orchestrator/surfaces/pod-lease.ts',
6
+ 'src/task-orchestrator/surfaces/pod-bun-cache.ts', 'src/task-orchestrator/surfaces/pod-install-slots.ts', 'src/release-loop/gate-shards.ts'] as const;
4
7
  export const RELEASE_PATH_LABEL = 'elanous:release-path';
5
8
 
6
9
  /** Flatten every GitHub PR file page, including the source of a rename. */
@@ -35,7 +38,7 @@ export function releaseGitDiffPaths(output: string): string[] {
35
38
 
36
39
  /** Evaluate the paths from the opened PR, not the requested goal or local working tree. */
37
40
  export function releasePathHold(paths: readonly string[]): string | undefined {
38
- return paths.find((path) => RELEASE_PATH_PREFIXES.some((prefix) => path.startsWith(prefix)));
41
+ return paths.find((path) => RELEASE_PATH_PREFIXES.some((prefix) => prefix.endsWith('.ts') ? path === prefix : path.startsWith(prefix)));
39
42
  }
40
43
 
41
44
  /** Fixed opening of the hold comment — also how a PR held by several merge surfaces (or polls) is recognised, so it is posted once. */
@@ -4,6 +4,8 @@ import { createHash } from 'node:crypto';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
6
6
  import { debug } from '../debug/log.js';
7
+ import { enterJourneyNode, exitJourneyNode, passJourneyNode, withJourneyNodeSync } from '../self-dev/graph-journey-nodes.js';
8
+ import { routeJourneyEdge } from '../self-dev/graph-journey-route.js';
7
9
  import { beginLandingMerge, type LandingFreeze } from '../release-loop/landing-freeze.js';
8
10
 
9
11
  /** `manual`: the owning repository could not be determined — a sweep never resumes it; a person does. */
@@ -183,6 +185,26 @@ export function admitLandingMerge(
183
185
  hooks: { afterQueue?: () => void } = {},
184
186
  claimKey?: { prNumber: number; repoRoot: string; headCommit?: string },
185
187
  opts: { prodFreezeRoot?: string; forceReason?: string } = {},
188
+ ): LandingAdmission {
189
+ // HARNESS-FULL-GRAPH — 병합 직전 한 곳의 동결 검사가 그래프 노드 freeze-check(출구: open | frozen | taken)이고,
190
+ // 동결이면 보류 대기열이 노드 hold 다. 판정은 바꾸지 않는다 — 관측만.
191
+ const pr = claimKey?.prNumber;
192
+ enterJourneyNode('freeze-check', { provenance: 'admit-landing-merge', ...(pr === undefined ? {} : { data: { pr } }) });
193
+ const admission = withJourneyNodeSync('freeze-check', { provenance: 'admit-landing-merge', ...(pr === undefined ? {} : { data: { pr } }) },
194
+ () => admitLandingMergeUnobserved(heldEntry, root, hooks, claimKey, opts));
195
+ const freezeLabel = admission.kind === 'merge' ? 'open' : admission.kind === 'held' ? 'frozen' : 'taken';
196
+ exitJourneyNode('freeze-check', { provenance: 'admit-landing-merge', outcome: freezeLabel, ...(pr === undefined ? {} : { data: { pr } }) });
197
+ // 2판: 간선 판독을 남긴다(관측). 승인 요구(open→hold) 강제는 0.2.22 — 보류 사유 값이 먼저다(RFC §3).
198
+ routeJourneyEdge('freeze-check', freezeLabel, { freeze: freezeLabel });
199
+ return admission;
200
+ }
201
+
202
+ function admitLandingMergeUnobserved(
203
+ heldEntry: FrozenMerge | null | (() => FrozenMerge | null),
204
+ root: string,
205
+ hooks: { afterQueue?: () => void },
206
+ claimKey: { prNumber: number; repoRoot: string; headCommit?: string } | undefined,
207
+ opts: { prodFreezeRoot?: string; forceReason?: string },
186
208
  ): LandingAdmission {
187
209
  let entry: FrozenMerge | null | undefined;
188
210
  const prodFreezeRoot = opts.prodFreezeRoot ?? prodInstanceRoot();
@@ -223,6 +245,7 @@ export function admitLandingMerge(
223
245
  if (entry === undefined) entry = typeof heldEntry === 'function' ? heldEntry() : heldEntry; // only built when frozen
224
246
  if (!entry) return { kind: 'held', freeze: landing.frozen };
225
247
  queueFrozenMerge(entry, root);
248
+ passJourneyNode('hold', { provenance: 'admit-landing-merge', outcome: 'queued', data: { pr: entry.prNumber } });
226
249
  hooks.afterQueue?.();
227
250
  const afterQueue = beginLandingMerge(root, new Date(), prodFreezeRoot, opts.forceReason);
228
251
  if (afterQueue.frozen) return { kind: 'held', freeze: afterQueue.frozen };
@@ -1363,6 +1363,20 @@ export function tracedPathReferences(document: string): TracedPathReference[] {
1363
1363
  return references;
1364
1364
  }
1365
1365
 
1366
+ /**
1367
+ * AUTO-TARGET (10-08 canary · TSC-HEAP run-446cdc71): an authored goal whose `## PROBLEM` Situation line says
1368
+ * NOT-GROUNDED has no persistent (Read-verified) evidence — `scqaNarrative` writes NOT-GROUNDED exactly when that
1369
+ * channel is empty, and `## TRACED PATHS` then carries no path. Such a goal is a scope card, not an implementation
1370
+ * goal: any target path it carries was not verified by grounding. Callers that know a path was machine-suggested
1371
+ * (not written by the human) must not launch on it. Lite goals have no Situation line and return false.
1372
+ */
1373
+ export function isNotGroundedWithoutPersistentEvidence(document: string): boolean {
1374
+ const problem = markdownSection(document, 'PROBLEM');
1375
+ if (problem === null) return false;
1376
+ const situation = problem.split(/\r?\n/).find((line) => line.startsWith('Situation: '));
1377
+ return situation !== undefined && situation.startsWith('Situation: NOT-GROUNDED') && tracedPathReferences(document).length === 0;
1378
+ }
1379
+
1366
1380
  /** Inspect supplied goal text and branch name, optionally validating traced paths through an injected reader. */
1367
1381
  /**
1368
1382
  * Lint findings plus the number of inline invariant markers recognized for judgment candidates.
@@ -3,6 +3,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmdir
3
3
  import { dirname, join } from 'node:path';
4
4
  import { effectiveInstanceRoot } from '../instance/resolve.js';
5
5
  import { debug } from '../debug/log.js';
6
+ import { passJourneyNode } from '../self-dev/graph-journey-nodes.js';
6
7
  import { getUserConfig } from '../user-config.js';
7
8
  import { psProcessStartMs, START_TOLERANCE_MS } from '../harness/harness-stop.js';
8
9
 
@@ -184,6 +185,8 @@ export function recordFailureEvent(event: FailureEvent, root = effectiveInstance
184
185
  return false;
185
186
  });
186
187
  debug.log('heal.intake', 'recorded', { source: event.source, kind: event.kind, ref: event.ref, folded });
188
+ // HARNESS-FULL-GRAPH — 하니스 런 실패 사건의 접수가 그래프 노드 heal 이다(출구: started | folded).
189
+ if (event.source === 'harness-run') passJourneyNode('heal', { provenance: 'heal-intake', outcome: folded ? 'folded' : 'started', data: { kind: event.kind, ref: event.ref } });
187
190
  if (!folded) {
188
191
  const runId = healRunId(event);
189
192
  void Promise.resolve().then(() => startLoop(HEAL_GRAPH, { runId, input: { failureEvent: event }, deps: { root } }))
@@ -72,6 +72,7 @@ import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
72
72
  import { homedir } from 'node:os';
73
73
  import { enqueueControlMemo, readSoftStopRequestStatus, type SoftStopRequestRead } from '../harness/control-inbox.js';
74
74
  import { debug } from '../debug/log.js';
75
+ import { enterJourneyNode, exitJourneyNode, journeyJoinFields, withJourneyNode } from '../self-dev/graph-journey-nodes.js';
75
76
  import { classifyGateEnvDeficit, DEFAULT_GATE_ENV_RETRY, GATE_ENV_DEFICIT_HARVESTABLE_MARK, type GateEnvDeficitKind } from './gate-env-retry.js';
76
77
  import { recordFailureEvent } from './heal-intake.js';
77
78
  import { classifyReworkCapExhaustion, type ReworkCapHealDecision } from './heal-triage.js';
@@ -975,6 +976,8 @@ export interface SelfImplementSeams {
975
976
  readSoftStopRequestStatus?: (spaceId: string) => SoftStopRequestRead;
976
977
  /** Parent harness space whose durable stop marker is read. Tests inject this; production uses `getHarnessSpace()`. */
977
978
  parentSoftStopSpaceId?: string;
979
+ /** Real, created worktree's soft-stop target; observation only, never guesses a space. */
980
+ onSoftStopSpaceReady?: (spaceId: string) => void;
978
981
  /** disposable worktree 생성 → 경로·브랜치 ⊕ **어디서 갈랐나**(관측용).
979
982
  * ⚠️ 관측 3필드는 **선택**이다 — 시임은 주입점이고, 테스트 더블에게 git SHA 를 지어내라고
980
983
  * 요구하면 계약이 아니라 부담이 된다. 실 시임(`defaultSeams`)은 항상 채운다.
@@ -3805,6 +3808,8 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
3805
3808
  const attemptOrdinal = readRunAttemptOrdinal(runId);
3806
3809
  const identified = {
3807
3810
  ...graphIdentity,
3811
+ // HARNESS-FULL-GRAPH — 앞단 여정 걸음(runId 없음)과 이 런의 걸음을 잇는 조인 키.
3812
+ ...journeyJoinFields(),
3808
3813
  ...data,
3809
3814
  attemptOrdinal,
3810
3815
  };
@@ -5019,6 +5024,9 @@ async function runSelfImplementInner(
5019
5024
  // 그래서 getHarnessSpace() 만 보면 운영에서 늘 undefined 이고 정지 확인이 «한 번도» 안 돈다(#20040 착지 직후 실측).
5020
5025
  // `self send <space> --stop` 이 겨냥하는 것은 자식의 공간 = 워크트리 이름이다(아래 activeChildInboxId 와 같은 식 · dev-cli.ts recordRestart 폴백과 같다).
5021
5026
  const parentSoftStopSpaceId = s.parentSoftStopSpaceId || getHarnessSpace()?.id || normalizeSpaceId(basename(wt.path)) || undefined;
5027
+ if (parentSoftStopSpaceId) {
5028
+ try { s.onSoftStopSpaceReady?.(parentSoftStopSpaceId); } catch { /* UI registration must not break execution */ }
5029
+ }
5022
5030
  const readParentSoftStop = s.readSoftStopRequestStatus ?? readSoftStopRequestStatus;
5023
5031
  const honorParentSoftStop = (
5024
5032
  beforeNode: 'gate' | 'review' | 'rework' | 'open-pr',
@@ -8088,7 +8096,14 @@ async function runSelfImplementInner(
8088
8096
  }
8089
8097
  const defaultBranch = resolveDefaultBranchTarget(s.defaultBranchRef ?? defaultBranchRef, wt.path).target ?? undefined;
8090
8098
  progress('merged', formatAutoMergeSuccessMessage({ prNumber: pr.number, mergedBase, defaultBranch }));
8091
- await runPostMergeCleanup(s.postMergeCleanup, wt.path, wt.branch, opts.goalFile, mergedBase && defaultBranch && displayBranchName(mergedBase) === displayBranchName(defaultBranch) ? defaultBranch : undefined, observe);
8099
+ // HARNESS-FULL-GRAPH — 회수도 그래프 노드(cleanup)다. 결과 = completed | preserved | failed.
8100
+ let cleanupOutcome = 'completed';
8101
+ enterJourneyNode('cleanup', { provenance: 'post-merge', runId });
8102
+ await withJourneyNode('cleanup', { provenance: 'post-merge', runId }, () => runPostMergeCleanup(s.postMergeCleanup, wt.path, wt.branch, opts.goalFile, mergedBase && defaultBranch && displayBranchName(mergedBase) === displayBranchName(defaultBranch) ? defaultBranch : undefined, (event, data) => {
8103
+ if (event.startsWith('post-merge-cleanup-')) cleanupOutcome = event.slice('post-merge-cleanup-'.length);
8104
+ observe(event, data);
8105
+ }));
8106
+ exitJourneyNode('cleanup', { provenance: 'post-merge', runId, outcome: cleanupOutcome });
8092
8107
  const mergedLedger = (() => {
8093
8108
  try { return loadRunLedger(runId); } catch { return null; }
8094
8109
  })();
@@ -972,6 +972,8 @@ export interface DefaultSeamsOptions {
972
972
  signal?: AbortSignal;
973
973
  /** Parent-surface progress receiver supplied by the dev pipeline. */
974
974
  onProgress?: SelfImplementSeams['onProgress'];
975
+ /** Relay the actual worktree soft-stop target to the invoking surface. */
976
+ onSoftStopSpaceReady?: SelfImplementSeams['onSoftStopSpaceReady'];
975
977
  /** ⑤ HITL — PR 승인 게이트. ★fail-closed: 생략 시 PR 안 열림(자동 승인 없음). 실전 필수. */
976
978
  approvePr?: SelfImplementSeams['approvePr'];
977
979
  /** gate 스텝(기본 ['test']). */
@@ -1394,6 +1396,7 @@ export function defaultSeams(o: DefaultSeamsOptions = {}): SelfImplementSeams {
1394
1396
  };
1395
1397
  return {
1396
1398
  ...(o.onProgress ? { onProgress: o.onProgress } : {}),
1399
+ ...(o.onSoftStopSpaceReady ? { onSoftStopSpaceReady: o.onSoftStopSpaceReady } : {}),
1397
1400
  ...(escalateGoalClarifications ? { escalateGoalClarifications } : {}),
1398
1401
  queryChildProviderErrors,
1399
1402
  persistPrBodyArtifact: (input) => createArtifactStore().put('block', input.body, {
@@ -55,6 +55,13 @@ interface SelfImplementRuntimeDeps {
55
55
  }
56
56
  let runtimeDeps: SelfImplementRuntimeDeps = {};
57
57
 
58
+ // TUI-only observer. The tool call id is furnished by the actual dispatcher;
59
+ // other surfaces and calls without an id cannot register a stop target.
60
+ let softStopSpaceObserver: ((toolCallId: string, spaceId: string) => void) | null = null;
61
+ export function setSelfImplementSoftStopSpaceObserver(observer: typeof softStopSpaceObserver): void {
62
+ softStopSpaceObserver = observer;
63
+ }
64
+
58
65
  /** 자식 헤드리스 elanous 의 config/state 격리 + 구현 대기 상한을 주입. */
59
66
  export function setSelfImplementRuntimeDeps(d: SelfImplementRuntimeDeps | null): void {
60
67
  runtimeDeps = d ?? {};
@@ -711,6 +718,11 @@ export const selfImplementRuntime: ToolRuntime<SelfImplementRuntimeRequest, Self
711
718
  ...(runtimeDeps.implementMaxWaitSec ? { implementMaxWaitSec: runtimeDeps.implementMaxWaitSec } : {}),
712
719
  ...(approvePr ? { approvePr } : {}),
713
720
  onProgress: resolveHarnessProgressSink(ctx),
721
+ ...(ctx.surface === 'tui' && ctx.toolCallId && softStopSpaceObserver ? {
722
+ onSoftStopSpaceReady: (spaceId: string) => {
723
+ try { softStopSpaceObserver?.(ctx.toolCallId!, spaceId); } catch { /* UI observer cannot break harness */ }
724
+ },
725
+ } : {}),
714
726
  });
715
727
 
716
728
  const runnableDocumentReferences = documentReferences.filter(({ result }) => result.kind !== 'outside-repository');
@@ -162,6 +162,8 @@ export interface SessionPostureSnapshot {
162
162
 
163
163
  export interface SessionRuntimeDispatchDeps {
164
164
  signal?: AbortSignal;
165
+ /** Current LLM tool call, for correlating a foreground harness stop target with the TUI call. */
166
+ toolCallId?: string;
165
167
  userText?: string;
166
168
  modelFamily?: ModelFamily;
167
169
  /** Parent Agent capability context for an inline runtime fallback. */
@@ -183,7 +185,7 @@ export interface SessionRuntimeDispatchDeps {
183
185
  // scheduler-retirement R1 의 LLM tool unwire 후 모두 no-op stub 였고
184
186
  // 본 PR 에서 정식 폐기.
185
187
  getToolRuntime(name: string): ToolRuntime<Record<string, unknown>, ToolRunResult> | undefined;
186
- dispatchToolRuntime(name: string, args: Record<string, unknown>): Promise<unknown>;
188
+ dispatchToolRuntime(name: string, args: Record<string, unknown>, toolCallId?: string): Promise<unknown>;
187
189
  dispatchPluginTool(name: string, args: Record<string, unknown>): Promise<
188
190
  { ok: true; result: unknown } | { ok: false; error: string }
189
191
  >;
@@ -2166,7 +2168,7 @@ export async function dispatchSessionRuntimeTool(
2166
2168
  // registered runtimes) and drops `pathPolicy` on the floor.
2167
2169
  const nativeRuntime = nativeRule?.preferRuntime ? deps.getToolRuntime(name) : undefined;
2168
2170
  if (nativeRuntime) {
2169
- const result = await deps.dispatchToolRuntime(name, normalizedArgs);
2171
+ const result = await deps.dispatchToolRuntime(name, normalizedArgs, deps.toolCallId);
2170
2172
  rememberCandidateListingResult(name, normalizedArgs, result, scopedAnalysis, deps.searchPlannerState);
2171
2173
  return result;
2172
2174
  }
@@ -2201,7 +2203,7 @@ export async function dispatchSessionRuntimeTool(
2201
2203
  if (rt) {
2202
2204
  const isPtyTool = name.startsWith('PtyShell') || name.startsWith('pty_shell');
2203
2205
  if (!isPtyTool || deps.ptyDashboardOn) {
2204
- const result = await deps.dispatchToolRuntime(name, normalizedArgs);
2206
+ const result = await deps.dispatchToolRuntime(name, normalizedArgs, deps.toolCallId);
2205
2207
  rememberCandidateListingResult(name, normalizedArgs, result, scopedAnalysis, deps.searchPlannerState);
2206
2208
  return result;
2207
2209
  }
@@ -55,6 +55,11 @@ import { basename } from 'node:path';
55
55
  import { debug } from './debug/log.js';
56
56
 
57
57
  const TIMEOUT_MS = 3000;
58
+ // An interactive shell (`-i`) ignores SIGTERM, so the default timeout signal never ends it: the
59
+ // capture then blocks until the rc files finish. 10-08 TUI-BOOT-60: a stale pyenv rehash lock made
60
+ // every `zsh -l -i` wait 60 s, and the «3 s» capture held the TUI boot for ~65 s. SIGKILL makes the
61
+ // timeout real.
62
+ const TIMEOUT_SIGNAL = 'SIGKILL' as const;
58
63
  const POSIX_SHELLS = new Set(['zsh', 'bash', 'fish', 'sh', 'dash', 'ksh']);
59
64
 
60
65
  let cached: Record<string, string> | null = null;
@@ -126,6 +131,7 @@ export function runPrintenvCapture(): Record<string, string> | null {
126
131
  env: seedEnv,
127
132
  encoding: 'utf8',
128
133
  timeout: TIMEOUT_MS,
134
+ killSignal: TIMEOUT_SIGNAL,
129
135
  stdio: ['ignore', 'pipe', 'pipe'],
130
136
  // Don't inherit our stdio — rc files that run `clear` or issue
131
137
  // OSC sequences would corrupt our TUI output otherwise.
@@ -133,6 +139,8 @@ export function runPrintenvCapture(): Record<string, string> | null {
133
139
  } catch {
134
140
  return null;
135
141
  }
142
+ // ETIMEDOUT with status 0 = the shell outlived the timeout; never trust a late capture.
143
+ if (res.error) return null;
136
144
  if (res.status !== 0 && res.status !== null) return null;
137
145
  if (res.signal) return null;
138
146
  return acceptCapture(typeof res.stdout === 'string' ? res.stdout : '');
@@ -149,10 +157,16 @@ export async function warmCapturedEnv(spawn: typeof Bun.spawn = Bun.spawn): Prom
149
157
  const start = Date.now();
150
158
  try {
151
159
  const proc = spawn([seed.shell, '-l', '-i', '-c', 'printenv'], { env: seed.seedEnv as Record<string, string>, stdin: 'ignore', stdout: 'pipe', stderr: 'ignore' });
152
- const timer = setTimeout(() => proc.kill(), TIMEOUT_MS);
153
- const [out, code] = await Promise.all([new Response(proc.stdout as ReadableStream).text(), proc.exited]);
160
+ // A grandchild (e.g. a pyenv rehash) can keep the stdout pipe open after the shell is killed,
161
+ // so the timeout settles the race itself instead of waiting for EOF.
162
+ let timer: ReturnType<typeof setTimeout> | undefined;
163
+ const timedOut = new Promise<null>((resolve) => {
164
+ timer = setTimeout(() => { proc.kill(TIMEOUT_SIGNAL); resolve(null); }, TIMEOUT_MS);
165
+ });
166
+ const finished = Promise.all([new Response(proc.stdout as ReadableStream).text(), proc.exited]);
167
+ const result = await Promise.race([finished, timedOut]);
154
168
  clearTimeout(timer);
155
- const parsed = code === 0 ? acceptCapture(out) : null;
169
+ const parsed = result && result[1] === 0 ? acceptCapture(result[0]) : null;
156
170
  if (captured) return cached !== null; // a synchronous capture won the race
157
171
  if (!parsed) return false;
158
172
  cached = parsed;
@@ -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