elanous 0.2.24 → 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 (551) 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-24282bf9f90031a5.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-dea4b795741126fd.js +1 -0
  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-1d809a87139dd024.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-b92caddb5c715f30.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/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_buildManifest.js +1 -1
  183. package/apps/pwa/out/approvals/index.html +1 -1
  184. package/apps/pwa/out/approvals/index.txt +22 -22
  185. package/apps/pwa/out/autopilot/index.html +1 -1
  186. package/apps/pwa/out/autopilot/index.txt +22 -22
  187. package/apps/pwa/out/board/index.html +1 -1
  188. package/apps/pwa/out/board/index.txt +22 -22
  189. package/apps/pwa/out/botlab/index.html +1 -1
  190. package/apps/pwa/out/botlab/index.txt +21 -21
  191. package/apps/pwa/out/bots/index.html +1 -1
  192. package/apps/pwa/out/bots/index.txt +21 -21
  193. package/apps/pwa/out/ceo/index.html +1 -1
  194. package/apps/pwa/out/ceo/index.txt +22 -22
  195. package/apps/pwa/out/chat/index.html +1 -1
  196. package/apps/pwa/out/chat/index.txt +21 -21
  197. package/apps/pwa/out/consult/index.html +1 -1
  198. package/apps/pwa/out/consult/index.txt +22 -22
  199. package/apps/pwa/out/control/index.html +1 -1
  200. package/apps/pwa/out/control/index.txt +22 -22
  201. package/apps/pwa/out/decisions/index.html +1 -1
  202. package/apps/pwa/out/decisions/index.txt +21 -21
  203. package/apps/pwa/out/design-check/index.html +1 -1
  204. package/apps/pwa/out/design-check/index.txt +22 -22
  205. package/apps/pwa/out/editor/index.html +1 -1
  206. package/apps/pwa/out/editor/index.txt +22 -22
  207. package/apps/pwa/out/exec/index.html +1 -1
  208. package/apps/pwa/out/exec/index.txt +22 -22
  209. package/apps/pwa/out/field/index.html +1 -1
  210. package/apps/pwa/out/field/index.txt +22 -22
  211. package/apps/pwa/out/healthz +1 -1
  212. package/apps/pwa/out/index.html +1 -1
  213. package/apps/pwa/out/index.txt +21 -21
  214. package/apps/pwa/out/inside/index.html +1 -1
  215. package/apps/pwa/out/inside/index.txt +21 -21
  216. package/apps/pwa/out/intake/index.html +1 -1
  217. package/apps/pwa/out/intake/index.txt +22 -22
  218. package/apps/pwa/out/live/index.html +1 -1
  219. package/apps/pwa/out/live/index.txt +22 -22
  220. package/apps/pwa/out/live-run/index.html +1 -1
  221. package/apps/pwa/out/live-run/index.txt +22 -22
  222. package/apps/pwa/out/loops/index.html +1 -1
  223. package/apps/pwa/out/loops/index.txt +21 -21
  224. package/apps/pwa/out/market/index.html +1 -1
  225. package/apps/pwa/out/market/index.txt +21 -21
  226. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  227. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  228. package/apps/pwa/out/morning/index.html +1 -1
  229. package/apps/pwa/out/morning/index.txt +22 -22
  230. package/apps/pwa/out/observatory/index.html +1 -1
  231. package/apps/pwa/out/observatory/index.txt +22 -22
  232. package/apps/pwa/out/ops/checklist/index.html +1 -1
  233. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  234. package/apps/pwa/out/ops/release/index.html +1 -1
  235. package/apps/pwa/out/ops/release/index.txt +21 -21
  236. package/apps/pwa/out/ops/seats/index.html +1 -1
  237. package/apps/pwa/out/ops/seats/index.txt +21 -21
  238. package/apps/pwa/out/outputs/index.html +1 -1
  239. package/apps/pwa/out/outputs/index.txt +21 -21
  240. package/apps/pwa/out/reflection/index.html +1 -1
  241. package/apps/pwa/out/reflection/index.txt +22 -22
  242. package/apps/pwa/out/scheduler/index.html +1 -1
  243. package/apps/pwa/out/scheduler/index.txt +22 -22
  244. package/apps/pwa/out/sessions/index.html +1 -1
  245. package/apps/pwa/out/sessions/index.txt +21 -21
  246. package/apps/pwa/out/settings/devices/index.html +1 -1
  247. package/apps/pwa/out/settings/devices/index.txt +22 -22
  248. package/apps/pwa/out/settings/index.html +1 -1
  249. package/apps/pwa/out/settings/index.txt +22 -22
  250. package/apps/pwa/out/setup/done/index.html +1 -1
  251. package/apps/pwa/out/setup/done/index.txt +22 -22
  252. package/apps/pwa/out/setup/index.html +1 -1
  253. package/apps/pwa/out/setup/index.txt +22 -22
  254. package/apps/pwa/out/share/index.html +1 -1
  255. package/apps/pwa/out/share/index.txt +22 -22
  256. package/apps/pwa/out/showroom/index.html +1 -1
  257. package/apps/pwa/out/showroom/index.txt +21 -21
  258. package/apps/pwa/out/tasks/index.html +1 -1
  259. package/apps/pwa/out/tasks/index.txt +22 -22
  260. package/apps/pwa/out/term/index.html +1 -1
  261. package/apps/pwa/out/term/index.txt +22 -22
  262. package/apps/pwa/out/today/index.html +1 -1
  263. package/apps/pwa/out/today/index.txt +22 -22
  264. package/apps/pwa/out/trace/index.html +1 -1
  265. package/apps/pwa/out/trace/index.txt +22 -22
  266. package/apps/pwa/out/vault/index.html +1 -1
  267. package/apps/pwa/out/vault/index.txt +22 -22
  268. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  269. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  270. package/apps/pwa/out/workflows/index.html +1 -1
  271. package/apps/pwa/out/workflows/index.txt +22 -22
  272. package/apps/pwa/out/workspace/index.html +1 -1
  273. package/apps/pwa/out/workspace/index.txt +22 -22
  274. package/apps/pwa/out/worktrees/index.html +1 -1
  275. package/apps/pwa/out/worktrees/index.txt +22 -22
  276. package/graphs/release/release-loop.yaml +5 -5
  277. package/graphs/steward/recipes.yaml +4 -0
  278. package/graphs/steward/steward.yaml +10 -1
  279. package/package.json +1 -1
  280. package/scripts/bench-report.ts +46 -1
  281. package/scripts/ci-typecheck-changed.ts +7 -5
  282. package/scripts/release-loop/auto-approve-node.ts +6 -0
  283. package/scripts/release-loop/gate-closure.ts +286 -0
  284. package/scripts/release-loop/gate-node.ts +73 -13
  285. package/scripts/release-loop/gate-partial.ts +34 -6
  286. package/scripts/release-loop/ops-upgrade-node.ts +63 -42
  287. package/scripts/release-loop/publish-node.ts +6 -0
  288. package/scripts/release-loop/resume-release.ts +37 -10
  289. package/scripts/release-loop/resume.ts +69 -4
  290. package/scripts/tsc-baseline-cache.ts +28 -3
  291. package/scripts/usage-rollup.ts +27 -13
  292. package/scripts/ux-sim.ts +30 -1
  293. package/skills/youtube-master/scripts/main.ts +4 -1
  294. package/skills/youtube-master/src/obsidian.ts +9 -0
  295. package/src/agent-substrate/acp-implementer.ts +14 -7
  296. package/src/agent-substrate/pr-reviewer.ts +30 -10
  297. package/src/agent-substrate/self-review-cli.ts +126 -10
  298. package/src/budget/cost-tier-advisor.ts +91 -0
  299. package/src/budget/shadow-arms.ts +77 -0
  300. package/src/budget/types.ts +5 -3
  301. package/src/budget/unified-usage.ts +172 -8
  302. package/src/cli/doctor-cli.ts +21 -0
  303. package/src/cli/friendly-errors.ts +113 -0
  304. package/src/cli/intake-cli.ts +3 -1
  305. package/src/cli/memory-cli.ts +182 -0
  306. package/src/cli/model-watch-cli.ts +4 -1
  307. package/src/cli/pr-land-pod-shadow.ts +54 -0
  308. package/src/cli/release-cli.ts +9 -7
  309. package/src/cli/release-run-if-ready.ts +11 -0
  310. package/src/cli/resource-cli.ts +48 -0
  311. package/src/cli/retro-cli.ts +12 -3
  312. package/src/cli/seat-requests-cli.ts +25 -0
  313. package/src/cli/tasks-cli.ts +31 -7
  314. package/src/cli/usage-cli.ts +3 -1
  315. package/src/compact/verify-probe.ts +23 -3
  316. package/src/context-card/index.ts +50 -0
  317. package/src/control/control-status.ts +30 -1
  318. package/src/dashboard/slash-runtime/dashboard-handlers.ts +4 -138
  319. package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
  320. package/src/debug/log-diet.ts +16 -4
  321. package/src/domains/morning-essential.ts +18 -3
  322. package/src/domains/release-tool.ts +4 -0
  323. package/src/execution-loop/launch-gate.ts +158 -2
  324. package/src/fleet/host-doctor.ts +375 -0
  325. package/src/goals/judge.ts +20 -6
  326. package/src/graph-runner/runner.ts +9 -5
  327. package/src/graph-wizard/archetypes.ts +14 -8
  328. package/src/graph-wizard/generate.ts +77 -1
  329. package/src/grok.ts +13 -7
  330. package/src/harness/harness-cli-command.ts +56 -47
  331. package/src/harness/harness-stop.ts +82 -12
  332. package/src/index.ts +17 -175
  333. package/src/intake-plane/collect-github.ts +7 -2
  334. package/src/intake-plane/lens.ts +46 -4
  335. package/src/intake-plane/requirement-funnel.ts +53 -1
  336. package/src/intelligence-map/catalog-feed.ts +119 -0
  337. package/src/intelligence-map/model-watch-intake.ts +40 -0
  338. package/src/intelligence-map/model-watch-mission.ts +14 -1
  339. package/src/llm/open-weight-discipline.ts +21 -0
  340. package/src/llm.ts +4 -8
  341. package/src/maturity/feature-maturity.ts +1 -1
  342. package/src/nexus/api/http-server.ts +22 -0
  343. package/src/oauth/codex-account-rotation.ts +4 -1
  344. package/src/oauth/codex-account-store.ts +20 -7
  345. package/src/oauth/codex-quota-policy.ts +33 -4
  346. package/src/preview/terminal.ts +15 -5
  347. package/src/project/project-store.ts +20 -0
  348. package/src/release-loop/auto-start.ts +7 -5
  349. package/src/release-loop/checklist.ts +11 -1
  350. package/src/release-loop/gate-shards.ts +4 -0
  351. package/src/release-loop/light-rc.ts +84 -13
  352. package/src/release-loop/merged-pr-checklist.ts +35 -5
  353. package/src/release-loop/rehearsal.ts +1 -1
  354. package/src/seat-loop/duty-ledger.ts +64 -0
  355. package/src/self-dev/decompose.ts +37 -3
  356. package/src/self-dev/dev-pipeline.ts +32 -7
  357. package/src/self-dev/draft-residue.ts +16 -6
  358. package/src/self-dev/draft-sweep.ts +52 -4
  359. package/src/self-dev/fabric-decompose-adapter.ts +9 -2
  360. package/src/self-dev/run-supervisor.ts +37 -7
  361. package/src/self-implement/gate-cli.ts +29 -10
  362. package/src/self-implement/gate-remote.ts +4 -1
  363. package/src/self-implement/goal-author.ts +12 -2
  364. package/src/self-implement/goal-new-paths.ts +42 -0
  365. package/src/self-implement/host-regate.ts +124 -30
  366. package/src/self-implement/importer-test-index.ts +3 -1
  367. package/src/self-implement/l8-merge-queue.ts +80 -2
  368. package/src/self-implement/merge-train.ts +19 -0
  369. package/src/self-implement/off-diff-evidence.ts +40 -1
  370. package/src/self-implement/orchestrator.ts +88 -19
  371. package/src/self-implement/premise-review.ts +159 -0
  372. package/src/self-implement/regate-detail.ts +79 -0
  373. package/src/self-implement/review-deferred-to-host.ts +21 -0
  374. package/src/self-implement/rework-budget-judgment.ts +23 -3
  375. package/src/self-implement/running-runs.ts +2 -2
  376. package/src/self-implement/scope-adjacency.ts +23 -0
  377. package/src/self-implement/seams.ts +42 -7
  378. package/src/skills/tools/agent.ts +16 -1
  379. package/src/skills/tools/persistent-grounding.ts +11 -1
  380. package/src/skills/tools/shell.ts +33 -1
  381. package/src/steward/rejudge-tick.ts +142 -0
  382. package/src/task-agent/board.ts +92 -3
  383. package/src/task-agent/card-evidence.ts +88 -1
  384. package/src/task-agent/cover.ts +65 -0
  385. package/src/task-agent/parent-host.ts +27 -3
  386. package/src/task-agent/rejudge-on-head.ts +151 -7
  387. package/src/task-agent/review-result-capture.ts +3 -1
  388. package/src/task-agent/shadow.ts +12 -0
  389. package/src/task-agent/task-hand.ts +4 -1
  390. package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
  391. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
  392. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
  393. package/src/task-orchestrator/surfaces/pod-pool.ts +53 -0
  394. package/src/task-orchestrator/surfaces/self-implement-pod.ts +235 -28
  395. package/src/user-config.ts +18 -4
  396. package/src/ux-sim/fault-cred-expiry.ts +100 -0
  397. package/src/ux-sim/fault-pod-death.ts +74 -0
  398. package/src/ux-sim/fault-pool-cap.ts +81 -0
  399. package/src/version/packed-revision.json +1 -1
  400. package/src/webclone/qa-table.ts +22 -0
  401. package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
  402. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
  403. package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
  404. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
  405. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
  406. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
  407. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
  408. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
  409. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
  410. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
  411. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
  412. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
  413. package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
  414. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
  415. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
  416. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
  417. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
  418. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
  419. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
  420. package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +0 -1
  421. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
  422. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
  423. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
  424. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
  425. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
  426. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
  427. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
  428. package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +0 -1
  429. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
  430. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
  431. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
  432. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
  433. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
  434. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
  435. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
  436. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
  437. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
  438. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
  439. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
  440. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
  441. package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
  442. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
  443. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
  444. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
  445. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
  446. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
  447. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
  448. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
  449. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
  450. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
  452. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
  454. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
  455. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
  457. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
  458. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
  462. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
  465. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
  466. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
  467. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
  468. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
  469. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
  472. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
  475. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
  479. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
  480. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
  485. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
  486. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
  488. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
  490. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
  491. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
  496. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +0 -1
  499. package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +0 -1
  503. package/apps/pwa/out/_next/static/chunks/app/consult/page-c0ab229673a8b0eb.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +0 -1
  506. package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +0 -1
  507. package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
  511. package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +0 -1
  516. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +0 -1
  517. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +0 -1
  518. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +0 -1
  521. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +0 -1
  528. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +0 -1
  529. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +0 -1
  534. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +0 -1
  535. package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +0 -1
  537. package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +0 -1
  539. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +0 -1
  540. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
  545. package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
  551. /package/apps/pwa/out/_next/static/{Q-7iofoxOEv1WX18S35of → dRS6lEhSRRBr1abbzp7fJ}/_ssgManifest.js +0 -0
