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,367 @@
1
+ // 시험 간섭 꼴 정적 래칫 (TEST-INTERFERENCE-RATCHET · 0.2.31 · 대표 승인)
2
+ //
3
+ // 왜 있나: 0.2.30 게이트가 «측정 불가»로 네 번 멈췄다. 넷 다 제품 결함이 아니라 «시험이 다음 시험을
4
+ // 건드린» 간섭이었다. bun 은 시간초과된 시험의 약속을 «취소하지 않는다» — 본문은 afterEach 뒤에도 계속
5
+ // 돌며 전역(env · cwd · window · 잠금)을 다음 시험 위에서 만진다. 표본(수리 PR):
6
+ // A nexus #28517 e56d8c28 — 시험 본문 안 `await import('../src/nexus/index.js')` 가 차가운 Pod 에서
7
+ // 5s 를 넘겨, 남은 runNexus 가 다음 시험 폴더의 잠금을 잡았다(TelegramLockError).
8
+ // B probe #28527 b5ca5041 — 본문 안 무거운 import 로 시간초과 → afterEach 가 폴더를 지운 «뒤에»
9
+ // 본문이 그 폴더로 chdir(ENOENT). 복원은 본문 finally 뿐(시간초과면 afterEach 보다 늦다).
10
+ // E integrity #28527 — 자식 bun 에 100ms 한도 → 차가운 Pod 에서 처리기 걸기 전에 SIGTERM.
11
+ // D PWA #28527 — react-test-renderer 맨몸 unmount 가 passive 정리를 afterAll(window 걷기) 뒤로 미뤄
12
+ // 다음 파일에서 «window is not defined».
13
+ // 꼴 C(afterEach 없이 env 바꿈)는 칸 문면의 넷째 꼴이다 — 표본 넷 중 직접 짝은 없다(nexus 는 afterEach 가 있었다).
14
+ //
15
+ // 판정은 «보수적»이다: 꼴마다 «정리 짝»이 보이면 통과시킨다. 기존 위반은 허용 목록(파일·꼴·개수)으로
16
+ // 시작하고, 개수가 «늘면»만 실패한다(래칫). 줄면 갱신 안내만 낸다.
17
+ //
18
+ // 쓰는 법:
19
+ // bun scripts/ratchets/test-interference-patterns.ts # 전수 판정(새 위반이면 exit 1)
20
+ // bun scripts/ratchets/test-interference-patterns.ts <file…> # 그 파일만 판정(착지 범위용)
21
+ // bun scripts/ratchets/test-interference-patterns.ts --update-allowlist # 허용 목록을 지금 전수로 다시 쓴다
22
+
23
+ import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
24
+ import { join, relative, resolve, sep } from 'node:path';
25
+ import * as ts from 'typescript';
26
+
27
+ export const REPO_ROOT = resolve(import.meta.dir, '../..');
28
+ export const ALLOWLIST_PATH = join(REPO_ROOT, 'scripts/ratchets/test-interference-patterns.allowlist.txt');
29
+ export const UPDATE_COMMAND = 'bun scripts/ratchets/test-interference-patterns.ts --update-allowlist';
30
+
31
+ export type InterferenceForm =
32
+ | 'body-dynamic-import'
33
+ | 'chdir-without-restore'
34
+ | 'env-without-restore'
35
+ | 'bare-unmount-with-window'
36
+ | 'short-child-timeout';
37
+
38
+ export const FORMS: Record<InterferenceForm, string> = {
39
+ 'body-dynamic-import': '시험 본문 안 저장소 모듈 동적 import — 차가운 Pod 에서 5s 를 넘기고 남은 본문이 다음 시험 위에서 돈다. 처방: beforeAll(넉넉한 한도)로 데우기 또는 정적 import (test/helpers/nexus-boot-guard.ts 꼴)',
40
+ 'chdir-without-restore': 'process.chdir 에 정리 짝이 없다 — afterEach/afterAll 의 cwd 복원 또는 «동기» 함수의 finally 복원. 비동기 본문의 finally 는 시간초과면 afterEach 보다 늦다(test/helpers/inflight-test-guard.ts 꼴)',
41
+ 'env-without-restore': 'process.env 를 바꾸는데 afterEach/afterAll 또는 finally 복원이 없다 — 다음 시험이 바뀐 env 위에서 돈다',
42
+ 'bare-unmount-with-window': 'react-test-renderer 맨몸 unmount() — passive 정리를 afterAll(window 걷기) 뒤로 미뤄 «window is not defined». 처방: await act(async () => renderer.unmount())',
43
+ 'short-child-timeout': '자식 프로세스(process.execPath)에 1000ms 미만 한도 — 차가운 Pod 에서 기동 전에 죽는다. 처방: 기동 여유를 둔 한도',
44
+ };
45
+
46
+ export interface Violation { file: string; line: number; form: InterferenceForm; text: string }
47
+
48
+ const TEST_FILE = /\.test\.tsx?$/;
49
+ const SKIP_DIRS = new Set(['node_modules']); // ⚠️ 'build'·'out' 은 소스 폴더 이름이기도 하다(src/autopilot/build) — 빼지 않는다
50
+ /** 내용 사전 거름 — 이 낱말이 하나도 없으면 파싱하지 않는다(전수 스캔 시간). */
51
+ const PREFILTER = /import\(|chdir|process\.env|unmount|execPath/;
52
+
53
+ export function listTestFiles(root = REPO_ROOT): string[] {
54
+ const out: string[] = [];
55
+ const walk = (dir: string) => {
56
+ let names: string[];
57
+ try { names = readdirSync(dir); } catch { return; }
58
+ for (const name of names) {
59
+ if (name.startsWith('.') || SKIP_DIRS.has(name)) continue;
60
+ const full = join(dir, name);
61
+ let st;
62
+ try { st = statSync(full); } catch { continue; }
63
+ if (st.isDirectory()) walk(full);
64
+ else if (TEST_FILE.test(name)) out.push(relative(root, full).split(sep).join('/'));
65
+ }
66
+ };
67
+ walk(root);
68
+ return out.sort();
69
+ }
70
+
71
+ type Role = 'test' | 'before' | 'after' | 'helper' | 'top';
72
+ const HOOKS: Record<string, Role> = { beforeAll: 'before', beforeEach: 'before', afterAll: 'after', afterEach: 'after' };
73
+
74
+ function baseIdentifier(expr: ts.Expression): string | undefined {
75
+ let e: ts.Expression = expr;
76
+ for (;;) {
77
+ if (ts.isIdentifier(e)) return e.text;
78
+ if (ts.isPropertyAccessExpression(e)) e = e.expression;
79
+ else if (ts.isCallExpression(e)) e = e.expression;
80
+ else return undefined;
81
+ }
82
+ }
83
+
84
+ function isFunctionLike(node: ts.Node): node is ts.ArrowFunction | ts.FunctionExpression | ts.FunctionDeclaration | ts.MethodDeclaration {
85
+ return ts.isArrowFunction(node) || ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node);
86
+ }
87
+
88
+ /** `import { afterEach as freezeIsolationAfterEach } from 'bun:test'` — local name → bun:test name. */
89
+ type Aliases = Map<string, string>;
90
+ let aliases: Aliases = new Map();
91
+
92
+ function readAliases(sf: ts.SourceFile): Aliases {
93
+ const map: Aliases = new Map();
94
+ for (const st of sf.statements) {
95
+ if (!ts.isImportDeclaration(st) || !ts.isStringLiteral(st.moduleSpecifier) || st.moduleSpecifier.text !== 'bun:test') continue;
96
+ const named = st.importClause?.namedBindings;
97
+ if (named && ts.isNamedImports(named)) for (const el of named.elements) map.set(el.name.text, (el.propertyName ?? el.name).text);
98
+ }
99
+ return map;
100
+ }
101
+
102
+ function bunName(expr: ts.Expression): string | undefined {
103
+ const base = baseIdentifier(expr);
104
+ return base === undefined ? undefined : aliases.get(base) ?? base;
105
+ }
106
+
107
+ /** The role a function plays when it is (or is wrapped as) an argument of test()/it()/hook calls. */
108
+ function callbackRole(fn: ts.Node): Role | undefined {
109
+ let child: ts.Node = fn;
110
+ let parent = fn.parent;
111
+ // `guard.track(async () => …)` — the callback may sit one call deep.
112
+ for (let depth = 0; depth < 2 && parent && ts.isCallExpression(parent); depth++) {
113
+ if (!parent.arguments.includes(child as ts.Expression)) return undefined;
114
+ const base = bunName(parent.expression);
115
+ if (base === 'test' || base === 'it') return 'test';
116
+ if (base && HOOKS[base]) return HOOKS[base];
117
+ child = parent;
118
+ parent = parent.parent;
119
+ }
120
+ return undefined;
121
+ }
122
+
123
+ interface Ctx { role: Role; fns: ts.Node[] /* enclosing functions, nearest first */ }
124
+
125
+ function context(node: ts.Node): Ctx {
126
+ const fns: ts.Node[] = [];
127
+ for (let p: ts.Node | undefined = node.parent; p; p = p.parent) {
128
+ if (isFunctionLike(p)) {
129
+ fns.push(p);
130
+ const role = callbackRole(p);
131
+ if (role) return { role, fns };
132
+ }
133
+ }
134
+ return { role: fns.length ? 'helper' : 'top', fns };
135
+ }
136
+
137
+ /** A function whose own name says it restores (`const restore = () => …` · `function resetEnv()`) — its writes are the pair. */
138
+ function isRestoreHelper(fn: ts.Node): boolean {
139
+ let name: string | undefined;
140
+ if ((ts.isFunctionDeclaration(fn) || ts.isMethodDeclaration(fn)) && fn.name) name = fn.name.getText();
141
+ else if (fn.parent && ts.isVariableDeclaration(fn.parent)) name = fn.parent.name.getText();
142
+ else if (fn.parent && ts.isPropertyAssignment(fn.parent)) name = fn.parent.name.getText();
143
+ return !!name && /restore|reset|cleanup|teardown|dispose/i.test(name);
144
+ }
145
+
146
+ function inFinally(node: ts.Node): boolean {
147
+ for (let p: ts.Node | undefined = node; p && p.parent; p = p.parent) {
148
+ if (isFunctionLike(p)) return false;
149
+ if (ts.isTryStatement(p.parent) && p.parent.finallyBlock === p) return true;
150
+ }
151
+ return false;
152
+ }
153
+
154
+ function isAsyncFn(fn: ts.Node): boolean {
155
+ const mods = ts.canHaveModifiers(fn) ? ts.getModifiers(fn) : undefined;
156
+ return !!mods?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword);
157
+ }
158
+
159
+ function finallyTexts(fn: ts.Node, sf: ts.SourceFile): string[] {
160
+ const out: string[] = [];
161
+ const visit = (n: ts.Node) => {
162
+ if (n !== fn && isFunctionLike(n)) return;
163
+ if (ts.isTryStatement(n) && n.finallyBlock) out.push(n.finallyBlock.getText(sf));
164
+ ts.forEachChild(n, visit);
165
+ };
166
+ ts.forEachChild(fn, visit);
167
+ return out;
168
+ }
169
+
170
+ function isProcessMember(expr: ts.Expression, member: string): boolean {
171
+ return ts.isPropertyAccessExpression(expr) && expr.name.text === member && ts.isIdentifier(expr.expression) && expr.expression.text === 'process';
172
+ }
173
+
174
+ function isProcessEnvAccess(expr: ts.Expression): boolean {
175
+ if (ts.isPropertyAccessExpression(expr) || ts.isElementAccessExpression(expr)) return isProcessMember(expr.expression, 'env');
176
+ return false;
177
+ }
178
+
179
+ function normalizeSpecifier(spec: string): string {
180
+ return spec.replace(/\.(m?[jt]sx?)$/, '');
181
+ }
182
+
183
+ export function scanSource(text: string, file: string): Violation[] {
184
+ if (!PREFILTER.test(text)) return [];
185
+ const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, file.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
186
+ aliases = readAliases(sf);
187
+ const out: Violation[] = [];
188
+ const add = (node: ts.Node, form: InterferenceForm) => {
189
+ const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
190
+ out.push({ file, line, form, text: node.getText(sf).split('\n')[0]!.slice(0, 120) });
191
+ };
192
+
193
+ // File-level facts.
194
+ const staticImports = new Set<string>();
195
+ const warmedImports = new Set<string>();
196
+ const afterHookTexts: string[] = [];
197
+ const topFunctions = new Map<string, ts.Node>();
198
+ let usesRenderer = false;
199
+ for (const st of sf.statements) {
200
+ if (ts.isImportDeclaration(st) && ts.isStringLiteral(st.moduleSpecifier)) {
201
+ const spec = st.moduleSpecifier.text;
202
+ if (spec === 'react-test-renderer' || spec.startsWith('@testing-library/')) usesRenderer = true;
203
+ if (!st.importClause?.isTypeOnly) staticImports.add(normalizeSpecifier(spec));
204
+ }
205
+ if (ts.isFunctionDeclaration(st) && st.name) topFunctions.set(st.name.text, st);
206
+ }
207
+ const collect = (n: ts.Node) => {
208
+ if (ts.isCallExpression(n)) {
209
+ const base = ts.isIdentifier(n.expression) ? aliases.get(n.expression.text) ?? n.expression.text : undefined;
210
+ if (base && HOOKS[base] === 'after') {
211
+ for (const arg of n.arguments) {
212
+ afterHookTexts.push(arg.getText(sf));
213
+ if (ts.isIdentifier(arg) && topFunctions.has(arg.text)) afterHookTexts.push(topFunctions.get(arg.text)!.getText(sf));
214
+ }
215
+ }
216
+ if (n.expression.kind === ts.SyntaxKind.ImportKeyword && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0])) {
217
+ const role = context(n).role;
218
+ if (role === 'before' || role === 'top') warmedImports.add(normalizeSpecifier(n.arguments[0].text));
219
+ }
220
+ }
221
+ ts.forEachChild(n, collect);
222
+ };
223
+ collect(sf);
224
+ const afterHooks = afterHookTexts.join('\n');
225
+ const mentionsWindow = /\bwindow\b/.test(text);
226
+
227
+ const insideAct = (node: ts.Node): boolean => {
228
+ for (let p: ts.Node | undefined = node.parent; p; p = p.parent) {
229
+ if (ts.isCallExpression(p) && bunName(p.expression) === 'act') return true;
230
+ }
231
+ return false;
232
+ };
233
+
234
+ const visit = (n: ts.Node) => {
235
+ if (ts.isCallExpression(n)) {
236
+ // A — dynamic import of a repository module inside a test body.
237
+ if (n.expression.kind === ts.SyntaxKind.ImportKeyword && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0])) {
238
+ const spec = n.arguments[0].text;
239
+ const norm = normalizeSpecifier(spec);
240
+ const ctx = context(n);
241
+ // `mock.module(…)` then import is the bun idiom for a freshly mocked module — not this form.
242
+ const mocks = ctx.fns.some((fn) => /\bmock\.module\s*\(/.test(fn.getText(sf)));
243
+ if (spec.startsWith('.') && ctx.role === 'test' && !mocks && !staticImports.has(norm) && !warmedImports.has(norm)) add(n, 'body-dynamic-import');
244
+ }
245
+ // B — process.chdir without a restore pair.
246
+ if (isProcessMember(n.expression, 'chdir')) {
247
+ const ctx = context(n);
248
+ if (ctx.role !== 'after' && !inFinally(n) && !ctx.fns.some(isRestoreHelper) && !/process\.chdir\s*\(/.test(afterHooks)) {
249
+ const paired = ctx.fns.some((fn) => !isAsyncFn(fn) && finallyTexts(fn, sf).some((t) => /process\.chdir\s*\(/.test(t)));
250
+ if (!paired) add(n, 'chdir-without-restore');
251
+ }
252
+ }
253
+ // E — a child bun/node process with a sub-second timeout.
254
+ if (n.arguments.some((a) => isProcessMember(a as ts.Expression, 'execPath'))) {
255
+ const literalArgs = n.arguments.filter(ts.isNumericLiteral);
256
+ const optionTimeouts = n.arguments.filter(ts.isObjectLiteralExpression).flatMap((o) => o.properties
257
+ .filter((p): p is ts.PropertyAssignment => ts.isPropertyAssignment(p) && /^(timeout|timeoutMs)$/.test(p.name.getText(sf)) && ts.isNumericLiteral(p.initializer))
258
+ .map((p) => p.initializer as ts.NumericLiteral));
259
+ if ([...literalArgs, ...optionTimeouts].some((lit) => { const v = Number(lit.text.replace(/_/g, '')); return v > 0 && v < 1000; })) add(n, 'short-child-timeout');
260
+ }
261
+ // D — bare react-test-renderer unmount in a file that stubs window.
262
+ if (usesRenderer && mentionsWindow && ts.isPropertyAccessExpression(n.expression) && n.expression.name.text === 'unmount'
263
+ && n.arguments.length === 0 && !insideAct(n)) add(n, 'bare-unmount-with-window');
264
+ }
265
+ // C — process.env mutation without a restore pair.
266
+ let envMutation = false;
267
+ if (ts.isBinaryExpression(n) && n.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
268
+ envMutation = isProcessEnvAccess(n.left) || isProcessMember(n.left, 'env');
269
+ } else if (ts.isDeleteExpression(n)) {
270
+ envMutation = isProcessEnvAccess(n.expression);
271
+ } else if (ts.isCallExpression(n) && ts.isPropertyAccessExpression(n.expression) && n.expression.name.text === 'assign'
272
+ && ts.isIdentifier(n.expression.expression) && n.expression.expression.text === 'Object' && n.arguments[0] && isProcessMember(n.arguments[0], 'env')) {
273
+ envMutation = true;
274
+ }
275
+ if (envMutation) {
276
+ const ctx = context(n);
277
+ if (ctx.role !== 'after' && !inFinally(n) && !ctx.fns.some(isRestoreHelper) && !/process\.env|restore|[Ee]nv/.test(afterHooks)) {
278
+ const paired = ctx.fns.some((fn) => finallyTexts(fn, sf).some((t) => /process\.env|restore|[Ee]nv/.test(t)));
279
+ if (!paired) add(n, 'env-without-restore');
280
+ }
281
+ }
282
+ ts.forEachChild(n, visit);
283
+ };
284
+ visit(sf);
285
+ return out;
286
+ }
287
+
288
+ export function scanFiles(files: readonly string[], root = REPO_ROOT): Violation[] {
289
+ const out: Violation[] = [];
290
+ for (const file of files) {
291
+ let text: string;
292
+ try { text = readFileSync(join(root, file), 'utf8'); } catch { continue; }
293
+ out.push(...scanSource(text, file));
294
+ }
295
+ return out;
296
+ }
297
+
298
+ export type Allowlist = Map<string, number>; // `${form}\t${file}` → count
299
+
300
+ export const allowKey = (form: InterferenceForm, file: string) => `${form}\t${file}`;
301
+
302
+ export function parseAllowlist(text: string): Allowlist {
303
+ const map: Allowlist = new Map();
304
+ for (const raw of text.split('\n')) {
305
+ const line = raw.trim();
306
+ if (!line || line.startsWith('#')) continue;
307
+ const [form, file, count] = line.split('\t');
308
+ if (!form || !file) continue;
309
+ map.set(`${form}\t${file}`, Number(count ?? '1') || 1);
310
+ }
311
+ return map;
312
+ }
313
+
314
+ export function countByKey(violations: readonly Violation[]): Allowlist {
315
+ const map: Allowlist = new Map();
316
+ for (const v of violations) map.set(allowKey(v.form, v.file), (map.get(allowKey(v.form, v.file)) ?? 0) + 1);
317
+ return map;
318
+ }
319
+
320
+ export interface RatchetResult {
321
+ /** Violations in a file·form whose count exceeds the allowlist (all of that file·form's lines are listed). */
322
+ fresh: Violation[];
323
+ /** Allowlist entries that are now smaller than allowed (or gone) — the list can be tightened. */
324
+ stale: { key: string; allowed: number; now: number }[];
325
+ }
326
+
327
+ export function judge(violations: readonly Violation[], allow: Allowlist, scope?: ReadonlySet<string>): RatchetResult {
328
+ const now = countByKey(violations);
329
+ const fresh = violations.filter((v) => (now.get(allowKey(v.form, v.file)) ?? 0) > (allow.get(allowKey(v.form, v.file)) ?? 0));
330
+ const stale = [...allow].filter(([key]) => !scope || scope.has(key.split('\t')[1]!))
331
+ .filter(([key, allowed]) => (now.get(key) ?? 0) < allowed).map(([key, allowed]) => ({ key, allowed, now: now.get(key) ?? 0 }));
332
+ return { fresh, stale };
333
+ }
334
+
335
+ export function renderAllowlist(violations: readonly Violation[]): string {
336
+ const counts = countByKey(violations);
337
+ const header = [
338
+ '# TEST-INTERFERENCE-RATCHET 허용 목록 — 이 줄이 생긴 시점(2026-10-16)의 기존 위반 전수.',
339
+ '# 형식: <꼴>\\t<파일>\\t<개수> · 개수가 «늘면» scripts/ratchets/test-interference-patterns.test.ts 가 실패한다.',
340
+ '# ⛔ 새 위반을 여기 더하지 마라 — 꼴의 처방대로 고친다. 줄었으면 다시 쓴다:',
341
+ `# ${UPDATE_COMMAND}`,
342
+ ];
343
+ return `${[...header, ...[...counts].sort(([a], [b]) => a.localeCompare(b)).map(([key, n]) => `${key}\t${n}`)].join('\n')}\n`;
344
+ }
345
+
346
+ export function formatViolation(v: Violation): string {
347
+ return `${v.file}:${v.line} [${v.form}] ${v.text}\n → ${FORMS[v.form]}`;
348
+ }
349
+
350
+ if (import.meta.main) {
351
+ const args = process.argv.slice(2);
352
+ const started = performance.now();
353
+ if (args.includes('--update-allowlist')) {
354
+ const all = scanFiles(listTestFiles());
355
+ writeFileSync(ALLOWLIST_PATH, renderAllowlist(all));
356
+ console.log(`[test-interference] allowlist rewritten: ${countByKey(all).size} file·form entries · ${all.length} sites (${Math.round(performance.now() - started)}ms)`);
357
+ } else {
358
+ const files = args.filter((a) => !a.startsWith('--')).filter((f) => TEST_FILE.test(f));
359
+ const scope = files.length ? new Set(files) : undefined;
360
+ const scanned = files.length ? files : listTestFiles();
361
+ const result = judge(scanFiles(scanned), parseAllowlist(readFileSync(ALLOWLIST_PATH, 'utf8')), scope);
362
+ for (const v of result.fresh) console.log(formatViolation(v));
363
+ if (result.stale.length) console.log(`[test-interference] ${result.stale.length} allowlist entries shrank — tighten with: ${UPDATE_COMMAND}`);
364
+ console.log(`[test-interference] scanned ${scanned.length} test files · new violations ${result.fresh.length} (${Math.round(performance.now() - started)}ms)`);
365
+ process.exitCode = result.fresh.length ? 1 : 0;
366
+ }
367
+ }
@@ -1,4 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
+ import { SPAWN_SYNC_MAX_BUFFER } from '../../src/util/spawn-sync-output.js';
2
3
  import { mkdtempSync, rmSync } from 'node:fs';
