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
@@ -38,8 +38,12 @@
38
38
  # (파일 이름은 RFC 어휘를 남겨 둔다 — 사람이 찾는 이름과 조인 키가 다를 수 있다.)
39
39
  graph_id: self-implement
40
40
  version: 1
41
- entry_node: author
42
- terminal_nodes: [merge]
41
+ # ⭐ HARNESS-FULL-GRAPH (0.2.21 · 대표 10-08) — 입구부터 회수까지 «여정 전체»가 노드다.
42
+ # 📄 내부 문서 `RFC-harness-full-journey-as-graph-2026-10-08` · 코드 = src/self-dev/graph-journey-nodes.ts
43
+ # ⛔ 여정 노드(intake … stopped)의 id 는 원장·라이브 그래프 화면의 조인 키다 — 바꾸지 마라.
44
+ # 🔀 분기는 «데이터»다(`on:` 상태 키 ⊕ `map:` 값→노드) — 기본 = 풀세트, 환경(substrate·freeze·queue)이 일부를 건너뛴다.
45
+ entry_node: intake
46
+ terminal_nodes: [cleanup, stopped]
43
47
 
44
48
  # Runner-provided inputs are declared here so contract-flow can distinguish them from undeclared gaps.
45
49
  runner_inputs: [ask_text, goal, worktree, branch, review-intent, head-sha, base-branch]