@@ -192,9 +192,9 @@ export function remoteParentAlive(parentHost: { host: string; pid?: number; runI
192
192
  }
193
193
 
194
194
  /** 발사 전 점검 결과 — `gaps` 가 비어야 원격으로 띄운다. */
195
- export interface ParentHostPreflight { ok: boolean; gaps: string[]; facts: Record<string, string> }
195
+ export interface ParentHostPreflight { ok: boolean; gaps: string[]; warnings: string[]; facts: Record<string, string> }
196
196
 
197
- /** 원격 사실 한 번에 — key=value 줄. */
197
+ /** 원격 사실 한 번에 — key=value 줄. LLM 자격은 «존재·개수»만 센다(값을 읽지도 찍지도 않는다). */
198
198
  export function preflightScript(target: ParentHostConfig): string {
199
199
  const elanous = remotePath(target.elanous ?? DEFAULT_REMOTE_ELANOUS);
200
200
  const configDir = remotePath(target.configDir ?? DEFAULT_REMOTE_CONFIG_DIR);
@@ -204,6 +204,9 @@ export function preflightScript(target: ParentHostConfig): string {
204
204
  `grep -Eq '"podPool"[[:space:]]*:[[:space:]]*"[^"[:space:]]+' ${configDir}/config.json 2>/dev/null && echo podPool=1`,
205
205
  `(cd ${shellQuote(target.cwd)} 2>/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2>&1) && echo repo=1`,
206
206
  `command -v kubectl >/dev/null 2>&1 && echo kubectl=1`,
207
+ `n=$(grep -Ec '^[[:space:]]*"openai-codex(:[^"]*)?"[[:space:]]*:[[:space:]]*\\{' ${configDir}/auth.json 2>/dev/null); echo "codexAccounts=\${n:-0}"`,
208
+ `{ grep -Eq '"key"[[:space:]]*:[[:space:]]*"[^"]+"' "$HOME/.grok/auth.json" 2>/dev/null || [ -n "\${XAI_API_KEY:-}\${GROK_API_KEY:-}\${GROK_CODE_XAI_API_KEY:-}" ]; } && echo grok=1`,
209
+ `{ [ -s "\${ELANOUS_KEY_CACHE_DIR:-$HOME/.cache}/openrouter_api_key" ] || [ -n "\${OPENROUTER_API_KEY:-}" ]; } && echo openrouter=1`,
207
210
  `true`,
208
211
  ].join('; ');
209
212
  }
@@ -242,6 +245,16 @@ export function judgeParentHostFacts(facts: Record<string, string>, input: Omit<
242
245
  return gaps;
243
246
  }
244
247
 
248
+ /** 순수 판정 — 원격 LLM 자격 사실 → 경고 목록(막지 않는다 · gaps 와 별개). 못 닿은 호스트는 사실이 없으므로 경고도 없다. */
249
+ export function judgeParentHostCredentials(facts: Record<string, string>): string[] {
250
+ if (facts.unreachable) return [];
251
+ const warnings: string[] = [];
252
+ if (!(Number(facts.codexAccounts) > 1)) warnings.push('codex-accounts-low');
253
+ if (facts.grok !== '1') warnings.push('grok-credential-missing');
254
+ if (facts.openrouter !== '1') warnings.push('openrouter-key-missing');
255
+ return warnings;
256
+ }
257
+
245
258
  export function preflightParentHost(input: PreflightInput): ParentHostPreflight {
246
259
  const ssh = input.ssh ?? defaultSshRunner;
247
260
  const facts: Record<string, string> = {};
@@ -252,7 +265,18 @@ export function preflightParentHost(input: PreflightInput): ParentHostPreflight
252
265
  if (at > 0) facts[line.slice(0, at).trim()] = line.slice(at + 1).trim();
253
266
  }
254
267
  const gaps = judgeParentHostFacts(facts, { localVersion: input.localVersion, launchHoldActive: input.launchHoldActive, podPoolOverride: Boolean(input.target.podPool) });
255
- return { ok: gaps.length === 0, gaps, facts };
268
+ const warnings = judgeParentHostCredentials(facts);
269
+ if (warnings.length) {
270
+ try {
271
+ debug.log('task-agent.parent-host', 'credential-warning', {
272
+ host: input.target.host,
273
+ codexAccounts: Number(facts.codexAccounts) || 0,
274
+ grok: facts.grok === '1' ? 1 : 0,
275
+ openrouter: facts.openrouter === '1' ? 1 : 0,
276
+ });
277
+ } catch { /* fail-soft */ }
278
+ }
279
+ return { ok: gaps.length === 0, gaps, warnings, facts };
256
280
  }
