elanous 0.2.29 → 0.2.32

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 (775) 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/{cIpv5nU9AycwYWZI9H589 → IVKr3AlRUVLKsw2fh7eXF}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{058a98ba.7eb28d5e6dc03565.js → 0bb0ff36.b8d418980951e5ba.js} +7 -7
  5. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +27 -0
  8. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +287 -0
  9. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +62 -0
  10. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/{6013-2f769370d8b4c2c6.js → 1335-6731f392c35216eb.js} +3 -3
  12. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{8332.6f0f49df772e163b.js → 1654.32de4b324981a188.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/1834-98b64172bc1efe77.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +149 -0
  17. package/apps/pwa/out/_next/static/chunks/{8795.32573a185af18c7b.js → 1913.7cc6fb6055b1ed3f.js} +2 -2
  18. package/apps/pwa/out/_next/static/chunks/{419.736c0d6f426249a7.js → 2001.6c7e0fd02190886c.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2112-e4efc21a6505d5bc.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{6767.1fcfc9b8be83975f.js → 2213.2ccbada92c33ea0f.js} +16 -16
  24. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2534.e85ae21ad0dac829.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/{4759.1f76713aefb87db5.js → 2871.0bca6137343b3f76.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/{6776.06ff1e3b464cc607.js → 2898.fd781bc7cf01a7b7.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{1782-59db1b5aa06df38a.js → 2940-619bfd8ef337c611.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{8471.8d2a8c74f09c36ff.js → 2985.39ccdecd36848b12.js} +4 -4
  31. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +115 -0
  32. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +64 -0
  33. package/apps/pwa/out/_next/static/chunks/{bc324b7c.02a09dd93f6a399b.js → 3267c0e6.d34854e7b3984a6e.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3278.2e5d15b53a4091c8.js +2 -0
  35. package/apps/pwa/out/_next/static/chunks/{7725-4f83d5541fbdb81b.js → 3541-ce3a5424ed5ad7f1.js} +1 -1
  36. package/apps/pwa/out/_next/static/chunks/3583.a05e88cc8d594628.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +34 -0
  39. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{46bd8bea.2f4b4099172fcdb7.js → 409f1e57.d0649fc47691ebfe.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{1142.65d002789ab3af7d.js → 4174.92ed04922709ac9e.js} +2 -2
  43. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +36 -0
  45. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +286 -0
  49. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +77 -0
  50. package/apps/pwa/out/_next/static/chunks/4745.67d6f99c245af3f7.js +226 -0
  51. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +79 -0
  53. package/apps/pwa/out/_next/static/chunks/5173-233188df2f42c626.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/5307.60f2209e809bd627.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{3396-97b97928c49190c9.js → 5458-16cd7a2b51b74c8c.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{3403.7199205e65124486.js → 5525.86debf231e181813.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9143.ff14585db1d275ff.js → 5543.a438b8ab5a13ea47.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +94 -0
  67. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{8398.73a19b39715eda04.js → 6092.a7f99e68b188ca66.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{5591.a35e7a217734a8b9.js → 6157.0c9af021de4fb31b.js} +2 -2
  72. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/{7375.050ea0d72968e49f.js → 6433.fc573af22bbc9ab7.js} +17 -17
  75. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +90 -0
  77. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +32 -0
  78. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +104 -0
  80. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +24 -0
  85. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +93 -0
  86. package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  94. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  95. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  100. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  110. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  112. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  123. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-a9717a67c2eecbaf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/ceo/page-c0f1ca371f710b06.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/chat/page-46430d45a9e04eac.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/control/page-a27b1e5a0d1b308f.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/design-check/page-8ea49a4c6dd2c6e7.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/exec/page-0e5a41fac1c75396.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/field/page-31aaf1ed37c6df9a.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/intake/page-c69247e7134d329d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/layout-66dc5cd3a0999abe.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/loops/page-d256f5d5d9552823.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/market/page-ce8f1907b8a6101c.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/morning/page-32866485913d6a04.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/not-found-7607cca9b84950c6.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eeab86176b03dc3b.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-5b93dbae3432b996.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f47e768b5b242b5a.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-95306f892aa2d0ee.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/sessions/page-940fb6c217f6b470.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-8c66a3b24a745630.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/page-7b675dfd35c36fc9.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-8bd0d3cf7665bcfc.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-c219f2ed171131be.js} +1 -1
  163. package/apps/pwa/out/_next/static/chunks/app/share/page-40f8fa21bdae955b.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/showroom/page-468f8313e4f1fbd9.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/term/page-04d00ae9b0890349.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/today/page-4214b855d9233ea8.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/trace/page-936752c7aa58762e.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/vault/page-ec052ad359df1797.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/page-fad650e4793adb65.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  184. package/apps/pwa/out/_next/static/css/b5d88eba78a3d7bf.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +26 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/bin/elanous.mjs +7 -3
  279. package/graphs/context/nightly-condense.yaml +1 -0
  280. package/graphs/implement-loop.yaml +5 -0
  281. package/graphs/intake/intake-daily.yaml +8 -1
  282. package/graphs/intake/recipes.yaml +5 -0
  283. package/graphs/lecture/lecture-note.yaml +2 -2
  284. package/graphs/ops/harness-gc.yaml +1 -0
  285. package/graphs/release/recipes.yaml +3 -0
  286. package/graphs/release/release-loop.yaml +9 -5
  287. package/graphs/units/recipes.yaml +3 -0
  288. package/graphs/units/release-gate-recheck.yaml +15 -0
  289. package/package.json +2 -1
  290. package/scripts/check-native-tool-wiring.ts +3 -2
  291. package/scripts/ci-android-unit-tests.ts +16 -0
  292. package/scripts/ci-typecheck-changed.ts +63 -10
  293. package/scripts/coord-channel-watch.sh +22 -16
  294. package/scripts/coord-role-pack.ts +81 -2
  295. package/scripts/cron-run.ts +96 -3
  296. package/scripts/detect-test-interference.ts +38 -5
  297. package/scripts/gate-pr-cache.ts +65 -0
  298. package/scripts/gh-surface/capture.ts +126 -0
  299. package/scripts/gh-surface/gh +40 -0
  300. package/scripts/import-graph-scc.ts +38 -0
  301. package/scripts/install.ps1 +19 -0
  302. package/scripts/intake-social.ts +181 -0
  303. package/scripts/lecture-note/node.ts +71 -4
  304. package/scripts/lib/android-toolchain.ts +32 -0
  305. package/scripts/lib/deterministic-env.ts +62 -0
  306. package/scripts/lib/gate-test-env.ts +19 -0
  307. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  308. package/scripts/measure-si-task-cpu.ts +143 -0
  309. package/scripts/ratchets/test-interference-patterns.allowlist.txt +255 -0
  310. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  311. package/scripts/release-loop/cut-branch.ts +4 -3
  312. package/scripts/release-loop/export-check-node.ts +0 -1
  313. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  314. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  315. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  316. package/scripts/release-loop/gate-closure.ts +12 -8
  317. package/scripts/release-loop/gate-diff.ts +1 -1
  318. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  319. package/scripts/release-loop/gate-node.ts +523 -75
  320. package/scripts/release-loop/gate-partial.ts +106 -9
  321. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  322. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  323. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  324. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  325. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  326. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  327. package/scripts/release-loop/import-graph-scc.ts +215 -0
  328. package/scripts/release-loop/node-verdict.ts +2 -0
  329. package/scripts/release-loop/prepare-node.ts +102 -4
  330. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  331. package/scripts/release-loop/resume-release.ts +33 -4
  332. package/scripts/release-loop/resume.ts +13 -5
  333. package/scripts/release-loop/spawn-lane.ts +2 -19
  334. package/scripts/release-loop/tui-sim-node.ts +3 -2
  335. package/scripts/release-loop/unattended-release.ts +16 -0
  336. package/scripts/test-deterministic.ts +5 -61
  337. package/scripts/train-reach-grouping.ts +48 -0
  338. package/scripts/tsc-incremental-cache.ts +86 -0
  339. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  340. package/scripts/tsc-main-safety-net.ts +2 -2
  341. package/src/acp/client.ts +4 -1
  342. package/src/acp/core-turn-bridge.ts +65 -8
  343. package/src/acp/elanous-extensions.ts +3 -0
  344. package/src/acp/server.ts +3 -0
  345. package/src/acp/tool-trace.ts +186 -11
  346. package/src/ad-pipeline/run.ts +4 -2
  347. package/src/agent/runner.ts +169 -3
  348. package/src/agent/self-ambient-cache.ts +156 -0
  349. package/src/agent/self-ambient.ts +8 -1
  350. package/src/agent/subagent-callable.ts +3 -2
  351. package/src/agent/task-notification.ts +5 -0
  352. package/src/agent-mission/review-loop.ts +6 -3
  353. package/src/agent-substrate/acp-implementer.ts +14 -2
  354. package/src/agent-substrate/pr-reviewer.ts +14 -0
  355. package/src/agent-substrate/self-review-cli.ts +30 -4
  356. package/src/ask-user-question/tool.ts +22 -0
  357. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  358. package/src/autopilot/pr-manager.ts +80 -7
  359. package/src/briefing/brief-items.ts +24 -22
  360. package/src/capture/frame-state-detect.ts +39 -0
  361. package/src/capture/tui-self-report.ts +149 -6
  362. package/src/chat/chat-cli.ts +10 -2
  363. package/src/chat/index.ts +138 -26
  364. package/src/chat/input-control-key.ts +5 -3
  365. package/src/chat/pickers/modal-runtime.ts +6 -0
  366. package/src/chat/pickers/modals.ts +8 -2
  367. package/src/chat/tool-interrupt-behavior.ts +38 -0
  368. package/src/chat/tool-render/dispatch.ts +5 -1
  369. package/src/chat/turn-typeahead.ts +75 -20
  370. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  371. package/src/cli/agent-cli.ts +41 -13
  372. package/src/cli/ask-bare.ts +1 -0
  373. package/src/cli/config-audit.ts +123 -0
  374. package/src/cli/decisions-cli.ts +80 -6
  375. package/src/cli/import-cli.ts +12 -0
  376. package/src/cli/log-event-names.ts +17 -0
  377. package/src/cli/mcp-login.ts +21 -5
  378. package/src/cli/msg-cli.ts +89 -0
  379. package/src/cli/pod-cli.ts +14 -3
  380. package/src/cli/pr-cli.ts +273 -81
  381. package/src/cli/pr-land-base-read.ts +34 -0
  382. package/src/cli/pr-land-heavy-remote.ts +82 -26
  383. package/src/cli/pr-land-overlap-evidence.ts +109 -11
  384. package/src/cli/pr-land-pod-shadow-job.ts +106 -0
  385. package/src/cli/pr-land-pod-shadow.ts +16 -3
  386. package/src/cli/pr-land-refusal.ts +20 -5
  387. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  388. package/src/cli/pty-takeover-cli.ts +88 -14
  389. package/src/cli/release-cli.ts +80 -14
  390. package/src/cli/seat-cli.ts +138 -3
  391. package/src/cli/self-update.ts +5 -2
  392. package/src/cli/sim-cli.ts +18 -0
  393. package/src/cli/tasks-cli.ts +97 -19
  394. package/src/context-bus/context-first.ts +13 -0
  395. package/src/context-bus/context-now.ts +13 -2
  396. package/src/context-bus/ops-events.ts +79 -0
  397. package/src/control-plane/lease-holder.ts +12 -8
  398. package/src/control-plane/ledger.ts +163 -4
  399. package/src/control-plane/server.ts +91 -11
  400. package/src/core-turn/run-core-turn.ts +2 -0
  401. package/src/core-turn/run-goal-loop.ts +243 -3
  402. package/src/core-turn/seat-turn-cap.ts +79 -0
  403. package/src/core-turn/short-question.ts +38 -6
  404. package/src/core-turn/types.ts +6 -0
  405. package/src/dashboard/acp-active-model.ts +42 -1
  406. package/src/dashboard/acp-boot.ts +3 -0
  407. package/src/dashboard/background-jobs-status.ts +66 -0
  408. package/src/dashboard/index.ts +339 -657
  409. package/src/dashboard/input/agent-wake.ts +242 -0
  410. package/src/dashboard/input/chat-main-entry-runtime.ts +6 -1
  411. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  412. package/src/dashboard/input/chat-main-session.ts +8 -1
  413. package/src/dashboard/input/chat-main-turn.ts +12 -3
  414. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  415. package/src/dashboard/input/external-input-host.ts +49 -9
  416. package/src/dashboard/input/internal-turn.ts +261 -0
  417. package/src/dashboard/input/mouse-wiring.ts +108 -11
  418. package/src/dashboard/input/seat-autowake.ts +318 -0
  419. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  420. package/src/dashboard/log-click-runtime.ts +118 -2
  421. package/src/dashboard/loop-scheduler.ts +72 -0
  422. package/src/dashboard/seat-boot-preamble.ts +18 -0
  423. package/src/dashboard/skill-runtime.ts +2 -0
  424. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  425. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  426. package/src/dashboard/slash-runtime/index.ts +13 -0
  427. package/src/dashboard/turn-busy-teardown.ts +50 -0
  428. package/src/dashboard/turn-preamble.ts +116 -40
  429. package/src/dashboard/turn-session-layers.ts +4 -2
  430. package/src/dashboard/turn-start-segments.ts +222 -0
  431. package/src/decisions/decision-ledger.ts +45 -4
  432. package/src/discord-self-message.ts +4 -4
  433. package/src/display/prompt-row-owner.ts +146 -0
  434. package/src/display/resize-listener.ts +33 -2
  435. package/src/domains/release-tool.ts +18 -1
  436. package/src/field-note/transcribe.ts +17 -0
  437. package/src/fold-stack.ts +4 -2
  438. package/src/git-fs/index.ts +263 -36
  439. package/src/github/remote-call.ts +81 -0
  440. package/src/goals/registry.ts +46 -6
  441. package/src/goals/types.ts +7 -1
  442. package/src/graph-runner/runner.ts +1 -0
  443. package/src/grok/credential.ts +26 -0
  444. package/src/harness/gate-reserve.ts +87 -0
  445. package/src/harness/harness-clean.ts +2 -1
  446. package/src/harness/harness-cli-command.ts +52 -5
  447. package/src/harness/harness-gc.ts +2 -1
  448. package/src/harness/harness-incidents.ts +70 -20
  449. package/src/harness/harness-pod-dispatch.ts +87 -10
  450. package/src/harness/harness-queue.ts +68 -4
  451. package/src/harness/harness-stop.ts +4 -3
  452. package/src/harness/harness-substrate-default.ts +78 -7
  453. package/src/harness/harness-worktree-auto.ts +2 -1
  454. package/src/harness/harness-worktrees.ts +3 -2
  455. package/src/hooks/dispatch.ts +2 -1
  456. package/src/index.ts +156 -27
  457. package/src/input/external-input-queue.ts +64 -7
  458. package/src/intake-plane/slash.ts +14 -3
  459. package/src/keybindings.ts +4 -1
  460. package/src/llm/route-decision.ts +36 -0
  461. package/src/llm/tool-loop-steered-rejection.ts +41 -0
  462. package/src/llm-request-shape.ts +209 -0
  463. package/src/llm.ts +301 -283
  464. package/src/loops/consensus.ts +348 -0
  465. package/src/loops/msg-wake.ts +206 -4
  466. package/src/loops/observe.ts +19 -3
  467. package/src/loops/orchestrator/tick.ts +88 -12
  468. package/src/loops/orchestrator/traffic.ts +64 -1
  469. package/src/loops/registry.ts +30 -0
  470. package/src/market/signed-index.ts +14 -0
  471. package/src/maturity/feature-maturity.ts +1 -1
  472. package/src/mcp/mcp-oauth.ts +54 -5
  473. package/src/models/prompts.ts +28 -0
  474. package/src/msg/msg-sse-client.ts +223 -0
  475. package/src/msg/msg-store.ts +86 -2
  476. package/src/mss/logging/log-store.ts +225 -1
  477. package/src/mss/logging/render-categories.ts +5 -0
  478. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  479. package/src/nexus/api/http-server.ts +54 -15
  480. package/src/nexus/api/loop-resources.ts +19 -3
  481. package/src/nexus/api/ops-api.ts +11 -0
  482. package/src/nexus/daemon-thin-inventory.md +37 -0
  483. package/src/nexus/index.ts +70 -0
  484. package/src/nexus/state/state.ts +1 -0
  485. package/src/oauth/store.ts +32 -7
  486. package/src/onboarding/first-run.ts +28 -3
  487. package/src/ops/overview-cache.ts +16 -4
  488. package/src/ops/overview.ts +59 -2
  489. package/src/ops/resources.ts +82 -0
  490. package/src/plugins/maker/connector-maker.ts +41 -0
  491. package/src/plugins/maker/skill-maker.ts +42 -0
  492. package/src/pr-tool/census.ts +303 -0
  493. package/src/pr-tool/inflight-registry.ts +143 -0
  494. package/src/prompt-library/chat-conciseness.ts +13 -0
  495. package/src/prompt-library/universal-preamble.ts +10 -5
  496. package/src/pty-shell/pty-manifest.ts +12 -3
  497. package/src/pty-shell/tui-run-state.ts +34 -3
  498. package/src/release-loop/gate-host-reservation.ts +97 -0
  499. package/src/release-loop/landing-freeze.ts +5 -0
  500. package/src/release-loop/light-rc.ts +5 -2
  501. package/src/release-loop/placement.ts +92 -1
  502. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  503. package/src/release-loop/rehearsal.ts +73 -17
  504. package/src/repl/index.ts +20 -2
  505. package/src/seat-loop/seat-knowhow.ts +282 -0
  506. package/src/seat-loop/seat-loop.ts +41 -2
  507. package/src/seat-loop/traffic-signal.ts +5 -1
  508. package/src/self-dev/ask-launch-flow.ts +37 -3
  509. package/src/self-dev/decompose-compose-graph.ts +28 -27
  510. package/src/self-dev/decompose-proposal.ts +53 -38
  511. package/src/self-dev/decompose.ts +17 -0
  512. package/src/self-dev/dev-pipeline.ts +31 -2
  513. package/src/self-dev/draft-residue.ts +267 -33
  514. package/src/self-dev/draft-sweep.ts +59 -4
  515. package/src/self-dev/external-call-zero.ts +77 -0
  516. package/src/self-dev/launch-preflight-text.ts +6 -0
  517. package/src/self-dev/launch-preflight.ts +25 -3
  518. package/src/self-dev/local-supervisor-judge.ts +185 -0
  519. package/src/self-dev/run-supervisor.ts +229 -19
  520. package/src/self-dev/run-types.ts +20 -0
  521. package/src/self-dev/shard-aggregate.ts +13 -2
  522. package/src/self-dev/shard-plan.ts +56 -1
  523. package/src/self-dev/shard-run.ts +207 -12
  524. package/src/self-dev/spawn-lane-files.ts +19 -0
  525. package/src/self-implement/app-api-budget.ts +51 -11
  526. package/src/self-implement/config-gate.ts +2 -1
  527. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  528. package/src/self-implement/expose-gate.ts +2 -1
  529. package/src/self-implement/follow-up-placement.ts +79 -0
  530. package/src/self-implement/gate-artifacts.ts +416 -0
  531. package/src/self-implement/gate-baseline.ts +96 -5
  532. package/src/self-implement/gate-cli.ts +207 -17
  533. package/src/self-implement/gate-remote.ts +136 -26
  534. package/src/self-implement/gate-scenario.ts +85 -0
  535. package/src/self-implement/goal-author.ts +160 -8
  536. package/src/self-implement/graph-authority.ts +38 -6
  537. package/src/self-implement/graph-overlay-condition.ts +92 -1
  538. package/src/self-implement/heal-triage.ts +79 -0
  539. package/src/self-implement/host-regate.ts +97 -7
  540. package/src/self-implement/orchestrator.ts +115 -134
  541. package/src/self-implement/pr-title.ts +123 -0
  542. package/src/self-implement/run-checkpoint.ts +235 -0
  543. package/src/self-implement/run-ledger.ts +162 -15
  544. package/src/self-implement/run-stop.ts +4 -3
  545. package/src/self-implement/run-ttl.ts +28 -4
  546. package/src/self-implement/seams.ts +2 -0
  547. package/src/self-implement/shadow-stage.ts +7 -6
  548. package/src/self-implement/stop-autoheal.ts +2 -1
  549. package/src/self-implement/train-gate-remote.ts +37 -8
  550. package/src/self-implement/train-reach-grouping.ts +157 -0
  551. package/src/self-implement/train-scenario-layers.ts +133 -0
  552. package/src/self-implement/uncommitted-work.ts +2 -0
  553. package/src/session/pending-input.ts +19 -0
  554. package/src/session/session-start.ts +224 -0
  555. package/src/session-runtime/index.ts +22 -267
  556. package/src/session-runtime/parallel-dispatch.ts +22 -5
  557. package/src/shell-runner/background-surface.ts +15 -5
  558. package/src/skills/tools/agent.ts +39 -6
  559. package/src/skills/tools/dev-harness.ts +6 -4
  560. package/src/skills/tools/list-dir.ts +11 -0
  561. package/src/skills/tools/schedule-wakeup.ts +408 -0
  562. package/src/skills/tools/shell.ts +246 -4
  563. package/src/status/bar.ts +26 -0
  564. package/src/steward/digest-delivery.ts +118 -0
  565. package/src/steward/hold-hygiene.ts +120 -0
  566. package/src/steward/resync-tick.ts +114 -23
  567. package/src/steward/ta-repair-event-collect.ts +158 -0
  568. package/src/steward/triage.ts +10 -0
  569. package/src/surface/shell-runner-boot.ts +5 -2
  570. package/src/task-agent/card-evidence.ts +25 -1
  571. package/src/task-agent/green-sweep.ts +8 -3
  572. package/src/task-agent/judge.ts +76 -0
  573. package/src/task-agent/land-queue.ts +79 -0
  574. package/src/task-agent/live-moves.ts +30 -9
  575. package/src/task-agent/postland-card.ts +5 -0
  576. package/src/task-agent/prelaunch-already-done.ts +98 -0
  577. package/src/task-agent/real-launch-guard.ts +37 -0
  578. package/src/task-agent/rejudge-on-head.ts +89 -12
  579. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  580. package/src/task-agent/repair-cycle.ts +45 -7
  581. package/src/task-agent/repair-worker.ts +7 -0
  582. package/src/task-agent/run-identity.ts +200 -0
  583. package/src/task-agent/shadow.ts +50 -3
  584. package/src/task-agent/task-hand.ts +182 -5
  585. package/src/task-agent/train-landing.ts +77 -0
  586. package/src/task-agent/work-order.ts +104 -0
  587. package/src/task-orchestrator/surfaces/pod-command-job.ts +151 -37
  588. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  589. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  590. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  591. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  592. package/src/task-orchestrator/surfaces/pod-lease.ts +118 -6
  593. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  594. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  595. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  596. package/src/task-orchestrator/surfaces/pod-pool.ts +3 -1
  597. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  598. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +67 -0
  599. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  600. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  601. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  602. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +525 -0
  603. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  604. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  605. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +362 -0
  606. package/src/task-orchestrator/surfaces/self-implement-pod.ts +138 -19
  607. package/src/telegram.ts +2 -4
  608. package/src/tui/chat/execution-badge.ts +5 -1
  609. package/src/tui/input/pickers.ts +732 -0
  610. package/src/tui/input-lag-probe.ts +230 -0
  611. package/src/tui/slash/mission.ts +492 -0
  612. package/src/tui/slash/term.ts +877 -0
  613. package/src/tui-client/dashboard-session.ts +9 -0
  614. package/src/tui.ts +52 -0
  615. package/src/user-config/gemini-server-tools.ts +9 -0
  616. package/src/user-config.ts +53 -16
  617. package/src/util/spawn-sync-output.ts +7 -0
  618. package/src/ux-sim/fake-bin.ts +154 -0
  619. package/src/ux-sim/fake-clock.ts +36 -0
  620. package/src/ux-sim/headless-tui.ts +72 -0
  621. package/src/ux-sim/in-process-cli.ts +2 -1
  622. package/src/ux-sim/scenario.ts +255 -0
  623. package/src/ux-sim/temp-git-remote.ts +82 -0
  624. package/src/version/packed-revision.json +1 -1
  625. package/src/video-pipeline/recipes/vlog.ts +25 -7
  626. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  630. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  632. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  635. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  636. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  639. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  641. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  647. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  651. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  662. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  668. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  671. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  672. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  673. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  676. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  678. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  679. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  680. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  682. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  688. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  695. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  698. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  703. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  705. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/botlab/page-a5635eba0d73b84e.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9f92737b8766009a.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  768. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  774. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +0 -1
  775. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → IVKr3AlRUVLKsw2fh7eXF}/_ssgManifest.js +0 -0
@@ -1,19 +1,117 @@
1
1
  #!/usr/bin/env bun
2
- import { existsSync } from 'node:fs';
2
+ import { closeSync, constants, existsSync, fstatSync, lstatSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, writeFileSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
+ import { debug } from '../../src/debug/log.js';
4
5
  import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
5
6
  import { errorResult, finishNode, lastResult, nodeOutput, readGraphContext, runCommand, type CommandRunner } from './node-verdict.js';
7
+ import { isReleaseVersion } from './release-version.js';
6
8
 
7
- export function runPrepare(run: CommandRunner = runCommand) {
9
+ /** Apparent bytes of the preserved archive; never follow a symlink out of its private directory. */
10
+ function archiveBytes(path: string): number {
11
+ const entry = lstatSync(path);
12
+ if (!entry.isDirectory()) return entry.size;
13
+ return readdirSync(path).reduce((sum, name) => sum + archiveBytes(join(path, name)), 0);
14
+ }
15
+
16
+ function readRegularManifest(path: string): Buffer {
17
+ const fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);
18
+ try {
19
+ if (!fstatSync(fd).isFile()) throw new Error(`prepared manifest is not a regular file: ${path}`);
20
+ return readFileSync(fd);
21
+ } finally { closeSync(fd); }
22
+ }
23
+
24
+ export function runPrepare(run: CommandRunner = runCommand, move: typeof renameSync = renameSync) {
8
25
  const context = readGraphContext();
9
26
  const { version, previousVersion } = context.input;
27
+ if (!isReleaseVersion(version)) throw new Error(`invalid release version: ${version}`);
10
28
  const commit = nodeOutput(context, 'version-release', 'commit');
11
29
  for (const node of ['gate', 'pwa']) if (context.outputs[node]?.outcome !== 'ok') throw new Error(`${node} did not pass`);
12
- const out = join(effectiveInstanceRoot(), 'release', version, 'prepared');
13
- if (existsSync(out)) throw new Error(`prepare output already exists: ${out}`);
30
+ const root = effectiveInstanceRoot();
31
+ const out = join(root, 'release', version, 'prepared');
32
+ if ([join(root, 'release'), join(root, 'release', version)]
33
+ .some((path) => lstatSync(path, { throwIfNoEntry: false })?.isSymbolicLink()))
34
+ throw new Error(`prepare output escapes release root: ${out}`);
35
+ let staleSource: string | undefined;
36
+ let staleManifestBytes: Buffer | undefined;
37
+ let staleParents: Array<{ path: string; dev: number; ino: number; real: string }> | undefined;
38
+ const occupied = lstatSync(out, { throwIfNoEntry: false });
39
+ if (occupied) {
40
+ // Only a tip refresh can prove that this archive belongs to the prior commit. An incomplete or unknown
41
+ // archive is left untouched for investigation; never erase it merely because the path is occupied.
42
+ const old = context.outputs['version-release']?.refreshedFrom;
43
+ const manifestPath = join(out, 'release.json');
44
+ if (typeof old !== 'string' || !/^[0-9a-f]{40}$/i.test(old) || old === commit
45
+ || !occupied.isDirectory() || !existsSync(manifestPath) || !lstatSync(manifestPath).isFile())
46
+ throw new Error(`prepare output already exists with unverified source: ${out}`);
47
+ if (realpathSync(out) !== join(realpathSync(root), 'release', version, 'prepared'))
48
+ throw new Error(`prepare output escapes release root: ${out}`);
49
+ let manifest: { version?: unknown; sourceCommit?: unknown };
50
+ try { staleManifestBytes = readRegularManifest(manifestPath); manifest = JSON.parse(staleManifestBytes.toString('utf8')) as typeof manifest; }
51
+ catch { throw new Error(`prepare output already exists with unreadable manifest: ${out}`); }
52
+ if (manifest.version !== version || manifest.sourceCommit !== old)
53
+ throw new Error(`prepare output already exists for another source: ${out}`);
54
+ staleParents = [join(root, 'release'), join(root, 'release', version)].map((path) => {
55
+ const stat = lstatSync(path);
56
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(`prepare output escapes release root: ${out}`);
57
+ return { path, dev: stat.dev, ino: stat.ino, real: realpathSync(path) };
58
+ });
59
+ staleSource = old;
60
+ }
14
61
  const ref = `v${previousVersion}^{commit}`;
15
62
  const prev = run('git', ['rev-parse', '--verify', ref]);
16
63
  if (prev.status !== 0 || !/^[0-9a-f]{40}\s*$/i.test(prev.stdout)) throw new Error(`previous release ref unavailable: ${ref}`);
64
+ if (staleSource) {
65
+ const current = lstatSync(out, { throwIfNoEntry: false });
66
+ const manifestPath = join(out, 'release.json');
67
+ if (!current?.isDirectory() || current.dev !== occupied?.dev || current.ino !== occupied?.ino
68
+ || !lstatSync(manifestPath, { throwIfNoEntry: false })?.isFile()
69
+ || [join(root, 'release'), join(root, 'release', version)]
70
+ .some((path) => lstatSync(path, { throwIfNoEntry: false })?.isSymbolicLink()))
71
+ throw new Error(`prepared output changed before cleanup: ${out}`);
72
+ if (realpathSync(out) !== join(realpathSync(root), 'release', version, 'prepared'))
73
+ throw new Error(`prepare output escapes release root: ${out}`);
74
+ let manifestBytes: Buffer;
75
+ try { manifestBytes = readRegularManifest(manifestPath); }
76
+ catch { throw new Error(`prepared manifest changed before cleanup: ${out}`); }
77
+ if (!staleManifestBytes?.equals(manifestBytes))
78
+ throw new Error(`prepared manifest changed before cleanup: ${out}`);
79
+ // Rename is atomic on this filesystem. Preserve the moved inode even if it differs from the checked one;
80
+ // no later operation deletes a quarantine directory or follows a link inside the archive.
81
+ const quarantine = mkdtempSync(join(realpathSync(root), '.prepared-cleanup-'));
82
+ const moved = join(quarantine, 'prepared');
83
+ move(out, moved);
84
+ const movedStat = lstatSync(moved);
85
+ let movedManifestBytes: Buffer | undefined;
86
+ try { movedManifestBytes = readRegularManifest(join(moved, 'release.json')); }
87
+ catch { /* preserve the quarantined archive for inspection */ }
88
+ if (!movedStat.isDirectory() || movedStat.dev !== occupied?.dev || movedStat.ino !== occupied?.ino
89
+ || !staleManifestBytes || !movedManifestBytes?.equals(staleManifestBytes))
90
+ throw new Error(`prepared output changed during cleanup; preserved at ${moved}`);
91
+ const receipt = join(quarantine, 'receipt.json');
92
+ const record = { version, old: staleSource, commit, from: out, to: moved, movedAt: new Date().toISOString(),
93
+ bytes: null as number | null, sizeStatus: 'pending' as 'pending' | 'measured' | 'unmeasured', sizeError: undefined as string | undefined };
94
+ try { writeFileSync(receipt, JSON.stringify(record, null, 2) + '\n', { flag: 'wx', mode: 0o600 }); }
95
+ catch (error) { throw new Error(`prepared archive preserved at ${moved}; receipt write failed: ${String(error)}`); }
96
+ try { record.bytes = archiveBytes(moved); record.sizeStatus = 'measured'; }
97
+ catch (error) { record.sizeStatus = 'unmeasured'; record.sizeError = String(error).slice(0, 200); }
98
+ const receiptNext = join(quarantine, 'receipt.next.json');
99
+ try {
100
+ writeFileSync(receiptNext, JSON.stringify(record, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
101
+ renameSync(receiptNext, receipt);
102
+ } catch (error) { throw new Error(`prepared archive preserved at ${moved}; receipt update failed: ${String(error)}`); }
103
+ debug.log('release-loop.prepare', 'stale-prepared-quarantined', { version, old: staleSource, commit,
104
+ from: out, to: moved, bytes: record.bytes, sizeStatus: record.sizeStatus, receipt });
105
+ const parentsStable = staleParents?.every(({ path, dev, ino, real }) => {
106
+ try {
107
+ const stat = lstatSync(path);
108
+ return stat.isDirectory() && !stat.isSymbolicLink() && stat.dev === dev && stat.ino === ino
109
+ && realpathSync(path) === real;
110
+ } catch { return false; }
111
+ });
112
+ if (!parentsStable || lstatSync(out, { throwIfNoEntry: false }))
113
+ throw new Error(`prepare parent changed after quarantine; preserved at ${moved}`);
114
+ }
17
115
  const command = run('bun', ['bin/elanous.mjs', 'release', 'prepare', '--version', version, '--source', commit, '--notes-from', prev.stdout.trim(), '--out', out, '--json']);
18
116
  if (command.stderr) process.stderr.write(command.stderr);
19
117
  const manifest = lastResult(command)?.manifest as { version?: string; sourceCommit?: string; distDir?: string } | undefined;
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bun
2
+ // Run on a host with kubectl access. Each arm launches a real k3d Job; no test seam replaces kubectl.
3
+ import { spawnSync } from 'node:child_process';
4
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../src/util/spawn-sync-output.js';
5
+ import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
+ import { join, resolve } from 'node:path';
8
+ import { runPodCommand } from '../../src/task-orchestrator/surfaces/pod-command-job';
9
+ import { PodPoolScheduler, type PodPoolMember } from '../../src/task-orchestrator/surfaces/pod-pool';
10
+ import { prepareHostDirsOnce, resetHostDirsPrepMemo } from '../../src/task-orchestrator/surfaces/pod-install-slots';
11
+
12
+ type Probe = { arm: 'node-prepared' | 'init-fallback'; job: string; exitCode: number; prep: Record<string, unknown> | null;
13
+ hostPaths: string[]; initContainers: string[]; node: string; childWritable: boolean; artifactsError: string | null };
14
+
15
+ function option(name: string, fallback?: string): string {
16
+ const index = process.argv.indexOf(`--${name}`);
17
+ const value = index < 0 ? fallback : process.argv[index + 1];
18
+ if (!value || value.startsWith('--')) throw new Error(`--${name} required`);
19
+ return value;
20
+ }
21
+
22
+ async function main(): Promise<void> {
23
+ const context = option('context');
24
+ const host = option('host');
25
+ const cluster = option('cluster', 'elanous-pool');
26
+ const image = option('image');
27
+ const namespace = option('namespace', 'elanous-test');
28
+ const cacheBase = option('cache', '/var/lib/elanous/gate-probe-cache');
29
+ const slotsBase = option('slots', '/var/lib/elanous/gate-probe-slots');
30
+ for (const path of [cacheBase, slotsBase]) {
31
+ if (!/^\/[A-Za-z0-9._/-]+$/.test(path) || path.split('/').includes('..')) throw new Error(`unsafe host path: ${path}`);
32
+ }
33
+ const member: PodPoolMember = { context, sshHost: host, k3dCluster: cluster, capacity: 1 };
34
+ const kubectl = (args: readonly string[], input?: string) => {
35
+ const run = spawnSync('kubectl', args, { input, encoding: 'utf8', timeout: 30_000, maxBuffer: 4 * 1024 * 1024 });
36
+ return { status: run.status ?? 1, stdout: run.stdout ?? '', stderr: run.stderr ?? String(run.error ?? '') };
37
+ };
38
+ const check = kubectl(['--context', context, '-n', namespace, 'get', 'namespace', namespace]);
39
+ if (check.status !== 0) throw new Error(`cluster/namespace unreadable: ${check.stderr.trim()}`);
40
+ const artifactRoot = mkdtempSync(join(tmpdir(), 'gate-host-dirs-live-'));
41
+ const nonce = `${Date.now().toString(36)}-${process.pid}`;
42
+ const sourceCommit = spawnSync('git', ['rev-parse', 'HEAD'], { cwd: resolve(import.meta.dir, '../..'), encoding: 'utf8', maxBuffer: SPAWN_SYNC_MAX_BUFFER }).stdout?.trim() || null;
43
+ const results: Probe[] = [];
44
+ try {
45
+ for (const arm of ['node-prepared', 'init-fallback'] as const) {
46
+ const name = `gate-host-dirs-${arm}-${Date.now().toString(36)}`;
47
+ // Distinct absent paths: the fallback arm cannot pass merely because the first arm already chowned its dirs.
48
+ const cache = join(cacheBase, `${arm}-${nonce}`);
49
+ const slots = join(slotsBase, `${arm}-${nonce}`);
50
+ let prep: Record<string, unknown> | null = null;
51
+ let completed = false;
52
+ try {
53
+ const result = await runPodCommand({
54
+ command: ['sh', '-c', 'printf cache-ok > /bun-cache/.host-dir-probe && printf slots-ok > /gate-install-slots/.host-dir-probe && test "$(cat /bun-cache/.host-dir-probe)" = cache-ok && test "$(cat /gate-install-slots/.host-dir-probe)" = slots-ok && rm /bun-cache/.host-dir-probe /gate-install-slots/.host-dir-probe && echo HOST_DIRS_WRITTEN'],
55
+ name,
56
+ namespace, image, imageCommit: null, deadlineSeconds: 120, pollMs: 1_000, statusUnreadableMs: 30_000,
57
+ memoryLimit: '2Gi',
58
+ bunCache: cache, installSlots: slots, env: { NODE_ENV: 'test' }, configHostMirror: () => undefined,
59
+ poolScheduler: new PodPoolScheduler([member]), artifactsRoot: artifactRoot,
60
+ // The exact image was selected by the operator. This probe does not build or sync it.
61
+ syncImages: async () => new Map([[context, { ok: true, action: 'fresh' as const, detail: 'operator-selected image', ms: 0 }]]),
62
+ prepareHostDirs: arm === 'node-prepared'
63
+ ? async (args) => prepareHostDirsOnce(args)
64
+ : async () => ({ host, ok: false, ms: 0, detail: 'forced init fallback probe' }),
65
+ kubectl,
66
+ log: (_category, event, data) => { if (event === 'host-dirs-prep') prep = data; },
67
+ });
68
+ const job = kubectl(['--context', context, '-n', namespace, 'get', 'job', result.job, '-o', 'json']);
69
+ if (job.status !== 0) throw new Error(`applied Job unreadable: ${job.stderr.trim()}`);
70
+ const applied = JSON.parse(job.stdout) as { spec?: { template?: { spec?: {
71
+ initContainers?: Array<{ name: string }>;
72
+ containers?: Array<{ name: string; volumeMounts?: Array<{ name: string; mountPath: string }> }>;
73
+ volumes?: Array<{ name: string; hostPath?: { path: string } }>;
74
+ } } } };
75
+ const podSpec = applied.spec?.template?.spec;
76
+ const childMounts = podSpec?.containers?.find((item) => item.name === 'child')?.volumeMounts ?? [];
77
+ const mountedPath = (name: string, mountPath: string): string | null => {
78
+ if (!childMounts.some((mount) => mount.name === name && mount.mountPath === mountPath)) return null;
79
+ return podSpec?.volumes?.find((volume) => volume.name === name)?.hostPath?.path ?? null;
80
+ };
81
+ const appliedCache = mountedPath('bun-cache', '/bun-cache');
82
+ const appliedSlots = mountedPath('install-slots', '/gate-install-slots');
83
+ if (appliedCache !== cache || appliedSlots !== slots) {
84
+ throw new Error(`applied Job hostPath mismatch: cache=${appliedCache} slots=${appliedSlots}`);
85
+ }
86
+ const pod = kubectl(['--context', context, '-n', namespace, 'get', 'pod', '-l', `job-name=${result.job}`, '-o', 'jsonpath={.items[0].spec.nodeName}']);
87
+ const child = readFileSync(join(result.artifactsDir, 'child.log'), 'utf8');
88
+ results.push({ arm, job: result.job, exitCode: result.exitCode, prep, hostPaths: [appliedCache, appliedSlots],
89
+ initContainers: applied.spec?.template?.spec?.initContainers?.map((item) => item.name) ?? [],
90
+ node: pod.status === 0 ? pod.stdout.trim() : '',
91
+ childWritable: child.includes('HOST_DIRS_WRITTEN'), artifactsError: result.artifacts?.error ?? null });
92
+ completed = true;
93
+ } finally {
94
+ if (completed) {
95
+ const deleted = kubectl(['--context', context, '-n', namespace, 'delete', 'job', name, '--ignore-not-found']);
96
+ if (deleted.status !== 0) throw new Error(`probe Job cleanup failed: ${name}: ${deleted.stderr.trim()}`);
97
+ } else console.error(`probe incomplete; retained Job for triage: ${name}`);
98
+ }
99
+ }
100
+ const [warm, fallback] = results;
101
+ const ok = warm?.prep?.ok === true && warm.initContainers.length === 0 && warm.exitCode === 0 && warm.childWritable && warm.artifactsError === null &&
102
+ fallback?.prep?.ok === false && fallback.initContainers.includes('host-dirs') && fallback.exitCode === 0 && fallback.childWritable && fallback.artifactsError === null &&
103
+ Boolean(warm.node && fallback.node);
104
+ console.log(JSON.stringify({ verdict: ok ? 'pass' : 'fail', measuredAt: new Date().toISOString(), sourceCommit,
105
+ context, namespace, image, results }));
106
+ if (!ok) process.exitCode = 1;
107
+ } finally {
108
+ resetHostDirsPrepMemo();
109
+ rmSync(artifactRoot, { recursive: true, force: true });
110
+ }
111
+ }
112
+
113
+ if (import.meta.main) main().catch((error) => { console.error(String(error)); process.exitCode = 2; });
@@ -7,6 +7,7 @@ import { join } from 'node:path';
7
7
  import { debug } from '../../src/debug/log.js';
8
8
  import { effectiveInstanceRoot, releaseLedgerRoot } from '../../src/instance/resolve.js';
9
9
  import { lastJsonObject, runGraph, type GraphRunState } from '../../src/graph-runner/runner.js';
10
+ import { withOpSeatFlock } from '../../src/steward/resync-tick.js';
10
11
  import { releaseRunUniverse } from './release-universe.js';
11
12
  import { isReleaseVersion } from './release-version.js';
12
13
  import { changedFilesBetween, clearPartialPlan, planPartialRegate, writePartialPlan } from './gate-partial.js';
@@ -104,9 +105,12 @@ export function refreshReleaseBranchTip(runId: string, deps: ResumeReleaseDeps =
104
105
  }
105
106
  // A new tip invalidates everything built from the old one (gate verdict, prepared archive, …): restart no later
106
107
  // than the first node that consumed the commit, so each of them runs again on the new tip.
107
- const firstConsumer = state.path.indexOf('gate');
108
+ // The public export now consumes the cut before the gate. Old saved graphs still have export-check after gate,
109
+ // so use the earliest consumer in this run's recorded path rather than assuming either graph version.
110
+ const consumers = ['export-check', 'gate'].map((node) => state.path.indexOf(node)).filter((index) => index >= 0);
111
+ const firstConsumer = consumers.length ? Math.min(...consumers) : -1;
108
112
  if (restartAt >= 0 && firstConsumer >= 0 && restartAt > firstConsumer) {
109
- throw new Error(`${branch} moved (${recorded.slice(0, 12)} → ${to.slice(0, 12)}): resume at gate or earlier — later nodes were built from the old tip`);
113
+ throw new Error(`${branch} moved (${recorded.slice(0, 12)} → ${to.slice(0, 12)}): resume at ${state.path[firstConsumer]} or earlier — later nodes were built from the old tip`);
110
114
  }
111
115
  const stamp = (deps.now?.() ?? new Date()).toISOString().replace(/[:.]/g, '-');
112
116
  const backup = `${statePath}.before-tip-${stamp}-${process.pid}-${to.slice(0, 12)}.bak`;
@@ -135,14 +139,20 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
135
139
  // Any resume starts from no plan: one without a partial plan (from whatever node) never inherits an older plan.
136
140
  clearPartialPlan(root, tip.version);
137
141
  const auto = opts.partial === undefined;
142
+ // The current graph checks public export before gate. A moved tip must resume there, so its gate still needs
143
+ // the diff plan; in older saved graphs export-check followed gate and cannot consume one.
144
+ const saved = JSON.parse(readFileSync(tip.statePath, 'utf8')) as GraphRunState;
145
+ const fromIndex = saved.path.indexOf(opts.from);
146
+ const gateIndex = saved.path.indexOf('gate');
147
+ const reachesGate = (opts.from === 'gate' || opts.from === 'export-check') && fromIndex >= 0 && gateIndex >= fromIndex;
138
148
  // The default applies only where it can help: a gate re-run on a tip that moved. An unchanged tip re-uses its own
139
149
  // shard results by commit already.
140
- if (opts.partial === false || (auto && (opts.from !== 'gate' || !tip.changed))) return { requested: false };
150
+ if (opts.partial === false || (auto && (!reachesGate || !tip.changed))) return { requested: false };
141
151
  const fallback = (reason: string): PartialOutcome => {
142
152
  debug.log('release-loop.resume', 'partial-fallback', { version: tip.version, reason, auto });
143
153
  return { requested: true, applied: false, reason, ...(auto ? { auto: true as const } : {}) };
144
154
  };
145
- if (opts.from !== 'gate') return fallback('--partial only applies to --from gate');
155
+ if (!reachesGate) return fallback('--partial requires a restart that reaches gate');
146
156
  if (!tip.changed) return fallback('release branch tip unchanged — nothing new to re-check');
147
157
  let prior: { commit?: unknown; failures?: unknown; errors?: unknown } | undefined;
148
158
  for (const location of [...new Set([deps.ledgerRoot ?? releaseLedgerRoot(), root])]) {
@@ -178,6 +188,19 @@ function preparePartial(tip: TipRefresh, opts: { from: string; partial?: boolean
178
188
  closure: (changedCode) => testsReachingChanged(tree, changedCode, tests, { cliEntries: CLI_ENTRIES }) });
179
189
  if (!planned.ok) return fallback(planned.reason);
180
190
  if (planned.plan.files.length >= tests.length) return fallback(`every test is re-run (${tests.length}) — full gate`);
191
+ if (planned.plan.kind === 'carry') {
192
+ // A cut-failures file can exist even when a later gate check errored. Reuse only a completed, clean verdict.
193
+ const verdicts = [...new Set([deps.ledgerRoot ?? releaseLedgerRoot(), root])].map((location) => join(location, 'release', tip.version, 'gate-verdict.json'));
194
+ let clean = false;
195
+ for (const verdictPath of verdicts) {
196
+ if (!existsSync(verdictPath)) continue;
197
+ try {
198
+ const verdict = JSON.parse(readFileSync(verdictPath, 'utf8')) as { commit?: unknown; outcome?: unknown };
199
+ if (verdict.commit === tip.from && verdict.outcome === 'ok') { clean = true; break; }
200
+ } catch { return fallback(`unreadable prior gate verdict: ${verdictPath}`); }
201
+ }
202
+ if (!clean) return fallback(`no clean gate verdict for ${tip.from.slice(0, 12)} — full gate`);
203
+ }
181
204
  const path = writePartialPlan(root, planned.plan);
182
205
  debug.log('release-loop.resume', 'partial-planned', { version: tip.version, priorCommit: tip.from, commit: tip.to, files: planned.plan.files.length,
183
206
  tests: tests.length, auto, path, ...(planned.closure ? { reached: planned.closure.reached, opaque: planned.closure.opaque } : {}) });
@@ -195,6 +218,12 @@ function savedGraphPath(statePath: string): string | undefined {
195
218
 
196
219
  /** Refresh the branch tip, then restart the failed run at `from` with the saved graph snapshot. */
197
220
  export async function resumeReleaseRun(opts: { runId: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[]; gateExecutor?: string; gateHost?: string }, deps: ResumeReleaseDeps = {}): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
221
+ // The lock root is the OP seat's (opSeatLockRoot), never the injected ledger root: a different `deps.root` must not
222
+ // move this run onto a separate lock inode from the steward resync and the unattended release.
223
+ return withOpSeatFlock(() => resumeReleaseRunLocked(opts, deps));
224
+ }
225
+
226
+ async function resumeReleaseRunLocked(opts: { runId: string; from: string; partial?: boolean; waive?: string; reason?: string; acceptedRegressions?: AcceptedRegression[]; gateExecutor?: string; gateHost?: string }, deps: ResumeReleaseDeps): Promise<{ tip: TipRefresh; partial: PartialOutcome; state: GraphRunState }> {
198
227
  if (opts.from === 'version-release') throw new Error('--from version-release would cut again — resume at a later node');
199
228
  // RELEASE-LEDGER-UNIVERSE: decide the universe once; the run lookup and every resumed node use it.
200
229
  deps = { ...deps, root: releaseRunUniverse({ root: deps.root }) };
@@ -35,7 +35,8 @@ const SWEEP_INCOMPLETE = /^(?:pod sweep incomplete|sweep incomplete|[\w-]+ shard
35
35
  * Fail-closed: only three shapes count, each read from what the runner and gate-node actually write:
36
36
  * ① stopped — `graph runs stop` wrote {ok:false, executed:false, exit:null, error:STOPPED_NODE_ERROR} as the run's last record;
37
37
  * ② no verdict — the gate process ended with exit null (signal, idle timeout, or a spawn that failed) and printed no result line at
38
- * all (no output line is a JSON object with an `outcome`), so the run went gate → failed. A verdict followed by more
38
+ * all (no output line is a JSON object with an `outcome`), so the run went gate → failed (possibly through the
39
+ * release-only gate-triage shadow). A verdict followed by more
39
40
  * log lines and then a kill is still a verdict: refused;
40
41
  * ③ sweep incomplete — gate-node printed outcome `error` (no verdict: the baseline comparison never ran, so `introduced`
41
42
  * is still the empty initial list) and the error is an incomplete sweep (stalled shards / no tests ran). The finished
@@ -52,6 +53,14 @@ function printedVerdict(output: unknown): boolean {
52
53
  });
53
54
  }
54
55
 
56
+ /** The only post-gate detour allowed before the terminal failure is the executed, release-only triage shadow. */
57
+ function failedAfterGate(state: GraphRunState, index: number): boolean {
58
+ if (state.nodes.length !== state.path.length || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') return false;
59
+ if (index === state.path.length - 2) return true;
60
+ return index === state.path.length - 3 && state.path[index + 1] === 'gate-triage'
61
+ && state.nodes[index + 1]?.nodeId === 'gate-triage' && state.nodes[index + 1]?.executed === true;
62
+ }
63
+
55
64
  export function gateUnmeasuredDetail(state: GraphRunState, index: number): string | undefined {
56
65
  const record = state.nodes[index];
57
66
  if (!record || record.nodeId !== 'gate' || state.path[index] !== 'gate' || record.ok !== false || record.waiver !== undefined) return undefined;
@@ -60,9 +69,7 @@ export function gateUnmeasuredDetail(state: GraphRunState, index: number): strin
60
69
  if (last && record.executed === false && record.exit === null && record.error === STOPPED_NODE_ERROR && record.output === undefined) {
61
70
  return `stopped: ${STOPPED_NODE_ERROR}${typeof record.seconds === 'number' ? ` after ${record.seconds}s` : ''}`;
62
71
  }
63
- const failedAfter = index === state.path.length - 2 && state.path.at(-1) === 'failed' && state.nodes.at(-1)?.nodeId === 'failed'
64
- && state.nodes.length === state.path.length;
65
- if (!failedAfter || record.executed !== true) return undefined;
72
+ if (!failedAfterGate(state, index) || record.executed !== true) return undefined;
66
73
  const result = lastJsonObject(record.output);
67
74
  if (result === undefined) {
68
75
  if (record.exit !== null || printedVerdict(record.output)) return undefined;
@@ -105,7 +112,8 @@ export function releaseResumeWaiver(
105
112
  [...(opts.acceptedRegressions ?? []), { id: `waive:${opts.waive}`, note: reason }]) };
106
113
  }
107
114
  if (!unique || state.path.lastIndexOf(opts.waive) !== index || state.nodes[index]?.nodeId !== opts.waive || state.nodes[index]?.ok !== false ||
108
- state.nodes[index]?.executed !== true || state.path.at(-2) !== opts.waive || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed') {
115
+ state.nodes[index]?.executed !== true || (opts.waive === 'gate' ? !failedAfterGate(state, index)
116
+ : state.path.at(-2) !== opts.waive || state.path.at(-1) !== 'failed' || state.nodes.at(-1)?.nodeId !== 'failed')) {
109
117
  throw new Error(`--waive ${opts.waive} requires the failed executable node on the saved path`);
110
118
  }
111
119
  // Only user-visible, non-publication checks can become accepted regressions; build, safety and approval gates stay blocking.
@@ -1,4 +1,6 @@
1
1
  import { planShards } from './shard-plan';
2
+ import { isGateSpawnLaneFile } from '../../src/self-dev/spawn-lane-files.js';
3
+ export { GATE_SPAWN_LANE_FILES, isGateSpawnLaneFile } from '../../src/self-dev/spawn-lane-files.js';
2
4
 
3
5
  /**
4
6
  * Gate tests that exercise a real process or PTY. Keep them in their own Pod
@@ -9,27 +11,8 @@ import { planShards } from './shard-plan';
9
11
  * real child. Add a file only after checking its test body, not merely because
10
12
  * its name mentions a process.
11
13
  */
12
- export const GATE_SPAWN_LANE_FILES = [
13
- 'scripts/lib/tui-runshell-group-e2e.test.ts',
14
- 'scripts/lib/tui-streaming-e2e.test.ts',
15
- 'src/agent-mission/doc-guided-install.test.ts',
16
- 'src/dashboard/first-screen-band-wiring.test.ts',
17
- 'src/git-fs/spawn-discipline.test.ts',
18
- 'src/self-implement/run-ledger.test.ts',
19
- 'src/video-pipeline/recipes/reframe.test.ts',
20
- 'test/ch5730-watch-delivery.test.ts',
21
- 'test/cli-dev-command.test.ts',
22
- 'test/preview-terminal.test.ts',
23
- ] as const;
24
-
25
- const SPAWN_FILES = new Set<string>(GATE_SPAWN_LANE_FILES);
26
-
27
14
  export const GATE_SPAWN_LANE_SHARDS = 3;
28
15
 
29
- export function isGateSpawnLaneFile(file: string): boolean {
30
- return SPAWN_FILES.has(file);
31
- }
32
-
33
16
  /** Every assigned test file is returned exactly once, including a partial gate. */
34
17
  export function partitionGateSpawnLane(files: readonly string[]): { regular: string[]; spawn: string[] } {
35
18
  const regular: string[] = [];
@@ -12,6 +12,7 @@
12
12
  * Exit: 0 = pass or flaky · 1 = fail · 2 = could not run (not macOS, worktree).
13
13
  */
14
14
  import { spawn, spawnSync } from 'node:child_process';
15
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../src/util/spawn-sync-output.js';
15
16
  import { copyFileSync, existsSync, mkdtempSync, openSync, symlinkSync } from 'node:fs';
16
17
  import { tmpdir } from 'node:os';
17
18
  import { basename, join, resolve } from 'node:path';
@@ -101,7 +102,7 @@ async function main(): Promise<number> {
101
102
  let regress: TuiRegress = { unmeasured: 'worktree를 만들지 못했다' };
102
103
  let worktreeReady = false;
103
104
  try {
104
- const add = spawnSync('git', ['worktree', 'add', '--detach', worktree, commit], { cwd: repo, encoding: 'utf8' });
105
+ const add = spawnSync('git', ['worktree', 'add', '--detach', worktree, commit], { cwd: repo, encoding: 'utf8', maxBuffer: SPAWN_SYNC_MAX_BUFFER });
105
106
  if (add.status !== 0) throw new Error(`worktree add failed: ${(add.stderr ?? '').trim()}`);
106
107
  worktreeReady = true;
107
108
  symlinkSync(join(repo, 'node_modules'), join(worktree, 'node_modules'));
@@ -119,7 +120,7 @@ async function main(): Promise<number> {
119
120
  attempts = [];
120
121
  } finally {
121
122
  if (worktreeReady) regress = measureTuiRegress(worktree);
122
- spawnSync('git', ['worktree', 'remove', '--force', worktree], { cwd: repo });
123
+ spawnSync('git', ['worktree', 'remove', '--force', worktree], { cwd: repo, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
123
124
  }
124
125
 
125
126
  const out = tuiNodeOutput(commit, attempts, regress, failure);
@@ -9,6 +9,7 @@ import { getSchedule } from '../../src/release-loop/release-schedule.js';
9
9
  import { isLandingFreezeRefusal, readLandingFreeze, LandingFrozenError } from '../../src/release-loop/landing-freeze.js';
10
10
  import { debug } from '../../src/debug/log.js';
11
11
  import { runGraph, type GraphRunState } from '../../src/graph-runner/runner.js';
12
+ import { withOpSeatFlock } from '../../src/steward/resync-tick.js';
12
13
  import { releaseRunUniverse } from './release-universe.js';
13
14
  import { baseVersion, isStableVersion, nextPrereleaseVersion, type PrereleaseKind } from './release-version.js';
14
15
  import { publishAtError } from './publish-at.js';
@@ -27,6 +28,10 @@ export interface ReleaseLoopConfig {
27
28
  gatePodInstallSlots?: number;
28
29
  /** GATE-MEM-ADMIT — seconds a gate shard waits for pool admission (memory headroom) before launching anyway with `admission-timeout` (default 300 · 0 = off). */
29
30
  gatePodAdmissionWaitSeconds?: number;
31
+ /** Maximum simultaneous file-level isolation retries across all gate shards (default 4). */
32
+ gatePodIsolationConcurrency?: number;
33
+ /** Final isolated recheck files per window; overflow continues in later windows (default 32). */
34
+ gateRecheckFileLimit?: number;
30
35
  /** GATE-SPEED A3①: gate shard Pod CPU — `2` (request = limit) or `{ request, limit }`. Omitted = request 1 / limit 4. */
31
36
  gatePodCpu?: number | string | { request?: number | string; limit?: number | string };
32
37
  gateRemote?: string;
@@ -135,6 +140,17 @@ export function buildReleaseRunInput(version: string, deps: UnattendedReleaseDep
135
140
  export async function runUnattendedRelease(
136
141
  opts: { version: string; dryRun?: boolean; cutCommit?: string; forceFreeze?: boolean; mainCut?: boolean; prerelease?: PrereleaseKind; publishAt?: string; gateExecutor?: string; gateHost?: string },
137
142
  deps: UnattendedReleaseDeps = {},
143
+ ): Promise<{ input: ReleaseRunInput; dryRun: boolean; state?: GraphRunState }> {
144
+ // A dry run only builds the input and mutates nothing, so it neither creates nor waits on the OP-seat lock.
145
+ if (opts.dryRun) return runUnattendedReleaseLocked(opts, deps);
146
+ // The lock root is the OP seat's (opSeatLockRoot), never the injected ledger root: a different `deps.ledgerRoot` must
147
+ // not move this run onto a separate lock inode from the steward resync and a manual resume.
148
+ return withOpSeatFlock(() => runUnattendedReleaseLocked(opts, deps));
149
+ }
150
+
151
+ async function runUnattendedReleaseLocked(
152
+ opts: { version: string; dryRun?: boolean; cutCommit?: string; forceFreeze?: boolean; mainCut?: boolean; prerelease?: PrereleaseKind; publishAt?: string; gateExecutor?: string; gateHost?: string },
153
+ deps: UnattendedReleaseDeps,
138
154
  ): Promise<{ input: ReleaseRunInput; dryRun: boolean; state?: GraphRunState }> {
139
155
  // RELEASE-BRANCH (10-06): the default cut is a release branch, so main keeps landing and the run no longer needs a
140
156
  // landing freeze. A freeze stays the emergency switch: when one is on, it still stops the run (`--force-freeze` overrides).
@@ -39,44 +39,15 @@ import * as ts from 'typescript';
39
39
  // importing THIS file used to spawn the suite at load time. The runner is now
40
40
  // behind `import.meta.main` / `runDeterministicTests()`, but the filter stays
41
41
  // in the helper so an untested credential check cannot rot silently.
42
- import { isCredentialKey } from './lib/deterministic-env.js';
43
- import { envLiteral } from '../src/platform/env-literal.js';
42
+ import { GIT_LOCATION_ENV_KEYS, prepareIsolatedTestEnv } from './lib/deterministic-env.js';
44
43
 
45
44
  export const TEMP_ROOT_PREFIX = 'elanous-deterministic-test-';
46
45
  export const CHILD_EXIT_GRACE_MS = 2_000;
47
46
 
48
- // A deterministic test child is not a harness executor: these inherited
49
- // markers would activate write-boundary policy against each test's temp files.
50
- const HARNESS_TEST_ENV_KEYS = [
51
- 'ELANOUS_HARNESS_SPACE',
52
- 'ELANOUS_HARNESS_SPACE_ID',
53
- 'ELANOUS_HARNESS_BOUNDARY',
54
- 'ELANOUS_HARNESS_ROLE',
55
- 'ELANOUS_HARNESS_DETACHED',
56
- ] as const;
57
-
58
- // Discovery: rg -n "process\.env\.ELANOUS_(HOST|RUN|ORIGIN|SUPERVISOR|PARENT)" src
59
- // These are ambient execution identities, not inputs to a deterministic test.
60
- // debug.log also attributes SUBSTRATE and ARM_ID to every plain-object record.
61
- export const GIT_LOCATION_ENV_KEYS = [
62
- 'GIT_DIR', 'GIT_WORK_TREE', 'GIT_COMMON_DIR', 'GIT_INDEX_FILE',
63
- 'GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES',
64
- ] as const;
65
-
66
- const EXECUTION_ORIGIN_ENV_KEYS = [
67
- 'ELANOUS_HOST_ID',
68
- 'ELANOUS_RUN_ID',
69
- 'ELANOUS_RUN_CONTEXT',
70
- 'ELANOUS_PARENT_RUN_ID',
71
- 'ELANOUS_PARENT_PTY_ID',
72
- 'ELANOUS_PARENT_SELF_DEV_RUNS_DIR',
73
- 'ELANOUS_SUBSTRATE',
74
- 'ELANOUS_ARM_ID',
75
- // Parent account selection changes CLI rotation assertions in the child.
76
- 'ELANOUS_CODEX_ACCOUNT',
77
- // A parent's derived-root label must not reclassify a test's explicit state dir.
78
- 'ELANOUS_STATE_DIR_SOURCE',
79
- ] as const;
47
+ // Key lists and the isolated child env live in the side-effect-free `lib/deterministic-env.ts` (R7 · 10-16):
48
+ // the host regate runner needs the same env, and importing this file would pull `typescript`/Bun stream types into
49
+ // graphs (the PWA tsc program) that must not see them.
50
+ export { GIT_LOCATION_ENV_KEYS, prepareIsolatedTestEnv } from './lib/deterministic-env.js';
80
51
 
81
52
  export type ShutdownSignal = 'SIGINT' | 'SIGTERM';
82
53
 
@@ -297,33 +268,6 @@ function gitConfig(cwd: string, args: string[]): string | undefined {
297
268
  return args.includes('--get-all') ? result.stdout : result.stdout.trim();
298
269
  }
299
270
 
300
- export function prepareIsolatedTestEnv(sourceEnv: NodeJS.ProcessEnv, testRoot: string): NodeJS.ProcessEnv {
301
- const env = Object.fromEntries(
302
- Object.entries(sourceEnv).filter(([key]) => !isCredentialKey(key)
303
- && !HARNESS_TEST_ENV_KEYS.includes(key as typeof HARNESS_TEST_ENV_KEYS[number])
304
- && !EXECUTION_ORIGIN_ENV_KEYS.includes(key as typeof EXECUTION_ORIGIN_ENV_KEYS[number])
305
- && !GIT_LOCATION_ENV_KEYS.includes(key as typeof GIT_LOCATION_ENV_KEYS[number])),
306
- );
307
- env.HOME = testRoot;
308
- // userConfigPath() warns whenever XDG_CONFIG_HOME is set, including when
309
- // config.json is absent. Use its non-XDG path; migrateLegacyXdgUserConfig()
310
- // resolves the old path through ELANOUS_TEST_HOME rather than the real home.
311
- delete env.XDG_CONFIG_HOME;
312
- env.ELANOUS_TEST_HOME = testRoot;
313
- // HOME and ELANOUS_STATE_DIR isolate both the state and default config roots.
314
- // ELANOUS_CONFIG_DIR is not a config-dir override; discard an inherited value
315
- // rather than passing an ignored variable that appears to provide isolation.
316
- env.ELANOUS_STATE_DIR = join(testRoot, 'state');
317
- delete env.ELANOUS_CONFIG_DIR;
318
- // All ambient execution identities are removed by EXECUTION_ORIGIN_ENV_KEYS
319
- // above, before the child is spawned; logger API-shape tests need their absence.
320
- // ⚠️ No `ELANOUS_TEST_DETERMINISTIC` marker is exported. Nothing reads it yet,
321
- // and an env var with no consumer is a surface that looks like a contract
322
- // while guaranteeing nothing — a later test could branch on it believing it
323
- // means something. The tier work in PLAN-test-suite-diet introduces the
324
- // signal together with the code that honours it.
325
- return envLiteral(env);
326
- }
327
271
 
328
272
  /** Read every stderr line, retaining only Bun's verdict signals. A long test
329
273
  * log must not become a second in-memory copy of the full output. */
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bun
2
+ import { existsSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { isAbsolute, resolve } from 'node:path';
4
+ import { buildTrainReachDecision, type TrainReachInput } from '../src/self-implement/train-reach-grouping.js';
5
+ import { buildTrainScenarioDecision, readTrainTestPopulation, type TrainRiskEvidence } from '../src/self-implement/train-scenario-layers.js';
6
+
7
+ type ScenarioInput = TrainReachInput & { riskEvidence?: TrainRiskEvidence };
8
+
9
+ function option(name: string): string {
10
+ const index = process.argv.indexOf(name);
11
+ const value = process.argv[index + 1];
12
+ if (index < 0 || !value || value.startsWith('--') || !isAbsolute(value)) throw new Error(`${name} requires an absolute path`);
13
+ return value;
14
+ }
15
+
16
+ let temporary = '';
17
+ let outputPath = '';
18
+ let protectsInput = false;
19
+ try {
20
+ if (process.argv.length !== 6) throw new Error('usage: train-reach-grouping.ts --input <absolute> --output <absolute>');
21
+ const inputPath = option('--input');
22
+ outputPath = option('--output');
23
+ if (!existsSync(inputPath)) throw new Error('input file missing');
24
+ protectsInput = resolve(inputPath) === resolve(outputPath)
25
+ || (existsSync(outputPath) && realpathSync(inputPath) === realpathSync(outputPath));
26
+ if (protectsInput) throw new Error('input and output paths must differ');
27
+ const input = JSON.parse(readFileSync(inputPath, 'utf8')) as ScenarioInput;
28
+ const reach = buildTrainReachDecision(input);
29
+ const scenario = input.riskEvidence === undefined ? undefined : (() => {
30
+ if (input.prs.length === 0) throw new Error('scenario has no PR tree for pinned population');
31
+ const baseTests = readTrainTestPopulation(input.prs[0]!.tree, input.baseSha);
32
+ const headTests = input.prs.map((candidate) => new Set(readTrainTestPopulation(candidate.tree, candidate.headSha)));
33
+ const survivingTests = baseTests.filter((test) => headTests.every((present) => present.has(test)));
34
+ return buildTrainScenarioDecision(input, reach, survivingTests, input.riskEvidence!);
35
+ })();
36
+ const result = scenario ? { ...reach, scenario, parallelSafe: scenario.parallelSafe } : reach;
37
+ temporary = `${outputPath}.tmp-${process.pid}`;
38
+ writeFileSync(temporary, JSON.stringify(result, null, 2) + '\n', { flag: 'wx' });
39
+ renameSync(temporary, outputPath);
40
+ temporary = '';
41
+ if (!result.parallelSafe) process.exitCode = 2;
42
+ } catch (error) {
43
+ if (outputPath && !protectsInput) rmSync(outputPath, { force: true }); // never reuse a previous decision after failure
44
+ console.error(`train reach unmeasured: ${error instanceof Error ? error.message : String(error)}`);
45
+ process.exitCode = 2;
46
+ } finally {
47
+ if (temporary) rmSync(temporary, { force: true });
48
+ }