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
@@ -0,0 +1,253 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
3
+ import { parseFailures } from './gate-diff.js';
4
+ import { isCompleteOneFileGateJunit, parseXml, type XmlElement } from '../../src/self-dev/shard-aggregate.js';
5
+ import type { WarmWorkerFileResult } from '../../src/task-orchestrator/surfaces/pod-warm-worker-protocol.js';
6
+
7
+ const relative = (path: string) => path.replace(/^(?:\.\.\/)*\/?home\/ubuntu\/repo\//, '').replace(/^\.\//, '');
8
+ const lastCount = (log: string, name: string): number | null => {
9
+ let count: number | null = null;
10
+ for (const match of log.matchAll(new RegExp(`(?:^|\\n)\\s*(\\d+) ${name}s?\\s*(?=\\n|$)`, 'g'))) count = Number(match[1]);
11
+ return count;
12
+ };
13
+ const validXmlCodePoint = (code: number): boolean => Number.isSafeInteger(code)
14
+ && (code === 9 || code === 10 || code === 13 || code >= 0x20 && code <= 0xd7ff
15
+ || code >= 0xe000 && code <= 0xfffd || code >= 0x10000 && code <= 0x10ffff);
16
+ const numericXmlEntitiesValid = (value: string): boolean => [...value.matchAll(/&#(x[0-9a-fA-F]+|[0-9]+);/g)]
17
+ .every((match) => validXmlCodePoint(match[1]!.startsWith('x') ? parseInt(match[1]!.slice(1), 16) : parseInt(match[1]!, 10)));
18
+ const xmlText = (value: string): string => value.replace(/&#(x[0-9a-fA-F]+|[0-9]+);|&(amp|lt|gt|quot|apos);/g, (match, numeric: string | undefined, named: string | undefined) => {
19
+ if (numeric) {
20
+ const code = numeric.startsWith('x') ? parseInt(numeric.slice(1), 16) : parseInt(numeric, 10);
21
+ return validXmlCodePoint(code) ? String.fromCodePoint(code) : match;
22
+ }
23
+ return ({ amp: '&', lt: '<', gt: '>', quot: '"', apos: "'" } as Record<string, string>)[named ?? ''] ?? match;
24
+ });
25
+ const failureDetail = (value: string): string => xmlText(value).replace(/\x1b\[[0-9;]*[A-Za-z]/g, '').replace(/\r\n/g, '\n').trim();
26
+ function junitFailureDetails(xml: string): Map<string, string> {
27
+ const details = new Map<string, string>();
28
+ const root = parseXml(xml);
29
+ if (!root) return details;
30
+ const walkSuite = (suite: XmlElement, file: string, names: string[]): void => {
31
+ const suiteFile = file || suite.attrs.file || suite.attrs.name || '';
32
+ const nestedNames = file ? [...names, suite.attrs.name ?? ''] : names;
33
+ for (const child of suite.children) {
34
+ if (child.name === 'testsuite') { walkSuite(child, suiteFile, nestedNames); continue; }
35
+ if (child.name !== 'testcase') continue;
36
+ const id = `${relative(child.attrs.file ?? suiteFile)} > ${[...nestedNames, child.attrs.name ?? ''].join(' > ')}`;
37
+ const failures = child.children.filter((element) => element.name === 'failure');
38
+ // One log failure line cannot identify which of several JUnit failure
39
+ // elements it belongs to. Leave the case unmeasured instead of allowing
40
+ // a later element to overwrite an earlier, different diagnostic.
41
+ if (failures.length > 1) { details.set(id, ''); continue; }
42
+ for (const failure of failures) {
43
+ const diagnostic = failure.attrs.message === undefined ? '' : failureDetail(failure.attrs.message);
44
+ const bodyLines = failure.text.split(/\r?\n/);
45
+ const stackAt = bodyLines.findIndex(line => /^\s*at\s/.test(line));
46
+ const body = failureDetail((stackAt < 0 ? bodyLines : bodyLines.slice(0, stackAt)).join('\n')
47
+ .replace(new RegExp(`^${(failure.attrs.type ?? 'Error').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}:[ \\t]*`), ''));
48
+ details.set(id, body && body !== diagnostic ? '' : diagnostic);
49
+ }
50
+ }
51
+ };
52
+ if (root.name === 'testsuite') walkSuite(root, '', []);
53
+ else if (root.name === 'testsuites') for (const suite of root.children) if (suite.name === 'testsuite') walkSuite(suite, '', []);
54
+ return details;
55
+ }
56
+ function logFailureDetails(log: string): Map<string, string> | null {
57
+ const details = new Map<string, string>();
58
+ let file = '';
59
+ let block: string[] = [];
60
+ let errorCount = 0;
61
+ let unboundError = false;
62
+ for (const raw of log.split(/\r?\n/)) {
63
+ const line = raw.trim();
64
+ const header = /^(?:\.\/)?((?:[\w.-]+\/)+[\w.-]+\.test\.tsx?):(?:\s|$)/.exec(line);
65
+ if (header) { if (errorCount > 0) unboundError = true; file = relative(header[1]!); block = []; errorCount = 0; continue; }
66
+ const failed = /\(fail\)\s+(.+?)(?:\s+\[[\d.]+(?:ms|s)\])?$/.exec(line);
67
+ if (failed && file) {
68
+ // Bun's JUnit message includes multiline assertion diffs but excludes
69
+ // the stack. Compare the complete normalized diagnostic, never a prefix.
70
+ const stackAt = block.findIndex(item => /^\s*at\s/.test(item));
71
+ const diagnostic = stackAt < 0 ? block : block.slice(0, stackAt);
72
+ details.set(`${file} > ${failed[1]!.trim()}`, errorCount === 1 ? failureDetail(diagnostic.join('\n')) : '');
73
+ block = []; errorCount = 0;
74
+ continue;
75
+ }
76
+ if (/^error:\s*/i.test(line)) { block = [raw.replace(/^\s*error:\s*/i, '')]; errorCount++; }
77
+ else if (errorCount > 0 && !/^\(pass\)/.test(line)) block.push(raw);
78
+ else if (/^\(pass\)/.test(line)) { if (errorCount > 0) unboundError = true; block = []; errorCount = 0; }
79
+ }
80
+ // An error after the last named failure has no JUnit testcase to bind it.
81
+ // Bun can omit the numeric `errors` summary, so the open diagnostic itself
82
+ // must make the reference unmeasured.
83
+ return unboundError || errorCount > 0 ? null : details;
84
+ }
85
+ function junitCases(root: XmlElement): Array<{ file: string; id: string; failed: boolean; error: boolean; skipped: boolean }> {
86
+ const cases: Array<{ file: string; id: string; failed: boolean; error: boolean; skipped: boolean }> = [];
87
+ const walkSuite = (suite: XmlElement, file: string, names: string[]): void => {
88
+ const suiteFile = file || suite.attrs.file || suite.attrs.name || '';
89
+ const nestedNames = file ? [...names, suite.attrs.name ?? ''] : names;
90
+ for (const child of suite.children) {
91
+ if (child.name === 'testsuite') { walkSuite(child, suiteFile, nestedNames); continue; }
92
+ if (child.name !== 'testcase') continue;
93
+ const caseFile = relative(child.attrs.file ?? suiteFile);
94
+ cases.push({ file: caseFile, id: `${caseFile} > ${[...nestedNames, child.attrs.name ?? ''].join(' > ')}`,
95
+ failed: child.children.some((element) => element.name === 'failure'),
96
+ error: child.children.some((element) => element.name === 'error'),
97
+ skipped: child.children.some((element) => element.name === 'skipped') });
98
+ }
99
+ };
100
+ if (root.name === 'testsuite') walkSuite(root, '', []);
101
+ else if (root.name === 'testsuites') for (const suite of root.children) if (suite.name === 'testsuite') walkSuite(suite, '', []);
102
+ return cases;
103
+ }
104
+ function logPassIds(log: string): string[] {
105
+ const ids: string[] = [];
106
+ let file = '';
107
+ for (const raw of log.split(/\r?\n/)) {
108
+ const line = raw.trim();
109
+ const header = /^(?:\.\/)?((?:[\w.-]+\/)+[\w.-]+\.test\.tsx?):(?:\s|$)/.exec(line);
110
+ if (header) { file = relative(header[1]!); continue; }
111
+ const passed = /^\(pass\)\s+(.+?)(?:\s+\[[\d.]+(?:ms|s)\])?$/.exec(line);
112
+ if (passed && file) ids.push(`${file} > ${passed[1]!.trim()}`);
113
+ }
114
+ return ids.sort();
115
+ }
116
+ const MAX_WARM_ARTIFACT_BYTES = 64 * 1024 * 1024;
117
+ const readMaybe = (path: string): Buffer | null => {
118
+ try { return statSync(path).size <= MAX_WARM_ARTIFACT_BYTES ? readFileSync(path) : null; }
119
+ catch { return null; }
120
+ };
121
+ const sha256 = (value: Buffer): string => createHash('sha256').update(value).digest('hex');
122
+
123
+ /** Bind a completed one-file Job's collected outbox to its host metadata. */
124
+ export function writeWarmJobManifest(prefix: string, file: string, cutSha: string, attemptId: string): boolean {
125
+ const meta = readMaybe(`${prefix}.json`);
126
+ const log = readMaybe(`${prefix}.log`);
127
+ const junit = readMaybe(`${prefix}.junit.xml`);
128
+ const rcBytes = readMaybe(`${prefix}.rc`);
129
+ if (!meta || !log || !junit || !rcBytes || !file || !cutSha || !attemptId) return false;
130
+ let row: Record<string, unknown>;
131
+ try { row = JSON.parse(meta.toString('utf8')) as Record<string, unknown>; } catch { return false; }
132
+ if (!row || typeof row !== 'object' || Array.isArray(row) || row.commit !== cutSha
133
+ || row.attemptId !== attemptId || !Array.isArray(row.files) || row.files.length !== 1 || row.files[0] !== file
134
+ || (row.rc !== 0 && row.rc !== 1) || row.jobFailed !== false || row.jobExitCode !== 0
135
+ || rcBytes.toString('utf8').trim() !== String(row.rc)) return false;
136
+ writeFileSync(`${prefix}.warm-manifest.json`, JSON.stringify({ protocol: 1, cutSha, attemptId, file, rc: row.rc,
137
+ logSha256: sha256(log), junitSha256: sha256(junit), metaSha256: sha256(meta), rcSha256: sha256(rcBytes) }) + '\n', { mode: 0o600 });
138
+ return true;
139
+ }
140
+
141
+ /** Convert only a cut/attempt-bound, complete one-file artifact set. */
142
+ export function warmReferenceFromJobArtifacts(prefix: string, file: string, expected: { cutSha: string; attemptId: string }): WarmWorkerFileResult | null {
143
+ if (!file || !expected?.cutSha || !expected?.attemptId
144
+ || !existsSync(`${prefix}.log`)
145
+ || !existsSync(`${prefix}.junit.xml`) || !existsSync(`${prefix}.json`)
146
+ || !existsSync(`${prefix}.rc`) || !existsSync(`${prefix}.warm-manifest.json`)) return null;
147
+ let rc: number;
148
+ const metadata = readMaybe(`${prefix}.json`);
149
+ if (metadata === null) return null;
150
+ {
151
+ let meta: unknown;
152
+ try { meta = JSON.parse(metadata.toString('utf8')); } catch { return null; }
153
+ if (!meta || typeof meta !== 'object' || Array.isArray(meta)) return null;
154
+ const row = meta as Record<string, unknown>;
155
+ if ((row.rc !== 0 && row.rc !== 1) || row.jobFailed !== false || row.jobExitCode !== 0
156
+ || !Array.isArray(row.files) || row.files.length !== 1 || row.files[0] !== file
157
+ || row.commit !== expected.cutSha || row.attemptId !== expected.attemptId) return null;
158
+ rc = row.rc;
159
+ }
160
+ const logBytes = readMaybe(`${prefix}.log`);
161
+ const xmlBytes = readMaybe(`${prefix}.junit.xml`);
162
+ const rcBytes = readMaybe(`${prefix}.rc`);
163
+ if (logBytes === null || xmlBytes === null || rcBytes === null || rcBytes.toString('utf8').trim() !== String(rc)) return null;
164
+ {
165
+ let manifest: unknown;
166
+ try { manifest = JSON.parse(readMaybe(`${prefix}.warm-manifest.json`)?.toString('utf8') ?? ''); } catch { return null; }
167
+ if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) return null;
168
+ const bound = manifest as Record<string, unknown>;
169
+ if (bound.protocol !== 1 || bound.cutSha !== expected.cutSha || bound.attemptId !== expected.attemptId
170
+ || bound.file !== file || bound.rc !== rc || bound.logSha256 !== sha256(logBytes)
171
+ || bound.junitSha256 !== sha256(xmlBytes) || bound.metaSha256 !== sha256(metadata)
172
+ || bound.rcSha256 !== sha256(rcBytes)) return null;
173
+ }
174
+ const log = logBytes.toString('utf8').replace(/\x1b\[[0-9;]*[A-Za-z]/g, '');
175
+ const xml = xmlBytes.toString('utf8');
176
+ if (!numericXmlEntitiesValid(xml)) return null;
177
+ const sourceBindings = [...log.matchAll(/^\[warm-worker\] cut=([^\s]+) attempt=([^\s]+)$/gm)];
178
+ if (sourceBindings.length !== 1 || sourceBindings[0]![1] !== expected.cutSha
179
+ || sourceBindings[0]![2] !== expected.attemptId
180
+ || sourceBindings[0]!.index! > log.indexOf('bun test v')) return null;
181
+ // The one-file shell writes the JUnit digest into its log before collection.
182
+ // A new host manifest cannot legitimize a JUnit from another Job whose
183
+ // message matches but exception type or stack location differs.
184
+ const junitBindings = [...log.matchAll(/^\[warm-worker\] junit-sha256=([0-9a-f]{64})$/gm)];
185
+ if (junitBindings.length !== 1 || junitBindings[0]![1] !== sha256(xmlBytes)) return null;
186
+ // Bind the run command to the requested file before comparing result names.
187
+ // Legacy one-shot Jobs record the wrapper invocation; the resident worker
188
+ // writes a dedicated header.
189
+ const workerSources = [...log.matchAll(/^\[warm-worker\] file=([^\s]+)$/gm)].map(match => match[1]);
190
+ const jobSources = [...log.matchAll(/^\$ bun run scripts\/test-deterministic\.ts[^\n]*$/gm)].map(match => match[0]);
191
+ const bunSources = [...log.matchAll(/^(?:\.\/)?([A-Za-z0-9_./-]+\.test\.tsx?):(?:\r?\n|$)/gm)].map(match => relative(match[1]!));
192
+ const escapedFile = file.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
193
+ const invokedFile = jobSources[0] && new RegExp(`(?:^|[\\s"'])(?:\\.\\/)?${escapedFile}(?=$|[\\s"'])`).test(jobSources[0]);
194
+ if (workerSources.length > 1 || jobSources.length > 1
195
+ || (workerSources.length === 1 && workerSources[0] !== file)
196
+ || (jobSources.length === 1 && !invokedFile)
197
+ || (workerSources.length === 1 && (bunSources.length !== 1 || bunSources[0] !== file))
198
+ || (jobSources.length === 1 && bunSources.some(source => source !== file))
199
+ || (workerSources.length === 0 && jobSources.length === 0)) return null;
200
+ const runStarts = [...log.matchAll(/(?:^|\n)bun test v[^\n]*/g)];
201
+ const runSummaries = [...log.matchAll(/Ran (\d+) tests? across (\d+) files?/g)];
202
+ if (runSummaries.length !== 1 || (existsSync(`${prefix}.json`) && runStarts.length !== 1)) return null;
203
+ const root = parseXml(xml);
204
+ const cases = root ? junitCases(root) : [];
205
+ const declared = root ? Number(root.attrs.tests) : NaN;
206
+ if (!root || !isCompleteOneFileGateJunit(xml, file) || !cases.length || !Number.isSafeInteger(declared) || declared !== cases.length
207
+ || cases.some(item => item.file !== file || item.error || item.skipped)) return null;
208
+ const failureIds = cases.filter(item => item.failed).map(item => item.id).sort();
209
+ // Dots-only success logs lack test identities. A same-file, same-count
210
+ // JUnit can then be rebound with a fresh manifest, so fail closed.
211
+ {
212
+ const allIds = cases.map(item => item.id).sort();
213
+ // A duplicate name cannot identify which JUnit case matches which log
214
+ // line, even when the counts and diagnostics happen to agree.
215
+ if (new Set(allIds).size !== allIds.length) return null;
216
+ const fromXml = allIds.filter(id => !failureIds.includes(id));
217
+ const fromLog = logPassIds(log);
218
+ if (fromXml.length !== cases.length - failureIds.length || fromLog.length !== fromXml.length
219
+ || fromXml.some((id, index) => id !== fromLog[index])) return null;
220
+ }
221
+ // A manifest can be rebound after mixing two complete runs. Match each
222
+ // failure's content, not only its test name, against the captured log.
223
+ const xmlDetails = junitFailureDetails(xml);
224
+ const logDetails = logFailureDetails(log);
225
+ if (!logDetails || xmlDetails.size !== failureIds.length || logDetails.size !== failureIds.length
226
+ || [...xmlDetails].some(([id, message]) => !message || logDetails.get(id) !== message)) return null;
227
+ const loggedFailureIds = parseFailures(log).map(id => {
228
+ const at = id.indexOf(' > ');
229
+ return at < 0 ? id : `${relative(id.slice(0, at))}${id.slice(at)}`;
230
+ });
231
+ if (failureIds.length !== loggedFailureIds.length
232
+ || failureIds.some(id => !loggedFailureIds.includes(id))) return null;
233
+ const passes = lastCount(log, 'pass');
234
+ const fails = lastCount(log, 'fail');
235
+ // Bun omits the error counter entirely when it is zero.
236
+ const errors = lastCount(log, 'error') ?? 0;
237
+ const ran = runSummaries[0];
238
+ const ranEnd = ran === undefined ? -1 : ran.index! + ran[0].length;
239
+ const tail = ranEnd < 0 ? '' : log.slice(ranEnd);
240
+ const runTail = junitBindings.length === 1
241
+ ? tail.replace(/\s*\[warm-worker\] junit-sha256=[0-9a-f]{64}\s*$/, '') : tail;
242
+ // A completed one-file run may only end with Bun's duration line. Any
243
+ // partial next-run prefix (including a truncated `bun te`) is unmeasured.
244
+ if (!/^\.?\s*(?:\[[\d.]+(?:ms|s)\])?\s*$/.test(runTail)) return null;
245
+ // Bun's unhandled errors are absent from testcase JUnit. With no second
246
+ // diagnostic channel to bind them, a reused worker must treat them as unknown.
247
+ if (passes === null || fails === null || errors !== 0 || !ran || Number(ran[1]) !== cases.length || Number(ran[2]) !== 1
248
+ || passes + fails !== cases.length
249
+ || failureIds.length !== fails || new Set(failureIds).size !== failureIds.length
250
+ || failureIds.some(id => !id.startsWith(`${file} > `))
251
+ || (rc === 0 ? fails !== 0 : fails === 0)) return null;
252
+ return { file, rc, failureIds, errorIds: [], junitComplete: true };
253
+ }
@@ -0,0 +1,54 @@
1
+ // Bind the shared gate selector to the committed-tree SCC report at one exact HEAD.
2
+ import { spawnSync } from 'node:child_process';
3
+ import { selectGateTestFiles } from '../../src/self-implement/gate-cli.js';
4
+ import { gitClosureTree } from './gate-closure.js';
5
+ import { analyzeImportGraphScc, type ImportGraphSccReport } from './import-graph-scc.js';
6
+
7
+ export type ImportGraphGateResult =
8
+ | { readonly ok: false; readonly reason: string }
9
+ | { readonly ok: true; readonly head40: string; readonly base40: string; readonly changedFiles: readonly string[]; readonly report: ImportGraphSccReport };
10
+
11
+ function git(repo: string, args: readonly string[]): { status: number | null; stdout: string; stderr: string } {
12
+ // git-spawn-allow: read-only HEAD/cleanliness checks; no checkout or mutation.
13
+ const result = spawnSync('git', [...args], { cwd: repo, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
14
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
15
+ }
16
+
17
+ /** Run only from a clean checkout. Selector and closure reader then observe the same committed HEAD. */
18
+ export function reportImportGraphSccForGate(repo: string, base40: string): ImportGraphGateResult {
19
+ if (!/^[0-9a-f]{40}$/i.test(base40)) return { ok: false, reason: 'base must be a full commit SHA' };
20
+ const head = git(repo, ['rev-parse', '--verify', 'HEAD']);
21
+ const head40 = head.stdout.trim();
22
+ if (head.status !== 0 || !/^[0-9a-f]{40}$/i.test(head40)) return { ok: false, reason: 'HEAD unreadable' };
23
+ if (git(repo, ['merge-base', '--is-ancestor', base40, head40]).status !== 0) return { ok: false, reason: 'base is not an ancestor of HEAD' };
24
+ const status = git(repo, ['status', '--porcelain', '--untracked-files=normal']);
25
+ if (status.status !== 0 || status.stdout.trim()) return { ok: false, reason: 'working tree is not clean' };
26
+
27
+ let selection: ReturnType<typeof selectGateTestFiles>;
28
+ try {
29
+ selection = selectGateTestFiles(repo, { base: base40, includeImporterTests: true });
30
+ } catch (error) {
31
+ return { ok: false, reason: `gate selector failed: ${error instanceof Error ? error.message : String(error)}` };
32
+ }
33
+ if (selection.baseRef !== base40) return { ok: false, reason: 'gate selector base mismatch' };
34
+ const afterHead = git(repo, ['rev-parse', '--verify', 'HEAD']);
35
+ const afterStatus = git(repo, ['status', '--porcelain', '--untracked-files=normal']);
36
+ if (afterHead.status !== 0 || afterHead.stdout.trim() !== head40 || afterStatus.status !== 0 || afterStatus.stdout.trim()) {
37
+ return { ok: false, reason: 'HEAD or working tree changed during gate selection' };
38
+ }
39
+ const issues: string[] = [];
40
+ if (selection.lookupFailed) issues.push(`importer lookup failed: ${selection.lookupFailed}`);
41
+ if (selection.unrunImporterTotal === null) issues.push('unrun importer count unknown');
42
+ else if (selection.unrunImporterTotal > 0) issues.push(`unrun importer tests: ${selection.unrunImporterTotal}`);
43
+ if (selection.routeLookupFailures.length) issues.push(`route lookup failures: ${selection.routeLookupFailures.length}`);
44
+ if (selection.callerTestsOverflow.length) issues.push(`caller tests overflow: ${selection.callerTestsOverflow.length}`);
45
+ if (selection.alwaysIncludeMissing.length) issues.push(`always-include missing: ${selection.alwaysIncludeMissing.length}`);
46
+ if (selection.unverified.length) issues.push(`changed paths unverified: ${selection.unverified.length}`);
47
+ let report: ImportGraphSccReport;
48
+ try {
49
+ report = analyzeImportGraphScc(gitClosureTree(repo, head40), selection.testFiles, { complete: issues.length === 0, issues }, {}, selection.changedFiles);
50
+ } catch (error) {
51
+ return { ok: false, reason: `committed closure unreadable: ${error instanceof Error ? error.message : String(error)}` };
52
+ }
53
+ return { ok: true, head40, base40, changedFiles: selection.changedFiles, report };
54
+ }
@@ -0,0 +1,215 @@
1
+ // IMPORT-GRAPH-SCC: report cycles in the static import graph reached by the gate's selected test files.
2
+ // The graph comes from the same committed-tree reader as gate-closure. A cycle report is diagnostic;
3
+ // opaque or absent inputs remain unmeasured and cannot authorize a smaller gate or concurrent train.
4
+ import { isTestPath } from '../../src/self-implement/importer-test-index.js';
5
+ import { buildClosureGraph, type ClosureGraph, type ClosureOptions, type ClosureTree } from './gate-closure.js';
6
+
7
+ export interface ChangedFileImpact {
8
+ readonly file: string;
9
+ /** Definite reverse-dependency reach, including the test file itself. */
10
+ readonly affectedTests: readonly string[];
11
+ readonly affectedTestCount: number;
12
+ /** Tests with an opaque dependency can also be affected; they are never counted as definitely unaffected. */
13
+ readonly possibleTests: readonly string[];
14
+ readonly possibleTestCount: number;
15
+ readonly measured: boolean;
16
+ readonly issues: readonly string[];
17
+ }
18
+
19
+ function changedFileImpacts(graph: ClosureGraph, preload: readonly string[], changedFiles: readonly string[]): ChangedFileImpact[] {
20
+ const tests = [...graph.tracked].filter(isTestPath).sort();
21
+ const reverse = new Map<string, string[]>();
22
+ for (const [from, dependencies] of graph.forward) for (const dependency of dependencies) {
23
+ const importers = reverse.get(dependency) ?? [];
24
+ importers.push(from);
25
+ reverse.set(dependency, importers);
26
+ }
27
+ const reverseReach = (seeds: readonly string[]): Set<string> => {
28
+ const seen = new Set(seeds);
29
+ const queue = [...seeds];
30
+ for (let at = 0; at < queue.length; at++) for (const importer of reverse.get(queue[at]!) ?? []) {
31
+ if (seen.has(importer)) continue;
32
+ seen.add(importer);
33
+ queue.push(importer);
34
+ }
35
+ return seen;
36
+ };
37
+ const uncertainTests = reverseReach([...graph.opaque.keys()]);
38
+ const preloadClosure = new Set<string>();
39
+ const pending = [...preload];
40
+ while (pending.length) {
41
+ const file = pending.pop()!;
42
+ if (preloadClosure.has(file)) continue;
43
+ preloadClosure.add(file);
44
+ pending.push(...(graph.staticImports.get(file) ?? []));
45
+ }
46
+ const preloadOpaque = [...preloadClosure].some((file) => graph.opaque.has(file) || !graph.tracked.has(file));
47
+ return [...new Set(changedFiles)].sort().map((file) => {
48
+ const issues: string[] = [];
49
+ if (!graph.tracked.has(file)) issues.push('changed file missing at HEAD');
50
+ if (preloadOpaque) issues.push('preload closure opaque or missing');
51
+ const reached = preloadClosure.has(file) ? new Set(tests) : reverseReach([file]);
52
+ const affectedTests = tests.filter((test) => reached.has(test));
53
+ const possibleTests = tests.filter((test) => reached.has(test) || uncertainTests.has(test) || preloadOpaque || !graph.tracked.has(file));
54
+ if (possibleTests.length > affectedTests.length) issues.push('unresolved reach may affect more tests');
55
+ return { file, affectedTests, affectedTestCount: affectedTests.length, possibleTests,
56
+ possibleTestCount: possibleTests.length, measured: issues.length === 0, issues };
57
+ });
58
+ }
59
+
60
+ export interface ImportCutCandidate {
61
+ /** Removing these DFS back edges would make this SCC acyclic; the set is deterministic, not minimal. */
62
+ readonly from: string;
63
+ readonly to: string;
64
+ readonly sccSize: number;
65
+ /** Reverse dependency closure of `from` within the selected-test graph, including literal dynamic imports. */
66
+ readonly impactedFiles: readonly string[];
67
+ readonly impactedTests: readonly string[];
68
+ }
69
+
70
+ export interface ImportGraphSccReport {
71
+ readonly scope: 'selected-tests-static-imports';
72
+ readonly measured: boolean;
73
+ readonly selectedTests: readonly string[];
74
+ readonly reachableFiles: number;
75
+ readonly cycleCount: number;
76
+ readonly largestScc: number;
77
+ readonly cutCandidateTotal: number;
78
+ readonly cutCandidates: readonly ImportCutCandidate[];
79
+ readonly opaqueFiles: readonly string[];
80
+ readonly missingTests: readonly string[];
81
+ readonly selectionIssues: readonly string[];
82
+ readonly unmeasuredCount: number;
83
+ readonly changedFileImpacts: readonly ChangedFileImpact[];
84
+ }
85
+
86
+ export interface ImportGraphSelectionStatus {
87
+ /** True only after #28000 reports a complete lookup, with no overflow or unrunnable test. */
88
+ readonly complete: boolean;
89
+ readonly issues: readonly string[];
90
+ }
91
+
92
+ /** Read-only structural report. Call with #28000's exact selected test paths at the same HEAD. */
93
+ export function analyzeImportGraphScc(
94
+ tree: ClosureTree,
95
+ selectedTests: readonly string[],
96
+ selectionStatus: ImportGraphSelectionStatus,
97
+ options: ClosureOptions = {},
98
+ changedFiles: readonly string[] = [],
99
+ ): ImportGraphSccReport {
100
+ const graph = buildClosureGraph(tree, options);
101
+ const changedFileImpactsReport = changedFileImpacts(graph, tree.preload, changedFiles);
102
+ const tests = [...new Set(selectedTests)].sort();
103
+ const missingTests = tests.filter((test) => !graph.staticImports.has(test));
104
+ const reachable = new Set<string>();
105
+ const pending = tests.filter((test) => graph.staticImports.has(test));
106
+ while (pending.length) {
107
+ const file = pending.pop()!;
108
+ if (reachable.has(file)) continue;
109
+ reachable.add(file);
110
+ pending.push(...(graph.staticImports.get(file) ?? []));
111
+ }
112
+ // The SCC is intentionally static, but certainty must follow every dependency the closure reader knows:
113
+ // a dynamic import can reach an opaque file even when that file is outside the static SCC graph.
114
+ const closureReachable = new Set<string>();
115
+ const closurePending = tests.filter((test) => graph.forward.has(test));
116
+ while (closurePending.length) {
117
+ const file = closurePending.pop()!;
118
+ if (closureReachable.has(file)) continue;
119
+ closureReachable.add(file);
120
+ closurePending.push(...(graph.forward.get(file) ?? []));
121
+ }
122
+ const opaqueFiles = [...closureReachable].filter((file) => graph.opaque.has(file)).sort();
123
+ // An empty selection does not prove that no test can observe a change.
124
+ const issues = [...new Set(selectionStatus.issues.length ? selectionStatus.issues
125
+ : selectionStatus.complete ? [] : ['selection incomplete'])].sort();
126
+ const measured = tests.length > 0 && missingTests.length === 0 && opaqueFiles.length === 0 && issues.length === 0;
127
+ const edges = new Map<string, string[]>();
128
+ const reverse = new Map<string, string[]>();
129
+ const impactReverse = new Map<string, string[]>();
130
+ for (const file of closureReachable) for (const next of graph.forward.get(file) ?? []) {
131
+ if (closureReachable.has(next)) impactReverse.set(next, [...(impactReverse.get(next) ?? []), file]);
132
+ }
133
+ for (const file of reachable) {
134
+ const neighbors = [...(graph.staticImports.get(file) ?? []), ...(graph.selfStaticImports.has(file) ? [file] : [])]
135
+ .filter((next) => reachable.has(next)).sort();
136
+ edges.set(file, neighbors);
137
+ for (const next of neighbors) reverse.set(next, [...(reverse.get(next) ?? []), file]);
138
+ }
139
+ for (const importers of reverse.values()) importers.sort();
140
+
141
+ // Iterative Kosaraju avoids a JS call-stack limit on a large repository SCC.
142
+ const visited = new Set<string>();
143
+ const order: string[] = [];
144
+ for (const root of [...reachable].sort()) {
145
+ if (visited.has(root)) continue;
146
+ const stack: { file: string; exit: boolean }[] = [{ file: root, exit: false }];
147
+ while (stack.length) {
148
+ const { file, exit } = stack.pop()!;
149
+ if (exit) { order.push(file); continue; }
150
+ if (visited.has(file)) continue;
151
+ visited.add(file);
152
+ stack.push({ file, exit: true });
153
+ for (const next of [...(edges.get(file) ?? [])].reverse()) if (!visited.has(next)) stack.push({ file: next, exit: false });
154
+ }
155
+ }
156
+ const assigned = new Set<string>();
157
+ const components: string[][] = [];
158
+ for (const root of order.reverse()) {
159
+ if (assigned.has(root)) continue;
160
+ const component: string[] = [];
161
+ const stack = [root];
162
+ assigned.add(root);
163
+ while (stack.length) {
164
+ const file = stack.pop()!;
165
+ component.push(file);
166
+ for (const next of reverse.get(file) ?? []) if (!assigned.has(next)) { assigned.add(next); stack.push(next); }
167
+ }
168
+ if (component.length > 1 || graph.selfStaticImports.has(component[0]!)) components.push(component.sort());
169
+ }
170
+ components.sort((a, b) => b.length - a.length || a[0]!.localeCompare(b[0]!));
171
+
172
+ const cutEdges: { from: string; to: string; sccSize: number }[] = [];
173
+ for (const component of components) {
174
+ const members = new Set(component);
175
+ const seen = new Set<string>();
176
+ const active = new Set<string>();
177
+ for (const root of component) {
178
+ if (seen.has(root)) continue;
179
+ const stack: { file: string; next: number; neighbors: string[] }[] = [];
180
+ const enter = (file: string): void => {
181
+ seen.add(file);
182
+ active.add(file);
183
+ stack.push({ file, next: 0, neighbors: (edges.get(file) ?? []).filter((next) => members.has(next)) });
184
+ };
185
+ enter(root);
186
+ while (stack.length) {
187
+ const frame = stack[stack.length - 1]!;
188
+ const next = frame.neighbors[frame.next++];
189
+ if (next === undefined) { active.delete(frame.file); stack.pop(); continue; }
190
+ if (active.has(next)) cutEdges.push({ from: frame.file, to: next, sccSize: component.length });
191
+ else if (!seen.has(next)) enter(next);
192
+ }
193
+ }
194
+ }
195
+ const testSet = new Set(tests);
196
+ const cutCandidates = cutEdges.slice(0, 10).map(({ from, to, sccSize }) => {
197
+ const impact = new Set<string>();
198
+ const stack = [from];
199
+ while (stack.length) {
200
+ const file = stack.pop()!;
201
+ if (impact.has(file)) continue;
202
+ impact.add(file);
203
+ stack.push(...(impactReverse.get(file) ?? []));
204
+ }
205
+ const impactedFiles = [...impact].sort();
206
+ return { from, to, sccSize, impactedFiles, impactedTests: impactedFiles.filter((file) => testSet.has(file)) };
207
+ });
208
+ return {
209
+ scope: 'selected-tests-static-imports', measured, selectedTests: tests,
210
+ reachableFiles: reachable.size, cycleCount: components.length, largestScc: components[0]?.length ?? 0,
211
+ cutCandidateTotal: cutEdges.length, cutCandidates, opaqueFiles, missingTests,
212
+ selectionIssues: issues, unmeasuredCount: opaqueFiles.length + missingTests.length + issues.length + (tests.length === 0 ? 1 : 0),
213
+ changedFileImpacts: changedFileImpactsReport,
214
+ };
215
+ }
@@ -8,6 +8,7 @@ export type NodeOutcome = 'ok' | 'fail' | 'error';
8
8
  export type NodeVerdict = 'pass' | 'flaky' | 'fail';
9
9
  export interface GraphContext {
10
10
  nodeId?: string;
11
+ runId?: string;
11
12
  input: { version: string; previousVersion: string; [key: string]: unknown };
12
13
  outputs: Record<string, Record<string, unknown>>;
13
14
  }
@@ -22,6 +23,7 @@ export function readGraphContext(env: NodeJS.ProcessEnv = process.env): GraphCon
22
23
  if (!input || typeof input.version !== 'string' || !isReleaseVersion(input.version)
23
24
  || typeof input.previousVersion !== 'string' || !/^\d+\.\d+\.\d+$/.test(input.previousVersion)) throw new Error('version and previousVersion required');
24
25
  return { ...(typeof context.nodeId === 'string' ? { nodeId: context.nodeId } : {}),
26
+ ...(typeof context.runId === 'string' ? { runId: context.runId } : {}),
25
27
  input: input as GraphContext['input'], outputs: context.outputs && typeof context.outputs === 'object' ? context.outputs as GraphContext['outputs'] : {} };
26
28
  }
27
29