257
281
 
258
282
  /** 원격이 «확실히 안 띄웠다»고 답했다 — 호출부가 로컬로 돌아가도 중복 발사가 아니다. */
@@ -19,6 +19,10 @@
19
19
  * 거절되면 그 시도는 `base-stale` 갈래로 적히고(judgement 1회 규칙과 섞이지 않는다), 다음 틱이 «같은 머리»를 새 base 위에서 한 번 더
20
20
  * 재게이트한다(`staleBase` = 낡은 base · 멱등 키 = 머리 ⊕ staleBase · 상한에 포함). 그 재게이트가 통과하고 base 가 실제로 바뀌었을 때만
21
21
  * 새 baseCommit 으로 증거를 다시 써 land 한다(`gateAt` 으로 앞 base-stale 시도를 소비) — 관측 `rejudge-on-head {step:'regate', reason:'base-stale-overlap …'}`.
22
+ * - TA-REJUDGE-REBASE-LOOP: 그 1회가 «같은 base» 로 돌아오거나 stale 재게이트에 `baseCommit` 이 없으면 needs-owner 로 멈추지 않는다. origin/main 을
23
+ * fetch 한 뒤 PR 가지에 3-way merge(rerere 켬 · ⛔ rebase/force-push/reset/파일째 checkout) 하고 일반 push 로 새 머리를 만든 다음, 그 머리는 기존
24
+ * ①②③ 사슬을 탄다. 머리마다 1회 · 카드당 `CATCH_UP_CAP`(기본 2)회. 충돌이면 `merge --abort` ⊕ needs-owner(`main 따라잡기 충돌 · 파일 …`).
25
+ * 관측 `rejudge-on-head {step:'catch-up', decision: pushed|conflict|cap-reached, fromBase, toBase, newHead}`.
22
26
  * - 대상: 카드에 묶인 PR(URL 로 저장소 확인) ⊕ 그 PR 로 TA 가 이미 리뷰를 요청한 카드(= 런이 멈춰 TA 판단이 시작됐다).
23
27
  * - 사람의 hold(draft PR)는 뒤집지 않는다 — 재게이트(`noMerge`)와 land 관문이 draft 를 거부한다.
24
28
  * - 허용: 설정 `taskAgent.liveMoves` 그대로 — 재게이트·land 는 `propose-land`, 리뷰 재요청은 `review` 가 있을 때만(없으면 «했을 수»).
@@ -26,7 +30,8 @@
26
30
  * 한 줄(`event:'rejudge-on-head'` · 같은 머리·같은 단계·같은 판단은 한 번).
27
31
  */
28
32
  import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
29
- import { spawn } from 'node:child_process';
33
+ import { spawn, spawnSync } from 'node:child_process';
34
+ import { tmpdir } from 'node:os';
30
35
  import { dirname, join } from 'node:path';
31
36
  import { debug } from '../debug/log.js';
32
37
  import type { DetachedSpawn } from '../cli/tasks-cli.js';