@@ -61,8 +65,13 @@ runner_inputs: [ask_text, goal, worktree, branch, review-intent, head-sha, base-
61
65
  # 🔑 ⇒ ***여기 적은 도구 권한은 「선언」이고 「제한」이 아니다.*** 자식의 실제 권한은 코드가 정한다.
62
66
  # ⛔ 그러니 이 칸을 좁혀 「자식이 그 도구를 못 쓴다」고 읽지 마라 — 지금은 안 그렇다.
63
67
  # 🔎 반증: rg -n "readonly contract" src/self-implement/graph-templates.ts (⇒ 0건이면 여전히 그렇다)
68
+ # 🧩 `group:` = 나중에 `graphs/units/*.yaml` 로 들어 올릴 «한 노드로 부르는 부분 그래프» 단위(대표 10-08).
69
+ # entry · dispatch · author · dispatch-pod · build · verify · land · recover · end
70
+ # ⛔ 지금 파서는 이 칸을 «읽지 않는다»(무시) — 단위 호출은 0.2.22(RFC §6). 묶음은 «위치»가 아니라 이 태그로 정한다
71
+ # (오버레이가 /nodes/<번호> 로 가리켜 노드를 재배열할 수 없다).
64
72
  nodes:
65
73
  - node_id: author
74
+ group: author
66
75
  kind: agent
67
76
  recipe: goal-author
68
77
  max_visits: 2
@@ -74,6 +83,7 @@ nodes:
74
83
  outputs: [goal_path, goal_id, goal_type, grounding_context]
75
84
 
76
85
  - node_id: plan
86
+ group: author
77
87
  kind: agent
78
88
  recipe: harness-plan-rfc
79
89
  max_visits: 2
@@ -85,6 +95,7 @@ nodes:
85
95
  outputs: [rfc_path, markdown, arcs, open_questions]
86
96
 
87
97
  - node_id: decompose
98
+ group: author
88
99
  kind: judge
89
100
  recipe: fabric-decompose-adapter
90
101
  max_visits: 12
@@ -96,6 +107,7 @@ nodes:
96
107
  outputs: [pieces, ordering, depends_on_edges, hot_path_edges, omitted_goal_count]
97
108
 
98
109
  - node_id: implement
110
+ group: build
99
111
  kind: agent
100
112
  recipe: headless-goal-loop # seams.implement → 자식 PTY
101
113
  max_visits: 12
@@ -109,6 +121,7 @@ nodes:
109
121
  outputs: [diff, summary, changed-files]
110
122
 
111
123
  - node_id: gate
124
+ group: verify
112
125
  kind: gate
113
126
  recipe: gate-baseline # 변경 파일 «범위» · 새 회귀만
114
127
  max_visits: 11
@@ -122,6 +135,7 @@ nodes:
122
135
  outputs: [passed, gate-log, reflect-gate-facts]
123
136
 
124
137
  - node_id: review
138
+ group: verify
125
139
  kind: judge
126
140
  recipe: pr-reviewer # agent-substrate/pr-reviewer
127
141
  max_visits: 11
@@ -135,6 +149,7 @@ nodes:
135
149
  outputs: [verdict, must-fix, should-fix, review-summary]
136
150
 
137
151
  - node_id: rework
152
+ group: verify
138
153
  kind: agent
139
154
  recipe: headless-goal-loop # 같은 루프의 다음 라운드
140
155
  max_visits: 10
@@ -148,6 +163,7 @@ nodes:
148
163
  outputs: [diff, summary]
149
164
 
150
165
  - node_id: main-sync
166
+ group: land
151
167
  kind: git
152
168
  recipe: seams-git-merge-main # LLM 충돌해결 포함
153
169
  max_visits: 2
@@ -159,6 +175,7 @@ nodes:
159
175
  outputs: [synced, conflicts]
160
176
 
161
177
  - node_id: regate
178
+ group: land
162
179
  kind: gate
163
180
  recipe: gate-baseline # 충돌해결 «뒤» 재-gate
164
181
  max_visits: 2
@@ -170,6 +187,7 @@ nodes:
170
187
  outputs: [passed, gate-log]
171
188
 
172
189
  - node_id: open-pr
190
+ group: land
173
191
  kind: git
174
192
  recipe: seams-gh-open-pr
175
193
  # 📏 실측 2026-09-08 (원장 30일 · 전 우주 · 걸음 191개 소급 계산):
@@ -185,6 +203,7 @@ nodes:
185
203
  outputs: [pr-number, pr-url]
186
204
 
187
205
  - node_id: merge
206
+ group: land
188
207
  kind: git
189
208
  recipe: seams-gh-merge-squash
190
209
  # 📏 실측 2026-09-08 (원장 30일 · 전 우주 · 걸음 191개 소급 계산):
@@ -199,6 +218,176 @@ nodes:
199
218
  tools: gh-pr-merge
200
219
  outputs: [merged]
201
220
 
221
+ # ⛔ 여정 노드는 «목록 끝»에 둔다 — 오버레이가 JSON 포인터(/nodes/<번호>)로 노드를 가리킨다(rework-patient). 앞에 끼우면 번호가 밀린다.
222
+ # ───────── 여정 앞단: 입구 → 대기열 → 발사 관문 → 배치 ─────────
223
+ - node_id: intake
224
+ group: entry
225
+ kind: observe
226
+ recipe: harness-entrance # src/harness/harness-cli-command.ts (say · ask · TUI /harness)
227
+ max_visits: 1
228
+ terminal_stages: []
229
+ contract:
230
+ inputs: [ask_text]
231
+ tools: none
232
+ outputs: [entrance, journey_key]
233
+
234
+ - node_id: queue
235
+ group: entry
236
+ kind: gate
237
+ recipe: harness-queue # src/harness/harness-queue.ts (directSay 플래그 · 기본 끔 → 건너뜀)
238
+ max_visits: 1
239
+ terminal_stages: []
240
+ contract:
241
+ inputs: [entrance, seat]
242
+ tools: queue-write
243
+ outputs: [queue_item, queue_outcome]
244
+
245
+ - node_id: launch-gate
246
+ group: entry
247
+ kind: gate
248
+ recipe: pre-launch-gate # harness-cli-command.ts preLaunchGate (예산 · 같은 골 활성 런)
249
+ max_visits: 1
250
+ terminal_stages: []
251
+ contract:
252
+ inputs: [goal_id, budget]
253
+ tools: read-only
254
+ outputs: [launch_decision]
255
+
256
+ - node_id: dispatch
257
+ group: dispatch
258
+ kind: judge
259
+ recipe: harness-substrate-select # resolveLaunchSubstrate → substrate = local | pod
260
+ max_visits: 2
261
+ terminal_stages: []
262
+ contract:
263
+ inputs: [launch_decision]
264
+ tools: read-only
265
+ outputs: [substrate]
266
+
267
+ # ───────── Pod 배치 (substrate == pod 일 때만 — local 은 건너뛴다) ─────────
268
+ - node_id: pool-admit
269
+ group: dispatch-pod
270
+ kind: gate
271
+ recipe: pod-pool-admission # src/task-orchestrator/surfaces/self-implement-pod.ts (입장 · 멤버 슬롯 · 메모리 등급)
272
+ max_visits: 4
273
+ terminal_stages: []
274
+ contract:
275
+ inputs: [substrate, memory_tier]
276
+ tools: pod-lease
277
+ outputs: [pool_member]
278
+
279
+ - node_id: image-sync
280
+ group: dispatch-pod
281
+ kind: gate
282
+ recipe: pod-pool-image-sync # src/task-orchestrator/surfaces/pod-pool.ts syncPoolImages (멤버별 · pack 한 번)
283
+ max_visits: 4
284
+ terminal_stages: []
285
+ contract:
286
+ inputs: [pool_member]
287
+ tools: image-ship
288
+ outputs: [image_current]
289
+
290
+ - node_id: credential-refresh
291
+ group: dispatch-pod
292
+ kind: gate
293
+ recipe: pod-credential-prerefresh # self-implement-pod.ts podCodexCredentialWithPrerefresh
294
+ max_visits: 4
295
+ terminal_stages: []
296
+ contract:
297
+ inputs: [pool_member]
298
+ tools: credential-refresh
299
+ outputs: [usable_accounts]
300
+
301
+ # ───────── 착지: 동결 검사 → (보류) → 병합 → 회수 ─────────
302
+ - node_id: freeze-check
303
+ group: land
304
+ kind: gate
305
+ recipe: landing-freeze-admission # src/self-implement/frozen-merges.ts admitLandingMerge (병합 직전 한 곳)
306
+ max_visits: 4
307
+ terminal_stages: []
308
+ contract:
309
+ inputs: [pr-number]
310
+ tools: read-only
311
+ outputs: [freeze]
312
+
313
+ - node_id: hold
314
+ group: land
315
+ kind: hitl
316
+ recipe: frozen-merge-queue # frozen-merges.ts queueFrozenMerge → sweepFrozenMerges 가 해제 뒤 재개
317
+ max_visits: 4
318
+ terminal_stages: []
319
+ contract:
320
+ inputs: [pr-number, head-sha]
321
+ tools: queue-write
322
+ outputs: [held]
323
+
324
+ - node_id: cleanup
325
+ group: land
326
+ kind: git
327
+ recipe: post-merge-cleanup # src/self-implement/orchestrator.ts (워크트리 ⊕ 브랜치 회수)
328
+ max_visits: 1
329
+ terminal_stages: []
330
+ contract:
331
+ inputs: [worktree, branch]
332
+ tools: git-write
333
+ outputs: [cleaned]
334
+
335
+ # ───────── 실패 쪽: 결과 해석 → 수확 → heal → 다음 한 수 ─────────
336
+ - node_id: result-parse
337
+ group: recover
338
+ kind: observe
339
+ recipe: pod-failure-reason # src/task-orchestrator/surfaces/pod-failure-reason.ts
340
+ max_visits: 4
341
+ terminal_stages: []
342
+ contract:
343
+ inputs: [pod_log]
344
+ tools: read-only
345
+ outputs: [failure_reason]
346
+
347
+ - node_id: salvage
348
+ group: recover
349
+ kind: git
350
+ recipe: salvage-branch # salvage/si-task-<job>/… (Pod Job 이 push · salvage-branches.ts 가 읽는다)
351
+ max_visits: 4
352
+ terminal_stages: []
353
+ contract:
354
+ inputs: [worktree]
355
+ tools: git-write
356
+ outputs: [salvage_ref]
357
+
358
+ - node_id: heal
359
+ group: recover
360
+ kind: judge
361
+ recipe: heal-intake # src/self-implement/heal-intake.ts (호스트에서만)
362
+ max_visits: 4
363
+ terminal_stages: []
364
+ contract:
365
+ inputs: [failure_reason, salvage_ref]
366
+ tools: read-only
367
+ outputs: [heal_signature]
368
+
369
+ - node_id: next-move
370
+ group: recover
371
+ kind: judge
372
+ recipe: task-agent-judge # src/task-agent/judge.ts (판단부 → 실행부)
373
+ max_visits: 4
374
+ terminal_stages: []
375
+ contract:
376
+ inputs: [heal_signature]
377
+ tools: read-only
378
+ outputs: [next_action]
379
+
380
+ - node_id: stopped
381
+ group: end
382
+ kind: observe
383
+ recipe: journey-stopped # 거절·포기 — 종결
384
+ max_visits: 1
385
+ terminal_stages: []
386
+ contract:
387
+ inputs: []
388
+ tools: none
389
+ outputs: []
390
+
202
391
  # ═══════════════════════════════════════════════════════════════════════
203
392
  # 엣지 — ⛔ 출처는 «코드 선언 ⊕ 원장 실측» 둘 다다. 어느 하나만 보면 틀린다.
204
393
  # 📏 2026-09-08 실측 (pipeline-traversal-shadow 182 걸음 · 판정 함수가 «실제로 본» 것):
@@ -207,14 +396,83 @@ nodes:
207
396
  # gate→main-sync · gate→open-pr · review→open-pr
208
397
  # 🔑 그래서 엣지마다 `observed` 를 «값으로» 적는다 — 「선언했다」와 「돈다」를 가른다.
209
398
  edges:
399
+ # ───── 여정 앞단 — 분기는 «데이터»(on/map). 값은 코드가 낸다(RFC §4.3 ⑵) ─────
400
+ - from: intake
401
+ on: queue
402
+ map:
403
+ queued: queue # harness.queue.directSay 켬 ⊕ 자리 있음
404
+ direct: launch-gate # 기본(플래그 끔) — 대기열을 건너뛴다
405
+
406
+ - from: queue
407
+ on: queue_outcome
408
+ map:
409
+ launched: launch-gate # 대기열이 발사한 자식이 다시 intake 를 밟는다(queueLaunchId 로 잇는다)
410
+ waiting: stopped # 이 프로세스는 여기서 끝난다(발사는 대기열 tick 의 몫)
411
+ refused: stopped # 같은 요청이 이미 대기열에 있다
412
+
413
+ - from: launch-gate
414
+ on: outcome
415
+ map:
416
+ pass: dispatch
417
+ refuse: stopped
418
+
419
+ - from: dispatch
420
+ to: author
421
+
210
422
  - from: author
211
423
  to: plan
212
424
 
213
425
  - from: plan
214
426
  to: decompose
215
427
 
428
+ # ⭐ 실행 칸(substrate)이 «Pod 쪽 세 노드»를 켜고 끈다 — local 은 곧장 구현.
216
429
  - from: decompose
217
- to: implement
430
+ on: substrate
431
+ map:
432
+ local: implement
433
+ pod: pool-admit
434
+
435
+ - from: pool-admit
436
+ on: outcome
437
+ map:
438
+ admitted: image-sync
439
+ refused: stopped
440
+
441
+ - from: image-sync
442
+ to: credential-refresh
443
+
444
+ - from: credential-refresh
445
+ on: outcome
446
+ map:
447
+ usable: implement
448
+ exhausted: stopped
449
+
450
+ # 실패 쪽 — Pod 구현이 rc≠0 이면 결과 해석으로.
451
+ - from: implement
452
+ on: pod_result
453
+ map:
454
+ failed: result-parse
455
+
456
+ - from: result-parse
457
+ to: salvage
458
+
459
+ # ⚠️ heal 은 실패 사건 «접수»다 — 호스트에서만(Pod 안에서는 시작 안 함 · POD-RESULT-PARSE).
460
+ - from: salvage
461
+ to: heal
462
+
463
+ - from: heal
464
+ to: next-move
465
+
466
+ # 출구 라벨 = task-agent 판단부의 수(TaskMove · src/task-agent/judge.ts). 관측 배선은 0.2.22(판단이 카드 단위라 런 조인 먼저).
467
+ - from: next-move
468
+ on: move
469
+ map:
470
+ narrow-relaunch: dispatch
471
+ salvage-relaunch: dispatch
472
+ alternative: dispatch
473
+ wait-retry: dispatch
474
+ decision-card: stopped
475
+ wait: stopped
218
476
 
219
477
  - from: implement
220
478
  to: gate
@@ -264,6 +522,20 @@ edges:
264
522
  to: open-pr
265
523
  observed: 80
266
524
 
525
+ # ⭐ HARNESS-FULL-GRAPH — 코드 간선 open-pr→merge 사이에 «동결 검사»가 늘 끼어 있었다(병합 직전 한 곳).
267
526
  - from: open-pr
268
- to: merge
269
- observed: 80
527
+ to: freeze-check
528
+ observed: 80 # 옛 open-pr→merge 관측 — 그 사이에 동결 검사가 늘 있었다
529
+
530
+ - from: freeze-check
531
+ on: freeze
532
+ map:
533
+ open: merge
534
+ frozen: hold
535
+ taken: stopped # 다른 착지자(재개 sweep)가 그 PR 을 쥐었다
536
+
537
+ - from: hold
538
+ to: freeze-check # 해제 뒤 재검사
539
+
540
+ - from: merge
541
+ to: cleanup
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "elanous",
3
3
  "mcpName": "io.github.ElanvitalAI/elanous",
4
- "version": "0.2.20",
4
+ "version": "0.2.21",
5
5
  "description": "Self-healing coding harness where eyes, hands, and memory all turn on one sentence — it authors its own goals, implements them in isolated worktrees, and reviews its own work.",
6
6
  "license": "Apache-2.0",
7
7
  "author": "Elanvital AI",
@@ -240,15 +240,42 @@ lsof_fd1() {
240
240
  return 0
241
241
  }
242
242
 
243
+ # 🐧 lsof 가 없는 리눅스(게이트 Pod 이미지 · 0.2.20 컷 실측)에서는 /proc/<pid>/fd/1 을 읽어
244
+ # lsof -Ftn 과 «같은 모양»(t<type>\nn<name>)으로 낸다 — 아래 판정 표를 그대로 쓴다.
245
+ # ⛔ 못 읽으면(죽은 pid·권한) 1 을 돌려 「모름」으로 끝낸다.
246
+ proc_fd1() {
247
+ local pid="$1" target
248
+ target=$(readlink "/proc/$pid/fd/1" 2>/dev/null) || return 1
249
+ [ -n "$target" ] || return 1
250
+ case "$target" in
251
+ pipe:*) printf 'tPIPE\nn%s\n' "$target" ;;
252
+ socket:*) printf 'tunix\nn%s\n' "$target" ;;
253
+ *)
254
+ if [ -c "$target" ]; then printf 'tCHR\nn%s\n' "$target"
255
+ elif [ -f "$target" ]; then printf 'tREG\nn%s\n' "$target"
256
+ else printf 'tunknown\nn%s\n' "$target"
257
+ fi ;;
258
+ esac
259
+ return 0
260
+ }
261
+
243
262
  delivery_of() {
244
263
  local pid="$1" out t n
245
264
  case "$pid" in
246
265
  ''|*[!0-9]*) printf '⚠️ «못 쟀다»(감시자 pid 를 «증명하지 못했다») — 「정상」이 아니라 «모름»이다'; return 0 ;;
