elanous 0.2.29 → 0.2.31

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 (709) 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 → LSXfY0u9QtfDbejY0Ukf_}/_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-50625904996a8fa8.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/6948.1062d4594652b5bf.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/{1852.7f7b53991fcb99ef.js → 7502.ccd5b8065545edd0.js} +2 -2
  93. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +8 -0
  94. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{6534.1ab00f370db7b105.js → 7862.30a8d6482bb238eb.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/{285adb1a.5654e605dddf86d2.js → 7a1887c4.f36b88fba31da8fd.js} +1 -1
  99. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9002.e5658224e3dc1b6f.js +24 -0
  109. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{1516.dfaceff3fd2d0e0d.js → 9138.b6e80031afb1d973.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/{9907.49be0fcadaf214b5.js → 9221.7d22eaf353a2d4e7.js} +1 -1
  113. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{8767-2f6a634f5abeaa01.js → 9279-d28c5b7754d010ae.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/{3160-95c96f4d2a21dd26.js → 9398-6aed28f0a96d0d6f.js} +1 -1
  117. package/apps/pwa/out/_next/static/chunks/9407.e49124dedf0f5e72.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{328bb3ab-6628a1114fe3fb3b.js → 997ce8a5-2ad501927003b41b.js} +1 -1
  121. package/apps/pwa/out/_next/static/chunks/{6853.cc5174a9dee59593.js → 9989.3694300e5f000b14.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-a5635eba0d73b84e.js → page-2ebb8fd59b9461f9.js} +1 -1
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0a07363b130182a1.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/{page-29900ed0011b2c83.js → page-521ee23ac8c0abfa.js} +1 -1
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/{page-9f92737b8766009a.js → page-149dc1caba411bb9.js} +1 -1
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{425cfc4d.fb91158e3971c39f.js → b313b242.cb1265eea908db61.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/ebc7d829.264a0bcb6c750b50.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +1 -0
  183. package/apps/pwa/out/_next/static/css/{72becfd42807b50d.css → 3f5fc6f96e2cf7b2.css} +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +23 -23
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +23 -23
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +23 -23
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +22 -22
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +22 -22
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +23 -23
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +22 -22
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +23 -23
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +23 -23
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +22 -22
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +23 -23
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +23 -23
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +23 -23
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +23 -23
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +22 -22
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +22 -22
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +23 -23
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +23 -23
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +23 -23
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +22 -22
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +22 -22
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +23 -23
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +23 -23
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +22 -22
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +22 -22
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +22 -22
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +23 -23
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +23 -23
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +22 -22
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +23 -23
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +23 -23
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +23 -23
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +23 -23
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +23 -23
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +22 -22
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +23 -23
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +23 -23
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +23 -23
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +23 -23
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +23 -23
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +23 -23
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +23 -23
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +23 -23
  277. package/bin/elanous.mjs +7 -3
  278. package/graphs/context/nightly-condense.yaml +1 -0
  279. package/graphs/intake/intake-daily.yaml +8 -1
  280. package/graphs/intake/recipes.yaml +5 -0
  281. package/graphs/lecture/lecture-note.yaml +2 -2
  282. package/graphs/ops/harness-gc.yaml +1 -0
  283. package/graphs/release/recipes.yaml +3 -0
  284. package/graphs/release/release-loop.yaml +9 -5
  285. package/graphs/units/recipes.yaml +3 -0
  286. package/graphs/units/release-gate-recheck.yaml +15 -0
  287. package/package.json +2 -1
  288. package/scripts/check-native-tool-wiring.ts +3 -2
  289. package/scripts/ci-android-unit-tests.ts +16 -0
  290. package/scripts/ci-typecheck-changed.ts +37 -9
  291. package/scripts/coord-channel-watch.sh +22 -16
  292. package/scripts/coord-role-pack.ts +81 -2
  293. package/scripts/cron-run.ts +96 -3
  294. package/scripts/detect-test-interference.ts +38 -5
  295. package/scripts/gate-pr-cache.ts +65 -0
  296. package/scripts/gh-surface/capture.ts +126 -0
  297. package/scripts/gh-surface/gh +40 -0
  298. package/scripts/import-graph-scc.ts +38 -0
  299. package/scripts/install.ps1 +19 -0
  300. package/scripts/intake-social.ts +181 -0
  301. package/scripts/lecture-note/node.ts +71 -4
  302. package/scripts/lib/android-toolchain.ts +32 -0
  303. package/scripts/lib/deterministic-env.ts +62 -0
  304. package/scripts/lib/gate-test-env.ts +19 -0
  305. package/scripts/measure-goal-grounding-corpus.ts +2 -1
  306. package/scripts/ratchets/test-interference-patterns.allowlist.txt +257 -0
  307. package/scripts/ratchets/test-interference-patterns.ts +367 -0
  308. package/scripts/release-loop/cut-branch.ts +4 -3
  309. package/scripts/release-loop/export-check-node.ts +0 -1
  310. package/scripts/release-loop/fixtures/warm-failure-assertion/sample.junit.xml +8 -0
  311. package/scripts/release-loop/fixtures/warm-job-029/sample.json +1 -0
  312. package/scripts/release-loop/fixtures/warm-job-029/sample.junit.xml +10 -0
  313. package/scripts/release-loop/gate-closure.ts +12 -8
  314. package/scripts/release-loop/gate-diff.ts +1 -1
  315. package/scripts/release-loop/gate-host-mirror.ts +66 -0
  316. package/scripts/release-loop/gate-node.ts +523 -75
  317. package/scripts/release-loop/gate-partial.ts +106 -9
  318. package/scripts/release-loop/gate-pr-cache.ts +66 -0
  319. package/scripts/release-loop/gate-prewarm-plan.ts +66 -0
  320. package/scripts/release-loop/gate-r2-verdict.ts +189 -0
  321. package/scripts/release-loop/gate-recheck-plan-node.ts +52 -0
  322. package/scripts/release-loop/gate-warm-artifacts.ts +253 -0
  323. package/scripts/release-loop/import-graph-scc-run.ts +54 -0
  324. package/scripts/release-loop/import-graph-scc.ts +215 -0
  325. package/scripts/release-loop/node-verdict.ts +2 -0
  326. package/scripts/release-loop/probe-pod-host-dirs-live.ts +113 -0
  327. package/scripts/release-loop/resume-release.ts +33 -4
  328. package/scripts/release-loop/resume.ts +13 -5
  329. package/scripts/release-loop/spawn-lane.ts +2 -19
  330. package/scripts/release-loop/tui-sim-node.ts +3 -2
  331. package/scripts/release-loop/unattended-release.ts +16 -0
  332. package/scripts/test-deterministic.ts +5 -61
  333. package/scripts/train-reach-grouping.ts +48 -0
  334. package/scripts/tsc-incremental-cache.ts +86 -0
  335. package/scripts/tsc-incremental-diagnostics.ts +76 -0
  336. package/scripts/tsc-main-safety-net.ts +2 -2
  337. package/src/acp/client.ts +4 -1
  338. package/src/acp/core-turn-bridge.ts +50 -5
  339. package/src/ad-pipeline/run.ts +4 -2
  340. package/src/agent/runner.ts +169 -3
  341. package/src/agent/subagent-callable.ts +3 -2
  342. package/src/agent-mission/review-loop.ts +6 -3
  343. package/src/agent-substrate/acp-implementer.ts +14 -2
  344. package/src/agent-substrate/pr-reviewer.ts +12 -0
  345. package/src/agent-substrate/self-review-cli.ts +30 -4
  346. package/src/autopilot/pr-manager.ts +62 -7
  347. package/src/briefing/brief-items.ts +24 -22
  348. package/src/capture/tui-self-report.ts +15 -0
  349. package/src/chat/chat-cli.ts +10 -2
  350. package/src/chat/index.ts +77 -11
  351. package/src/chat/input-control-key.ts +5 -3
  352. package/src/chat/tool-interrupt-behavior.ts +38 -0
  353. package/src/chat/tool-render/dispatch.ts +5 -1
  354. package/src/chat/turn-typeahead.ts +75 -20
  355. package/src/cli/__fixtures__/agent-help-before/agent.txt +4 -2
  356. package/src/cli/agent-cli.ts +41 -13
  357. package/src/cli/config-audit.ts +123 -0
  358. package/src/cli/decisions-cli.ts +80 -6
  359. package/src/cli/log-event-names.ts +7 -0
  360. package/src/cli/mcp-login.ts +21 -5
  361. package/src/cli/msg-cli.ts +88 -0
  362. package/src/cli/pr-cli.ts +214 -57
  363. package/src/cli/pr-land-heavy-remote.ts +2 -2
  364. package/src/cli/pr-land-overlap-evidence.ts +63 -9
  365. package/src/cli/pr-land-pod-shadow-job.ts +83 -0
  366. package/src/cli/pr-land-pod-shadow.ts +16 -3
  367. package/src/cli/pr-land-virtual-rebase.ts +108 -0
  368. package/src/cli/release-cli.ts +80 -14
  369. package/src/cli/seat-cli.ts +138 -3
  370. package/src/cli/self-update.ts +5 -2
  371. package/src/cli/tasks-cli.ts +97 -19
  372. package/src/context-bus/context-first.ts +13 -0
  373. package/src/context-bus/context-now.ts +13 -2
  374. package/src/context-bus/ops-events.ts +75 -0
  375. package/src/control-plane/lease-holder.ts +12 -8
  376. package/src/control-plane/ledger.ts +163 -4
  377. package/src/control-plane/server.ts +91 -11
  378. package/src/core-turn/run-core-turn.ts +1 -0
  379. package/src/core-turn/run-goal-loop.ts +222 -3
  380. package/src/core-turn/seat-turn-cap.ts +79 -0
  381. package/src/core-turn/short-question.ts +38 -6
  382. package/src/core-turn/types.ts +3 -0
  383. package/src/dashboard/acp-boot.ts +3 -0
  384. package/src/dashboard/index.ts +224 -615
  385. package/src/dashboard/input/chat-main-entry-runtime.ts +1 -1
  386. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +4 -1
  387. package/src/dashboard/input/chat-main-session.ts +8 -1
  388. package/src/dashboard/input/chat-main-turn.ts +12 -3
  389. package/src/dashboard/input/compact-prepass-recovery.ts +33 -0
  390. package/src/dashboard/input/external-input-host.ts +26 -0
  391. package/src/dashboard/input/internal-turn.ts +261 -0
  392. package/src/dashboard/input/seat-autowake.ts +318 -0
  393. package/src/dashboard/input/turn-steer-bridge.ts +70 -0
  394. package/src/dashboard/loop-scheduler.ts +72 -0
  395. package/src/dashboard/seat-boot-preamble.ts +18 -0
  396. package/src/dashboard/skill-runtime.ts +2 -0
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +126 -1181
  398. package/src/dashboard/slash-runtime/help-from-registry.ts +2 -1
  399. package/src/dashboard/slash-runtime/index.ts +13 -0
  400. package/src/dashboard/turn-busy-teardown.ts +50 -0
  401. package/src/decisions/decision-ledger.ts +45 -4
  402. package/src/discord-self-message.ts +4 -4
  403. package/src/domains/release-tool.ts +18 -1
  404. package/src/field-note/transcribe.ts +17 -0
  405. package/src/github/remote-call.ts +81 -0
  406. package/src/goals/registry.ts +46 -6
  407. package/src/goals/types.ts +7 -1
  408. package/src/graph-runner/runner.ts +1 -0
  409. package/src/grok/credential.ts +26 -0
  410. package/src/harness/harness-clean.ts +2 -1
  411. package/src/harness/harness-cli-command.ts +52 -5
  412. package/src/harness/harness-gc.ts +2 -1
  413. package/src/harness/harness-incidents.ts +57 -20
  414. package/src/harness/harness-pod-dispatch.ts +87 -10
  415. package/src/harness/harness-queue.ts +53 -4
  416. package/src/harness/harness-stop.ts +4 -3
  417. package/src/harness/harness-substrate-default.ts +78 -7
  418. package/src/harness/harness-worktree-auto.ts +2 -1
  419. package/src/harness/harness-worktrees.ts +3 -2
  420. package/src/hooks/dispatch.ts +2 -1
  421. package/src/index.ts +152 -25
  422. package/src/input/external-input-queue.ts +33 -1
  423. package/src/intake-plane/slash.ts +14 -3
  424. package/src/keybindings.ts +4 -1
  425. package/src/llm/tool-loop-steered-rejection.ts +33 -0
  426. package/src/llm.ts +138 -19
  427. package/src/loops/consensus.ts +348 -0
  428. package/src/loops/msg-wake.ts +206 -4
  429. package/src/loops/observe.ts +19 -3
  430. package/src/loops/orchestrator/tick.ts +64 -10
  431. package/src/loops/orchestrator/traffic.ts +64 -1
  432. package/src/loops/registry.ts +30 -0
  433. package/src/market/signed-index.ts +14 -0
  434. package/src/mcp/mcp-oauth.ts +54 -5
  435. package/src/models/prompts.ts +28 -0
  436. package/src/msg/msg-sse-client.ts +223 -0
  437. package/src/msg/msg-store.ts +86 -2
  438. package/src/mss/logging/log-store.ts +225 -1
  439. package/src/nexus/DAEMON-THIN-inventory-2026-10-15.md +122 -0
  440. package/src/nexus/api/http-server.ts +54 -15
  441. package/src/nexus/api/loop-resources.ts +19 -3
  442. package/src/nexus/api/ops-api.ts +11 -0
  443. package/src/nexus/daemon-thin-inventory.md +37 -0
  444. package/src/nexus/index.ts +70 -0
  445. package/src/nexus/state/state.ts +1 -0
  446. package/src/oauth/store.ts +32 -7
  447. package/src/onboarding/first-run.ts +28 -3
  448. package/src/ops/overview-cache.ts +16 -4
  449. package/src/ops/resources.ts +82 -0
  450. package/src/plugins/maker/connector-maker.ts +41 -0
  451. package/src/plugins/maker/skill-maker.ts +42 -0
  452. package/src/pr-tool/census.ts +288 -0
  453. package/src/prompt-library/chat-conciseness.ts +13 -0
  454. package/src/prompt-library/universal-preamble.ts +10 -5
  455. package/src/release-loop/gate-host-reservation.ts +97 -0
  456. package/src/release-loop/landing-freeze.ts +5 -0
  457. package/src/release-loop/light-rc.ts +5 -2
  458. package/src/release-loop/placement.ts +92 -1
  459. package/src/release-loop/rehearsal-shard-plan.ts +149 -0
  460. package/src/release-loop/rehearsal.ts +73 -17
  461. package/src/repl/index.ts +20 -2
  462. package/src/seat-loop/seat-knowhow.ts +282 -0
  463. package/src/seat-loop/seat-loop.ts +41 -2
  464. package/src/seat-loop/traffic-signal.ts +3 -0
  465. package/src/self-dev/ask-launch-flow.ts +24 -3
  466. package/src/self-dev/decompose-compose-graph.ts +28 -27
  467. package/src/self-dev/decompose-proposal.ts +53 -38
  468. package/src/self-dev/decompose.ts +17 -0
  469. package/src/self-dev/dev-pipeline.ts +31 -2
  470. package/src/self-dev/draft-residue.ts +24 -9
  471. package/src/self-dev/draft-sweep.ts +59 -4
  472. package/src/self-dev/external-call-zero.ts +77 -0
  473. package/src/self-dev/launch-preflight-text.ts +6 -0
  474. package/src/self-dev/launch-preflight.ts +25 -3
  475. package/src/self-dev/local-supervisor-judge.ts +185 -0
  476. package/src/self-dev/run-supervisor.ts +229 -19
  477. package/src/self-dev/run-types.ts +20 -0
  478. package/src/self-dev/shard-aggregate.ts +13 -2
  479. package/src/self-dev/shard-plan.ts +47 -0
  480. package/src/self-dev/shard-run.ts +112 -10
  481. package/src/self-dev/spawn-lane-files.ts +19 -0
  482. package/src/self-implement/app-api-budget.ts +51 -11
  483. package/src/self-implement/config-gate.ts +2 -1
  484. package/src/self-implement/expose-gate.ts +2 -1
  485. package/src/self-implement/gate-artifacts.ts +405 -0
  486. package/src/self-implement/gate-cli.ts +201 -16
  487. package/src/self-implement/gate-remote.ts +110 -25
  488. package/src/self-implement/gate-scenario.ts +85 -0
  489. package/src/self-implement/goal-author.ts +160 -8
  490. package/src/self-implement/graph-authority.ts +38 -6
  491. package/src/self-implement/graph-overlay-condition.ts +92 -1
  492. package/src/self-implement/heal-triage.ts +79 -0
  493. package/src/self-implement/host-regate.ts +61 -3
  494. package/src/self-implement/orchestrator.ts +14 -123
  495. package/src/self-implement/pr-title.ts +123 -0
  496. package/src/self-implement/run-checkpoint.ts +235 -0
  497. package/src/self-implement/run-ledger.ts +155 -10
  498. package/src/self-implement/run-stop.ts +4 -3
  499. package/src/self-implement/run-ttl.ts +28 -4
  500. package/src/self-implement/seams.ts +2 -0
  501. package/src/self-implement/shadow-stage.ts +7 -6
  502. package/src/self-implement/stop-autoheal.ts +2 -1
  503. package/src/self-implement/train-gate-remote.ts +37 -8
  504. package/src/self-implement/train-reach-grouping.ts +157 -0
  505. package/src/self-implement/train-scenario-layers.ts +133 -0
  506. package/src/self-implement/uncommitted-work.ts +2 -0
  507. package/src/session/pending-input.ts +19 -0
  508. package/src/session/session-start.ts +224 -0
  509. package/src/session-runtime/parallel-dispatch.ts +22 -5
  510. package/src/skills/tools/dev-harness.ts +6 -4
  511. package/src/skills/tools/shell.ts +1 -1
  512. package/src/steward/resync-tick.ts +114 -23
  513. package/src/steward/ta-repair-event-collect.ts +158 -0
  514. package/src/task-agent/card-evidence.ts +25 -1
  515. package/src/task-agent/green-sweep.ts +8 -3
  516. package/src/task-agent/judge.ts +76 -0
  517. package/src/task-agent/land-queue.ts +79 -0
  518. package/src/task-agent/live-moves.ts +30 -9
  519. package/src/task-agent/postland-card.ts +5 -0
  520. package/src/task-agent/prelaunch-already-done.ts +98 -0
  521. package/src/task-agent/real-launch-guard.ts +37 -0
  522. package/src/task-agent/rejudge-on-head.ts +89 -12
  523. package/src/task-agent/remote-rejudge-bind.ts +28 -8
  524. package/src/task-agent/repair-cycle.ts +45 -7
  525. package/src/task-agent/repair-worker.ts +7 -0
  526. package/src/task-agent/run-identity.ts +200 -0
  527. package/src/task-agent/shadow.ts +50 -3
  528. package/src/task-agent/task-hand.ts +158 -5
  529. package/src/task-agent/train-landing.ts +77 -0
  530. package/src/task-agent/work-order.ts +104 -0
  531. package/src/task-orchestrator/surfaces/pod-command-job.ts +88 -28
  532. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +88 -19
  533. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +2 -1
  534. package/src/task-orchestrator/surfaces/pod-image-source.ts +2 -1
  535. package/src/task-orchestrator/surfaces/pod-install-slots.ts +121 -9
  536. package/src/task-orchestrator/surfaces/pod-lease.ts +20 -6
  537. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +169 -0
  538. package/src/task-orchestrator/surfaces/pod-mirror-seed.ts +27 -0
  539. package/src/task-orchestrator/surfaces/pod-result-marker-wait.ts +33 -0
  540. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +63 -0
  541. package/src/task-orchestrator/surfaces/pod-source-receive.ts +19 -3
  542. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +141 -0
  543. package/src/task-orchestrator/surfaces/pod-warm-ta-shadow.ts +85 -0
  544. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +153 -0
  545. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +208 -0
  546. package/src/task-orchestrator/surfaces/self-implement-pod.ts +132 -15
  547. package/src/telegram.ts +2 -4
  548. package/src/tui/input/pickers.ts +732 -0
  549. package/src/tui/slash/mission.ts +492 -0
  550. package/src/tui/slash/term.ts +877 -0
  551. package/src/tui-client/dashboard-session.ts +9 -0
  552. package/src/tui.ts +48 -0
  553. package/src/user-config/gemini-server-tools.ts +9 -0
  554. package/src/user-config.ts +53 -16
  555. package/src/util/spawn-sync-output.ts +7 -0
  556. package/src/ux-sim/fake-bin.ts +154 -0
  557. package/src/ux-sim/fake-clock.ts +36 -0
  558. package/src/ux-sim/headless-tui.ts +72 -0
  559. package/src/ux-sim/in-process-cli.ts +2 -1
  560. package/src/ux-sim/temp-git-remote.ts +82 -0
  561. package/src/version/packed-revision.json +1 -1
  562. package/src/video-pipeline/recipes/vlog.ts +25 -7
  563. package/apps/pwa/out/_next/static/chunks/1015-9cba22a5a4554797.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/1084-4e66af7376a18db7.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/1106.3a6410b7b0c70ad4.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/1127.32fc642f70423506.js +0 -8
  567. package/apps/pwa/out/_next/static/chunks/1189-d9b8e1995a831fae.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/1224.6da98c7ad0eb7dd8.js +0 -34
  569. package/apps/pwa/out/_next/static/chunks/1370.4e3e2558f111fd5d.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1514-b7da377fdc4eb17a.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/1577.3c24c32584e10d70.js +0 -286
  572. package/apps/pwa/out/_next/static/chunks/161.130a569855c4d68c.js +0 -24
  573. package/apps/pwa/out/_next/static/chunks/1864.16da9556e78a9236.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1b6f6b2a.aff090122be3726e.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/2341.e8a9135e5b910dd5.js +0 -36
  576. package/apps/pwa/out/_next/static/chunks/257.10afdbe3520f2fc2.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/2658.87550e692dc493f6.js +0 -64
  578. package/apps/pwa/out/_next/static/chunks/2673.85e2f02efae7a85f.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/2766-bee623b37472ed63.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/2794.6d836872b0bf43e2.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2806.eb57ced1a528ed39.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/283.7a121c4910e6dad7.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2870.1dc29aa5fc01f09f.js +0 -115
  584. package/apps/pwa/out/_next/static/chunks/293.fd38e77ce5d48103.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2993-5952a1cd3fd5d441.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/32-a523427c5bd5ed00.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/3280.af38002a6424a905.js +0 -90
  588. package/apps/pwa/out/_next/static/chunks/3292-5ddffdb2f517b44f.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3523.d3231daaf7aba993.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3763.577de3181e1e6ea0.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/4138-cc56b0938ef72783.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4255-8350c43d307a8875.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4352.a4954693499c2714.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4421-f2dcbc6fd80ec013.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/4513-51b94aeee37c9905.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4928-c3b72f99aa588699.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4986-f9fc0283fb325219.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/5014.671a7b9f69c2b7b1.js +0 -94
  599. package/apps/pwa/out/_next/static/chunks/5137.d398e24710b3feb6.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/5298.0bea74885cabe754.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/5315.74c53a39739b11c4.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/5317-8b1df8d02105cd07.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5358-33051f41a2b239af.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5388.a2ec02501f714ad5.js +0 -62
  605. package/apps/pwa/out/_next/static/chunks/5395.e6ac948a2d15058d.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5409-f282bf533c151849.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5466.d0f4aba9d52acfa8.js +0 -27
  608. package/apps/pwa/out/_next/static/chunks/5564.3d28b353470fe305.js +0 -104
  609. package/apps/pwa/out/_next/static/chunks/569.b0cbfb4dee4a167a.js +0 -93
  610. package/apps/pwa/out/_next/static/chunks/5835-72465b73a8bb8d74.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/5941.045d6093139e1f7a.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/6228.47cabb83564dfe54.js +0 -24
  613. package/apps/pwa/out/_next/static/chunks/6457-8d1993002a87d0fe.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/6513.ef54cfae52351982.js +0 -2
  615. package/apps/pwa/out/_next/static/chunks/6582.13d245bf87df69f1.js +0 -148
  616. package/apps/pwa/out/_next/static/chunks/6655.c33f6acc2c61bb89.js +0 -149
  617. package/apps/pwa/out/_next/static/chunks/6731-9d7195af289c8d4c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6733.0be05b1db9279fc5.js +0 -79
  619. package/apps/pwa/out/_next/static/chunks/6742-90937146253a8b9e.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/687-816858f77a396a4e.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6888.72c7b8cfb02a7e61.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/6993.c17c828ac3ef3253.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/7076.9f27ef666b0cefdd.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/7113.1403c5d451804e8c.js +0 -287
  625. package/apps/pwa/out/_next/static/chunks/7169.9dd603c726c2cd7c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/7247-e3ec21f761f86710.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/7261-a47b72f96f5199df.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/7335-5cda81ac90310077.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7356-c2e4af090546e2d4.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/738-59518742078fda71.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7385.a7375f10db73243a.js +0 -77
  632. package/apps/pwa/out/_next/static/chunks/7445.cf1cf2fe109bcd96.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7505.a2057432ab6ef99a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7515.31f45fac1f9c70cb.js +0 -74
  635. package/apps/pwa/out/_next/static/chunks/7658-d4ce8c72a9548a91.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/8107-0b1ae46bc5bcb788.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/8132.bfea2f016ce8d992.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8672.e299832bc7d18ee2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8735.f1ef798a5f260f6f.js +0 -226
  640. package/apps/pwa/out/_next/static/chunks/8774-88f67f7d8d53d299.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8782.252e5a405d86e4ed.js +0 -32
  642. package/apps/pwa/out/_next/static/chunks/909-9ed7aa0dba804316.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/9100.22b0301256827007.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/9140-dde77575570bc71e.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/9292-a7ad9a01c7044b93.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/9517.00627dc51b02821c.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9725.dcbb585652d8e9c5.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9761.a3ebf5c389c24ddc.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9972.834d2b2b7d48f1ed.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9995-1a90486f5ae01546.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/a435ad95.577add051b4facb2.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-83372d8b5863ebf7.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d69256d7613c140a.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-352c5e9ba3f9b858.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/board/page-69f1d725524201a8.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/bots/page-ad9181d84285e4ea.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/ceo/page-86feb08080261a2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/chat/page-ffa15987e4756d03.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/consult/page-11a3ab44ac327cc1.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/control/page-6309b11c4264d24d.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/decisions/page-8800472079612e87.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/design-check/page-d387bf3f2301882a.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/editor/page-048f88d8c8658da6.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/exec/page-6c14f9739b7f6880.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/field/page-2834f44f64e98d74.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/healthz/route-83372d8b5863ebf7.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/inside/page-a13df6f88e824887.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/intake/page-8a4397248754cf2b.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/layout-daf0bd329360a336.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/live/page-f7ef1c28764cb476.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/live-run/page-61e74f28b9353dac.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/loops/page-8aaa6dedc4c10dfb.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/market/page-294602ba649be829.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-5fa5f41ed3fce323.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/morning/page-33bf667a5fb297bf.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/not-found-5ae3cbd6e5dba515.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/observatory/page-eb867d16ad6fdede.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1ab789fa68682f7e.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6fd41b5b6ff13a71.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fb3d5f7642c99fba.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/outputs/page-70f705b2b5ed42ca.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/page-c9c93b358a7667b5.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1563c556b81c96ed.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ce89c20c45b3a673.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/sessions/page-423ae63d786f4ee9.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-591a5378a4c4447c.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/settings/page-a250496b19a5824b.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c36a9277febc5911.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/setup/layout-83372d8b5863ebf7.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/share/page-a5de57edc6d7f942.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/showroom/page-16bdd4c9f40498df.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/tasks/page-75e946e6e71cc6d8.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/term/page-9eb56166774eb256.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/today/page-1c5f9ef35dbb22c5.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/trace/page-657ff9985e508498.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/vault/page-22dc72499da68fb2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/workflows/page-094ad334e40f8169.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8bcd379852ff6287.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-6b04413f280cd344.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/de70ab42-d28d47437208d458.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/f800c5e3.46dbd7f2af8c3fce.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/f8bc19ad.47579f6d684b0760.js +0 -122
  703. package/apps/pwa/out/_next/static/chunks/framework-ca9ac4609fb9fed8.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/main-app-0dd08d32d15a030f.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/main-f0399d33955c4e01.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/pages/_app-d42caca6f8ac2211.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/pages/_error-42e713c13aa41ca8.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/webpack-8fbf8f61a377aa16.js +0 -1
  709. /package/apps/pwa/out/_next/static/{cIpv5nU9AycwYWZI9H589 → LSXfY0u9QtfDbejY0Ukf_}/_ssgManifest.js +0 -0
@@ -0,0 +1,157 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
3
+ import { isAbsolute } from 'node:path';
4
+ import { selectGateTestFiles } from './gate-cli.js';
5
+
6
+ export interface TrainReachCandidate {
7
+ pr: string;
8
+ headSha: string;
9
+ tree: string;
10
+ changedFiles: string[];
11
+ }
12
+
13
+ export interface TrainReachInput {
14
+ version: 1;
15
+ baseSha: string;
16
+ queueSig: string;
17
+ prs: TrainReachCandidate[];
18
+ }
19
+
20
+ export interface TrainReachObservation {
21
+ changedFiles: readonly string[];
22
+ testFiles: readonly string[];
23
+ unverified: readonly string[];
24
+ unrunImporterTotal: number | null;
25
+ lookupFailed?: string;
26
+ routeLookupFailures: readonly { source: string; reason: string }[];
27
+ callerTestsOverflow: readonly { file: string }[];
28
+ alwaysIncludeMissing: readonly string[];
29
+ }
30
+
31
+ export interface TrainReachGroup {
32
+ prs: string[];
33
+ reachTests: string[];
34
+ interactionTests: string[];
35
+ overlapEdges: Array<{ a: string; b: string; tests: string[]; paths: string[] }>;
36
+ status: 'measured' | 'unmeasured';
37
+ capacityBlocked: boolean;
38
+ reasons: string[];
39
+ }
40
+
41
+ export interface TrainReachDecision {
42
+ version: 1;
43
+ baseSha: string;
44
+ queueSig: string;
45
+ parallelSafe: boolean;
46
+ groups: TrainReachGroup[];
47
+ deferred: Array<{ pr: string; reason: string }>;
48
+ }
49
+
50
+ type InspectCandidate = (candidate: TrainReachCandidate, baseSha: string) => TrainReachObservation;
51
+
52
+ const SHA40 = /^[a-f0-9]{40}$/i;
53
+ const SHA256 = /^[a-f0-9]{64}$/i;
54
+ const safePath = (path: string) => path.length > 0 && !path.startsWith('/')
55
+ && !path.includes('\\') && !/[\x00-\x1f\x7f]/.test(path)
56
+ && !path.split('/').some((part) => part === '..' || part === '.');
57
+ const sortedUnique = (values: readonly string[]) => [...new Set(values)].sort();
58
+
59
+ function git(tree: string, ...args: string[]): string {
60
+ const result = spawnSync('git', args, { cwd: tree, encoding: 'utf8', timeout: 15_000, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
61
+ if (result.status !== 0 || result.error) {
62
+ throw new Error(`git ${args[0]} unmeasured: ${result.error?.message ?? result.stderr?.trim() ?? `rc=${result.status}`}`);
63
+ }
64
+ return result.stdout.trim();
65
+ }
66
+
67
+ /** The selector's own base...HEAD comparison is independently checked against the queue snapshot. */
68
+ function inspectTrainReachCandidate(candidate: TrainReachCandidate, baseSha: string): TrainReachObservation {
69
+ if (git(candidate.tree, 'rev-parse', 'HEAD').toLowerCase() !== candidate.headSha.toLowerCase()) {
70
+ throw new Error('tree HEAD differs from queued headSha');
71
+ }
72
+ if (git(candidate.tree, 'status', '--porcelain=v1')) throw new Error('tree is dirty');
73
+ git(candidate.tree, 'cat-file', '-e', `${baseSha}^{commit}`);
74
+ const observation = selectGateTestFiles(candidate.tree, { base: baseSha, includeImporterTests: true });
75
+ if (git(candidate.tree, 'rev-parse', 'HEAD').toLowerCase() !== candidate.headSha.toLowerCase()) {
76
+ throw new Error('tree HEAD changed during reach selection');
77
+ }
78
+ if (git(candidate.tree, 'status', '--porcelain=v1')) throw new Error('tree changed during reach selection');
79
+ return observation;
80
+ }
81
+
82
+ function validateInput(input: TrainReachInput): void {
83
+ if (input?.version !== 1 || !SHA40.test(input.baseSha) || !SHA256.test(input.queueSig) || !Array.isArray(input.prs)) {
84
+ throw new Error('train reach input identity unmeasured');
85
+ }
86
+ const seen = new Set<string>();
87
+ for (const candidate of input.prs) {
88
+ if (!/^[1-9]\d*$/.test(candidate?.pr) || seen.has(candidate.pr) || !SHA40.test(candidate.headSha)
89
+ || !isAbsolute(candidate.tree) || !Array.isArray(candidate.changedFiles) || candidate.changedFiles.length === 0
90
+ || !candidate.changedFiles.every((path) => typeof path === 'string' && safePath(path))) {
91
+ throw new Error(`train reach candidate invalid: ${candidate?.pr ?? 'unknown'}`);
92
+ }
93
+ seen.add(candidate.pr);
94
+ }
95
+ }
96
+
97
+ /** Pure grouping after one independently measured selector observation per queued PR. */
98
+ export function buildTrainReachDecision(input: TrainReachInput, inspect: InspectCandidate = inspectTrainReachCandidate): TrainReachDecision {
99
+ validateInput(input);
100
+ const measured: Array<{ candidate: TrainReachCandidate; tests: string[]; files: string[] }> = [];
101
+ const deferred: TrainReachDecision['deferred'] = [];
102
+ for (const candidate of input.prs) {
103
+ try {
104
+ const observed = inspect(candidate, input.baseSha);
105
+ const actual = sortedUnique(observed.changedFiles);
106
+ const expected = sortedUnique(candidate.changedFiles);
107
+ if (actual.length !== expected.length || actual.some((path, index) => path !== expected[index])) {
108
+ throw new Error('changedFiles differ from selector observation');
109
+ }
110
+ if (observed.lookupFailed || observed.routeLookupFailures.length || observed.unrunImporterTotal !== 0
111
+ || observed.callerTestsOverflow.length || observed.alwaysIncludeMissing.length || observed.unverified.length) {
112
+ throw new Error('test selection has unmeasured reach');
113
+ }
114
+ if (!observed.testFiles.every(safePath)) throw new Error('selected test path invalid');
115
+ measured.push({ candidate, tests: sortedUnique(observed.testFiles), files: sortedUnique(observed.changedFiles) });
116
+ } catch (error) {
117
+ deferred.push({ pr: candidate.pr, reason: error instanceof Error ? error.message : String(error) });
118
+ }
119
+ }
120
+
121
+ const parent = measured.map((_, index) => index);
122
+ const find = (index: number): number => {
123
+ while (parent[index] !== index) index = parent[index] = parent[parent[index]];
124
+ return index;
125
+ };
126
+ const edges: Array<{ left: number; right: number; tests: string[]; paths: string[] }> = [];
127
+ for (let left = 0; left < measured.length; left++) {
128
+ for (let right = left + 1; right < measured.length; right++) {
129
+ const tests = measured[left].tests.filter((path) => measured[right].tests.includes(path));
130
+ const paths = measured[left].files.filter((path) => measured[right].files.includes(path));
131
+ if (!tests.length && !paths.length) continue;
132
+ edges.push({ left, right, tests, paths });
133
+ parent[find(right)] = find(left);
134
+ }
135
+ }
136
+ const components = new Map<number, number[]>();
137
+ for (let index = 0; index < measured.length; index++) {
138
+ const root = find(index);
139
+ components.set(root, [...(components.get(root) ?? []), index]);
140
+ }
141
+ const groups = [...components.values()].map((indices): TrainReachGroup => {
142
+ const prs = indices.map((index) => measured[index].candidate.pr);
143
+ const counts = new Map<string, number>();
144
+ for (const index of indices) for (const test of measured[index].tests) counts.set(test, (counts.get(test) ?? 0) + 1);
145
+ const reachTests = sortedUnique([...counts.keys()]);
146
+ const interactionTests = reachTests.filter((test) => (counts.get(test) ?? 0) > 1);
147
+ const overlapEdges = edges.filter(({ left, right }) => indices.includes(left) && indices.includes(right))
148
+ .map(({ left, right, tests, paths }) => ({ a: measured[left].candidate.pr, b: measured[right].candidate.pr, tests, paths }));
149
+ const capacityBlocked = indices.length > 5;
150
+ const reasons = capacityBlocked ? ['connected reach group exceeds five PR train limit'] : [];
151
+ return { prs, reachTests, interactionTests, overlapEdges,
152
+ status: 'measured', capacityBlocked, reasons };
153
+ });
154
+ return { version: 1, baseSha: input.baseSha, queueSig: input.queueSig,
155
+ parallelSafe: deferred.length === 0 && groups.every(({ status, capacityBlocked }) => status === 'measured' && !capacityBlocked),
156
+ groups, deferred };
157
+ }
@@ -0,0 +1,133 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { isGateSpawnLaneFile } from '../self-dev/spawn-lane-files.js';
4
+ import { isTestPath } from './importer-test-index.js';
5
+ import type { TrainReachDecision, TrainReachInput } from './train-reach-grouping.js';
6
+
7
+ export interface TrainRiskEvidence {
8
+ /** Only evidence-backed paths; an empty list asserts no known hot paths for this queue. */
9
+ verifiedHotFiles: Array<{ path: string; evidence: string }>;
10
+ /** Both endpoints are test paths; evidence must describe a reproduced interaction. */
11
+ verifiedInterferencePairs: Array<{ a: string; b: string; evidence: string }>;
12
+ /** Unreproduced pairs remain visible and prohibit parallel apply when either endpoint is reached. */
13
+ suspectedPairs: Array<{ a: string; b: string; reason: string }>;
14
+ }
15
+
16
+ export interface TrainScenarioGroup {
17
+ prs: string[];
18
+ reachTests: string[];
19
+ interactionTests: string[];
20
+ riskTests: string[];
21
+ riskReasons: Array<{ test: string; reason: string; evidence: string }>;
22
+ groupRiskReasons: Array<{ reason: string; evidence: string }>;
23
+ canaryTests: string[];
24
+ scenarioTests: string[];
25
+ populationSize: number;
26
+ eligiblePopulationSize: number;
27
+ canaryTarget: number;
28
+ /** Reproducible SHA-256 input prefix: baseSha, queueSig, and sorted PRs separated by NUL. */
29
+ canarySelectionKey: string;
30
+ canaryHashMethod: string;
31
+ unmeasured: string[];
32
+ }
33
+
34
+ export interface TrainScenarioDecision {
35
+ version: 1;
36
+ baseSha: string;
37
+ queueSig: string;
38
+ parallelSafe: boolean;
39
+ groups: TrainScenarioGroup[];
40
+ unmeasured: string[];
41
+ }
42
+
43
+ const sorted = (paths: readonly string[]) => [...new Set(paths)].sort();
44
+ const validPath = (path: unknown): path is string => typeof path === 'string' && !!path && !path.startsWith('/') && !path.includes('\\')
45
+ && !/[\x00-\x1f\x7f]/.test(path) && !path.split('/').some((part) => part === '.' || part === '..');
46
+ const hash = (value: string) => createHash('sha256').update(value).digest('hex');
47
+
48
+ /** Read the tracked test population from the pinned base commit, including paths containing spaces. */
49
+ export function readTrainTestPopulation(tree: string, baseSha: string): string[] {
50
+ if (!/^[a-f0-9]{40}$/i.test(baseSha)) throw new Error('invalid baseSha for test population');
51
+ const result = spawnSync('git', ['ls-tree', '-r', '-z', '--name-only', baseSha],
52
+ { cwd: tree, encoding: 'utf8', timeout: 30_000, maxBuffer: 256 * 1024 * 1024 });
53
+ if (result.error || result.status !== 0) throw new Error(`test population unmeasured: ${result.error?.message ?? result.stderr?.trim() ?? result.status}`);
54
+ return sorted(result.stdout.split('\0').filter(isTestPath));
55
+ }
56
+
57
+ /** Pure scenario composition. No unverified hot path or interference guess is promoted to a verified risk. */
58
+ export function buildTrainScenarioDecision(
59
+ input: TrainReachInput, reach: TrainReachDecision, population: readonly string[], evidence: TrainRiskEvidence,
60
+ ): TrainScenarioDecision {
61
+ if (reach.version !== 1 || reach.baseSha !== input.baseSha || reach.queueSig !== input.queueSig
62
+ || !Array.isArray(population) || !population.every((path) => typeof path === 'string' && validPath(path) && isTestPath(path))
63
+ || !evidence || !Array.isArray(evidence.verifiedHotFiles) || !Array.isArray(evidence.verifiedInterferencePairs)
64
+ || !Array.isArray(evidence.suspectedPairs)) throw new Error('scenario identity or population unmeasured');
65
+ const tests = sorted(population);
66
+ const commonTests = new Set(tests);
67
+ const known = new Set([...tests, ...reach.groups.flatMap((group) => group.reachTests)]);
68
+ const validEvidence = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;
69
+ for (const item of evidence.verifiedHotFiles) {
70
+ if (!validPath(item?.path) || !validEvidence(item?.evidence)) throw new Error('hot-file evidence unmeasured');
71
+ }
72
+ for (const item of [...evidence.verifiedInterferencePairs, ...evidence.suspectedPairs]) {
73
+ if (!validPath(item?.a) || !validPath(item?.b) || !known.has(item.a) || !known.has(item.b)
74
+ || item.a === item.b || !validEvidence(item && 'evidence' in item ? item.evidence : item?.reason)) {
75
+ throw new Error('interference-pair evidence unmeasured');
76
+ }
77
+ }
78
+ const changedByPr = new Map(input.prs.map(({ pr, changedFiles }) => [pr, changedFiles]));
79
+ const groups = reach.groups.map((group): TrainScenarioGroup => {
80
+ const reached = new Set(group.reachTests);
81
+ if ([...reached].some((path) => !validPath(path) || !isTestPath(path))) throw new Error('reached test path invalid');
82
+ const riskReasons: TrainScenarioGroup['riskReasons'] = [];
83
+ const groupRiskReasons: TrainScenarioGroup['groupRiskReasons'] = [];
84
+ const unavailable: string[] = [];
85
+ const risk = new Set<string>();
86
+ const addRisk = (test: string, reason: string, source: string): void => {
87
+ risk.add(test);
88
+ riskReasons.push({ test, reason, evidence: source });
89
+ };
90
+ for (const test of reached) if (isGateSpawnLaneFile(test)) addRisk(test, 'spawn-lane', 'src/self-dev/spawn-lane-files.ts');
91
+ const changed = new Set(group.prs.flatMap((pr) => changedByPr.get(pr) ?? []));
92
+ for (const hot of evidence.verifiedHotFiles) if (changed.has(hot.path)) {
93
+ groupRiskReasons.push({ reason: `hot-file:${hot.path}`, evidence: hot.evidence });
94
+ }
95
+ for (const pair of evidence.verifiedInterferencePairs) {
96
+ if (reached.has(pair.a) || reached.has(pair.b)) {
97
+ const endpoints: Array<[string, string]> = [[pair.a, pair.b], [pair.b, pair.a]];
98
+ for (const [test, other] of endpoints) {
99
+ if (reached.has(test) || commonTests.has(test)) addRisk(test, `interference-with:${other}`, pair.evidence);
100
+ else unavailable.push(`verified interference endpoint unavailable in every PR head: ${test}`);
101
+ }
102
+ }
103
+ }
104
+ const canaryPrefix = `${input.baseSha}\0${input.queueSig}\0${sorted(group.prs).join(',')}`;
105
+ const used = new Set([...reached, ...risk]);
106
+ const eligible = tests.filter((test) => !used.has(test));
107
+ const canaryTarget = eligible.length ? Math.max(1, Math.round(eligible.length * 0.02)) : 0;
108
+ const canaryTests = eligible
109
+ .sort((a, b) => hash(`${canaryPrefix}\0${a}`).localeCompare(hash(`${canaryPrefix}\0${b}`)) || a.localeCompare(b))
110
+ .slice(0, canaryTarget).sort();
111
+ const scenarioTests = sorted([...reached, ...risk, ...canaryTests]);
112
+ const scenarioSet = new Set(scenarioTests);
113
+ const unmeasured = [...unavailable, ...evidence.suspectedPairs
114
+ .filter((pair) => scenarioSet.has(pair.a) || scenarioSet.has(pair.b))
115
+ .map((pair) => `suspected interference ${pair.a} ↔ ${pair.b}: ${pair.reason}`)];
116
+ return { prs: group.prs, reachTests: group.reachTests, interactionTests: group.interactionTests,
117
+ riskTests: sorted([...risk]), riskReasons, groupRiskReasons, canaryTests,
118
+ scenarioTests, populationSize: tests.length, eligiblePopulationSize: eligible.length,
119
+ canaryTarget, canarySelectionKey: canaryPrefix,
120
+ canaryHashMethod: 'sha256(canarySelectionKey\\0path)', unmeasured };
121
+ });
122
+ const unmeasured = groups.flatMap((group) => group.unmeasured);
123
+ // A verified interference pair executed by multiple scenarios bars parallel trains, including canary selection.
124
+ for (const pair of evidence.verifiedInterferencePairs) {
125
+ const aOwners = groups.flatMap((group, index) => group.scenarioTests.includes(pair.a) ? [index] : []);
126
+ const bOwners = groups.flatMap((group, index) => group.scenarioTests.includes(pair.b) ? [index] : []);
127
+ if (aOwners.some((a) => bOwners.some((b) => a !== b))) {
128
+ unmeasured.push(`verified interference crosses groups ${pair.a} ↔ ${pair.b}: ${pair.evidence}`);
129
+ }
130
+ }
131
+ return { version: 1, baseSha: input.baseSha, queueSig: input.queueSig,
132
+ parallelSafe: reach.parallelSafe && unmeasured.length === 0, groups, unmeasured };
133
+ }
@@ -1,4 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../util/spawn-sync-output.js';
2
3
  import { isElanousRuntimeArtifactPath } from './gate-scope.js';
3
4
 
4
5
  export type UncommittedWork =
@@ -19,6 +20,7 @@ export function detectUncommittedWork(worktree: string): UncommittedWork {
19
20
  env: gitEnv,
20
21
  encoding: 'utf8',
21
22
  timeout: 10_000,
23
+ maxBuffer: SPAWN_SYNC_MAX_BUFFER,
22
24
  });
23
25
  } catch (error) {
24
26
  return { status: 'unavailable', reason: error instanceof Error ? error.message : String(error) };
@@ -99,6 +99,25 @@ export function removePendingUserInput(
99
99
  return removedIds.length;
100
100
  }
101
101
 
102
+ /**
103
+ * id 로 고른 항목을 버킷 «맨 앞»으로 옮긴다(주어진 순서대로) — «지금 밀어 넣기»가 끊을 수 없는 도구 때문에
104
+ * 다음 경계로 떨어질 때, 같은 버킷의 다른 항목(goal-loop 메모 등)보다 먼저 들어가게 한다. 옮긴 수를 낸다.
105
+ */
106
+ export function prioritizePendingUserInput(ids: readonly string[]): number {
107
+ if (ids.length === 0) return 0;
108
+ const order = new Map(ids.map((id, index) => [id, index]));
109
+ let moved = 0;
110
+ for (const bucket of buckets.values()) {
111
+ const front = bucket.items.filter(item => order.has(item.id))
112
+ .sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0));
113
+ if (front.length === 0) continue;
114
+ bucket.items = [...front, ...bucket.items.filter(item => !order.has(item.id))];
115
+ moved += front.length;
116
+ }
117
+ if (moved > 0) debug.log('llm.interjection', 'prioritized', { requested: ids.length, moved });
118
+ return moved;
119
+ }
120
+
102
121
  /** 지금 이 세션에 대기 중인 수(관측·표시용). 비우지 «않는다». */
103
122
  export function pendingUserInputCount(sessionId: string): number {
104
123
  return buckets.get(sessionId)?.items.length ?? 0;
@@ -0,0 +1,224 @@
1
+ // 🧭 세션 시작 결정 — «인자 없음 = 깨끗한 새 세션», 이어하기는 명시 인자일 때만 (TUI-H8-SESSION-NEW-DEFAULT · 대표 10-16 #73).
2
+ //
3
+ // S: `elanous chat` · `agent` · `repl` 은 인자 없이 뜨면 «활성 세션»(~/.local/state/elanous/active)을 조용히 이어받았다.
4
+ // 그래서 앞 프로세스가 도구 호출 도중 죽은 기록(호출·결과 짝이 깨진 꼬리)까지 이어받아 첫 턴이 400 으로 죽었다(#69).
5
+ // C: 다른 에이전트(codex·claude·grok)는 인자 없음 = 새 세션 · 이어하기 = `--resume`/`--continue` 다.
6
+ // A: 시작 결정을 이 함수 하나로 모으고, 결정마다 `session`/`start` 한 줄을 남긴다(관측).
7
+ // ⛔ 자리 맥락은 세션이 아니라 자리 문서(AGENTS.local.md · `.AGENTS.local.last-session.md` · 부트 카드)가 매 턴 싣는다 —
8
+ // 새 세션이어도 맥락은 그대로다(`turn-preamble.ts` · `universal-preamble.ts`).
9
+
10
+ import { debug } from '../debug/log.js';
11
+
12
+ export type SessionStartOrigin = 'new' | 'resume';
13
+ export type SessionStartReason =
14
+ | 'default-new'
15
+ | 'force-new'
16
+ | 'explicit-session'
17
+ | 'continue-active'
18
+ | 'continue-latest'
19
+ | 'continue-no-active';
20
+
21
+ export interface SessionStartDecision {
22
+ origin: SessionStartOrigin;
23
+ reason: SessionStartReason;
24
+ /** 이어받을 세션 id(명시 id 는 호출부가 이미 풀어서 넘긴다). 새 세션이면 undefined. */
25
+ sessionIdHint?: string;
26
+ }
27
+
28
+ /** 단일 결정 — 명시 id > `--new` > `--continue`/`--resume`(활성 세션 ⊕ 표지가 낡았으면 최신 세션) > 기본 새 세션.
29
+ * `sessionExists`·`latestSessionId` 를 주면 활성 표지가 «사라진 세션»을 가리킬 때 최신 세션으로 넘어간다
30
+ * (TUI-H8-FOLLOW ① · #28509 리뷰 should-fix). 안 주면 옛 동작(표지를 그대로 믿는다). */
31
+ export function decideSessionStart(input: {
32
+ explicitSessionId?: string;
33
+ continueActive: boolean;
34
+ forceNew: boolean;
35
+ activeSessionId: () => string | null;
36
+ sessionExists?: (id: string) => boolean;
37
+ latestSessionId?: () => string | null;
38
+ }): SessionStartDecision {
39
+ if (input.explicitSessionId) {
40
+ return { origin: 'resume', reason: 'explicit-session', sessionIdHint: input.explicitSessionId };
41
+ }
42
+ if (input.forceNew) return { origin: 'new', reason: 'force-new' };
43
+ if (input.continueActive) {
44
+ const picked = pickContinueSession(input);
45
+ if (!picked) return { origin: 'new', reason: 'continue-no-active' };
46
+ return {
47
+ origin: 'resume',
48
+ reason: picked.from === 'active' ? 'continue-active' : 'continue-latest',
49
+ sessionIdHint: picked.id,
50
+ };
51
+ }
52
+ return { origin: 'new', reason: 'default-new' };
53
+ }
54
+
55
+ /** 존재 확인 — 확인 자체가 실패하면 «있다»고 보지 않는다(이어받을 수 없는 세션을 고르지 않는다). */
56
+ function sessionAlive(exists: ((id: string) => boolean) | undefined, id: string): boolean {
57
+ if (!exists) return true;
58
+ try { return exists(id); } catch { return false; }
59
+ }
60
+
61
+ /** «이어하기» 대상 — 활성 표지 ⊕ (표지가 없거나 사라진 세션이면) 최신 세션. 낡은 표지는 `session`/`active-marker-stale` 로 남긴다. */
62
+ function pickContinueSession(deps: {
63
+ activeSessionId: () => string | null;
64
+ sessionExists?: (id: string) => boolean;
65
+ latestSessionId?: () => string | null;
66
+ }): { id: string; from: 'active' | 'latest' } | null {
67
+ let active: string | null = null;
68
+ try { active = deps.activeSessionId(); } catch { /* 활성 표지 읽기 실패 — 최신 세션으로 넘어간다 */ }
69
+ if (active && sessionAlive(deps.sessionExists, active)) return { id: active, from: 'active' };
70
+ const picked = pickLatest(deps, active);
71
+ if (active) {
72
+ // 관측은 «실제로 고른 결과»로 남긴다(r1 should-fix — 최신이 없어 새 세션이면 fallback:'none').
73
+ try {
74
+ debug.log('session', 'active-marker-stale', { activeSessionId: active, fallback: picked ? 'latest' : 'none' });
75
+ } catch { /* 관측 실패가 시작을 막지 않는다 */ }
76
+ }
77
+ return picked;
78
+ }
79
+
80
+ function pickLatest(deps: {
81
+ sessionExists?: (id: string) => boolean;
82
+ latestSessionId?: () => string | null;
83
+ }, staleActive: string | null): { id: string; from: 'latest' } | null {
84
+ if (!deps.latestSessionId) return null;
85
+ let latest: string | null = null;
86
+ try { latest = deps.latestSessionId(); } catch { return null; }
87
+ if (!latest || latest === staleActive || !sessionAlive(deps.sessionExists, latest)) return null;
88
+ return { id: latest, from: 'latest' };
89
+ }
90
+
91
+ /** `elanous --resume`/`--continue` 처럼 id 없이 «이어하기»만 받은 표면이 이어받을 세션 — 활성 표지 ⊕ 없거나 사라졌으면 최신. */
92
+ export function resolveLatestSessionId(deps: {
93
+ activeSessionId: () => string | null;
94
+ latestSessionId: () => string | null;
95
+ sessionExists?: (id: string) => boolean;
96
+ }): string | null {
97
+ return pickContinueSession(deps)?.id ?? null;
98
+ }
99
+
100
+ /** 세션 id 꼴인가 — 세션 id 는 uuid v4(`randomUUID` · 8-4-4-4-12 hex)이고 «고유 접두»도 받는다.
101
+ * uuid 의 «접두»(하이픈은 9·14·19·24번째 자리에만) 4~36자 ⊕ 숫자 하나 이상(«face»·«deadbeef» 같은 낱말을 id 로 먹지 않게).
102
+ * 숫자 없는 hex 접두를 id 로 쓰려면 `--session <id>` 를 쓴다. */
103
+ export function looksLikeSessionId(value: string): boolean {
104
+ const v = value.trim().toLowerCase();
105
+ if (v.length < 4 || v.length > 36 || !/[0-9]/.test(v)) return false;
106
+ for (let i = 0; i < v.length; i += 1) {
107
+ const c = v[i]!;
108
+ const hyphenSlot = i === 8 || i === 13 || i === 18 || i === 23;
109
+ if (hyphenSlot ? c !== '-' : !/[0-9a-f]/.test(c)) return false;
110
+ }
111
+ return true;
112
+ }
113
+
114
+ /** `--resume [id]` 뒤 위치 인자 — Commander 는 값 선택형 옵션 뒤 첫 낱말을 값으로 먹는다.
115
+ * 그 값이 세션 id 꼴이 아니면 «id 없는 --resume ⊕ 프롬프트 낱말»로 되돌린다(TUI-H8-FOLLOW ②).
116
+ * `argv` 를 주면 되돌린 낱말을 입력 «순서 그대로» 끼운다(`chat hello --resume world` → `hello world`);
117
+ * 안 주면 맨 앞에 놓는다. */
118
+ export function splitResumeArgument(
119
+ resume: string | boolean | undefined,
120
+ parts: readonly string[],
121
+ surface: 'chat' | 'agent',
122
+ argv?: readonly string[],
123
+ ): { resume: string | boolean | undefined; parts: string[] } {
124
+ if (typeof resume !== 'string' || looksLikeSessionId(resume)) return { resume, parts: [...parts] };
125
+ const at = argv ? resumeInsertIndex(argv, parts, resume, surface) : 0;
126
+ try {
127
+ debug.log('session', 'resume-value-as-prompt', { surface, words: resume.split(/\s+/).filter(Boolean).length, at });
128
+ } catch { /* 관측 실패가 시작을 막지 않는다 */ }
129
+ return { resume: true, parts: [...parts.slice(0, at), resume, ...parts.slice(at)] };
130
+ }
131
+
132
+ /** chat·agent argv 를 «한 번» 토큰화한 결과 — 위치 인자(순서대로) ⊕ `--resume` 값이 몇 번째 위치 인자 «앞»에 왔나.
133
+ * (r3 TF 결정: 한 지점 땜질 대신 토큰화로 일반화 — 리뷰 진동을 끊는다.)
134
+ * 규칙(Commander 와 같은 읽기):
135
+ * - 명령 낱말(`chat`/`agent`) «뒤»부터 본다(앞은 루트 옵션).
136
+ * - `--` 뒤는 전부 위치 인자.
137
+ * - `--resume=X` → X 가 resume 값. `--resume X` → X 가 `-` 로 시작하지 않으면 resume 값(값 선택형).
138
+ * - 값을 받는 옵션(`--session`)은 `--session X`·`--session=X` 모두 값을 건너뛴다.
139
+ * - 그 밖의 `-` 로 시작하는 토큰은 값 없는 플래그(`--continue` 등 · `--continue=X` 는 Commander 가 거부한다).
140
+ * - 나머지는 위치 인자. */
141
+ export function tokenizeResumeArgv(
142
+ argv: readonly string[],
143
+ surface: 'chat' | 'agent',
144
+ ): { positionals: string[]; resumeValue: string | null; resumeValueAt: number | null } {
145
+ const VALUE_OPTIONS = new Set(['--session']);
146
+ const positionals: string[] = [];
147
+ let resumeValue: string | null = null;
148
+ let resumeValueAt: number | null = null;
149
+ let afterDoubleDash = false;
150
+ for (let i = argv.indexOf(surface) + 1; i < argv.length; i += 1) {
151
+ const token = argv[i]!;
152
+ if (afterDoubleDash) { positionals.push(token); continue; }
153
+ if (token === '--') { afterDoubleDash = true; continue; }
154
+ if (token.startsWith('--resume=')) {
155
+ resumeValue = token.slice('--resume='.length);
156
+ resumeValueAt = positionals.length;
157
+ continue;
158
+ }
159
+ if (token === '--resume') {
160
+ const next = argv[i + 1];
161
+ if (next !== undefined && !next.startsWith('-')) {
162
+ resumeValue = next;
163
+ resumeValueAt = positionals.length;
164
+ i += 1;
165
+ }
166
+ continue;
167
+ }
168
+ const eq = token.indexOf('=');
169
+ if (token.startsWith('--') && VALUE_OPTIONS.has(eq >= 0 ? token.slice(0, eq) : token)) {
170
+ if (eq < 0) i += 1;
171
+ continue;
172
+ }
173
+ if (token.startsWith('-')) continue;
174
+ positionals.push(token);
175
+ }
176
+ return { positionals, resumeValue, resumeValueAt };
177
+ }
178
+
179
+ /** 되돌린 낱말을 끼울 자리 — 토큰화 결과가 Commander 가 준 값·위치 인자와 «다르면» 맨 앞(옛 동작)으로 접고 남긴다. */
180
+ function resumeInsertIndex(argv: readonly string[], parts: readonly string[], resume: string, surface: 'chat' | 'agent'): number {
181
+ const t = tokenizeResumeArgv(argv, surface);
182
+ const agrees = t.resumeValue === resume
183
+ && t.resumeValueAt !== null
184
+ && t.positionals.length === parts.length
185
+ && t.positionals.every((p, i) => p === parts[i]);
186
+ if (agrees) return t.resumeValueAt!;
187
+ try { debug.log('session', 'resume-argv-mismatch', { surface, positionals: t.positionals.length, parts: parts.length }); } catch { /* best-effort */ }
188
+ return 0;
189
+ }
190
+
191
+ /** 대시보드 TUI 루트 이어하기 — 우선순위 `--resume <id>` > `--continue`·id 없는 `--resume`(최신 세션) >
192
+ * (폐기 예정) `ELANOUS_RESUME_SESSION`. ⛔ 명시 인자가 있으면 환경변수가 이기지 않는다. 아무것도 없으면 새 세션. */
193
+ export function resolveRootResumeSessionId(input: {
194
+ flagId?: string;
195
+ continueLatest: boolean;
196
+ /** 폐기 예정 env 읽기 — 명시 인자가 하나도 없을 때만 «부른다»(읽기 자체가 폐기 경고를 낸다 · r2 must-fix). */
197
+ readEnvId: () => string | null | undefined;
198
+ latest: () => string | null;
199
+ }): { sessionId?: string; source: 'flag' | 'continue' | 'continue-none' | 'env' | 'none' } {
200
+ const flagId = (input.flagId ?? '').trim();
201
+ if (flagId) return { sessionId: flagId, source: 'flag' };
202
+ if (input.continueLatest) {
203
+ const latest = input.latest();
204
+ return latest ? { sessionId: latest, source: 'continue' } : { source: 'continue-none' };
205
+ }
206
+ const envId = (input.readEnvId() ?? '').trim();
207
+ if (envId) return { sessionId: envId, source: 'env' };
208
+ return { source: 'none' };
209
+ }
210
+
211
+ /** 관측 — 세션이 «어떻게» 시작됐나. 실패해도 시작을 막지 않는다. */
212
+ export function observeSessionStart(data: {
213
+ surface: 'chat' | 'agent' | 'repl' | 'tui' | 'ask';
214
+ origin: SessionStartOrigin;
215
+ reason: string;
216
+ sessionId?: string | null;
217
+ [key: string]: unknown;
218
+ }): void {
219
+ try {
220
+ debug.log('session', 'start', data);
221
+ } catch {
222
+ // Observation must never block a session start.
223
+ }
224
+ }
@@ -93,31 +93,48 @@ export function partitionByParallelSafety<T extends { name: string }>(
93
93
  *
94
94
  * When `safe.length < 2`, the helper degenerates into pure sequential
95
95
  * dispatch in original order — no parallelism benefit for 0-1 safe
96
- * calls so we keep behaviour identical to pre-P2. */
96
+ * calls so we keep behaviour identical to pre-P2.
97
+ *
98
+ * ⭐ `signal` (TUI-ESC-ABORT-TOOLS · 2026-10-15) — 턴 중단(Esc)이 걸리면 묶음 안
99
+ * «남은» 호출을 새로 시작하지 않는다. 순차 갈래·unsafe 갈래에서 호출마다
100
+ * `signal.aborted` 를 보고, 참이면 그 호출과 뒤의 호출을 부르지 않는다.
101
+ * ⛔ 이미 시작한 호출은 끊지 않는다(진행 중 도구의 중단은 도구가 받는 신호의 몫).
102
+ * ⛔ 병렬(safe) 묶음은 한꺼번에 시작되므로 시작 «전»에만 본다.
103
+ * 부르지 않은 호출의 결과 칸은 비어 있다 — 호출자가 «중단됨» 결과로 채워
104
+ * 공급자 이력의 tool_call/tool_result 짝을 지킨다(`skippedIndices`). */
97
105
  export async function dispatchWithParallelSafety<T extends { name: string }>(
98
106
  calls: readonly T[],
99
107
  dispatchOne: (call: T, index: number) => Promise<void>,
100
- ): Promise<{ safeCount: number; unsafeCount: number; parallelActivated: boolean }> {
108
+ signal?: AbortSignal,
109
+ ): Promise<{ safeCount: number; unsafeCount: number; parallelActivated: boolean; skippedIndices: number[] }> {
101
110
  const { safe, unsafe } = partitionByParallelSafety(calls);
102
111
  const parallelActivated = safe.length >= 2;
112
+ const skippedIndices: number[] = [];
103
113
  if (!parallelActivated) {
104
114
  // Fall back to pure sequential in original order. Keeps pre-P2
105
115
  // behaviour bit-exact when only one read tool is in the batch
106
116
  // (common case — no benefit to firing Promise.all for a single
107
117
  // call).
108
118
  for (let i = 0; i < calls.length; i += 1) {
119
+ if (signal?.aborted) { skippedIndices.push(i); continue; }
109
120
  await dispatchOne(calls[i]!, i);
110
121
  }
111
- return { safeCount: safe.length, unsafeCount: unsafe.length, parallelActivated };
122
+ return { safeCount: safe.length, unsafeCount: unsafe.length, parallelActivated, skippedIndices };
112
123
  }
113
124
  // Parallel kickoff for the safe group. Promise.all is safe here
114
125
  // because `dispatchOne` is expected to catch its own errors and
115
126
  // write an error result into the caller's storage — we never want
116
127
  // one failing Read to cancel two sibling Reads.
117
- await Promise.all(safe.map(({ call, index }) => dispatchOne(call, index)));
128
+ if (signal?.aborted) {
129
+ for (const { index } of safe) skippedIndices.push(index);
130
+ } else {
131
+ await Promise.all(safe.map(({ call, index }) => dispatchOne(call, index)));
132
+ }
118
133
  // Unsafe group: sequential, in original order.
119
134
  for (const { call, index } of unsafe) {
135
+ if (signal?.aborted) { skippedIndices.push(index); continue; }
120
136
  await dispatchOne(call, index);
121
137
  }
122
- return { safeCount: safe.length, unsafeCount: unsafe.length, parallelActivated };
138
+ skippedIndices.sort((a, b) => a - b);
139
+ return { safeCount: safe.length, unsafeCount: unsafe.length, parallelActivated, skippedIndices };
123
140
  }
@@ -96,6 +96,8 @@ export function buildRunDevHarnessTool(): LLMToolSpec {
96
96
 
97
97
  /** dev-harness 실행 seam 세트(테스트/대체 주입). */
98
98
  export interface DevHarnessDeps {
99
+ /** 시험 전용 target HOME. 생략하면 resolveHarnessTarget 의 실제 homedir 기본값을 쓴다. */
100
+ targetHome?: string;
99
101
  /** 하니스 구동(기본 runStagedHarnessOnSurface). */
100
102
  runHarness?: (opts: RunHarnessOnSurfaceOptions) => Promise<HarnessResult>;
101
103
  /** In-process 실행 직전의 관측 전용 디스패치 seam. */
@@ -319,7 +321,7 @@ export async function dispatchRunDevHarness(
319
321
  let targetResolution: HarnessTargetResolution | undefined;
320
322
  if (!targetOptions && target) {
321
323
  const elanousBinRoot = resolveMainRepoRoot(process.cwd()) ?? process.cwd();
322
- const resolution = resolveHarnessTarget(target);
324
+ const resolution = resolveHarnessTarget(target, { home: deps?.targetHome });
323
325
  targetResolution = resolution;
324
326
  debug.log('harness.frontdoor', 'target.resolved', {
325
327
  target, kind: resolution.status, elanousBinRoot,
@@ -343,7 +345,7 @@ export async function dispatchRunDevHarness(
343
345
  debug.log('harness.frontdoor', 'refused', { target, reason: 'outside-home-declined', interactive: ux.interactive });
344
346
  return { output: `RunDevHarness ⚠️ 거부: 홈 밖 시스템경로 '${target}' — 진입 ${ux.interactive ? '취소됨(HITL 미승인).' : '승인 채널 없음(fail-closed).'}` };
345
347
  }
346
- const authorized = revalidateHarnessTarget(resolution);
348
+ const authorized = revalidateHarnessTarget(resolution, { home: deps?.targetHome });
347
349
  if (authorized.status === 'normalization-failed' || authorized.status === 'missing') {
348
350
  debug.log('harness.frontdoor', 'refused', { target, reason: 'outside-home-revalidation-failed', detail: authorized.reason });
349
351
  return { output: `RunDevHarness ⚠️ 거부: target '${target}' — 승인 중 경로 재검증에 실패했습니다.` };
@@ -369,7 +371,7 @@ export async function dispatchRunDevHarness(
369
371
  // Recheck immediately before handing paths to seams; a symlink retarget after
370
372
  // classification must not reach staging or apply through stale options.
371
373
  if (targetResolution) {
372
- const revalidated = revalidateHarnessTarget(targetResolution);
374
+ const revalidated = revalidateHarnessTarget(targetResolution, { home: deps?.targetHome });
373
375
  if (revalidated.status === 'normalization-failed') {
374
376
  debug.log('harness.frontdoor', 'refused', { target, reason: 'target-revalidation-failed', detail: revalidated.reason });
375
377
  return { output: `RunDevHarness ⚠️ 거부: target '${target}' — 스테이징 전 경로 재검증에 실패했습니다.` };
@@ -421,7 +423,7 @@ export async function dispatchRunDevHarness(
421
423
  });
422
424
  if (targetResolution) {
423
425
  const assertStableTarget = (): void => {
424
- const current = revalidateHarnessTarget(targetResolution!);
426
+ const current = revalidateHarnessTarget(targetResolution!, { home: deps?.targetHome });
425
427
  if (current.status === 'normalization-failed' || current.status === 'missing') {
426
428
  debug.log('harness.frontdoor', 'refused', { target, reason: 'target-revalidation-failed', detail: current.reason });
427
429
  throw new Error(`harness target revalidation failed: ${current.reason ?? current.status}`);