@@ -39,18 +44,37 @@ import { cardPrNumber, readTaskCard, taskAgentStatePath, updateTaskCard, type Ta
39
44
  export const REJUDGE_ON_HEAD_EVENT = 'rejudge-on-head';
40
45
  /** 카드·PR 당 재게이트하는 머리 수 상한(머리가 바뀔 때마다 하나) — 넘으면 멈추고 사람에게 넘긴다. */
41
46
  export const REJUDGE_HEAD_CAP = 3;
47
+ /** 카드당 origin/main 따라잡기(merge⊕push) 상한 — 넘으면 멈추고 사람에게 넘긴다. 머리마다 1회. */
48
+ export const CATCH_UP_CAP = 2;
42
49
  /** 떼어 띄운 재게이트 결과를 기다리는 상한 — 지나도 파일이 없으면 «결과 없음»으로 적는다(같은 머리는 다시 안 돌린다). */
43
50
  export const REGATE_RESULT_WAIT_MS = 90 * 60_000;
44
51
 
45
- export type RejudgeStep = 'regate' | 'review' | 'land' | 'target';
46
- export interface RejudgeOutcome { card: string; pr: number | null; fromHead: string | null; toHead: string | null; step: RejudgeStep; decision: string; reason: string }
52
+ export type RejudgeStep = 'regate' | 'review' | 'land' | 'target' | 'catch-up';
53
+ export type CatchUpDecision = 'pushed' | 'conflict' | 'cap-reached' | 'failed';
54
+ export interface RejudgeOutcome {
55
+ card: string; pr: number | null; fromHead: string | null; toHead: string | null; step: RejudgeStep; decision: string; reason: string;
56
+ fromBase?: string; toBase?: string; newHead?: string;
57
+ }
47
58
 
48
59
  export interface RegateRequest { card: string; pr: number; head: string; repoRoot: string; resultPath: string }
60
+ export interface CatchUpRequest { cwd: string; pr: number; head: string; branch?: string; fromBase?: string; worktreePath?: string }
61
+ export interface CatchUpResult {
62
+ decision: Exclude<CatchUpDecision, 'cap-reached'>;
63
+ reason: string;
64
+ fromBase?: string;
65
+ toBase?: string;
66
+ newHead?: string;
67
+ files?: string[];
68
+ pushArgs?: string[];
69
+ }
70
+ export type CatchUpGit = (cwd: string, args: string[]) => { status: number | null; stdout: string; stderr: string };
49
71
  export interface RejudgeDeps {
50
72
  live?: LiveMoveDeps;
51
73
  liveMoves: ReadonlySet<TaskAgentLiveMove>;
52
74
  /** 재게이트를 떼어 띄운다 — 시험은 주입한다. 기본은 `tasks regate-run` 자식(stdio ignore · 결과는 파일). */
53
75
  requestRegate?: (request: RegateRequest) => Promise<void>;
76
+ /** TA-REJUDGE-REBASE-LOOP — origin/main 을 PR 가지에 3-way merge 하고 일반 push. 시험은 주입한다. */
77
+ catchUpMain?: (request: CatchUpRequest) => Promise<CatchUpResult>;
54
78
  log?: (category: string, event: string, data: Record<string, unknown>) => void;
55
79
  /** 시험 seam — 결과 파일 읽기(없으면 ENOENT). */
56
80
  readFile?: (path: string) => string;
@@ -104,6 +128,83 @@ export function parseRegateResult(text: string, pr: number, head: string): Regat
104
128
  const sameUrl = (a: string, b: string) => a.trim().replace(/\/+$/, '').toLowerCase() === b.trim().replace(/\/+$/, '').toLowerCase();
105
129
  const sameHead = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();
106
130
 
131
+ const defaultCatchUpGit: CatchUpGit = (cwd, args) => {
132
+ const r = spawnSync('git', args, { cwd, encoding: 'utf8', timeout: 120_000 });
133
+ return { status: r.status, stdout: String(r.stdout ?? ''), stderr: String(r.stderr ?? '') };
134
+ };
135
+
136
+ export function catchUpWorktreePath(statePath: string, cardId: string, pr: number, head: string): string {
137
+ return join(dirname(statePath), 'catch-up-worktrees', `${safe(cardId)}-${pr}-${safe(head.slice(0, 12))}`);
138
+ }
139
+
140
+ const gitSha = (text: string): string | null => {
141
+ const value = text.trim();
142
+ return /^[0-9a-f]{40}$/i.test(value) ? value : null;
143
+ };
144
+
145
+ const catchUpFail = (reason: string, extra: Partial<CatchUpResult> = {}): CatchUpResult => ({ decision: 'failed', reason, ...extra });
146
+
147
+ /**
148
+ * origin/main 을 PR 머리에 3-way merge(rerere 켬) 하고 일반 push 한다.
149
+ * ⛔ rebase · force-push · reset · 남의 가지 파일째 checkout — 충돌이면 merge --abort.
150
+ */
151
+ export async function defaultCatchUpMain(request: CatchUpRequest, git: CatchUpGit = defaultCatchUpGit): Promise<CatchUpResult> {
152
+ const repo = request.cwd;
153
+ const work = request.worktreePath ?? join(tmpdir(), `ta-catch-up-${request.pr}-${safe(request.head.slice(0, 12))}-${process.pid}`);
154
+ const gitRepo = (args: string[]) => git(repo, args);
155
+ const gitWork = (args: string[]) => git(work, args);
156
+ const fromBase = request.fromBase;
157
+ if (!request.branch) return catchUpFail('PR head branch name unknown', { fromBase });
158
+
159
+ const fetchMain = gitRepo(['fetch', 'origin', 'refs/heads/main']);
160
+ if (fetchMain.status !== 0) return catchUpFail(`origin/main fetch failed: ${(fetchMain.stderr || fetchMain.stdout).trim().slice(-200)}`, { fromBase });
161
+ const toBase = gitSha(gitRepo(['rev-parse', 'FETCH_HEAD']).stdout);
162
+ if (!toBase) return catchUpFail('origin/main sha unreadable', { fromBase });
163
+
164
+ const fetchPr = gitRepo(['fetch', 'origin', `pull/${request.pr}/head`]);
165
+ if (fetchPr.status !== 0) return catchUpFail(`fetch pull/${request.pr}/head failed: ${(fetchPr.stderr || fetchPr.stdout).trim().slice(-200)}`, { fromBase, toBase });
166
+ const fetchedHead = gitSha(gitRepo(['rev-parse', 'FETCH_HEAD']).stdout);
167
+ if (!fetchedHead || !sameHead(fetchedHead, request.head)) {
168
+ return catchUpFail(`fetched PR head ${(fetchedHead ?? '?').slice(0, 12)} ≠ ${request.head.slice(0, 12)}`, { fromBase, toBase });
169
+ }
170
+
171
+ const added = gitRepo(['worktree', 'add', '--detach', work, request.head]);
172
+ if (added.status !== 0) return catchUpFail(`worktree add failed: ${(added.stderr || added.stdout).trim().slice(-200)}`, { fromBase, toBase });
173
+ const cleanup = () => { gitRepo(['worktree', 'remove', '--force', work]); };
174
+
175
+ gitWork(['config', 'rerere.enabled', 'true']);
176
+ const merge = gitWork(['merge', '--no-ff', toBase, '-m', `catch-up: merge origin/main into PR #${request.pr}`]);
177
+ if (merge.status !== 0) {
178
+ const files = gitWork(['diff', '--name-only', '--diff-filter=U']).stdout.split('\n').map((line) => line.trim()).filter(Boolean);
179
+ gitWork(['merge', '--abort']);
180
+ cleanup();
181
+ return {
182
+ decision: 'conflict',
183
+ reason: `main 따라잡기 충돌 · 파일 ${files.join(', ') || '(unknown)'}`,
184
+ fromBase, toBase, files,
185
+ };
186
+ }
187
+ const newHead = gitSha(gitWork(['rev-parse', 'HEAD']).stdout);
188
+ if (!newHead) { cleanup(); return catchUpFail('merge produced no head sha', { fromBase, toBase }); }
189
+ const pushArgs = ['push', 'origin', `HEAD:${request.branch}`];
190
+ const push = gitWork(pushArgs);
191
+ cleanup();
192
+ if (push.status !== 0) return catchUpFail(`push failed: ${(push.stderr || push.stdout).trim().slice(-200)}`, { fromBase, toBase, newHead, pushArgs });
193
+ return {
194
+ decision: 'pushed',
195
+ reason: `merged origin/main ${toBase.slice(0, 12)} → head ${newHead.slice(0, 12)}`,
196
+ fromBase, toBase, newHead, pushArgs,
197
+ };
198
+ }
199
+
200
+ /** 실제로 «시도한» 따라잡기 기록(pushed·conflict·failed) — `cap-reached`·`would-catch-up` 표지는 시도가 아니다. */
201
+ const CATCH_UP_ATTEMPT_EFFECTS: ReadonlySet<string> = new Set(['pushed', 'conflict', 'failed']);
202
+
203
+ function catchUpHistory(card: Pick<TaskCard, 'history'>, pr: number) {
204
+ return (card.history ?? []).filter((item) => item.event === REJUDGE_ON_HEAD_EVENT && item.kind === 'catch-up' && item.pr === pr
205
+ && typeof item.effect === 'string' && CATCH_UP_ATTEMPT_EFFECTS.has(item.effect));
206
+ }
207
+
107
208
  /** 카드의 PR URL 과 같은 PR 을 돌려주는 후보 저장소 — 못 찾으면 이유. */
108
209
  async function resolveCardPr(card: TaskCard, pr: number, url: string, deps: LiveMoveDeps): Promise<{ cwd: string; view: PrHeadView } | { reason: string }> {
109
210
  let candidates: readonly ReviewRepoCandidate[];
@@ -195,7 +296,50 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
195
296
  const { cwd, view } = found;
196
297
  const toHead = view.head;
197
298
  if (view.state !== 'OPEN') return target('pr-not-open', `PR #${pr} is ${view.state}`, pr, fromHead, toHead);
198
- const step = (s: RejudgeStep, decision: string, reason: string, record: boolean) => emit({ card: card!.id, pr, fromHead, toHead, step: s, decision, reason }, record);
299
+ const step = (s: RejudgeStep, decision: string, reason: string, record: boolean, extra: Partial<RejudgeOutcome> = {}) =>
300
+ emit({ card: card!.id, pr, fromHead, toHead, step: s, decision, reason, ...extra }, record);
301
+
302
+ const tryCatchUp = async (fromBase: string | undefined, why: string): Promise<boolean> => {
303
+ const prior = catchUpHistory(card!, pr);
304
+ // 상한은 «실제 push» 만 센다 — 충돌·실패 뒤 사람이 새 머리를 올리면 다시 시도할 수 있어야 한다.
305
+ const pushed = prior.filter((item) => item.effect === 'pushed').length;
306
+ if (pushed >= CATCH_UP_CAP) {
307
+ step('catch-up', 'cap-reached', `${why} · catch-up pushed ${pushed} times already (cap ${CATCH_UP_CAP}) — needs owner`, true, { fromBase });
308
+ return true;
309
+ }
310
+ if (prior.some((item) => item.head && sameHead(item.head, toHead))) {
311
+ step('catch-up', 'cap-reached', `${why} · already catch-up on this head — needs owner`, true, { fromBase });
312
+ return true;
313
+ }
314
+ if (!deps.liveMoves.has('propose-land')) {
315
+ step('catch-up', 'would-catch-up', `${why} · propose-land not enabled in taskAgent.liveMoves — shadow`, false, { fromBase });
316
+ return true;
317
+ }
318
+ let result: CatchUpResult;
319
+ try {
320
+ result = await (deps.catchUpMain ?? defaultCatchUpMain)({
321
+ cwd, pr, head: toHead, branch: view.branch, fromBase,
322
+ worktreePath: catchUpWorktreePath(statePath, card!.id, pr, toHead),
323
+ });
324
+ } catch (error) {
325
+ result = { decision: 'failed', reason: `catch-up threw: ${(error instanceof Error ? error.message : String(error)).slice(-200)}`, fromBase };
326
+ }
327
+ const extra: Partial<RejudgeOutcome> = {
328
+ ...(result.fromBase ? { fromBase: result.fromBase } : fromBase ? { fromBase } : {}),
329
+ ...(result.toBase ? { toBase: result.toBase } : {}),
330
+ ...(result.newHead ? { newHead: result.newHead } : {}),
331
+ };
332
+ if (result.decision === 'pushed') {
333
+ step('catch-up', 'pushed', result.reason, true, extra);
334
+ return true;
335
+ }
336
+ if (result.decision === 'conflict') {
337
+ step('catch-up', 'conflict', result.reason, true, extra);
338
+ return true;
339
+ }
340
+ step('catch-up', result.decision, `${why} · ${result.reason} — needs owner`, true, extra);
341
+ return true;
342
+ };
199
343
 
200
344
  // 머리가 런 멈춤 때 그대로면 재판정하지 않는다 — 그 머리의 재게이트·리뷰·land 판단은 멈춤 때의 판단(슈퍼바이저 틱)이 이미 했다.
201
345
  // TA-LAND-RETRY-ON-INFRA — 단, 그 머리의 land 가 TA 쪽 인프라 결손으로 실패해 재시도가 남았으면 아래 ①②③ 을 그대로 탄다
@@ -208,7 +352,7 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
208
352
  const stale = regate?.passed === true ? baseStaleAttemptAfter(card, pr, toHead, regate.at) : undefined;
209
353
  const staleBase = stale ? regate?.baseCommit : undefined;
210
354
  if (stale && !staleBase) {
211
- step('regate', 'not-regating', `base-stale-overlap on head ${toHead.slice(0, 12)} but the stale regate has no baseCommit — needs owner`, true);
355
+ await tryCatchUp(undefined, `base-stale-overlap on head ${toHead.slice(0, 12)} but the stale regate has no baseCommit`);
212
356
  return outcomes;
213
357
  }
214
358
  if (!regate || staleBase) {
@@ -282,9 +426,9 @@ export async function rejudgeCardOnHead(cardId: string, deps: RejudgeDeps): Prom
282
426
  step('land', 'not-landing', regate ? (regate.passed === false ? `host regate not passed: ${regate.detail ?? regate.status ?? 'unknown'}` : 'host regate still running') : 'no host regate for this head', regate?.passed === false);
283
427
  return outcomes;
284
428
  }
285
- // REJUDGE base-stale — 새 base 위 재게이트가 «같은» base 로 돌아왔다 — 증거가 또 낡았다고 거절될 것이므로 land 하지 않는다(재게이트도 멱등 키로 0).
429
+ // REJUDGE base-stale — 새 base 위 재게이트가 «같은» base 로 돌아왔다 → origin/main 따라잡기(merge⊕push) 후 새 머리 재게이트.
286
430
  if (regate.staleBase && regate.baseCommit && sameHead(regate.baseCommit, regate.staleBase)) {
287
- step('land', 'not-landing', `base-stale-overlap — re-gate on head ${toHead.slice(0, 12)} returned the same base ${regate.staleBase.slice(0, 12)} (did not advance) — no land, no further re-gate on this base; needs owner`, true);
431
+ await tryCatchUp(regate.staleBase, `base-stale-overlap — re-gate on head ${toHead.slice(0, 12)} returned the same base ${regate.staleBase.slice(0, 12)} (did not advance)`);
288
432
  return outcomes;
289
433
  }
290
434
  if (!deps.liveMoves.has('propose-land')) { step('land', 'would-land', 'propose-land not enabled in taskAgent.liveMoves — shadow', false); return outcomes; }
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import { readFileSync } from 'node:fs';
14
14
  import { dirname, join } from 'node:path';
15
+ import { isNoneSentinelFinding } from '../agent-substrate/pr-reviewer.js';
15
16
  import { debug } from '../debug/log.js';
16
17
  import { LIVE_MOVE_RESULT_EVENT, readTaskAgentState, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
17
18
 
@@ -63,7 +64,8 @@ export function parseReviewResultOutput(text: string): ParsedReviewResult | null
63
64
  ...(Number.isSafeInteger(prRaw) && prRaw > 0 ? { pr: prRaw } : {}),
64
65
  verdict: typeof v.verdict === 'string' ? v.verdict : null,
65
66
  reviewed: typeof v.reviewed === 'boolean' ? v.reviewed : null,
66
- mustFix: Array.isArray(v.mustFix) && v.mustFix.every((fix) => typeof fix === 'string') ? v.mustFix.length : null,
67
+ // PR-LAND-MUSTFIX-NONE — 저장된 결과(옛 판 리뷰 · 다른 경로)에 «(없음 — …)» 표지 줄이 남아 있어도 리뷰 출력과 «같은» 판정으로 0 으로 센다.
68
+ mustFix: Array.isArray(v.mustFix) && v.mustFix.every((fix) => typeof fix === 'string') ? v.mustFix.filter((fix) => !isNoneSentinelFinding(fix)).length : null,
67
69
  reviewRoute: typeof v.reviewRoute === 'string' ? v.reviewRoute : null,
68
70
  head: typeof v.headCommit === 'string' && SHA40.test(v.headCommit) ? v.headCommit : null,
69
71
  error: typeof v.error === 'string' ? v.error : null,
@@ -17,6 +17,7 @@ import type { SupervisorJobResult, SupervisorStopReason } from '../self-dev/run-
17
17
  import { executeNextAction, type DeliveryKind, type NextAction } from './actions.js';
18
18
  import { judgeNextMove, type TaskJudgeInput, type TaskJudgement } from './judge.js';
19
19
  import { HARNESS_RUN_ID_ENV } from '../harness/harness-space.js';
20
+ import { collectWiringEvidence, type WiringEvidenceDeps } from './card-evidence.js';
20
21
  import { recordLiveMoveHistory } from './live-move-history.js';
21
22
  import { capturedSelfReview, captureReviewResults, hasCapturedPass } from './review-result-capture.js';
22
23
  import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
@@ -60,6 +61,8 @@ export interface TaskAgentShadowDeps {
60
61
  live?: LiveMoveDeps;
61
62
  /** 카드 조회 상태 파일(시험 주입 · 운영 파일을 건드리지 않게). 기본 = `live.statePath` ⊕ `taskAgentStatePath()`. */
62
63
  statePath?: string;
64
+ /** TA-WIRING-CHECK — 배선 근거 수집 의존(시험 주입 · 기본 = gh pr diff 한 번 ⊕ 카드 런 원장). */
65
+ wiring?: Omit<WiringEvidenceDeps, 'card'>;
63
66
  /** Process env for the launched-run id (`ELANOUS_RUN_ID`) — test seam; default process.env. */
64
67
  env?: NodeJS.ProcessEnv;
65
68
  }
@@ -325,6 +328,15 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
325
328
  ...move, completion: shadowCompletion(card, cardLookupFailed), card: liveCard?.id ?? null, live, liveExecuted: liveMove?.executed ?? false, ...(liveMove ? { liveOk: liveMove.ok } : {}),
326
329
  ...(reviewFromCapture ? { reviewSource: 'captured-review-result' } : {}),
327
330
  });
331
+ // TA-WIRING-CHECK — 병합 PR 은 판단한 «뒤» 배선 근거를 관측만 한다(move 불변 · 실패는 unknown 으로 남기고 던지지 않는다).
332
+ if (judgeInput.prState === 'MERGED' && typeof judgeInput.pr === 'number' && !delivery && liveCard) {
333
+ try {
334
+ const wiring = await collectWiringEvidence(judgeInput.pr, { ...deps.wiring, card: liveCard });
335
+ (deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'wiring-shadow', {
336
+ card: liveCard.id, pr: judgeInput.pr, required: wiring.required, liveRunRecorded: wiring.liveRunRecorded, unknown: wiring.unknown,
337
+ });
338
+ } catch { /* fail-soft — 관측일 뿐 판단을 막지 않는다 */ }
339
+ }
328
340
  // TA-LIVE-MOVE-CARD-HISTORY — live-move 수(review·propose-green·propose-land)는 실행이든 그림자든 그 카드 history 에 한 줄.
329
341
  // 결정·실행이 끝난 «뒤»에 덧붙이기만 한다(반환값·관측 무변경) · 실패는 관측만(live-move 를 막지 않는다).
330
342
  if (liveKind !== null) recordLiveMoveOnCard({
@@ -487,7 +487,10 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
487
487
  if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
488
488
  const runId = mintRunId();
489
489
  const launchId = `tl-${randomBytes(6).toString('hex')}`;
490
- const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id, ...(card.taLand ? { [TA_LAND_ENV]: '1' } : {}) }, cardLabelContext: taskCardLabelContext(card) };
490
+ const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
491
+ ...(card.checklistId ? { ELANOUS_POD_SLOT_ID: card.checklistId } : {}),
492
+ ...(card.seat ? { ELANOUS_POD_OWNER_KIND: 'seat', ELANOUS_POD_OWNER_ID: card.seat } : {}),
493
+ ...(card.taLand ? { [TA_LAND_ENV]: '1' } : {}) }, cardLabelContext: taskCardLabelContext(card) };
491
494
  let receipt: void | TaskLaunchReceipt;