247
266
  esac
248
- command -v lsof >/dev/null 2>&1 || { printf '⚠️ «못 쟀다»(lsof 없음) — 「정상」이 아니라 «모름»이다'; return 0; }
249
- if ! out=$(lsof_fd1 "$pid"); then
250
- printf '⚠️ «못 쟀다»(lsof 가 %s틱 안에 안 끝나 죽였다) — 「정상」이 아니라 «모름»이다' "$LSOF_WAIT_TICKS"
251
- return 0
267
+ if command -v lsof >/dev/null 2>&1; then
268
+ if ! out=$(lsof_fd1 "$pid"); then
269
+ printf '⚠️ «못 쟀다»(lsof 가 %s틱 안에 안 끝나 죽였다) — 「정상」이 아니라 «모름»이다' "$LSOF_WAIT_TICKS"
270
+ return 0
271
+ fi
272
+ elif command -v readlink >/dev/null 2>&1 && [ -d /proc/self/fd ]; then
273
+ if ! out=$(proc_fd1 "$pid"); then
274
+ printf '⚠️ «못 쟀다»(/proc/%s/fd/1 을 못 읽었다 · lsof 없음) — 「정상」이 아니라 «모름»이다' "$pid"
275
+ return 0
276
+ fi
277
+ else
278
+ printf '⚠️ «못 쟀다»(lsof 없음) — 「정상」이 아니라 «모름»이다'; return 0
252
279
  fi
