elanous 0.2.23 → 0.2.25

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 (688) 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/chunks/1027.a0f04663d24c2779.js +1 -0
  4. package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +36 -0
  8. package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +148 -0
  10. package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1454-37fd16f479f5554a.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/{8532.a86e99acf9b761cb.js → 1516.83dd2c1b86b4e507.js} +2 -2
  16. package/apps/pwa/out/_next/static/chunks/{89849432.9eaa2f4c9c010965.js → 16e57f67.3ea19e893461e611.js} +3 -3
  17. package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{1505.5826671109111e75.js → 1743.563d3168e95825ef.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +27 -0
  20. package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +24 -0
  25. package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +32 -0
  28. package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2846.d6a433b8663819a5.js +309 -0
  30. package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +34 -0
  31. package/apps/pwa/out/_next/static/chunks/{5967-c0a80f8ffe5d4050.js → 3259-86f3be56e43eaf6a.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +287 -0
  36. package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/{5578.ac963634373b28c6.js → 4084.15ecaf4240bd9e77.js} +2 -2
  41. package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/{8438.ee7f0df3b3f6fcb4.js → 4204.a409ab6250c0f6a8.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +8 -0
  47. package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{7905.b230b9d06cb4ad5d.js → 4593.10f5b9bd702d4a6c.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +149 -0
  53. package/apps/pwa/out/_next/static/chunks/{8569.b853a8daa8f31d12.js → 5081.a240b63fad28663a.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{2528.0af5c0e1fad88df6.js → 5408.377c8c543635b81f.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/{9502-32c5dc22e8f120f5.js → 5492-e05e26a033ba80d2.js} +3 -3
  61. package/apps/pwa/out/_next/static/chunks/5785-ea8d2c633b6688e3.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +23 -0
  67. package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{5974.360f8441eb0ac1ec.js → 6196.34d6b229079e9e28.js} +1 -1
  70. package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +77 -0
  72. package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +64 -0
  74. package/apps/pwa/out/_next/static/chunks/{ce383d63.d2ede338788ed18e.js → 65ebff95.081daeff622d238e.js} +1 -1
  75. package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +2 -0
  77. package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/{83cfc5c8.349535543c1548b6.js → 6def8a8e.c81f9ca41028eccf.js} +1 -1
  79. package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{2721.bc9a8f36bd85c07a.js → 7483.ba01c6c209b81bba.js} +1 -1
  84. package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +62 -0
  87. package/apps/pwa/out/_next/static/chunks/{6702.ebbd165d5e4a4a14.js → 7752.5cbdd0b433c54af9.js} +1 -1
  88. package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/{8925-2abfb48af477fb7f.js → 8085-1e5fce59500a2cc2.js} +1 -1
  94. package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +226 -0
  96. package/apps/pwa/out/_next/static/chunks/{b4e12462-5fab4a813a63dadd.js → 83a80514-b897b64df43ce108.js} +1 -1
  97. package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +93 -0
  98. package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/{8264.00e434fbd02e9311.js → 8578.dff22d988cc2b106.js} +3 -3
  100. package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +115 -0
  103. package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +41 -0
  105. package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +74 -0
  106. package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +94 -0
  107. package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{7518.49161e8f5814abdb.js → 9311.24c8f5ea793253dd.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/{9976.8f28864317639fe6.js → 94.4cfed21c0b781a06.js} +3 -3
  111. package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +90 -0
  113. package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{0e3acd34.d42b2ef87fdf4234.js → 973cbf1b.3bbcf2b41548eca7.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/{6571-926ddf024a6ad5df.js → 9917-9e26abc5f7772735.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +79 -0
  119. package/apps/pwa/out/_next/static/chunks/{740.90b31555290236a9.js → 9974.e77b4ff4884557b3.js} +2 -2
  120. package/apps/pwa/out/_next/static/chunks/{4c5e95ce.83e9b16add6fcd8c.js → ab4d57c2.e90bc2cb31949045.js} +7 -7
  121. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-ad3bd8084048bee4.js → page-b12149c51f7d04b1.js} +1 -1
  126. package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/decisions/page-305cd294e754906e.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-a648bc464c9dc754.js → page-dea4b795741126fd.js} +1 -1
  133. package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/exec/page-45889e7070d11126.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/field/page-16a2e893f83ae4d0.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/intake/page-56888bc744e08dac.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/live/page-952c6ceec6d9de38.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live-run/page-6d0202af568f4c63.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4fb6fc34e20c07b7.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/morning/page-e9502921f4f01b1f.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/not-found-b6169ea2f09cf287.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6a14333d1b1b3967.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-8c91a9a66c9ec90a.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/release/{page-48fb31810693c357.js → page-4e634c5b98fd4e93.js} +1 -1
  150. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-cb154acadb025414.js → page-b9cc8a10bc6078b4.js} +1 -1
  152. package/apps/pwa/out/_next/static/chunks/app/page-3d3fc73dd187ed52.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9c04dac0831c2bbb.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-04de9ca6d52a3893.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/page-62527677bbc2fdc4.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9a2e09c4a311764c.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/page-bfeb35d69e8b24bb.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/share/page-89cb33bced824e4a.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/today/page-6445ac4cbb8dd869.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/page-20162174b77f96cf.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-05a4b2c9b91034aa.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{53746282.1be36038d1abd949.js → e117f801.e92bf10242653497.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +122 -0
  175. package/apps/pwa/out/_next/static/chunks/{0673cc54.8e2ef1c23e49e190.js → f4dfbfc0.a69fb12f854882aa.js} +1 -1
  176. package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +1 -0
  182. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
  183. package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +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/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
  278. package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
  279. package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
  280. package/catalog/providers/openrouter.yaml +2 -0
  281. package/graphs/implement-loop.yaml +31 -0
  282. package/graphs/ops/harness-gc.yaml +17 -0
  283. package/graphs/ops/recipes.yaml +3 -0
  284. package/graphs/overlays/README.md +1 -1
  285. package/graphs/overlays/stop-heal-ladder.yaml +105 -0
  286. package/graphs/release/release-loop.yaml +5 -5
  287. package/graphs/steward/recipes.yaml +4 -0
  288. package/graphs/steward/steward.yaml +10 -1
  289. package/package.json +1 -1
  290. package/scripts/add-api-key.sh +1 -1
  291. package/scripts/bench-report.ts +46 -1
  292. package/scripts/ci-typecheck-changed.ts +73 -14
  293. package/scripts/fleet/bedrock-pod-secret.ts +122 -0
  294. package/scripts/fleet/node-setup-linux.sh +97 -0
  295. package/scripts/fleet/node-setup.sh +11 -0
  296. package/scripts/fleet/zai-pod-secret.ts +86 -0
  297. package/scripts/land-global-checks.ts +3 -0
  298. package/scripts/measure-log-diet-2.ts +213 -0
  299. package/scripts/measure-tsc-affected-roots.ts +289 -0
  300. package/scripts/release-loop/auto-approve-node.ts +6 -0
  301. package/scripts/release-loop/gate-closure.ts +286 -0
  302. package/scripts/release-loop/gate-executor.ts +28 -0
  303. package/scripts/release-loop/gate-node.ts +333 -37
  304. package/scripts/release-loop/gate-partial.ts +34 -6
  305. package/scripts/release-loop/ops-upgrade-node.ts +63 -42
  306. package/scripts/release-loop/publish-node.ts +6 -0
  307. package/scripts/release-loop/resume-release.ts +46 -13
  308. package/scripts/release-loop/resume.ts +110 -4
  309. package/scripts/release-loop/unattended-release.ts +22 -7
  310. package/scripts/tsc-baseline-cache.ts +172 -0
  311. package/scripts/usage-rollup.ts +72 -6
  312. package/scripts/ux-sim.ts +30 -1
  313. package/skills/youtube-master/scripts/main.ts +4 -1
  314. package/skills/youtube-master/src/obsidian.ts +9 -0
  315. package/src/agent/run-context.ts +10 -0
  316. package/src/agent-mission/driver.ts +18 -3
  317. package/src/agent-mission/resource-ladder.ts +8 -3
  318. package/src/agent-mission/review-loop.ts +8 -2
  319. package/src/agent-substrate/acp-implementer.ts +146 -0
  320. package/src/agent-substrate/pr-reviewer.ts +60 -13
  321. package/src/agent-substrate/self-review-cli.ts +170 -15
  322. package/src/autopilot/mission-critique.ts +18 -5
  323. package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
  324. package/src/autopilot/mission-trace.ts +12 -1
  325. package/src/autopilot/system-lookback-run.ts +16 -10
  326. package/src/bench/bench.ts +183 -0
  327. package/src/budget/cost-tier-advisor.ts +91 -0
  328. package/src/budget/fetchers/grok.ts +15 -5
  329. package/src/budget/llm-cost.ts +37 -5
  330. package/src/budget/shadow-arms.ts +77 -0
  331. package/src/budget/types.ts +10 -2
  332. package/src/budget/unified-usage.ts +256 -10
  333. package/src/cli/bench-cli.ts +34 -0
  334. package/src/cli/doctor-cli.ts +21 -0
  335. package/src/cli/friendly-errors.ts +113 -0
  336. package/src/cli/guardian-cli.ts +26 -1
  337. package/src/cli/image-cli.ts +101 -0
  338. package/src/cli/intake-cli.ts +3 -1
  339. package/src/cli/log-event-names.ts +4 -0
  340. package/src/cli/memory-cli.ts +182 -0
  341. package/src/cli/model-watch-cli.ts +4 -1
  342. package/src/cli/pr-cli.ts +62 -5
  343. package/src/cli/pr-land-overlap-evidence.ts +160 -12
  344. package/src/cli/pr-land-pod-shadow.ts +54 -0
  345. package/src/cli/release-cli.ts +27 -16
  346. package/src/cli/release-run-if-ready.ts +11 -0
  347. package/src/cli/resource-cli.ts +48 -0
  348. package/src/cli/retro-cli.ts +12 -3
  349. package/src/cli/rfc-status.ts +52 -2
  350. package/src/cli/seat-requests-cli.ts +25 -0
  351. package/src/cli/self-update.ts +104 -0
  352. package/src/cli/tasks-cli.ts +139 -10
  353. package/src/cli/usage-cli.ts +93 -8
  354. package/src/compact/verify-probe.ts +23 -3
  355. package/src/context-card/index.ts +50 -0
  356. package/src/control/control-status.ts +30 -1
  357. package/src/core-turn/run-goal-loop.ts +5 -4
  358. package/src/dashboard/ad-run-setup-bindings.ts +279 -0
  359. package/src/dashboard/index.ts +18 -276
  360. package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
  361. package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
  362. package/src/dashboard/stale-install-check.ts +11 -0
  363. package/src/debug/log-diet.ts +53 -10
  364. package/src/debug/log.ts +19 -1
  365. package/src/domains/morning-essential.ts +18 -3
  366. package/src/domains/release-tool.ts +43 -0
  367. package/src/error-report/report.ts +21 -4
  368. package/src/execution-loop/launch-gate.ts +158 -2
  369. package/src/fleet/host-doctor.ts +375 -0
  370. package/src/github/pr-labels.ts +1 -0
  371. package/src/goals/judge.ts +20 -6
  372. package/src/graph-runner/graph-cli.ts +42 -1
  373. package/src/graph-runner/runner.ts +176 -11
  374. package/src/graph-wizard/archetypes.ts +14 -8
  375. package/src/graph-wizard/generate.ts +77 -1
  376. package/src/grok/usage.ts +23 -2
  377. package/src/grok.ts +13 -7
  378. package/src/grounding/ref-index.ts +253 -0
  379. package/src/harness/dispatch-backpressure.ts +10 -2
  380. package/src/harness/harness-clean.ts +199 -78
  381. package/src/harness/harness-cli-command.ts +176 -52
  382. package/src/harness/harness-gc.ts +331 -0
  383. package/src/harness/harness-stop.ts +82 -10
  384. package/src/harness/harness-substrate-default.ts +142 -7
  385. package/src/harness/launch-registry.ts +6 -0
  386. package/src/harness/worktree-branch-prefix.ts +9 -0
  387. package/src/hq/fence.ts +187 -0
  388. package/src/hq/seats.ts +38 -22
  389. package/src/images/image-ledger.ts +179 -0
  390. package/src/index.ts +110 -186
  391. package/src/instance/child-scope.ts +32 -1
  392. package/src/instance/dev-project.ts +133 -0
  393. package/src/instance/resolve.ts +24 -0
  394. package/src/instance/spawn-elanous.ts +45 -0
  395. package/src/intake-plane/collect-github.ts +7 -2
  396. package/src/intake-plane/lens.ts +46 -4
  397. package/src/intake-plane/ref-prefetch.ts +110 -0
  398. package/src/intake-plane/requirement-funnel.ts +53 -1
  399. package/src/intelligence-map/catalog-feed.ts +119 -0
  400. package/src/intelligence-map/model-catalog.ts +72 -0
  401. package/src/intelligence-map/model-watch-intake.ts +40 -0
  402. package/src/intelligence-map/model-watch-mission.ts +14 -1
  403. package/src/llm/bedrock-eventstream.ts +215 -0
  404. package/src/llm/bedrock-provider.ts +114 -41
  405. package/src/llm/bedrock.ts +174 -28
  406. package/src/llm/open-weight-discipline.ts +21 -0
  407. package/src/llm/openrouter-byok-cost.ts +96 -0
  408. package/src/llm/openrouter-deepseek.ts +151 -0
  409. package/src/llm/openrouter-upstream-pins.config.ts +25 -0
  410. package/src/llm/zai-coding-plan.ts +700 -0
  411. package/src/llm.ts +91 -24
  412. package/src/loops/checker.ts +148 -9
  413. package/src/loops/orchestrator/resync-shadow.ts +34 -7
  414. package/src/maturity/feature-maturity.ts +3 -3
  415. package/src/model-tier/llm-tier-map.ts +9 -5
  416. package/src/models/prompts.ts +2 -1
  417. package/src/mss/logging/log-store.ts +58 -11
  418. package/src/nexus/api/http-server.ts +22 -0
  419. package/src/nexus/api/missions.ts +73 -2
  420. package/src/nexus/api/ops-api.ts +18 -0
  421. package/src/nexus/index.ts +7 -75
  422. package/src/nexus/tools-kind.ts +78 -0
  423. package/src/oauth/codex-account-rotation.ts +43 -3
  424. package/src/oauth/codex-account-store.ts +339 -27
  425. package/src/oauth/codex-quota-policy.ts +33 -4
  426. package/src/oauth/fallback-chain.ts +53 -15
  427. package/src/onboarding/first-run.ts +37 -18
  428. package/src/onboarding/web-first.ts +20 -2
  429. package/src/ops/machine-heartbeat.ts +185 -0
  430. package/src/ops/overview-cache.ts +175 -0
  431. package/src/ops/overview.ts +8 -0
  432. package/src/preview/terminal.ts +15 -5
  433. package/src/project/project-store.ts +20 -0
  434. package/src/prompt-cache/openai.ts +3 -0
  435. package/src/prompt-cache/types.ts +5 -0
  436. package/src/prompt-enhance/enhance.ts +23 -0
  437. package/src/release-loop/auto-start.ts +7 -5
  438. package/src/release-loop/checklist.ts +11 -1
  439. package/src/release-loop/gate-shards.ts +4 -0
  440. package/src/release-loop/light-rc.ts +84 -13
  441. package/src/release-loop/merged-pr-checklist.ts +35 -5
  442. package/src/release-loop/placement.ts +16 -1
  443. package/src/release-loop/rehearsal.ts +1 -1
  444. package/src/requirements/requirement-ledger.ts +536 -0
  445. package/src/retro/daily.ts +5 -5
  446. package/src/seat-loop/duty-ledger.ts +64 -0
  447. package/src/seat-loop/seat-loop.ts +32 -10
  448. package/src/self-dev/decompose.ts +37 -3
  449. package/src/self-dev/dev-cli.ts +44 -10
  450. package/src/self-dev/dev-pipeline.ts +39 -9
  451. package/src/self-dev/draft-residue.ts +27 -5
  452. package/src/self-dev/draft-sweep.ts +151 -0
  453. package/src/self-dev/fabric-decompose-adapter.ts +9 -2
  454. package/src/self-dev/graph-journey-route.ts +6 -0
  455. package/src/self-dev/orchestrate-cli.ts +25 -3
  456. package/src/self-dev/orchestrate.ts +41 -6
  457. package/src/self-dev/run-supervisor.ts +218 -15
  458. package/src/self-dev/run-types.ts +13 -0
  459. package/src/self-dev/supervisor-verdict-edges.ts +1 -0
  460. package/src/self-implement/budget-gate.ts +53 -13
  461. package/src/self-implement/child-context-composition.ts +139 -0
  462. package/src/self-implement/child-llm-preference.ts +13 -5
  463. package/src/self-implement/claude-acp-implement.ts +67 -0
  464. package/src/self-implement/flex-signals.ts +59 -0
  465. package/src/self-implement/frozen-merges.ts +8 -3
  466. package/src/self-implement/gate-cli.ts +29 -10
  467. package/src/self-implement/gate-remote.ts +4 -1
  468. package/src/self-implement/goal-author-decompose.ts +10 -2
  469. package/src/self-implement/goal-author.ts +36 -11
  470. package/src/self-implement/goal-new-paths.ts +42 -0
  471. package/src/self-implement/graph-overlay-condition.ts +28 -0
  472. package/src/self-implement/graph-overlay-yaml.ts +41 -7
  473. package/src/self-implement/graph-templates.ts +33 -1
  474. package/src/self-implement/graph-yaml.ts +56 -0
  475. package/src/self-implement/heal-intake.ts +5 -1
  476. package/src/self-implement/host-regate.ts +124 -30
  477. package/src/self-implement/importer-test-index.ts +3 -1
  478. package/src/self-implement/l8-merge-queue.ts +80 -2
  479. package/src/self-implement/merge-train.ts +19 -0
  480. package/src/self-implement/off-diff-evidence.ts +40 -1
  481. package/src/self-implement/orchestrator.ts +230 -32
  482. package/src/self-implement/premise-review.ts +159 -0
  483. package/src/self-implement/regate-detail.ts +79 -0
  484. package/src/self-implement/review-deferred-to-host.ts +21 -0
  485. package/src/self-implement/rework-budget-judgment.ts +23 -3
  486. package/src/self-implement/running-runs.ts +75 -5
  487. package/src/self-implement/scope-adjacency.ts +23 -0
  488. package/src/self-implement/seams.ts +89 -8
  489. package/src/self-implement/self-implement-cli.ts +9 -4
  490. package/src/self-implement/stop-autoheal.ts +69 -2
  491. package/src/session-runtime/retry-policy.ts +2 -1
  492. package/src/skills/tools/agent.ts +16 -1
  493. package/src/skills/tools/persistent-grounding.ts +11 -1
  494. package/src/skills/tools/shell.ts +33 -1
  495. package/src/steward/launch.ts +5 -4
  496. package/src/steward/rejudge-tick.ts +142 -0
  497. package/src/steward/triage-budget.ts +62 -0
  498. package/src/steward/triage.ts +83 -22
  499. package/src/task-agent/actions.ts +62 -5
  500. package/src/task-agent/board.ts +92 -3
  501. package/src/task-agent/card-evidence.ts +88 -1
  502. package/src/task-agent/completion-evidence.ts +5 -0
  503. package/src/task-agent/cover.ts +166 -3
  504. package/src/task-agent/judge.ts +16 -0
  505. package/src/task-agent/land-order-ledger.ts +95 -0
  506. package/src/task-agent/live-move-history.ts +87 -1
  507. package/src/task-agent/live-moves.ts +350 -20
  508. package/src/task-agent/parent-host.ts +27 -3
  509. package/src/task-agent/rejudge-on-head.ts +223 -24
  510. package/src/task-agent/review-prior-fix.ts +146 -0
  511. package/src/task-agent/review-result-capture.ts +3 -1
  512. package/src/task-agent/run-adopt.ts +136 -0
  513. package/src/task-agent/shadow.ts +65 -9
  514. package/src/task-agent/task-hand.ts +57 -7
  515. package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
  516. package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
  517. package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
  518. package/src/task-orchestrator/surfaces/pod-child-providers.ts +14 -1
  519. package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
  520. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +79 -6
  521. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
  522. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -5
  523. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +11 -5
  524. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
  525. package/src/task-orchestrator/surfaces/pod-pool.ts +73 -4
  526. package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
  527. package/src/task-orchestrator/surfaces/self-implement-pod.ts +432 -35
  528. package/src/task-orchestrator/surfaces/self-implement.ts +19 -1
  529. package/src/typecheck-ratchet.ts +1 -0
  530. package/src/user-config.ts +69 -15
  531. package/src/ux-sim/fault-cred-expiry.ts +100 -0
  532. package/src/ux-sim/fault-pod-death.ts +74 -0
  533. package/src/ux-sim/fault-pool-cap.ts +81 -0
  534. package/src/version/packed-revision.json +1 -1
  535. package/src/webclone/qa-table.ts +22 -0
  536. package/src/workflow-runtime/triggers/registry.ts +59 -0
  537. package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
  538. package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
  540. package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
  542. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
  543. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
  553. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
  554. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
  556. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/272-b23d2e92161d11fd.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
  563. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/3961-fbef064c213b2b18.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
  567. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
  579. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
  587. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
  591. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
  594. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
  595. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
  599. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
  602. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
  604. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
  605. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
  606. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
  609. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
  616. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
  617. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
  620. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
  622. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
  623. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
  625. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
  627. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
  628. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
  633. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/app/approvals/page-d5341ac96203a983.js +0 -1
  635. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-0160ab83c8685a12.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/app/board/page-55c631c032dcc47e.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/app/bots/page-e6784759a2531031.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5c5d0e370f495ef6.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/app/chat/page-c325e21543cd48a8.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/app/consult/page-6168a7c43e6ef8f5.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/app/control/page-31417d3604154a6d.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/app/decisions/page-e9606dc0bdec9305.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/app/editor/page-25bb425afdb27541.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/app/exec/page-32d72fdef1afe11a.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/app/field/page-d27b794c8ba76bbb.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/app/inside/page-2bd9ce9c020d02d4.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/app/intake/page-a34096245e63b9f2.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/app/layout-22170f4f00a15496.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/app/live/page-4cc66d22ca4ec502.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/app/live-run/page-83b14c729fcea837.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/app/loops/page-6e2781c523dad761.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/app/market/page-26dd415c8f13f341.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-ccdb83ed40c8d724.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/morning/page-7ad3de8fa06fdea9.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/not-found-015c02c4fec4023e.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/observatory/page-6b0ae5b5c42f6d2f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-786111f30b6f0969.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4e17cce5e2ed0fee.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/page-16258e956ea93fc2.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/reflection/page-c2dd2b19c93f90ab.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-85f35dd1dd96ae87.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d3c007c8a0ddd7ee.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7837ce2aacb97b04.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/settings/page-7350ee93f4fe1033.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-00723458575f2b19.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/setup/page-745d9b6c015076f8.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/share/page-736d33c7414a8a1a.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/showroom/page-119be9a0444d2482.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/tasks/page-fa806c018833e332.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/term/page-c782041b5f5199ba.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/today/page-d431fbdea6ad93dd.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/trace/page-0c056abff82b9891.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/vault/page-242d668e4fbf72c4.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-847c3de6ca8a4416.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/workflows/page-81dd0d8ae923ed72.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/workspace/page-74e69ba2c8e970d4.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-70038f41ae7cf931.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
  687. package/apps/pwa/out/_next/static/css/5619d59e87eddf66.css +0 -1
  688. /package/apps/pwa/out/_next/static/{rfkMm4movqkqMebBrCXiR → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
@@ -0,0 +1,331 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { isAbsolute, join, resolve } from 'node:path';
4
+ import { debug } from '../debug/log.js';
5
+ import { configuredWorktreeRoot } from '../user-config.js';
6
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
7
+ import { acquireLockSync } from '../storage/file-lock.js';
8
+ import { createGhRunner, execHarnessClean, gitStdout, type GitRunner, type GhRunner, type ActiveDirectoryProvider } from './harness-clean.js';
9
+ import type { WorktreeAssessmentInput, WorktreeAssessment } from './harness-worktrees.js';
10
+
11
+ export interface HarnessGcOptions {
12
+ repos?: string[];
13
+ dryRun?: boolean;
14
+ window?: number;
15
+ maxRemove?: number;
16
+ budgetMs?: number;
17
+ }
18
+
19
+ export interface HarnessGcDeps {
20
+ stateRoot?: string;
21
+ worktreeRoot?: string;
22
+ now?: () => number;
23
+ run?: GitRunner;
24
+ runGh?: GhRunner;
25
+ activeDirectoryProvider?: ActiveDirectoryProvider;
26
+ assessWorktree?: (input: WorktreeAssessmentInput) => WorktreeAssessment;
27
+ readWorktreeProvenance?: (path: string, run: GitRunner) => { owner: string; command: string; createdAt: string };
28
+ }
29
+
30
+ export interface HarnessGcRepo {
31
+ gitDir: string;
32
+ offset: number;
33
+ window: number;
34
+ total: number;
35
+ removed: number;
36
+ preserved: number;
37
+ deferred: number;
38
+ failed: number;
39
+ preservedByReason: Record<string, number>;
40
+ orphanScan: 'scanned' | 'unavailable' | 'not-requested';
41
+ unseenOutsideWindow?: number;
42
+ unseenOutsidePrefix?: number;
43
+ }
44
+
45
+ export interface HarnessGcResult {
46
+ outcome: 'ok' | 'skipped' | 'fail';
47
+ reason?: 'overlap' | 'no-target-repo' | 'repo-failed' | 'budget-exhausted';
48
+ repos: number;
49
+ removed: number;
50
+ preserved: number;
51
+ deferred: number;
52
+ failed: number;
53
+ unseenOutsideWindow?: number;
54
+ unseenOutsidePrefix?: number;
55
+ undiscoverable: number;
56
+ orphanScanUnavailable: number;
57
+ budgetMs: number;
58
+ elapsedMs: number;
59
+ repositories: HarnessGcRepo[];
60
+ repoFailures?: Array<{ gitDir: string; error: string }>;
61
+ /** The tick budget ran out inside a repository's queries; that repository was left unverified (cursor kept). */
62
+ budgetExhausted?: boolean;
63
+ }
64
+
65
+ /** Discover current linked worktrees; the tick also retains previously verified automatic targets. */
66
+ export function discoverHarnessGcRepos(root: string, expired: () => boolean = () => false):
67
+ { repos: string[]; undiscoverable: number; stopped?: boolean } {
68
+ const repos = new Set<string>();
69
+ let undiscoverable = 0;
70
+ // The deadline is checked *between* reads (each readdir / .git read); a stopped walk leaves the rest unverified.
71
+ let stopped = false;
72
+ const halt = (): boolean => { if (!stopped && expired()) stopped = true; return stopped; };
73
+ const done = () => ({ repos: [...repos].sort(), undiscoverable, ...(stopped ? { stopped } : {}) });
74
+ const children = (path: string): string[] => readdirSync(path, { withFileTypes: true })
75
+ .filter((entry) => entry.isDirectory()).map((entry) => join(path, entry.name));
76
+ let scopes: string[];
77
+ if (halt()) return done();
78
+ try { scopes = children(root); }
79
+ catch { return { repos: [], undiscoverable: 0 }; }
80
+ for (const scope of scopes) {
81
+ if (halt()) return done();
82
+ let parents: string[];
83
+ try { parents = children(scope); }
84
+ catch { undiscoverable++; continue; }
85
+ for (const parent of parents) {
86
+ if (!parent.endsWith('.worktrees')) continue;
87
+ if (halt()) return done();
88
+ let paths: string[];
89
+ try { paths = children(parent); }
90
+ catch { undiscoverable++; continue; }
91
+ for (const path of paths) {
92
+ if (halt()) return done();
93
+ try {
94
+ const line = readFileSync(join(path, '.git'), 'utf8').trim();
95
+ const match = /^gitdir:\s*(.+?)[/\\]worktrees[/\\][^/\\]+\s*$/.exec(line);
96
+ if (!match) { undiscoverable++; continue; }
97
+ const gitDir = isAbsolute(match[1]!) ? match[1]! : resolve(path, match[1]!);
98
+ repos.add(resolve(gitDir));
99
+ } catch { undiscoverable++; }
100
+ }
101
+ }
102
+ }
103
+ return done();
104
+ }
105
+
106
+ function defaultRun(args: string[]) {
107
+ const result = spawnSync('git', args, { encoding: 'utf8', timeout: 20_000 });
108
+ return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
109
+ }
110
+
111
+ function positive(value: number | undefined, fallback: number): number {
112
+ if (value === undefined) return fallback;
113
+ if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`invalid GC limit: ${value}`);
114
+ return value;
115
+ }
116
+
117
+ /** One lock guards discovery, every repository window, deletion, and cursor writes. */
118
+ export function runHarnessGcTick(opts: HarnessGcOptions = {}, deps: HarnessGcDeps = {}): HarnessGcResult {
119
+ const windowSize = positive(opts.window, 150);
120
+ const maxRemove = positive(opts.maxRemove, 30);
121
+ const budgetMs = positive(opts.budgetMs, 240_000);
122
+ const now = deps.now ?? Date.now;
123
+ const started = now();
124
+ const state = join(deps.stateRoot ?? effectiveInstanceRoot(), 'harness-gc');
125
+ mkdirSync(state, { recursive: true });
126
+ const lockPath = join(state, 'tick.lock');
127
+ let holder = '';
128
+ let release: () => void;
129
+ try {
130
+ release = acquireLockSync(lockPath, { maxTries: 2, retryBusyMs: 1, breakDeadHolder: true,
131
+ staleMs: Math.max(2 * budgetMs, 600_000), onWait: (value) => { holder = value; } });
132
+ } catch (error) {
133
+ if (!String(error).includes('timed out')) throw error;
134
+ debug.log('harness.gc', 'tick-skipped', { reason: 'overlap', holder });
135
+ return { outcome: 'skipped', reason: 'overlap', repos: 0, removed: 0, preserved: 0, deferred: 0, failed: 0,
136
+ undiscoverable: 0, orphanScanUnavailable: 0, budgetMs, elapsedMs: now() - started, repositories: [] };
137
+ }
138
+ try {
139
+ const runner = deps.run ?? defaultRun;
140
+ const cursorPath = join(state, 'cursor.json');
141
+ const targetsPath = join(state, 'targets.json');
142
+ let cursor: Record<string, number> = {};
143
+ let persistedTargets: string[] = [];
144
+ try {
145
+ const parsed: unknown = JSON.parse(readFileSync(cursorPath, 'utf8'));
146
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) cursor = parsed as Record<string, number>;
147
+ } catch { /* No cursor yet, or corrupt state: start at the beginning. */ }
148
+ try {
149
+ const parsed: unknown = JSON.parse(readFileSync(targetsPath, 'utf8'));
150
+ if (Array.isArray(parsed)) persistedTargets = parsed.filter((path): path is string =>
151
+ typeof path === 'string' && isAbsolute(path));
152
+ } catch { /* No persisted automatic targets yet. */ }
153
+ const discovery = opts.repos === undefined
154
+ ? discoverHarnessGcRepos(deps.worktreeRoot ?? configuredWorktreeRoot(), () => now() - started >= budgetMs)
155
+ : { repos: opts.repos, undiscoverable: 0 };
156
+ // A verified automatic target survives removal of its last linked worktree; --repo never enrolls it.
157
+ const candidates = opts.repos === undefined
158
+ ? [...new Set([...discovery.repos, ...persistedTargets])]
159
+ : discovery.repos;
160
+ const targets = new Set<string>();
161
+ const repoFailures: Array<{ gitDir: string; error: string }> = [];
162
+ let failed = 0;
163
+ // A discovery walk cut by the deadline: repositories it did not reach are unverified, not absent.
164
+ let discoveryBudgetExhausted = 'stopped' in discovery && discovery.stopped === true;
165
+ for (const repo of [...candidates].sort()) {
166
+ if (now() - started >= budgetMs) { discoveryBudgetExhausted = true; break; }
167
+ const common = gitStdout(['-C', repo, 'rev-parse', '--path-format=absolute', '--git-common-dir'], runner);
168
+ if (common.ok && common.value && isAbsolute(common.value)) {
169
+ const gitDir = resolve(common.value);
170
+ targets.add(gitDir);
171
+ if (!opts.dryRun && opts.repos === undefined) persistedTargets.push(gitDir);
172
+ } else { failed++; repoFailures.push({ gitDir: repo, error: 'git common directory unavailable' }); }
173
+ }
174
+ const repositories: HarnessGcRepo[] = [];
175
+ let removed = 0;
176
+ let preserved = 0;
177
+ let deferred = 0;
178
+ let unseenOutsideWindow: number | undefined = repoFailures.length || discoveryBudgetExhausted ? undefined : 0;
179
+ let unseenOutsidePrefix: number | undefined = repoFailures.length || discoveryBudgetExhausted ? undefined : 0;
180
+ let orphanScanUnavailable = 0;
181
+ let processedTargets = 0;
182
+ let budgetExhausted = false;
183
+ // maxRemove bounds deletion *attempts* (incl. partial/failed ones), not only successes.
184
+ let attempts = 0;
185
+ const overBudget = (): boolean => now() - started >= budgetMs;
186
+ const baseGh: GhRunner = deps.runGh ?? createGhRunner();
187
+ for (const gitDir of [...targets].sort()) {
188
+ if (overBudget()) { budgetExhausted = true; break; } // remaining repositories unprocessed — record it
189
+ processedTargets++;
190
+ const offset = Number.isSafeInteger(cursor[gitDir]) && cursor[gitDir]! >= 0 ? cursor[gitDir]! : 0;
191
+ // The deadline is enforced inside the clean too: once it passes, every further *read* (git query, PR lookup,
192
+ // safety measurement) fails fast instead of running on past the tick. Deletions are never cut mid-item —
193
+ // `shouldRemove` already refuses to start one after the deadline.
194
+ let budgetHit = false;
195
+ const isDeletion = (args: readonly string[]): boolean =>
196
+ (args.includes('worktree') && args.includes('remove')) || (args.includes('branch') && args.includes('-D'));
197
+ const run: GitRunner = (args) => {
198
+ if (!isDeletion(args) && overBudget()) { budgetHit = true; return { status: 1, stdout: '', stderr: 'harness gc tick budget exhausted' }; }
199
+ return runner(args[0] === '-C' ? args : ['-C', gitDir, ...args]);
200
+ };
201
+ const runGh: GhRunner = (args, options) => {
202
+ if (overBudget()) { budgetHit = true; return { status: 1, stdout: '', stderr: 'harness gc tick budget exhausted', error: 'budget' }; }
203
+ return baseGh(args, options);
204
+ };
205
+ try {
206
+ // gh's {owner}/{repo} placeholders refer to cwd, not this target repository.
207
+ const remote = gitStdout(['config', '--get', 'remote.origin.url'], run);
208
+ const identity = remote.ok ? /(?:github\.com[:/])([^/:]+)\/([^/]+?)(?:\.git)?\/?$/.exec(remote.value) : null;
209
+ if (!identity) throw new Error('target repository has no GitHub origin identity');
210
+ const result = execHarnessClean({ mode: 'merged', dryRun: opts.dryRun, repo: `${identity[1]}/${identity[2]}`,
211
+ window: { offset, size: windowSize }, forceWorktreeRemove: false, run, runGh, expired: overBudget,
212
+ activeDirectoryProvider: deps.activeDirectoryProvider,
213
+ assessWorktree: deps.assessWorktree,
214
+ readWorktreeProvenance: deps.readWorktreeProvenance,
215
+ shouldRemove: () => {
216
+ if (attempts >= maxRemove) return false; // count cap, not the time budget
217
+ if (overBudget()) { budgetExhausted = true; return false; } // deletion deferred by the time budget
218
+ attempts++;
219
+ return true;
220
+ } });
221
+ const plan = result.plan;
222
+ if (result.expired) budgetHit = true;
223
+ if (budgetHit) {
224
+ // Unverified, not failed: nothing is counted as preserved/failed and the cursor is kept for the next tick.
225
+ removed += result.removed.length;
226
+ failed += result.failed.length;
227
+ budgetExhausted = true;
228
+ debug.log('harness.gc', 'repo-budget-exhausted', { gitDir, removed: result.removed.length });
229
+ break;
230
+ }
231
+ if (plan.unavailable) {
232
+ repoFailures.push({ gitDir, error: 'required clean query unavailable' });
233
+ failed++;
234
+ }
235
+ const pending = result.deferred?.length ?? 0;
236
+ const byReason: Record<string, number> = {};
237
+ for (const item of plan.preserve) byReason[item.reason] = (byReason[item.reason] ?? 0) + 1;
238
+ const repo: HarnessGcRepo = {
239
+ gitDir, offset: result.window!.offset, window: result.window!.size, total: result.window!.total,
240
+ removed: result.removed.length, preserved: plan.preserve.length, deferred: pending,
241
+ failed: result.failed.length, preservedByReason: byReason, orphanScan: plan.orphanScan,
242
+ ...(plan.queryStatus?.branches && plan.queryStatus.worktrees
243
+ ? { unseenOutsideWindow: result.window!.unseenOutsideWindow } : {}),
244
+ ...(plan.queryStatus?.branches && plan.queryStatus.worktrees && plan.scope?.registeredWorktrees !== undefined
245
+ ? { unseenOutsidePrefix: Math.max(0, plan.scope.registeredWorktrees - plan.scope.matchedWorktrees) } : {}),
246
+ };
247
+ repositories.push(repo);
248
+ debug.log('harness.gc', 'repo', repo);
249
+ removed += repo.removed;
250
+ preserved += repo.preserved;
251
+ deferred += repo.deferred;
252
+ failed += repo.failed;
253
+ if (repo.unseenOutsideWindow === undefined) unseenOutsideWindow = undefined;
254
+ else if (unseenOutsideWindow !== undefined) unseenOutsideWindow += repo.unseenOutsideWindow;
255
+ if (repo.unseenOutsidePrefix === undefined) unseenOutsidePrefix = undefined;
256
+ else if (unseenOutsidePrefix !== undefined) unseenOutsidePrefix += repo.unseenOutsidePrefix;
257
+ if (plan.orphanScan === 'unavailable') orphanScanUnavailable++;
258
+ if (!opts.dryRun && repo.deferred === 0 && repo.failed === 0 && !plan.unavailable) {
259
+ const next = repo.offset + repo.window - repo.removed;
260
+ cursor[gitDir] = next >= repo.total - repo.removed ? 0 : Math.max(0, next);
261
+ }
262
+ } catch (error) {
263
+ if (budgetHit) {
264
+ budgetExhausted = true;
265
+ debug.log('harness.gc', 'repo-budget-exhausted', { gitDir, error: String(error) });
266
+ break;
267
+ }
268
+ failed++;
269
+ unseenOutsideWindow = undefined;
270
+ unseenOutsidePrefix = undefined;
271
+ repoFailures.push({ gitDir, error: String(error) });
272
+ debug.log('harness.gc', 'repo-failed', { gitDir, error: String(error) }, { level: 'error' });
273
+ }
274
+ }
275
+ if (processedTargets < targets.size || budgetExhausted) {
276
+ unseenOutsideWindow = undefined;
277
+ unseenOutsidePrefix = undefined;
278
+ }
279
+ if (!opts.dryRun && targets.size) {
280
+ const temp = join(state, `cursor.${process.pid}.tmp`);
281
+ writeFileSync(temp, JSON.stringify(cursor));
282
+ renameSync(temp, cursorPath);
283
+ }
284
+ if (!opts.dryRun && opts.repos === undefined && persistedTargets.length) {
285
+ const temp = join(state, `targets.${process.pid}.tmp`);
286
+ writeFileSync(temp, JSON.stringify([...new Set(persistedTargets)].sort()));
287
+ renameSync(temp, targetsPath);
288
+ }
289
+ // A tick whose budget ran out before any repository was verified did not succeed — it is «skipped», never «ok».
290
+ const outcome = (targets.size === 0 && !discoveryBudgetExhausted) || failed > 0 ? 'fail'
291
+ : repositories.length === 0 ? 'skipped' : 'ok';
292
+ const summary: HarnessGcResult = { outcome,
293
+ ...(outcome === 'fail' ? { reason: targets.size === 0 ? 'no-target-repo' as const : 'repo-failed' as const }
294
+ : outcome === 'skipped' ? { reason: 'budget-exhausted' as const } : {}),
295
+ repos: repositories.length, removed, preserved, deferred, failed,
296
+ ...(unseenOutsideWindow === undefined ? {} : { unseenOutsideWindow }),
297
+ ...(unseenOutsidePrefix === undefined ? {} : { unseenOutsidePrefix }),
298
+ undiscoverable: discovery.undiscoverable, orphanScanUnavailable, budgetMs,
299
+ elapsedMs: now() - started, repositories,
300
+ ...(repoFailures.length ? { repoFailures } : {}),
301
+ ...(budgetExhausted || discoveryBudgetExhausted ? { budgetExhausted: true } : {}) };
302
+ debug.log('harness.gc', 'tick', summary);
303
+ return summary;
304
+ } finally { release(); }
305
+ }
306
+
307
+ function cliArgs(args: string[]): HarnessGcOptions {
308
+ const opts: HarnessGcOptions = {};
309
+ for (let i = 0; i < args.length; i++) {
310
+ const arg = args[i];
311
+ if (arg === '--json') continue;
312
+ if (arg === '--dry-run') { opts.dryRun = true; continue; }
313
+ if (arg === '--repo') { (opts.repos ??= []).push(args[++i] ?? ''); continue; }
314
+ const key = arg === '--window' ? 'window' : arg === '--max-remove' ? 'maxRemove' : arg === '--budget-ms' ? 'budgetMs' : null;
315
+ if (!key) throw new Error(`unknown GC option: ${arg}`);
316
+ opts[key] = Number(args[++i]);
317
+ }
318
+ if (opts.repos?.some((repo) => !repo)) throw new Error('--repo needs a path');
319
+ return opts;
320
+ }
321
+
322
+ if (import.meta.main) {
323
+ try {
324
+ const result = runHarnessGcTick(cliArgs(process.argv.slice(2)));
325
+ console.log(JSON.stringify(result));
326
+ if (result.outcome === 'fail') process.exitCode = 1;
327
+ } catch (error) {
328
+ console.log(JSON.stringify({ outcome: 'fail', reason: String(error) }));
329
+ process.exitCode = 1;
330
+ }
331
+ }
@@ -3,10 +3,12 @@
3
3
  // 🩸 2026-09-27: 멈추려면 사람이 PID 둘(harness ask 부모 · self orchestrate 자식)과 Job 이름을 손으로 찾아야 했고,
4
4
  // 그 사이 떠 있던 조각이 main 에 병합됐다(#21048). 부모를 죽이면 자식이 PPID 1 고아로 2h36m 더 돌았다(🅞 보고).
5
5
  // B 조각(#21171)이 오케스트레이터에 `self-dev-runs/<runId>/pid.json` ⊕ SIGTERM 정리(새 잡 멈춤 · 자기 Job 삭제 · cancelled)를 넣었다.
6
- // 이 파일은 그 기록과 런 원장·프로세스 표를 읽고, 시작 시각이 확인된 후보에만 신호를 보내며, `elanous.run=<runId>` 라벨 Job 을 지운다.
6
+ // 이 파일은 그 기록과 런 원장·프로세스 표를 읽고, 시작 시각이 확인된 후보에만 신호를 보내며, 라벨 일치 Pod Job 을 지운다.
7
7
  //
8
8
  // ⛔ 불변식: 기록된 시작 시각과 실제 프로세스 시작 시각이 다르면 신호를 보내지 않는다(PID 재사용 방지).
9
- // ⛔ 불변식: `elanous.run=<runId>` 라벨이 붙은 Job 만 지운다.
9
+ // ⛔ 불변식: 라벨이 붙은 Job 만 지운다 — `elanous.run=<runId>` · 그 라벨이 0 이면 `elanous.child-run=<runId>` 폴백(자식 런 id 로 쳤을 때).
10
+ // 지우는 것은 라벨 일치 Job 뿐이다: 이름 추측 없음 · Pod 직접 삭제 없음 · namespace 기본값(elanous-test) 불변.
11
+ // (HARNESS-STOP-POD-LABEL 2026-10-11) 문맥마다 삭제 결과를 넷으로 가르고 관측 `harness.stop` `job-delete`(context·outcome·matchedBy) 로 남긴다.
10
12
  // ⛔ 불변식: 짧은 runId 의 후보가 둘 이상이면 프로세스 신호·Job 삭제 전에 중단한다.
11
13
 
12
14
  import { existsSync, readdirSync, readFileSync, readlinkSync } from 'node:fs';
@@ -151,6 +153,19 @@ export interface HarnessStopDeps {
151
153
  graceMs: number;
152
154
  }
153
155
 
156
+ export type HarnessStopJobMatchedBy = 'elanous.run' | 'elanous.child-run';
157
+
158
+ /**
159
+ * 문맥 하나의 Pod Job 삭제 결과(HARNESS-STOP-POD-LABEL) — «0개 지움» 의 종류를 가른다.
160
+ * deleted N — 라벨 일치 Job N 개 삭제 · none — 두 라벨 다 Job 0(진짜 없음 · Pod 생성 전 등)
161
+ * unreachable — kubectl 실패(그 0 을 진짜 0 으로 믿을 수 없다) · pods-only — Job 0 인데 같은 라벨 Pod 잔존
162
+ */
163
+ export type HarnessStopJobDelete =
164
+ | { context: string; outcome: 'deleted'; matchedBy: HarnessStopJobMatchedBy; deleted: number }
165
+ | { context: string; outcome: 'none'; matchedBy: null; deleted: 0 }
166
+ | { context: string; outcome: 'unreachable'; matchedBy: null; deleted: 0; error: string }
167
+ | { context: string; outcome: 'pods-only'; matchedBy: null; deleted: 0; podsRemaining: number };
168
+
154
169
  export interface HarnessStopResult {
155
170
  runId: string;
156
171
  givenRunId?: string;
@@ -161,6 +176,8 @@ export interface HarnessStopResult {
161
176
  pidRecordFound: boolean;
162
177
  dryRun: boolean;
163
178
  jobsDeleted: number;
179
+ /** 문맥별 Job 삭제 분류 — 출력 한 줄과 `--json` 의 근원. */
180
+ jobDeletes: HarnessStopJobDelete[];
164
181
  contexts: string[];
165
182
  }
166
183
 
@@ -231,6 +248,56 @@ export function defaultHarnessStopDeps(overrides: Partial<HarnessStopDeps> = {},
231
248
  };
232
249
  }
233
250
 
251
+ /** Pod Job 라벨 — `elanous.run` = 부모(오케스트레이터) 런 id · `elanous.child-run` = 자식 런 id(self-implement-pod podRunLabels). */
252
+ const POD_JOB_LABELS = ['elanous.run', 'elanous.child-run'] as const;
253
+
254
+ /** `kubectl get -o name` 출력에서 `<prefix>` 로 시작하는 줄 수를 센다. */
255
+ function countOutputLines(stdout: string, prefix: string): number {
256
+ return stdout.split('\n').filter((line) => line.startsWith(prefix)).length;
257
+ }
258
+
259
+ /**
260
+ * `kubectl delete job -o name` 출력에서 삭제된 Job 줄 수를 센다.
261
+ * `-o name` 출력은 `job.batch/<name>` 한 줄씩이지만, 일부 kubectl 버전·설정에서는
262
+ * `job.batch "<name>" deleted` 꼴도 나타난다(#26194). 두 꼴을 모두 센다.
263
+ */
264
+ function countDeletedJobLines(stdout: string): number {
265
+ return stdout.split('\n').filter((line) => /^job\.batch(?:\/|\s+")/.test(line.trim())).length;
266
+ }
267
+
268
+ /** 문맥 하나의 Pod Job 삭제 — 결과를 넷(deleted·none·unreachable·pods-only)으로 가르고 문맥마다 관측 `harness.stop` `job-delete` 를 남긴다. */
269
+ function deleteRunPodJobs(deps: HarnessStopDeps, runId: string, context: string): HarnessStopJobDelete {
270
+ const unreachable = (stderr: string): HarnessStopJobDelete => {
271
+ const error = stderr.slice(0, 200);
272
+ debug.log('harness.stop', 'job-delete', { runId, context, outcome: 'unreachable', matchedBy: null, error }, { level: 'warn' });
273
+ return { context, outcome: 'unreachable', matchedBy: null, deleted: 0, error };
274
+ };
275
+ // ① `elanous.run=<runId>` — 0 이면 `elanous.child-run=<runId>` 로 한 번 더 고른다(자식 런 id 로 쳤을 때). 지우는 것은 라벨 일치 Job 뿐이다.
276
+ for (const label of POD_JOB_LABELS) {
277
+ // `-o name` → «job.batch/<name>» 한 줄씩. 맨 출력은 «job.batch "<name>" deleted» 라 «job.batch/» 로만 세면
278
+ // 지워도 늘 0 이었다(10-11 · 여섯 번 «0개 지움» 뒤 Pod Terminating). 두 꼴을 다 센다(#26194).
279
+ const r = deps.kubectl(['--context', context, '-n', deps.namespace, 'delete', 'job', '-l', `${label}=${runId}`, '--wait=false', '-o', 'name']);
280
+ if (r.status !== 0) return unreachable(r.stderr);
281
+ const deleted = countDeletedJobLines(r.stdout);
282
+ if (deleted > 0) {
283
+ debug.log('harness.stop', 'job-delete', { runId, context, outcome: 'deleted', matchedBy: label, deleted });
284
+ return { context, outcome: 'deleted', matchedBy: label, deleted };
285
+ }
286
+ }
287
+ // ② 두 라벨 다 Job 0 — 같은 라벨 Pod(`get pods -l <라벨>=<runId>`)로 none 과 pods-only 를 가른다. Pod 는 직접 지우지 않는다.
288
+ for (const label of POD_JOB_LABELS) {
289
+ const p = deps.kubectl(['--context', context, '-n', deps.namespace, 'get', 'pods', '-l', `${label}=${runId}`, '-o', 'name']);
290
+ if (p.status !== 0) return unreachable(p.stderr);
291
+ const podsRemaining = countOutputLines(p.stdout, 'pod/');
292
+ if (podsRemaining > 0) {
293
+ debug.log('harness.stop', 'job-delete', { runId, context, outcome: 'pods-only', matchedBy: null, podsRemaining });
294
+ return { context, outcome: 'pods-only', matchedBy: null, deleted: 0, podsRemaining };
295
+ }
296
+ }
297
+ debug.log('harness.stop', 'job-delete', { runId, context, outcome: 'none', matchedBy: null });
298
+ return { context, outcome: 'none', matchedBy: null, deleted: 0 };
299
+ }
300
+
234
301
  export async function stopHarnessRun(runId: string, deps: HarnessStopDeps, contexts?: readonly string[], dryRun = false): Promise<HarnessStopResult> {
235
302
  if (!RUN_ID.test(runId)) throw new Error(`invalid run id: ${runId}`);
236
303
  const given = runId;
@@ -297,13 +364,9 @@ export async function stopHarnessRun(runId: string, deps: HarnessStopDeps, conte
297
364
  }
298
365
  // ── ⓑ Pod Job (라벨로만) ───────────────────────────────────
299
366
  const targets = dryRun ? [] : contexts && contexts.length > 0 ? [...contexts] : deps.kubeContexts();
300
- let jobsDeleted = 0;
301
- for (const context of targets) {
302
- const r = deps.kubectl(['--context', context, '-n', deps.namespace, 'delete', 'job', '-l', `elanous.run=${runId}`, '--wait=false']);
303
- if (r.status === 0) jobsDeleted += r.stdout.split('\n').filter((line) => line.startsWith('job.batch/')).length;
304
- else debug.log('harness.stop', 'job-delete-failed', { runId, context, error: r.stderr.slice(0, 200) }, { level: 'warn' });
305
- }
306
- const result: HarnessStopResult = { runId, ...(given !== runId ? { givenRunId: given } : {}), process: processState, ...(record ? { pid: record.pid } : {}), candidates, scanned: scan.status === 'ok', pidRecordFound: record !== null, dryRun, jobsDeleted, contexts: targets };
367
+ const jobDeletes = targets.map((context) => deleteRunPodJobs(deps, runId, context));
368
+ const jobsDeleted = jobDeletes.reduce((sum, job) => sum + job.deleted, 0);
369
+ const result: HarnessStopResult = { runId, ...(given !== runId ? { givenRunId: given } : {}), process: processState, ...(record ? { pid: record.pid } : {}), candidates, scanned: scan.status === 'ok', pidRecordFound: record !== null, dryRun, jobsDeleted, jobDeletes, contexts: targets };
307
370
  debug.log('harness.stop', 'stopped', { runId, process: processState, jobsDeleted, contexts: targets.length });
308
371
  return result;
309
372
  }
@@ -324,6 +387,15 @@ export function formatHarnessStop(r: HarnessStopResult): string {
324
387
  ...r.candidates.map(({ pid, startedAt, via }) => ` 후보: pid ${pid} · 시작 ${new Date(startedAt).toISOString()} · ${via}`),
325
388
  r.dryRun
326
389
  ? ` Pod Job: dry-run(조회·삭제하지 않음 · 라벨 elanous.run=${r.runId})`
327
- : ` Pod Job: ${r.jobsDeleted}개 지움 (문맥 ${r.contexts.length}개 · 라벨 elanous.run=${r.runId})`,
390
+ : ` Pod Job: ${r.jobsDeleted}개 지움 (문맥 ${r.contexts.length}개 · 라벨 elanous.run=${r.runId} · child-run 폴백)`,
391
+ ...r.jobDeletes.map(formatHarnessStopJobDelete),
328
392
  ].join('\n');
329
393
  }
394
+
395
+ /** 문맥 하나의 Pod Job 결과 줄 — none·unreachable·pods-only 는 서로 다른 문면으로 갈라 읽힌다. */
396
+ function formatHarnessStopJobDelete(job: HarnessStopJobDelete): string {
397
+ if (job.outcome === 'deleted') return ` ${job.context}: ${job.deleted}개 지움 (라벨 ${job.matchedBy})`;
398
+ if (job.outcome === 'pods-only') return ` ${job.context}: Job 0 · 같은 라벨 Pod ${job.podsRemaining} 남음 (Pod 는 직접 지우지 않는다)`;
399
+ if (job.outcome === 'unreachable') return ` ${job.context}: 못 닿음 (kubectl 실패: ${job.error})`;
400
+ return ` ${job.context}: 없음 (라벨 맞는 Job 0)`;
401
+ }
@@ -5,6 +5,9 @@ import { effectiveInstanceRoot, prodInstanceRoot, treeDerivedRootFor } from '../
5
5
  import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
6
6
  import { buildUserConfig, getUserConfig, type UserConfig } from '../user-config.js';
7
7
  import { resolveCodexQuotaPolicy } from '../oauth/codex-quota-policy.js';
8
+ import { debug } from '../debug/log.js';
9
+ import type { PoolLeaseRecommendation } from '../task-orchestrator/surfaces/pod-lease.js';
10
+ import type { PodPoolMember, PoolKubectl } from '../task-orchestrator/surfaces/pod-pool.js';
8
11
 
9
12
  /** Key-order-insensitive JSON so equal per-account caps written in another order do not warn. */
10
13
  function stableJson(value: unknown): string {
@@ -79,22 +82,154 @@ export interface ResolvedHarnessSubstrate {
79
82
  source: 'flag' | 'config' | 'default';
80
83
  }
81
84
 
82
- /** Only inspect the current context when no explicit pool is available. Never turn a failed Pod selection into local. */
85
+ /** Conservative local headroom for one standard harness goal (the Pod lease's default per-goal size). */
86
+ export const AUTO_LOCAL_MIN_AVAILABLE_MEMORY_BYTES = 16 * 1024 ** 3;
87
+
88
+ export interface AutoSubstrateSignals {
89
+ /** A blocked memory admission has recommended=0 and limitedBy=memory; unknown is not blocked. */
90
+ podAdmission: Pick<PoolLeaseRecommendation, 'recommended' | 'limitedBy'> | null;
91
+ load1: number | null;
92
+ cores: number | null;
93
+ availableMemoryBytes: number | null;
94
+ localLaneOpen: boolean;
95
+ }
96
+
97
+ export interface AutoSubstrateDecision {
98
+ substrate: HarnessSubstrate;
99
+ reason: string;
100
+ }
101
+
102
+ export interface NextLocalLaneCapInput {
103
+ current: number;
104
+ wanted: number;
105
+ lastRaisedAtMs: number | null;
106
+ nowMs: number;
107
+ load1: number | null;
108
+ cores: number | null;
109
+ }
110
+
111
+ export interface NextLocalLaneCapDecision {
112
+ cap: number;
113
+ action: 'raise' | 'hold' | 'lower';
114
+ reason: string;
115
+ }
116
+
117
+ /** Decide one conservative local-lane cap adjustment from the current observations. */
118
+ export function nextLocalLaneCap({ current, wanted, lastRaisedAtMs, nowMs, load1, cores }: NextLocalLaneCapInput): NextLocalLaneCapDecision {
119
+ let decision: NextLocalLaneCapDecision;
120
+ if (load1 === null || cores === null || !Number.isFinite(load1) || !Number.isFinite(cores) || load1 < 0 || cores <= 0) {
121
+ decision = { cap: current, action: 'hold', reason: 'load-unreadable' };
122
+ } else if (load1 >= cores) {
123
+ decision = { cap: Math.max(0, current - 5), action: 'lower', reason: 'local-load-overloaded' };
124
+ } else if (!Number.isFinite(current) || !Number.isFinite(wanted) || !Number.isFinite(nowMs)) {
125
+ decision = { cap: current, action: 'hold', reason: 'cap-or-time-unreadable' };
126
+ } else if (wanted <= current) {
127
+ decision = { cap: current, action: 'hold', reason: 'no-increase-requested' };
128
+ } else if (load1 >= cores / 2) {
129
+ decision = { cap: current, action: 'hold', reason: 'local-load-not-spare' };
130
+ } else if (lastRaisedAtMs !== null && (!Number.isFinite(lastRaisedAtMs) || nowMs - lastRaisedAtMs < 15 * 60 * 1000)) {
131
+ decision = { cap: current, action: 'hold', reason: 'raise-cooldown' };
132
+ } else {
133
+ decision = { cap: Math.min(wanted, current + 5), action: 'raise', reason: 'local-load-spare' };
134
+ }
135
+ debug.log('harness.guardian', 'lane-step', { current, wanted, lastRaisedAtMs, nowMs, load1, cores, ...decision });
136
+ return decision;
137
+ }
138
+
139
+ /** Pure routing judgment. Missing/invalid observations are not evidence that the host has room. */
140
+ export function routeAutoSubstrate(signals: AutoSubstrateSignals): AutoSubstrateDecision {
141
+ const { podAdmission, load1, cores, availableMemoryBytes, localLaneOpen } = signals;
142
+ if (podAdmission === null || podAdmission.recommended === null || podAdmission.limitedBy === null)
143
+ return { substrate: 'pod', reason: 'pod-admission-unobserved' };
144
+ if (podAdmission.recommended !== 0 || podAdmission.limitedBy !== 'memory')
145
+ return { substrate: 'pod', reason: 'pod-admission-not-memory-blocked' };
146
+ if (!localLaneOpen) return { substrate: 'pod', reason: 'local-lane-closed' };
147
+ if (cores === null || !Number.isFinite(cores) || cores <= 0 || load1 === null || !Number.isFinite(load1) || load1 < 0 || load1 >= cores / 2)
148
+ return { substrate: 'pod', reason: 'local-load-not-spare' };
149
+ if (availableMemoryBytes === null || !Number.isFinite(availableMemoryBytes) || availableMemoryBytes < AUTO_LOCAL_MIN_AVAILABLE_MEMORY_BYTES)
150
+ return { substrate: 'pod', reason: 'local-memory-not-spare' };
151
+ return { substrate: 'local', reason: 'pod-memory-blocked-local-spare' };
152
+ }
153
+
154
+ /**
155
+ * POD-POOL-UNCAPPED-SPEC — the pre-launch pool check of an «implicit» Pod pool (the current kube context),
156
+ * reported in context names. `unmeasured` = kubectl itself could not run, so nothing was measured:
157
+ * «unknown» is not «unfit» (same rule as LAUNCH-STALL's unreadable member memory).
158
+ */
159
+ export interface HarnessPoolCheck {
160
+ ok: boolean;
161
+ ready: string[];
162
+ dropped: { context: string; reason: string }[];
163
+ unmeasured?: string | null;
164
+ }
165
+
166
+ /** `checkPodPool` over one pool spec — a kube context that cannot answer before launch is refused, not silently kept. */
167
+ export function checkHarnessPodPool(pool: string, run?: PoolKubectl): HarnessPoolCheck {
168
+ // Lazy require: the Pod surface pulls `bun:ffi`, and only a Pod launch without an explicit pool needs it.
169
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
170
+ const surface = require('../task-orchestrator/surfaces/pod-pool.js') as typeof import('../task-orchestrator/surfaces/pod-pool.js');
171
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
172
+ const leaseKubectl = run ?? (require('../task-orchestrator/surfaces/pod-lease.js') as typeof import('../task-orchestrator/surfaces/pod-lease.js')).leaseKubectl;
173
+ let members: PodPoolMember[];
174
+ try { members = surface.parsePodPool(pool); }
175
+ catch (error) {
176
+ return { ok: false, ready: [], dropped: [{ context: pool, reason: error instanceof Error ? error.message : String(error) }] };
177
+ }
178
+ let calls = 0;
179
+ let unrunnable = 0;
180
+ const kubectl: PoolKubectl = (args, input) => {
181
+ const r = leaseKubectl(args, input);
182
+ calls++;
183
+ // Only «kubectl is not installed» (spawn ENOENT) is no verdict about the cluster. A kubectl that started but
184
+ // timed out (status null · ETIMEDOUT) is a cluster that did not answer — that stays a measured refusal.
185
+ if (r.status === null && /\bENOENT\b/.test(r.stderr)) unrunnable++;
186
+ return r;
187
+ };
188
+ const checked = surface.checkPodPool(members, kubectl);
189
+ if (!checked.ok && calls > 0 && unrunnable === calls) return { ok: true, ready: [], dropped: checked.dropped, unmeasured: 'kubectl 을 실행할 수 없다' };
190
+ return { ok: checked.ok, ready: checked.ready.map((m) => m.context), dropped: checked.dropped };
191
+ }
192
+
193
+ /** Only inspect the current context when no explicit pool is available. Never turn an explicit Pod selection into local. */
83
194
  export function resolveHarnessSubstrate({ flag, config, env, currentContext = () => {
84
195
  const result = spawnSync('kubectl', ['config', 'current-context'], { encoding: 'utf8', timeout: 5000 });
85
196
  return result.status === 0 ? result.stdout?.trim() : undefined;
86
- } }: {
87
- flag?: { substrate?: HarnessSubstrate; podPool?: string };
197
+ }, autoSignals, poolCheck = checkHarnessPodPool }: {
198
+ flag?: { substrate?: HarnessSubstrate | 'auto'; podPool?: string };
88
199
  config?: Pick<UserConfig, 'harness' | 'pod'>;
89
200
  env?: NodeJS.ProcessEnv;
90
201
  currentContext?: () => string | undefined;
202
+ /** Signals must come from the launch host and Pod admission, not a worktree's cached config. */
203
+ autoSignals?: AutoSubstrateSignals;
204
+ /** POD-POOL-UNCAPPED-SPEC — pre-launch check of the implicit kube context; tests inject it instead of shelling out. */
205
+ poolCheck?: (pool: string) => HarnessPoolCheck;
91
206
  }): ResolvedHarnessSubstrate {
92
- const substrate = flag?.substrate ?? config?.harness?.substrate ?? 'local';
93
- if (substrate !== 'local' && substrate !== 'pod') throw new Error('harness.substrate: local 또는 pod 만 허용한다');
207
+ const requested = flag?.substrate ?? config?.harness?.substrate ?? 'local';
208
+ if (requested !== 'local' && requested !== 'pod' && requested !== 'auto') throw new Error('harness.substrate: local, pod 또는 auto 만 허용한다');
94
209
  const source = flag?.substrate ? 'flag' : config?.harness?.substrate ? 'config' : 'default';
210
+ // Missing signals mean admission was not observed, not that the Pod has room.
211
+ const decision = requested === 'auto' ? routeAutoSubstrate(autoSignals ?? {
212
+ podAdmission: null, load1: null, cores: null, availableMemoryBytes: null, localLaneOpen: false,
213
+ }) : null;
214
+ const substrate: HarnessSubstrate = requested === 'auto' ? decision!.substrate : requested;
215
+ if (decision) debug.log('harness.substrate', 'route', { substrate, reason: decision.reason, source });
95
216
  if (substrate === 'local') return { substrate, pool: null, source };
96
- const pool = flag?.podPool?.trim() || env?.ELANOUS_POD_POOL?.trim() || config?.harness?.podPool?.trim() || config?.pod?.pool?.trim() || currentContext()?.trim();
97
- if (!pool) throw new Error('harness.substrate=pod: Pod 풀 또는 현재 컨텍스트에 닿지 못했다 — 풀을 설정하거나 `--substrate local` 로 명시하라');
217
+ const explicit = flag?.podPool?.trim() || env?.ELANOUS_POD_POOL?.trim() || config?.harness?.podPool?.trim() || config?.pod?.pool?.trim();
218
+ const pool = explicit || currentContext()?.trim();
219
+ if (!pool) throw new Error(`harness.substrate=${decision ? `auto→pod(${decision.reason})` : 'pod'}: Pod 풀 또는 현재 컨텍스트에 닿지 못했다 — 풀을 설정하거나 \`--substrate local\` 로 명시하라`);
220
+ // POD-POOL-UNCAPPED-SPEC — an explicit pool is the operator's own statement and gets `checkPodPool` at the launch
221
+ // site (`src/index.ts` self orchestrate · `src/loops/orchestrator/tick.ts` · `pod-command-job.ts`). The implicit
222
+ // kube context had no such gate: a context whose cluster is gone, or whose `elanous-test` namespace is missing,
223
+ // sailed through here and then sat on `recommended=0` for 35 minutes (10-10 probe, 6 runs). Check before launch.
224
+ if (!explicit) {
225
+ const checked = poolCheck(pool);
226
+ debug.log('harness.substrate', 'pool-check', { pool, origin: 'current-context', ok: checked.ok, ready: checked.ready, dropped: checked.dropped, unmeasured: checked.unmeasured ?? null });
227
+ if (!checked.ok) {
228
+ const why = checked.dropped.map((d) => `${d.context}: ${d.reason}`).join(' · ') || '노드가 하나도 준비되지 않았다';
229
+ throw new Error(`harness.substrate=pod: 현재 컨텍스트 「${pool}」 이 발사 전 풀 점검을 넘지 못했다 — ${why} · 풀을 설정하거나 \`--substrate local\` 로 명시하라`);
230
+ }
231
+ if (checked.unmeasured) debug.log('harness.substrate', 'pool-check-unmeasured', { pool, reason: checked.unmeasured }, { level: 'warn' });
232
+ }
98
233
  return { substrate, pool, source };
99
234
  }
100
235