492
495
  try {
493
496
  receipt = await opts.launcher(move.command!, project?.target, context);
@@ -371,6 +371,12 @@ export interface RunPodCommandOptions {
371
371
  runId?: string;
372
372
  name?: string;
373
373
  pollMs?: number;
374
+ /**
375
+ * GATE-MULTI-HOST — throw once the Job's status has been unreadable (`kubectl get job` failing) this long, instead of
376
+ * polling forever: a pool member that died mid-Job (host off · tailnet drop) then frees its caller to place the work
377
+ * elsewhere. Omitted = poll without a bound (unchanged for every caller but the release gate).
378
+ */
379
+ statusUnreadableMs?: number;
374
380
  kubectl?: Kubectl;
375
381
  /** A caller-owned scheduler is self-capped: acquires count only its own Jobs, never cluster occupancy (POOLGLOBAL-REG). */
376
382
  poolScheduler?: PodPoolScheduler;
@@ -536,10 +542,18 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
536
542
  throw new Error(applied.stderr.trim() || 'pod command: Job 적용 실패');
537
543
  }
538
544
  let state: 'complete' | 'failed' = 'failed';
545
+ let unreadableSince: number | null = null;
539
546
  for (;;) {
540
547
  const got = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.status.conditions[*].type}']);
541
548
  const finished = jobFinished(got.stdout);
542
549
  if (finished) { state = finished; break; }
550
+ if (got.status !== 0 && options.statusUnreadableMs !== undefined) {
551
+ unreadableSince ??= Date.now();
552
+ if (Date.now() - unreadableSince >= options.statusUnreadableMs) {
553
+ log('pod.command', 'job-status-unreadable', { job: name, context, unreadableMs: Date.now() - unreadableSince, error: (got.stderr ?? '').trim().slice(0, 300) });
554
+ throw new Error(`pod command: Job 상태를 ${Math.round(options.statusUnreadableMs / 1000)}초 동안 못 읽었다(${context}) — ${(got.stderr ?? '').trim().split('\n').pop()?.slice(0, 200) ?? ''}`);
555
+ }
556
+ } else unreadableSince = null;
543
557
  await sleep(options.pollMs ?? 15_000);
544
558
  }