253
280
  t=$(printf '%s\n' "$out" | sed -n 's/^t//p' | head -1)
254
281
  n=$(printf '%s\n' "$out" | sed -n 's/^n//p' | head -1)
@@ -13,6 +13,7 @@ import {
13
13
  } from '../src/autopilot/discovery/doc-lint.js';
14
14
  import { parseIndexLinks } from '../src/autopilot/discovery/doc-inventory.js';
15
15
  import { execFileSync } from 'node:child_process';
16
+ import { runGitCommand } from '../src/git-fs/runner.js';
16
17
  import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
17
18
  import { basename, join, relative } from 'node:path';
18
19
  import { sourceIdentifierInventory, inlineCodeIdentifiers } from '../src/autopilot/discovery/source-identifiers.js';
@@ -80,7 +81,9 @@ const readText = (relPath: string): string | null => { try { return readFileSync
80
81
  // 전부 「못 읽음」이 되어 이 규칙이 통째로 잡음이 된다. 그래서 파일명 → repo 경로를 «한 번» 만든다.
81
82
  // ⛔ 같은 파일명이 둘 이상이면 «해석하지 않는다** — 틀린 파일을 대면 「어긋남」이 거짓으로 난다.
82
83
  const sourcePathsByBasename = new Map<string, string | null>();
83
- for (const relPath of execFileSync('git', ['ls-files', '*.ts', '*.tsx'], { cwd: repoRoot, encoding: 'utf-8' }).split('\n')) {
84
+ const lsFiles = runGitCommand(repoRoot, ['ls-files', '*.ts', '*.tsx'], { encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 });
85
+ if (lsFiles.status !== 0) throw new Error(`git ls-files failed: ${lsFiles.stderr.trim() || `rc=${lsFiles.status}`}`);
86
+ for (const relPath of lsFiles.stdout.split('\n')) {
84
87
  if (relPath === '') continue;
85
88
  const base = basename(relPath);
86
89
  sourcePathsByBasename.set(base, sourcePathsByBasename.has(base) ? null : relPath);
@@ -1,10 +1,11 @@
1
1
  import { readFileSync, writeFileSync } from 'node:fs';
2
- import { resolve } from 'node:path';
2
+ import { basename, resolve } from 'node:path';
3
3
  import { FEATURE_MATURITY } from '../../src/maturity/feature-maturity.js';
4
4
  import type { ChecklistItem } from '../../src/release-loop/checklist.js';
5
5
  import type { ReleaseSchedule } from '../../src/release-loop/release-schedule.js';
6
6
  import type { MergedRunLedgerQuery } from '../../src/self-implement/run-ledger.js';
7
7
  import { generateFeatureMap } from './generate-feature-map.js';
8
+ import { draftReleaseStory } from '../release-story/draft.js';
8
9
 
9
10
  const MAP = resolve(import.meta.dir, '../../docs/marketing/MAP-value-props-to-features.md');
10
11
  const AUTONOMY = new Set(['ORCH1', 'ORCH2', 'LOOP-LIVE1', 'AUTOQ-LOOP', 'AUTHOR-PAR', 'RUN-HELPER', 'FINISH-RATE']);
@@ -110,6 +111,22 @@ export function generateAxBrief(version: string, sources: AxBriefSources): strin
110
111
  ].join('\n');
111
112
  }
112
113
 
114
+ /** Derive the next release's internal brief from its ledgers and the RELEASE-STORY version-note draft.
115
+ * The release loop supplies its version, ledger sources and isolated story paths; the standalone CLI stays unchanged. */
116
+ export function generateNextVersionAxBrief(
117
+ nextVersion: string,
118
+ sources: AxBriefSources,
119
+ storyOptions: Omit<Parameters<typeof draftReleaseStory>[0], 'version'> = {},
120
+ ): string {
121
+ const brief = generateAxBrief(nextVersion, sources);
122
+ const story = draftReleaseStory({ ...storyOptions, version: nextVersion });
123
+ const announcementFile = story.files.find((file) => basename(file) === 'announcement.md');
124
+ const announcement = story.status === 'drafted' && announcementFile
125
+ ? readFileSync(announcementFile, 'utf8').replace(/^# [^\r\n]*\r?\n/, '').trim()
126
+ : '사용자 대상 변경 없음 — RELEASE-STORY 초안을 건너뜀';
127
+ return `${brief}\n## 5. 다음 판 변화·근거 (RELEASE-STORY 초안)\n\n> 공개 전 CMO 확인 필요 · 원천: release/next.md, 해당 판의 green 칸, 연결된 검증 소구점 원장\n\n${announcement}\n`;
128
+ }
129
+
113
130
  if (import.meta.main) {
114
131
  const args = process.argv.slice(2);
115
132
  const option = (name: string) => {
@@ -3,7 +3,7 @@ import { readFileSync, writeFileSync } from 'node:fs';
3
3
  import { resolve } from 'node:path';
4
4
  import { buildEvalPromptToolSurface, EVAL_PROMPT_TOOL_SURFACES, isEvalPromptToolSurface, resolveReproModelId, runEvalPrompt, type EvalPromptToolSurface } from '../src/eval-prompt-cli.js';
5
5
  import { getModelFamily } from '../src/models/prompts.js';
6
- import { resolveDefaultProvider } from '../src/llm.js';
6
+ import { NoLlmProviderAvailableError, resolveDefaultProvider } from '../src/llm.js';
7
7
  import { filterToolsByDeny } from '../src/tool-runtime/tool-deny.js';
8
8
  import { getUserConfig } from '../src/user-config.js';
9
9
  import { resolveObserveOnlyDecision, type ObserveOnlyDecision } from '../src/self-implement/observe-only.js';
@@ -80,8 +80,16 @@ function formatMachineLoad(load: MachineLoad): string {
80
80
 
81
81
  function authoritativeSurfaceToolNames(surface: EvalPromptToolSurface): string[] {
82
82
  const cfg = getUserConfig();
83
- const provider = resolveDefaultProvider();
84
- const modelFamily = getModelFamily(resolveReproModelId(undefined, provider.defaultModel));
83
+ // ⛔ 안전 관문(노출된 변이 툴)은 «provider 해석보다 먼저» 닫혀야 한다 — 자격이 없는 기계(게이트 Pod)에서
84
+ // provider 해석이 먼저 던지면 관문이 안내 대신 「No LLM provider」로 끝났다(0.2.20 컷 pod-7·pod-22).
85
+ // provider 가 없으면 러너의 마지막 기본 모델로 서피스를 재서 관문을 그대로 판정한다(런은 어차피 못 돈다).
86
+ let providerDefaultModel: string | undefined;
87
+ try {
88
+ providerDefaultModel = resolveDefaultProvider().defaultModel;
89
+ } catch (error) {
90
+ if (!(error instanceof NoLlmProviderAvailableError)) throw error;
91
+ }
92
+ const modelFamily = getModelFamily(resolveReproModelId(undefined, providerDefaultModel));
85
93
  const { specs } = buildEvalPromptToolSurface(surface, modelFamily, cfg);
86
94
  const tools = filterToolsByDeny(specs, cfg.chat.toolDeny) ?? specs;
87
95
  return tools.map((tool) => tool.name);
@@ -20,6 +20,7 @@ import { runPodCommand, parsePodCpu, resolvePodCpu, type RunPodCommandOptions, t
20
20
  import { POD_BUN_CACHE_HOST_PATH, parseInstallSeconds, podBunCacheVolume } from '../../src/task-orchestrator/surfaces/pod-bun-cache.js';
21
21
  import { PodPoolScheduler, parsePodPool, checkPodPool } from '../../src/task-orchestrator/surfaces/pod-pool.js';
22
22
  import { POD_INSTALL_SLOTS_DEFAULT, POD_INSTALL_SLOTS_HOST_PATH, installSlotScript } from '../../src/task-orchestrator/surfaces/pod-install-slots.js';
23
+ import { gateDepsInstallScript, parseGateDeps } from '../../src/task-orchestrator/surfaces/pod-gate-deps.js';
23
24
  import { gateShardsPath, writeGateShards, type GateShard } from '../../src/release-loop/gate-shards.js';
24
25
  import { defaultKubectl } from '../../src/task-orchestrator/surfaces/self-implement-pod.js';
25
26
 
@@ -253,7 +254,7 @@ export function shardParts(paths: readonly string[], seconds: (file: string) =>
253
254
  * leaving `install.log`/`install.rc`, `part-<i>.log`/`.rc`/`.junit.xml`, and `shard.timeout` (the part index) when the
254
255
  * deadline cut the shard. A part without `.rc` did not finish. The shell itself always exits 0 (as before).
255
256
  */
256
- export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number }): string {
257
+ export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPatterns: readonly string[]; softSeconds: number; cachePrefix: string; installSlots: number; depsDir?: string }): string {
257
258
  const run = o.parts.map((part, index) => {
258
259
  const ignores = o.cdpPatterns.filter((pattern) => part.includes(pattern)).flatMap((pattern) => ['--path-ignore-patterns', pattern]);
259
260
  return `run_part ${index} ${['bun', 'run', 'test:deterministic', ...ignores, ...part.map(asPath)].map(quote).join(' ')}`;
@@ -276,9 +277,8 @@ export function gateShardShell(o: { parts: readonly (readonly string[])[]; cdpPa
276
277
  ' echo "$prc" > "$O/part-$i.rc"',
277
278
  '}',
278
279
  'if cd .. && cd repo; then',
279
- ...(o.installSlots > 0 ? [' install_slot_acquire >> "$O/install.log" 2>&1'] : []),
280
- ' { bun install && (cd apps/pwa && bun install); } >> "$O/install.log" 2>&1; irc=$?',
281
- ...(o.installSlots > 0 ? [' install_slot_release'] : []),
280
+ // GATE-IMAGE-DEPS: link the image's baked node_modules when the lockfiles match; only a miss installs (behind a slot).
281
+ ...gateDepsInstallScript({ log: '"$O/install.log"', installSlots: o.installSlots, ...(o.depsDir ? { depsDir: o.depsDir } : {}) }).split('\n').map((line) => ` ${line}`),
282
282
  ' echo "$irc" > "$O/install.rc"',
283
283
  ` if [ "$irc" -eq 0 ]; then ${run || 'true'}; fi`,
284
284
  'else echo 5 > "$O/install.rc"; fi',
@@ -800,7 +800,7 @@ export function createGateRunner(repo: string, remote?: string, commandOverride?
800
800
  }
801
801
  const installSeconds = parseInstallSeconds(output ?? '');
802
802
  // GATE-TIMEOUT-HEAL ③: a cut shard is «reason: timeout» (with the files that still finished), not a bare rc=null.
803
- if (!reused && !descent) debug.log('release-loop.gate', 'pod-shard', { shard, files: paths, durationMs, rc: rc ?? null, attempt: depth + 1, installSeconds, deadlineSeconds: shardDeadline, parts: parts.length,
803
+ if (!reused && !descent) debug.log('release-loop.gate', 'pod-shard', { shard, files: paths, durationMs, rc: rc ?? null, attempt: depth + 1, installSeconds, gateDeps: parseGateDeps(output ?? ''), deadlineSeconds: shardDeadline, parts: parts.length,
804
804
  ...(timedOut ? { reason: 'timeout', finishedFiles: finished.length } : {}) });
805
805
  if (!reused && !descent) markShard(shard, { ...(installSeconds !== null ? { installSec: installSeconds } : {}), ...(rc !== undefined ? { rc } : {}), ...(timedOut ? { state: 'timeout' as const } : {}) });
806
806
  let clean = output?.replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
@@ -1,15 +1,60 @@
1
- import { readdirSync, readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
1
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import { basename, dirname, join, resolve } from 'node:path';
3
3
  import { debug } from '../../src/debug/log.js';
4
4
 
5
5
  /** Plan weights for a Pod sweep: wall-scaled when the previous cut recorded shard wall times, junit seconds otherwise. */
6
- export function planDurations(durationSource: string | undefined): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number } } {
6
+ export function planDurations(durationSource: string | undefined): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number }; fallback?: string } {
7
7
  if (!durationSource) return { durations: new Map() };
8
- const junit = readFileDurations(durationSource);
9
- const wall = readFileWallWeights(durationSource, junit);
8
+ const primary = planDurationsFrom(durationSource);
9
+ if (primary.durations.size) return primary;
10
+ // GATE-PLAN-TIMINGS: the baseline cut left no reports (0.2.20: baseline 0.2.19 was gated from another universe, so
11
+ // all 5,585 files were «unknown», planned 3.9 min, measured 13–20 min). Use the most recent sibling cut instead.
12
+ const fallback = latestSiblingCutDir(durationSource);
13
+ if (!fallback) {
14
+ debug.log('release-loop.gate', 'plan-duration-fallback', { source: durationSource, fallback: null });
15
+ return primary;
16
+ }
17
+ const result = planDurationsFrom(fallback);
18
+ debug.log('release-loop.gate', 'plan-duration-fallback', { source: durationSource, fallback, files: result.durations.size, wall: !!result.wall });
19
+ return result.durations.size ? { ...result, fallback } : primary;
20
+ }
21
+
22
+ function planDurationsFrom(dir: string): { durations: Map<string, number>; wall?: { shards: number; scaledFiles: number } } {
23
+ const junit = readFileDurations(dir);
24
+ const wall = readFileWallWeights(dir, junit);
10
25
  return wall ? { durations: wall.weights, wall: { shards: wall.shards, scaledFiles: wall.scaledFiles } } : { durations: junit };
11
26
  }
12
27
 
28
+ /**
29
+ * For a `<root>/<version>/<a>/<b>` duration source (the gate passes `<ledger>/release/<baseline>/gate-logs/cut`), the
30
+ * sibling `<root>/<other>/<a>/<b>` directory whose newest `*.junit.xml` is the most recent — «the latest gate». The
31
+ * source itself is skipped. Undefined when the path is too shallow or no sibling holds a junit report.
32
+ */
33
+ export function latestSiblingCutDir(durationSource: string): string | undefined {
34
+ const source = resolve(durationSource);
35
+ const b = basename(source);
36
+ const a = basename(dirname(source));
37
+ const root = dirname(dirname(dirname(source)));
38
+ if (!a || !b || root === dirname(dirname(source))) return undefined;
39
+ let versions: string[];
40
+ try { versions = readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name); }
41
+ catch { return undefined; }
42
+ let best: { dir: string; mtimeMs: number } | undefined;
43
+ for (const version of versions.sort()) {
44
+ const dir = join(root, version, a, b);
45
+ if (dir === source) continue;
46
+ let newest = -1;
47
+ try {
48
+ for (const name of readdirSync(dir)) {
49
+ if (!name.endsWith('.junit.xml')) continue;
50
+ try { newest = Math.max(newest, statSync(join(dir, name)).mtimeMs); } catch { /* vanished mid-scan */ }
51
+ }
52
+ } catch { continue; }
53
+ if (newest >= 0 && (!best || newest > best.mtimeMs)) best = { dir, mtimeMs: newest };
54
+ }
55
+ return best?.dir;
56
+ }
57
+
13
58
  /** Observation for GATE-PLAN-WALLTIME, emitted once the shards are planned so `maxPlannedMin` is the heaviest shard. */
14
59
  export function logPlanWalltime(wall: { shards: number; scaledFiles: number } | undefined, shards: ReadonlyArray<{ plannedSeconds: number }>): void {
15
60
  if (!wall) return;
@@ -587,8 +587,9 @@ export async function main(args: string[] = process.argv.slice(2), deps: DailyDe
587
587
  for (const arg of args) if (!['--dry-run', '--no-news', '--json'].includes(arg)) throw new Error(`알 수 없는 옵션: ${arg}`);
588
588
  const result = await runDaily({ dryRun: args.includes('--dry-run'), noNews: args.includes('--no-news'), stage }, deps);
589
589
  (deps.print ?? console.log)(args.includes('--json') ? JSON.stringify(result) : `${result.markdown}\n파일: ${result.file} · ${result.deliveryLine}`);
590
- // 발송 설정 OFF 는 degraded 로 기록하고 done 으로 진행한다. 실제 발송 실패·볼트 사본 실패는 그래프를 멈춘다.
590
+ // 그래프 deliver 는 미발송도 출력·tick 에 기록한 뒤 실패로 종결한다.
591
591
  if ((stage === 'compose' || !stage) && result.vaultFatal) throw new Error(`볼트 사본 실패 · ${result.vaultError}`);
592
+ if (stage === 'deliver' && result.deliveryState === 'send-disabled') throw new Error('발송 실패 · 발송 비활성');
592
593
  if (stage === 'deliver' && result.sendError) throw new Error(`발송 실패 · ${result.sendError}`);
593
594
  return result;
594
595
  }