3
4
  import { tmpdir } from 'node:os';
4
5
  import { join, resolve } from 'node:path';
@@ -9,13 +10,13 @@ export interface CutBranchOptions { version: string; base: string; pick: string[
9
10
 
10
11
  // git-spawn-allow: release branch operations happen only in an isolated temporary worktree; main is never checked out or changed.
11
12
  function git(repo: string, args: string[]): string {
12
- const result = spawnSync('git', args, { cwd: repo, encoding: 'utf8' });
13
+ const result = spawnSync('git', args, { cwd: repo, encoding: 'utf8', maxBuffer: SPAWN_SYNC_MAX_BUFFER });
13
14
  if (result.status !== 0 || result.error) throw new Error(`git ${args[0]} failed: ${(result.stderr || result.error || result.stdout || 'no output').toString().trim()}`);
14
15
  return result.stdout.trim();
15
16
  }
16
17
 
17
18
  function ancestor(repo: string, sha: string, ref: string): boolean {
18
- const result = spawnSync('git', ['merge-base', '--is-ancestor', sha, ref], { cwd: repo });
19
+ const result = spawnSync('git', ['merge-base', '--is-ancestor', sha, ref], { cwd: repo, maxBuffer: SPAWN_SYNC_MAX_BUFFER });
19
20
  if (result.status !== 0 && result.status !== 1) throw new Error(`git merge-base failed: ${result.error || result.stderr || 'unknown'}`);
20
21
  return result.status === 0;
21
22
  }
@@ -41,7 +42,7 @@ export function cutReleaseBranch(opts: CutBranchOptions): { branch: string; comm
41
42
  const remoteLine = git(repo, ['ls-remote', '--heads', 'origin', `refs/heads/${branch}`]);
42
43
  if (remoteLine && !opts.append) throw new Error(`${branch} already exists on origin — use --append to fast-forward more picks onto it`);
43
44
  if (!remoteLine && opts.append) throw new Error(`${branch} does not exist on origin — omit --append to create it`);
44
- if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { cwd: repo }).status === 0) throw new Error(`${branch} already exists locally`);
45
+ if (spawnSync('git', ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { cwd: repo, maxBuffer: SPAWN_SYNC_MAX_BUFFER }).status === 0) throw new Error(`${branch} already exists locally`);
45
46
  let remoteTip: string | undefined;
46
47
  if (opts.append) {
47
48
  const advertised = remoteLine.split(/\s+/)[0] ?? '';
@@ -21,7 +21,6 @@ function failed(step: ExportCheckResult['step'], message: string, result?: Comma
21
21
  export function runExportCheck(run: CommandRunner = runCommand, repoRoot = process.cwd()): ExportCheckResult {
22
22
  const context = readGraphContext();
23
23
  const commit = nodeOutput(context, 'version-release', 'commit');
24
- if (context.outputs.gate?.outcome !== 'ok') return failed('export', 'gate did not pass');
25
24
  const root = resolve(repoRoot);
26
25
  const out = mkdtempSync(join(tmpdir(), 'elanous-export-check-'));
27
26
  const sourceDir = join(out, 'source');
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <testsuites name="bun test" tests="1" assertions="1" failures="1" skipped="0" time="0.453759">
3
+ <testsuite name="scripts/release-loop/.warm-failure-verify.test.ts" file="scripts/release-loop/.warm-failure-verify.test.ts" tests="1" assertions="1" failures="1" skipped="0" time="0.324634" hostname="MacBookProM5">
4
+ <testcase name="real multiline assertion" classname="" time="0.000284" file="scripts/release-loop/.warm-failure-verify.test.ts" line="2" assertions="1">
5
+ <failure type="AssertionError" message="expect(received).toEqual(expected)&#10;&#10; {&#10;- &quot;expected&quot;: 2,&#10;+ &quot;actual&quot;: 1,&#10; }&#10;&#10;- Expected - 1&#10;+ Received + 1&#10;">AssertionError: expect(received).toEqual(expected)&#10;&#10; {&#10;- &quot;expected&quot;: 2,&#10;+ &quot;actual&quot;: 1,&#10; }&#10;&#10;- Expected - 1&#10;+ Received + 1&#10;&#10; at scripts/release-loop/.warm-failure-verify.test.ts:3:25&#10;</failure>
6
+ </testcase>
7
+ </testsuite>
8
+ </testsuites>
@@ -0,0 +1 @@
1
+ {"durationMs":119678,"rc":0,"files":["src/chat/tool-render/dispatch.test.ts"],"plannedSeconds":0.007879255312742684,"deadlineSeconds":1200,"shardCount":28,"commit":"508f84ebf6d490c6e4f62ecda76bffb7873e4454","runKey":"bd9843754b3df86c17aeeadfb289c22737b3471de58f2ff19a098d194da78f1f","attemptId":"5763085b-b4ba-40a3-87ce-0de799224d5d","parentAttempt":"514b589b-2816-4639-b022-1bae6fd2f441","jobExitCode":0,"jobFailed":false,"host":"pool-host-e-wsl","phaseTimes":{"admissionStart":"2026-10-15T04:47:02.085Z","admissionEnd":"2026-10-15T04:47:11.107Z","poolPlaced":"2026-10-15T04:47:15.368Z","jobReturned":"2026-10-15T04:49:09.878Z","artifactsRead":"2026-10-15T04:49:10.785Z"},"podStages":{"prep-start":1792039682,"clone-end":1792039684,"shell-start":1792039684,"deps-start":1792039684,"deps-end":1792039684,"test-start":1792039684,"part-0-start":1792039684,"part-0-test-start":1792039684,"part-0-test-end":1792039688,"part-0-end":1792039688,"test-end":1792039688,"shell-end":1792039688},"podLifecycle":{"podCreated":"2026-10-15T04:47:59Z","podScheduled":"2026-10-15T04:47:59Z","init-isolation-gate-start":"2026-10-15T04:48:00Z","init-isolation-gate-end":"2026-10-15T04:48:01Z","childStart":"2026-10-15T04:48:01Z","childEnd":"2026-10-15T04:48:08Z"},"fileSeconds":{"src/chat/tool-render/dispatch.test.ts":0.295442442},"testSeconds":0.295442442,"testWallSeconds":4,"podOverheadSeconds":115.678,"admission":"granted","admissionWaitMs":9018}
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <testsuites name="bun test" tests="3" assertions="7" failures="0" skipped="0" time="0.29736114">
3
+ <testsuite name="src/chat/tool-render/dispatch.test.ts" file="src/chat/tool-render/dispatch.test.ts" tests="3" assertions="7" failures="0" skipped="0" time="0.295442442" hostname="gate-4a935594-9ba4-4f22-8081-dff669314775-nt44m">
4
+ <testsuite name="renderToolResultVariants kind-unit grouping" file="src/chat/tool-render/dispatch.test.ts" line="18" tests="3" assertions="7" failures="0" skipped="0" time="0.001" hostname="gate-4a935594-9ba4-4f22-8081-dff669314775-nt44m">
5
+ <testcase name="kind-unit attaches the classified operation kind" classname="renderToolResultVariants kind-unit grouping" time="0.001902" file="src/chat/tool-render/dispatch.test.ts" line="19" assertions="1" />
6
+ <testcase name="unknown tools fall back to the tool name only in kind-unit" classname="renderToolResultVariants kind-unit grouping" time="0.000023" file="src/chat/tool-render/dispatch.test.ts" line="24" assertions="1" />
7
+ <testcase name="line and task-unit omit operationKind and keep identical collapsed text" classname="renderToolResultVariants kind-unit grouping" time="0.00021" file="src/chat/tool-render/dispatch.test.ts" line="34" assertions="5" />
8
+ </testsuite>
9
+ </testsuite>
10
+ </testsuites>
@@ -57,17 +57,19 @@ export interface ClosureOptions {
57
57
  cliEntries?: readonly string[];
58
58
  }
59
59
 
60
- interface ClosureGraph {
60
+ export interface ClosureGraph {
61
61
  /** Every dependency a file can load: imports of any kind ⊕ literal repo paths. */
62
- forward: Map<string, string[]>;
62
+ readonly forward: ReadonlyMap<string, readonly string[]>;
63
63
  /** Only top-level `import`/`export … from` — what loading the file evaluates before any of its code runs. */
64
- staticImports: Map<string, string[]>;
65
- opaque: Map<string, string>;
66
- tracked: Set<string>;
64
+ readonly staticImports: ReadonlyMap<string, readonly string[]>;
65
+ /** Static self-imports are omitted from closure traversal but remain visible to structural diagnostics. */
66
+ readonly selfStaticImports: ReadonlySet<string>;
67
+ readonly opaque: ReadonlyMap<string, string>;
68
+ readonly tracked: ReadonlySet<string>;
67
69
  }
68
70
 
69
71
  /** Forward dependency edges of every code file at the tip ⊕ the files whose dependencies we cannot fully name. */
70
- function closureGraph(tree: ClosureTree, options: ClosureOptions = {}): ClosureGraph {
72
+ export function buildClosureGraph(tree: ClosureTree, options: ClosureOptions = {}): ClosureGraph {
71
73
  const tracked = new Set(tree.files);
72
74
  const dirs = new Set<string>();
73
75
  for (const file of tree.files) for (let at = file.indexOf('/'); at > 0; at = file.indexOf('/', at + 1)) dirs.add(file.slice(0, at));
@@ -98,6 +100,7 @@ function closureGraph(tree: ClosureTree, options: ClosureOptions = {}): ClosureG
98
100
  const transpilers = { ts: new Bun.Transpiler({ loader: 'ts' }), tsx: new Bun.Transpiler({ loader: 'tsx' }), js: new Bun.Transpiler({ loader: 'js' }) };
99
101
  const forward = new Map<string, string[]>();
100
102
  const staticImports = new Map<string, string[]>();
103
+ const selfStaticImports = new Set<string>();
101
104
  const opaque = new Map<string, string>();
102
105
  const blindAs = (file: string, why: string): void => { if (!opaque.has(file)) opaque.set(file, why); };
103
106
  for (const file of tree.files) {
@@ -175,17 +178,18 @@ function closureGraph(tree: ClosureTree, options: ClosureOptions = {}): ClosureG
175
178
  // is all we see — and a code file we cannot find is a path we miss.
176
179
  else if (CODE_FILE.test(plain) && !TEST_FILE.test(plain)) blindAs(file, `unresolved path ${plain}`);
177
180
  }
181
+ if (eager.has(file)) selfStaticImports.add(file);
178
182
  edges.delete(file);
179
183
  eager.delete(file);
180
184
  forward.set(file, [...edges]);
181
185
  staticImports.set(file, [...eager]);
182
186
  }
183
- return { forward, staticImports, opaque, tracked };
187
+ return { forward, staticImports, selfStaticImports, opaque, tracked };
184
188
  }
185
189
 
186
190
  /** The tests among `tests` that can reach any of `changed` (code files) — or whose closure is opaque. */
187
191
  export function testsReachingChanged(tree: ClosureTree, changed: readonly string[], tests: readonly string[], options: ClosureOptions = {}): ClosureVerdict {
188
- const { forward, staticImports, opaque, tracked } = closureGraph(tree, options);
192
+ const { forward, staticImports, opaque, tracked } = buildClosureGraph(tree, options);
189
193
  const reverse = new Map<string, string[]>();
190
194
  for (const [from, edges] of forward) for (const to of edges) {
191
195
  const list = reverse.get(to);
@@ -12,7 +12,7 @@ export function parseFailures(output: string): string[] {
12
12
  const line = raw.trim();
13
13
  const header = /^(?:\.\/)?((?:[\w.-]+\/)+[\w.-]+\.test\.tsx?):(?:\s|$)/.exec(line);
14
14
  if (header) { file = header[1]; continue; }
15
- const failed = /\(fail\)\s+(.+?)(?:\s+\[[\d.]+(?:ms|s)\])?$/.exec(line);
15
+ const failed = /^\(fail\)[ \t]+(.+?)(?:[ \t]+\[[\d.]+(?:ms|s)\])?$/.exec(line);
16
16
  if (failed && file) failures.add(`${file} > ${failed[1]!.trim()}`);
17
17
  }
18
18
  return [...failures].sort();
@@ -0,0 +1,66 @@
1
+ // GATE-HOSTMIRROR-EXPLICIT (10-16 · seat-state/OPC/GATE-POD-PRECHECKOUT-LAG-1016.md):
2
+ // a gate run under an isolated config dir (`setElanousConfigDir(<run root>)` — the HARD run book) resolved
3
+ // `pod.hostMirror` inside runPodCommand from the isolated config, found nothing, and every gate Pod cloned from
4
+ // GitHub (157/157 `SOURCE_VIA github` · node-b clone p50 252s). The gate now resolves the mirror once and passes it
5
+ // to every podCommand explicitly. Order: gate option → env ELANOUS_POD_HOST_MIRROR → current config pod.hostMirror
6
+ // → (isolated config only) the operating config's pod.hostMirror, read-only → none. A failed operating read is none.
7
+ import { readFileSync } from 'node:fs';
8
+ import { homedir } from 'node:os';
9
+ import { isAbsolute, join, resolve } from 'node:path';
10
+ import { getElanousConfigDir } from '../../src/elanous-config-dir.js';
11
+ import { getUserConfig } from '../../src/user-config.js';
12
+
13
+ export type GateHostMirrorSource = 'option' | 'env' | 'config' | 'operating-config' | 'none';
14
+
15
+ export interface GateHostMirrorReaders {
16
+ env?: NodeJS.ProcessEnv;
17
+ /** pod.hostMirror of the config the gate runs under. */
18
+ config?: () => string | undefined;
19
+ /** True when that config is not the operating one (`~/.elanous`). */
20
+ isolated?: () => boolean;
21
+ /** pod.hostMirror of the operating config — read only, never written. */
22
+ operatingConfig?: () => string | undefined;
23
+ }
24
+
25
+ export interface GateHostMirror { hostMirror?: string; source: GateHostMirrorSource; path: string | null }
26
+
27
+ export const OPERATING_CONFIG_DIR = join(homedir(), '.elanous');
28
+
29
+ /** The operating config's pod.hostMirror (raw file read; no migration, no write). Any failure reads as absent. */
30
+ export function readOperatingHostMirror(dir = OPERATING_CONFIG_DIR): string | undefined {
31
+ try {
32
+ const raw = JSON.parse(readFileSync(join(dir, 'config.json'), 'utf8')) as { pod?: { hostMirror?: unknown } } | null;
33
+ const value = raw?.pod?.hostMirror;
34
+ return typeof value === 'string' ? value : undefined;
35
+ } catch { return undefined; }
36
+ }
37
+
38
+ export function defaultGateHostMirrorReaders(): Required<GateHostMirrorReaders> {
39
+ return {
40
+ env: process.env,
41
+ config: () => getUserConfig().pod?.hostMirror,
42
+ isolated: () => resolve(getElanousConfigDir()) !== resolve(OPERATING_CONFIG_DIR),
43
+ operatingConfig: () => readOperatingHostMirror(),
44
+ };
45
+ }
46
+
47
+ export function resolveGateHostMirror(option: string | undefined, readers: GateHostMirrorReaders): GateHostMirror {
48
+ const pick = (value: string | undefined) => value?.trim() || undefined;
49
+ const found = (hostMirror: string, source: GateHostMirrorSource): GateHostMirror => ({ hostMirror, source, path: hostMirror });
50
+ const fromOption = pick(option);
51
+ if (fromOption) return found(fromOption, 'option');
52
+ const fromEnv = pick(readers.env?.ELANOUS_POD_HOST_MIRROR);
53
+ if (fromEnv) return found(fromEnv, 'env');
54
+ let fromConfig: string | undefined;
55
+ try { fromConfig = pick(readers.config?.()); } catch { fromConfig = undefined; }
56
+ if (fromConfig) return found(fromConfig, 'config');
57
+ let isolated = false;
58
+ try { isolated = readers.isolated?.() === true; } catch { isolated = false; }
59
+ if (isolated) {
60
+ let operating: string | undefined;
61
+ try { operating = pick(readers.operatingConfig?.()); } catch { operating = undefined; }
62
+ // A borrowed value that runPodCommand would reject (not absolute) must not fail the gate — it reads as none.
63
+ if (operating && isAbsolute(operating)) return found(operating, 'operating-config');
64
+ }
65
+ return { source: 'none', path: null };
66
+ }