545
559
  const logsResult = kubectl(['-n', namespace, 'logs', `job/${name}`, '-c', 'child']);
@@ -0,0 +1,122 @@
1
+ // REVIEW-ACP-POD (0.2.25 · REVIEW-ACP-DEFAULT ② 조각) — Pod 런이 낸 merge-ready PR 을 «호스트»가 Claude ACP(구독)로 다시 본다.
2
+ //
3
+ // S Pod 안 하니스 리뷰는 api 리뷰어(codex 기본 gpt-6-sol · OR Pod 는 glm 고정)로 돈다 — Pod 엔 Claude 구독도 정책 파일도 없어
4
+ // `roleLlm.reviewer = claude-acp`(운영에 이미 켜져 있다)가 Pod 안에선 «안 닿는다». 호스트 레인 런만 ACP 로 리뷰받는다.
5
+ // C Pod 가 호스트로 돌려보내는 유일한 문은 merge-ready → 호스트 재게이트 → 병합이다. 여기에 리뷰가 없다.
6
+ // Q Pod 런의 리뷰를 구독(ACP)으로 옮기려면 어디서 하나?
7
+ // A 호스트 병합 직전 한 자리에서, 하니스 레인과 «같은» 정책 행(`resolveSubscriptionReviewer`)·같은 가용성 검사
8
+ // (`subscriptionReviewerAvailability` — 구독 확인 · 상한 · 프록시)·같은 ACP 리뷰어(`makeAcpReviewLLM`)로 PR 을 본다.
9
+ // ⛔ 못 쓰면(설정 없음·구독 확인 실패·상한·프록시 없음·리뷰 미완) «refused» 로 돌려주고 호출자는 종전 길(Pod 리뷰 결과로 재게이트)을 그대로 간다.
10
+ // 조용히 다른 공급자로 새지 않는다 — 이 함수 안엔 api 폴백이 «없다».
11
+ // ⛔ 기본 꺼짐(opt-in): 옵션 → env `ELANOUS_POD_HOST_ACP_REVIEW` → config `llm.podHostAcpReview` 순.
12
+ // 📌 남은 조각(②-b): 이 문이 켜진 런에서 Pod 안 api 리뷰를 «끄는» 것은 Pod 이미지 쪽 변경이라 따로 간다.
13
+ import { spawnSync } from 'node:child_process';
14
+ import { debug } from '../../debug/log.js';
15
+ import type { ReviewResult } from '../../agent-substrate/pr-reviewer.js';
16
+ import type { SubscriptionReviewerSpec } from '../../user-config.js';
17
+ import type { SubscriptionReviewerDeps, subscriptionReviewerSpawn } from '../../self-dev/review-provider-fallback.js';
18
+
19
+ export const POD_HOST_ACP_REVIEW_ENV = 'ELANOUS_POD_HOST_ACP_REVIEW';
20
+
21
+ export type PodHostAcpReviewEnable = { enabled: boolean; source: 'option' | 'env' | 'config' | 'default' };
22
+
23
+ /** 켜는 순서: 옵션 → env(`1`/`true` 켬 · `0`/`false` 끔) → config `llm.podHostAcpReview === true` → 꺼짐. 읽기 실패는 꺼짐(종전). */
24
+ export function resolvePodHostAcpReview(
25
+ option: boolean | undefined,
26
+ env: NodeJS.ProcessEnv,
27
+ readConfig: () => unknown,
28
+ ): PodHostAcpReviewEnable {
29
+ if (typeof option === 'boolean') return { enabled: option, source: 'option' };
30
+ const raw = env[POD_HOST_ACP_REVIEW_ENV]?.trim().toLowerCase();
31
+ if (raw === '1' || raw === 'true') return { enabled: true, source: 'env' };
32
+ if (raw === '0' || raw === 'false') return { enabled: false, source: 'env' };
33
+ try {
34
+ const cfg = readConfig() as { llm?: { podHostAcpReview?: unknown } } | undefined;
35
+ if (cfg?.llm?.podHostAcpReview === true) return { enabled: true, source: 'config' };
36
+ } catch { /* 읽기 실패 = 꺼짐(종전 길) */ }
37
+ return { enabled: false, source: 'default' };
38
+ }
39
+
40
+ export type PodHostAcpReviewOutcome =
41
+ | { status: 'clean'; mustFix: 0; shouldFix: number }
42
+ | { status: 'must-fix'; mustFix: number; findings: string[]; verdict: ReviewResult['verdict'] }
43
+ | { status: 'refused'; reason: string };
44
+
45
+ export interface PodHostAcpReviewDeps {
46
+ /** `{ spec, cap }` — 기본은 하니스 레인과 같은 정책 행(`resolveSubscriptionReviewer`). */
47
+ resolveReviewer?: () => { spec: SubscriptionReviewerSpec; cap: number } | undefined;
48
+ /** 구독·상한·프록시 확인 — 기본은 `subscriptionReviewerAvailability`. */
49
+ availability?: (spec: SubscriptionReviewerSpec, cap: number) => { spawn?: ReturnType<typeof subscriptionReviewerSpawn>; reason?: string };
50
+ subscriptionReviewerDeps?: SubscriptionReviewerDeps;
51
+ /** PR 머리 sha·제목·본문·diff. 기본은 `gh`. */
52
+ readPr?: (prNumber: number, repoRoot: string) => { headRefOid: string; title: string; body: string; diff: string } | undefined;
53
+ /** ACP 리뷰어(prompt→text). 기본은 `makeAcpReviewLLM({ backend: 'claude', backendSpec, env })`. */
54
+ makeAcpReviewLLM?: (spawn: ReturnType<typeof subscriptionReviewerSpawn>, repoRoot: string) => (prompt: string) => Promise<string>;
55
+ reviewPullRequest?: (input: { prDiff: string; phaseIntent: string }, llm: (prompt: string) => Promise<string>) => Promise<ReviewResult>;
56
+ env?: NodeJS.ProcessEnv;
57
+ }
58
+
59
+ function defaultReadPr(prNumber: number, repoRoot: string): { headRefOid: string; title: string; body: string; diff: string } | undefined {
60
+ const view = spawnSync('gh', ['pr', 'view', String(prNumber), '--json', 'headRefOid,title,body'], { cwd: repoRoot, encoding: 'utf8', timeout: 60_000 });
61
+ if (view.status !== 0) return undefined;
62
+ const diff = spawnSync('gh', ['pr', 'diff', String(prNumber)], { cwd: repoRoot, encoding: 'utf8', timeout: 120_000, maxBuffer: 64 * 1024 * 1024 });
63
+ if (diff.status !== 0) return undefined;
64
+ try {
65
+ const parsed = JSON.parse(view.stdout) as { headRefOid?: unknown; title?: unknown; body?: unknown };
66
+ if (typeof parsed.headRefOid !== 'string') return undefined;
67
+ return { headRefOid: parsed.headRefOid, title: typeof parsed.title === 'string' ? parsed.title : '', body: typeof parsed.body === 'string' ? parsed.body : '', diff: diff.stdout };
68
+ } catch { return undefined; }
69
+ }
70
+
71
+ function refused(reason: string, data: Record<string, unknown>): PodHostAcpReviewOutcome {
72
+ try { debug.log('self-implement.pod', 'acp-review-refused', { ...data, reason }, { level: 'warn' }); } catch { /* 관측은 결과를 안 바꾼다 */ }
73
+ return { status: 'refused', reason };
74
+ }
75
+
76
+ /** Pod merge-ready PR 을 호스트 Claude ACP 로 리뷰한다. ⛔ 던지지 않는다 — 모든 실패는 `refused`(호출자는 종전 길). */
77
+ export async function runPodHostAcpReview(
78
+ input: { prNumber: number; headCommit: string; repoRoot: string; job?: string },
79
+ deps: PodHostAcpReviewDeps = {},
80
+ ): Promise<PodHostAcpReviewOutcome> {
81
+ const obs = { job: input.job ?? null, pr: input.prNumber, head: input.headCommit };
82
+ try {
83
+ const env = deps.env ?? process.env;
84
+ // 지연 import — 이 문이 꺼진 런은 정책·설정을 안 읽는다.
85
+ const picked = deps.resolveReviewer ? deps.resolveReviewer() : await (async () => {
86
+ const { loadLlmPolicy, resolveSubscriptionReviewer } = await import('../../policy/llm-policy.js');
87
+ const { getUserConfig } = await import('../../user-config.js');
88
+ return resolveSubscriptionReviewer(loadLlmPolicy(), getUserConfig().roleLlm);
89
+ })();
90
+ if (!picked) return refused('no-subscription-reviewer', obs);
91
+ const avail = deps.availability
92
+ ? deps.availability(picked.spec, picked.cap)
93
+ : (await import('../../self-dev/review-provider-fallback.js')).subscriptionReviewerAvailability(picked.spec, picked.cap, env, deps.subscriptionReviewerDeps);
94
+ if (!avail.spawn) return refused(`unavailable: ${avail.reason ?? 'unknown'}`, { ...obs, cap: picked.cap });
95
+ const pr = (deps.readPr ?? defaultReadPr)(input.prNumber, input.repoRoot);
96
+ if (!pr) return refused('pr-unreadable', obs);
97
+ if (pr.headRefOid.toLowerCase() !== input.headCommit.toLowerCase()) return refused('head-moved', { ...obs, prHead: pr.headRefOid });
98
+ if (!pr.diff.trim()) return refused('empty-diff', obs);
99
+ const llm = deps.makeAcpReviewLLM
100
+ ? deps.makeAcpReviewLLM(avail.spawn, input.repoRoot)
101
+ : await (async () => {
102
+ const { makeAcpReviewLLM } = await import('../../agent-substrate/acp-reviewer.js');
103
+ const spawn = avail.spawn!;
104
+ return makeAcpReviewLLM({ cwd: input.repoRoot, backend: 'claude', backendSpec: spawn.backendSpec, env: spawn.env });
105
+ })();
106
+ const review = deps.reviewPullRequest ?? (await import('../../agent-substrate/pr-reviewer.js')).reviewPullRequest;
107
+ const phaseIntent = [`Pod 런 PR #${input.prNumber} 의 호스트 Claude ACP 리뷰(병합 전 관문).`, pr.title, pr.body.slice(0, 4000)].filter((s) => s.trim()).join('\n\n');
108
+ const rr = await review({ prDiff: pr.diff, phaseIntent }, llm);
109
+ // ⛔ reviewed=false(파싱 실패·ACP 오류를 리뷰어가 흡수) 는 «리뷰 완료»가 아니다 — 통과로 읽지 않는다.
110
+ if (!rr.reviewed) return refused('acp-review-not-completed', obs);
111
+ const mustFix = rr.mustFix.length;
112
+ if (rr.verdict === 'fail' || mustFix > 0) {
113
+ debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'must-fix', verdict: rr.verdict, mustFix, shouldFix: rr.shouldFix.length });
114
+ return { status: 'must-fix', mustFix, findings: rr.mustFix.slice(0, 10), verdict: rr.verdict };
115
+ }
116
+ debug.log('self-implement.pod', 'host-acp-review', { ...obs, status: 'clean', verdict: rr.verdict, mustFix: 0, shouldFix: rr.shouldFix.length });
117
+ return { status: 'clean', mustFix: 0, shouldFix: rr.shouldFix.length };
118
+ } catch (error) {
119
+ // 원문은 싣지 않는다 — 계정·프록시 문면이 섞일 수 있다(하니스 레인과 같은 규율).
120
+ return refused(/handshake timeout/i.test(error instanceof Error ? error.message : String(error)) ? 'acp-handshake-timeout' : 'acp-error', obs);
121
+ }
122
+ }
@@ -0,0 +1,23 @@
1
+ import { BUDGET_SNAPSHOT_ENV } from '../../execution-loop/launch-gate.js';
2
+
3
+ // Preserve the manifest contract except for two values generated per launch.
4
+ export function stablePodManifestText(applied: Array<Record<string, any>>): string {
5
+ const manifests = structuredClone(applied.filter((entry) => entry.kind === 'Job' || entry.kind === 'Secret'));
6
+ let snapshots = 0;
7
+ for (const manifest of manifests) {
8
+ if (manifest.kind !== 'Job') continue;
9
+ for (const container of manifest.spec?.template?.spec?.containers ?? []) {
10
+ for (const entry of container.env ?? []) {
11
+ if (entry.name !== BUDGET_SNAPSHOT_ENV) continue;
12
+ snapshots++;
13
+ // Keep every original byte except this one volatile numeric value.
14
+ const measuredAt = /("measuredAt"\s*:\s*)\d+/g;
15
+ const matches = [...entry.value.matchAll(measuredAt)];
16
+ if (matches.length !== 1) throw new Error('budget snapshot must have exactly one numeric measuredAt');
17
+ entry.value = entry.value.replace(measuredAt, (_match: string, prefix: string) => `${prefix}0`);
18
+ }
19
+ }
20
+ }
21
+ if (snapshots === 0) throw new Error('manifest comparison requires a budget snapshot');
22
+ return JSON.stringify(manifests).replace(/run-[0-9a-f-]{36}/g, 'run-<id>');
23
+ }
@@ -154,6 +154,59 @@ export function parsePodPool(spec: string): PodPoolMember[] {
154
154
  */
155
155
  export type PodPlacementKind = 'lite' | 'standard';
156
156
 
157
+ /** Identity carried by a launched pool Job and its Pod; absent source fields stay absent. */
158
+ export interface PodWorkIdentity {
159
+ ownerKind?: 'seat' | 'steward' | 'orchestrator' | 'external';
160
+ ownerId?: string;
161
+ taskCard?: string;
162
+ slotId?: string;
163
+ work?: 'harness' | 'authoring' | 'lite';
164
+ }
165
+
166
+ /** Kubernetes label values cannot exceed 63 characters or contain arbitrary card/owner text. */
167
+ export function podWorkLabels(identity: PodWorkIdentity): Record<string, string> {
168
+ const value = (raw: string | undefined): string | undefined => {
169
+ const cleaned = (raw ?? '').replace(/[^A-Za-z0-9._-]+/g, '-').slice(0, 63).replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, '');
170
+ return cleaned || undefined;
171
+ };
172
+ const ownerId = identity.ownerId && value(identity.ownerId) === identity.ownerId ? identity.ownerId : undefined;
173
+ const taskCard = identity.taskCard && value(identity.taskCard) === identity.taskCard ? identity.taskCard : undefined;
174
+ const slotId = identity.slotId && value(identity.slotId) === identity.slotId ? identity.slotId : undefined;
175
+ return {
176
+ ...(identity.ownerKind && ownerId ? { 'elanous.owner-kind': identity.ownerKind, 'elanous.owner-id': ownerId } : {}),
177
+ ...(taskCard ? { 'elanous.task-card': taskCard } : {}),
178
+ ...(slotId ? { 'elanous.checklist': slotId } : {}),
179
+ ...(identity.work ? { 'elanous.work': identity.work } : {}),
180
+ };
181
+ }
182
+
183
+ /** Minih standard-Job policy, independent of the configured pool member capacity. Not wired into allocation. */
184
+ export type MinihLocation = 'home' | 'external';
185
+
186
+ export function minihStandardCapacity(location: MinihLocation): number {
187
+ return location === 'home' ? 1 : 2;
188
+ }
189
+
190
+ /** A drain withholds new slots until occupancy falls to the target; it never evicts Running Pods. */
191
+ export function decideMinihDrain(location: MinihLocation, runningPods: number, pendingPods = 0): {
192
+ capacity: number;
193
+ runningPods: number;
194
+ drainNewAdmissions: boolean;
195
+ availableSlots: number;
196
+ } {
197
+ if (![runningPods, pendingPods].every((count) => Number.isSafeInteger(count) && count >= 0)) {
198
+ throw new RangeError('node-c occupancy must be non-negative whole Pods');
199
+ }
200
+ const capacity = minihStandardCapacity(location);
201
+ const occupied = runningPods + pendingPods;
202
+ return {
203
+ capacity,
204
+ runningPods,
205
+ drainNewAdmissions: occupied > capacity,
206
+ availableSlots: Math.max(0, capacity - occupied),
207
+ };
208
+ }
209
+
157
210
  export interface PodPlacement {
158
211
  readonly member: string;
159
212
  readonly kind: PodPlacementKind | null;