elanous 0.2.24 → 0.2.27

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 (601) 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/{Q-7iofoxOEv1WX18S35of → Ev2jivDMTSoEc-5rIXdcy}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1027.a0f04663d24c2779.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1038.676007ae505822e7.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1113.a37eadf7f740d955.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/112-fa7c526c20ce1405.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1144.5fa1fa1d48dbcd12.js +36 -0
  9. package/apps/pwa/out/_next/static/chunks/1146.80d15ea7c6e6ee95.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/1157.f08bf2b70915e176.js +148 -0
  11. package/apps/pwa/out/_next/static/chunks/119b405e.8fdd0e44d1ff37aa.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/1296.04560d98e73fbf51.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/1314-f604ba013ec535b0.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/1454-a9c338f5bb556f42.js +1 -0
  15. package/apps/pwa/out/_next/static/chunks/1464.f3209af0d8ae4ff2.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/{8532.a86e99acf9b761cb.js → 1516.83dd2c1b86b4e507.js} +2 -2
  17. package/apps/pwa/out/_next/static/chunks/{89849432.9eaa2f4c9c010965.js → 16e57f67.3ea19e893461e611.js} +3 -3
  18. package/apps/pwa/out/_next/static/chunks/1729-d73dd25e564679d4.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{1505.5826671109111e75.js → 1743.563d3168e95825ef.js} +2 -2
  20. package/apps/pwa/out/_next/static/chunks/1843.5924c24295243261.js +27 -0
  21. package/apps/pwa/out/_next/static/chunks/1987.e28149724b92918b.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/2066-5ca18ffa5a4be68b.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/2240.d10a66695155fd93.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2391.e2cbc98d4abbb41a.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2528.3868070ef1be69f9.js +24 -0
  26. package/apps/pwa/out/_next/static/chunks/2566-734cb83bbd405886.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2697.76ca2ac3efef6f3b.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/275.0e6bad414729bfa0.js +32 -0
  29. package/apps/pwa/out/_next/static/chunks/2803-33bdae771855a8d1.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/2846.d6a433b8663819a5.js +309 -0
  31. package/apps/pwa/out/_next/static/chunks/3143.257997a5f1ed79df.js +34 -0
  32. package/apps/pwa/out/_next/static/chunks/{5967-c0a80f8ffe5d4050.js → 3259-86f3be56e43eaf6a.js} +1 -1
  33. package/apps/pwa/out/_next/static/chunks/3280-e177c33bfbdcfb0a.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/3294-2b6a6d45a46a6c1c.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3309.364573ceedbdfd5f.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/3522.758840fc5e7fe630.js +287 -0
  37. package/apps/pwa/out/_next/static/chunks/3525-a7c989c1a661e880.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3694.b1a66387756458c0.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/370.124f9e678a76fc01.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3797-9643105335e660fe.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{5578.ac963634373b28c6.js → 4084.15ecaf4240bd9e77.js} +2 -2
  42. package/apps/pwa/out/_next/static/chunks/4089-b3382b8843114eee.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/{8438.ee7f0df3b3f6fcb4.js → 4204.a409ab6250c0f6a8.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/4293.928a8d573c16aab7.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/4402.f9238a3b18a7bd43.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4490-9b090b0f9427f902.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4548.13502d0ca3b4f862.js +8 -0
  48. package/apps/pwa/out/_next/static/chunks/4565-67e4c620597965c8.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/{7905.b230b9d06cb4ad5d.js → 4593.10f5b9bd702d4a6c.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/4599-548bc96cda44a5a7.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4625.206574e33a9e7ae8.js +104 -0
  52. package/apps/pwa/out/_next/static/chunks/4862-392c9a71f0d8dfb4.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/5054.2906d1b02542edc5.js +149 -0
  54. package/apps/pwa/out/_next/static/chunks/{8569.b853a8daa8f31d12.js → 5081.a240b63fad28663a.js} +1 -1
  55. package/apps/pwa/out/_next/static/chunks/5102-c822bbbee5a022a4.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5194-8c93f2e7e4b6f717.js +1 -0
  57. package/apps/pwa/out/_next/static/chunks/5305-bacd7eca0b9a5848.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5311.9071ee3f44fd7ff5.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/5369.9f34353442daa421.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/{2528.0af5c0e1fad88df6.js → 5408.377c8c543635b81f.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9502-32c5dc22e8f120f5.js → 5492-e05e26a033ba80d2.js} +3 -3
  62. package/apps/pwa/out/_next/static/chunks/5785-ea8d2c633b6688e3.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/589-49d730cb8138b397.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5904-264a6412ae3c9028.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5980.728531d5c566535c.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/599-a914cc0468f56143.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6011.f525002e21bef0ac.js +23 -0
  68. package/apps/pwa/out/_next/static/chunks/6132.4381ab93683f1acf.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6149.2e698635e454d8f6.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/{5974.360f8441eb0ac1ec.js → 6196.34d6b229079e9e28.js} +1 -1
  71. package/apps/pwa/out/_next/static/chunks/6356-0afafc4230cf9767.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6406.64756073f7df35b8.js +77 -0
  73. package/apps/pwa/out/_next/static/chunks/6479-16e62aedafa0e310.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6599.b5246b46a2453329.js +64 -0
  75. package/apps/pwa/out/_next/static/chunks/{ce383d63.d2ede338788ed18e.js → 65ebff95.081daeff622d238e.js} +1 -1
  76. package/apps/pwa/out/_next/static/chunks/6610.5c26eec011565acb.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/666.37d18474edc1c552.js +2 -0
  78. package/apps/pwa/out/_next/static/chunks/6904.a0b5b1ed4f2d2c20.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/{83cfc5c8.349535543c1548b6.js → 6def8a8e.c81f9ca41028eccf.js} +1 -1
  80. package/apps/pwa/out/_next/static/chunks/7247-1f4aba94aba50d9f.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7274-e71a7c5b7760cd02.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7290.1fcaeef3adb5d0d4.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7477-2c64e42760f82f33.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/{2721.bc9a8f36bd85c07a.js → 7483.ba01c6c209b81bba.js} +1 -1
  85. package/apps/pwa/out/_next/static/chunks/7505-47002b76ff1aef6c.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7600-11884ca4da68e5d9.js +1 -0
  87. package/apps/pwa/out/_next/static/chunks/7607.40d8bb3689697ccb.js +62 -0
  88. package/apps/pwa/out/_next/static/chunks/{6702.ebbd165d5e4a4a14.js → 7752.5cbdd0b433c54af9.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7763.f51fcc19ca1414ec.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7785.846140c859b1adf6.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/7807-a0fdac6393e0bf36.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7837-20a63b4b7e9342b1.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/800.7815414cf280545d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/{8925-2abfb48af477fb7f.js → 8085-1e5fce59500a2cc2.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/8100.415f2105faa63e97.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8290.701aa42ed13aa767.js +226 -0
  97. package/apps/pwa/out/_next/static/chunks/{b4e12462-5fab4a813a63dadd.js → 83a80514-b897b64df43ce108.js} +1 -1
  98. package/apps/pwa/out/_next/static/chunks/8444.d9c74214a3145a43.js +93 -0
  99. package/apps/pwa/out/_next/static/chunks/8569.98c915534928c7f9.js +24 -0
  100. package/apps/pwa/out/_next/static/chunks/{8264.00e434fbd02e9311.js → 8578.dff22d988cc2b106.js} +3 -3
  101. package/apps/pwa/out/_next/static/chunks/8591.b1c7f876e5ec7cfb.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/8715-f63756021d3ab989.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8879.776c2ec7732aa114.js +115 -0
  104. package/apps/pwa/out/_next/static/chunks/8881.ddca15b3c82c490c.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/8946.5da5c87f32a2e1a8.js +41 -0
  106. package/apps/pwa/out/_next/static/chunks/9117.080b9b75be90e14d.js +74 -0
  107. package/apps/pwa/out/_next/static/chunks/9167.f3ecb28f367d6e69.js +94 -0
  108. package/apps/pwa/out/_next/static/chunks/9224.66095370ee28c93b.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9238-0682b013c83d6449.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{7518.49161e8f5814abdb.js → 9311.24c8f5ea793253dd.js} +1 -1
  111. package/apps/pwa/out/_next/static/chunks/{9976.8f28864317639fe6.js → 94.4cfed21c0b781a06.js} +3 -3
  112. package/apps/pwa/out/_next/static/chunks/9449.d3ed795da4befb1c.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/949.1e7d45ccb71580aa.js +90 -0
  114. package/apps/pwa/out/_next/static/chunks/9638-d268329f2c6f4f8d.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{0e3acd34.d42b2ef87fdf4234.js → 973cbf1b.3bbcf2b41548eca7.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/9842-d6644eb53d3dc6bf.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9863.94ca3263e760696e.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/{6571-926ddf024a6ad5df.js → 9917-9e26abc5f7772735.js} +1 -1
  119. package/apps/pwa/out/_next/static/chunks/9938.b23e4d4dfa0114cd.js +79 -0
  120. package/apps/pwa/out/_next/static/chunks/{740.90b31555290236a9.js → 9974.e77b4ff4884557b3.js} +2 -2
  121. package/apps/pwa/out/_next/static/chunks/{4c5e95ce.83e9b16add6fcd8c.js → ab4d57c2.e90bc2cb31949045.js} +7 -7
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d9babd8795f396a5.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-a1ce306364f08da9.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-07110da72c45e68f.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-d2d76d4a7eae91bd.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-30007380f2e2a3c1.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-e5a9302c105725a3.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-b93c04b5311c97ec.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-718a49e86bf25f9c.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-20662900d6b4b455.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-f707a509515ac50c.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-6a16a48d1aa6e91f.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-26345242e4049f55.js → page-fcb06e305f515527.js} +1 -1
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-6acf5ec4e6c6d1af.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-39f82acf619cca23.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/page-7c2c8f81b185f9c0.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-d9babd8795f396a5.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-ae7aff07e32676bb.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-482c60c1bc540d0a.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-7cb996c1aa08b6f5.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-623e08fe4477d606.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-db460cd8aecb8490.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-ff27902d0b11ef4f.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-8397a5c6ca569bf4.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1917ea87ea71ab6b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-25a302273b054fd7.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-670510eda8b9443f.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d73c3f1e00d93986.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-65caacf54389081e.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4bb7556e2e97a750.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-77e04b4f8762c666.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/{page-b92caddb5c715f30.js → page-15c0a4095baddfba.js} +1 -1
  153. package/apps/pwa/out/_next/static/chunks/app/page-4eb96fc7241c2456.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-63e272a4cd3b6634.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-0d64ff212dc55d03.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-7f096248993fc2d4.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e47fc72049149a38.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-f7d808e31e005895.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-5c2b24b5496dad73.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-d9babd8795f396a5.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-76cdb531668b5191.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-e2b63345bba1a11f.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-d376e0c83edc041a.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d6db55fe2c04d128.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-87b88f551f421d8b.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-dab163b338e3b966.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-08019efef111ed2e.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-0260ffc7eda50db1.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-980ce6fe36ad95eb.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-99c4e6c7345a9156.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-0ab42e0f05823013.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-ad9220422d20ba33.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/dcf24383-2f82e35f2d827393.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/{53746282.1be36038d1abd949.js → e117f801.e92bf10242653497.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/e87d89b9.2e71c0ae475d28a1.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/{0673cc54.8e2ef1c23e49e190.js → f4dfbfc0.a69fb12f854882aa.js} +1 -1
  177. package/apps/pwa/out/_next/static/chunks/framework-bf135b997155e90e.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-5571537543bea91c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-app-25c51c7df7f3a442.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-e3b2c1f5d82abd65.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-083f2e23e9bc3641.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-e94d22b7a028217b.js +1 -0
  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 +88 -7
  282. package/scripts/coord-msg-bridge.ts +209 -0
  283. package/scripts/coord-post.sh +40 -7
  284. package/scripts/coord-requests-bridge.ts +10 -5
  285. package/scripts/expose-rubric-suggest.ts +1 -1
  286. package/scripts/measure-tsc-affected-roots.ts +10 -1
  287. package/scripts/release-loop/auto-approve-node.ts +6 -0
  288. package/scripts/release-loop/export-check-node.ts +8 -5
  289. package/scripts/release-loop/gate-closure.ts +286 -0
  290. package/scripts/release-loop/gate-node.ts +73 -13
  291. package/scripts/release-loop/gate-partial.ts +34 -6
  292. package/scripts/release-loop/node-verdict.ts +7 -2
  293. package/scripts/release-loop/ops-upgrade-node.ts +63 -42
  294. package/scripts/release-loop/publish-node.ts +6 -0
  295. package/scripts/release-loop/resume-release.ts +37 -10
  296. package/scripts/release-loop/resume.ts +69 -4
  297. package/scripts/tsc-baseline-cache.ts +28 -3
  298. package/scripts/usage-rollup.ts +27 -13
  299. package/scripts/ux-sim.ts +30 -1
  300. package/skills/youtube-master/scripts/main.ts +4 -1
  301. package/skills/youtube-master/src/obsidian.ts +9 -0
  302. package/src/agent/task-notification.ts +30 -1
  303. package/src/agent-substrate/acp-implementer.ts +14 -7
  304. package/src/agent-substrate/pr-reviewer.ts +30 -10
  305. package/src/agent-substrate/review-observation.ts +9 -2
  306. package/src/agent-substrate/self-review-cli.ts +154 -16
  307. package/src/boot/daemon-tools/self-implement.ts +72 -4
  308. package/src/budget/cost-tier-advisor.ts +91 -0
  309. package/src/budget/llm-cost.ts +5 -1
  310. package/src/budget/shadow-arms.ts +77 -0
  311. package/src/budget/types.ts +5 -3
  312. package/src/budget/unified-usage.ts +172 -8
  313. package/src/cli/control-cli.ts +29 -0
  314. package/src/cli/doctor-cli.ts +106 -3
  315. package/src/cli/friendly-errors.ts +113 -0
  316. package/src/cli/intake-cli.ts +3 -1
  317. package/src/cli/memory-cli.ts +182 -0
  318. package/src/cli/model-watch-cli.ts +4 -1
  319. package/src/cli/msg-cli.ts +15 -5
  320. package/src/cli/pr-cli.ts +53 -0
  321. package/src/cli/pr-land-overlap-evidence.ts +18 -10
  322. package/src/cli/pr-land-pod-shadow.ts +54 -0
  323. package/src/cli/release-cli.ts +41 -12
  324. package/src/cli/release-run-if-ready.ts +11 -0
  325. package/src/cli/resource-cli.ts +48 -0
  326. package/src/cli/retro-cli.ts +12 -3
  327. package/src/cli/seat-cli.ts +121 -0
  328. package/src/cli/seat-requests-cli.ts +25 -0
  329. package/src/cli/self-utterances-cli.ts +140 -0
  330. package/src/cli/tasks-cli.ts +168 -14
  331. package/src/cli/usage-cli.ts +3 -1
  332. package/src/compact/verify-probe.ts +23 -3
  333. package/src/context-card/cell.ts +40 -0
  334. package/src/context-card/index.ts +50 -0
  335. package/src/control/control-status.ts +30 -1
  336. package/src/dashboard/boot-timing.ts +35 -0
  337. package/src/dashboard/index.ts +86 -24
  338. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +26 -0
  339. package/src/dashboard/slash-runtime/dashboard-handlers.ts +10 -138
  340. package/src/dashboard/slash-runtime/shell-slash.ts +145 -0
  341. package/src/debug/log-diet.ts +16 -4
  342. package/src/debug/log.ts +1 -1
  343. package/src/domains/morning-essential.ts +18 -3
  344. package/src/domains/release-tool.ts +29 -8
  345. package/src/domains/surface-events.ts +16 -0
  346. package/src/elanous-config-dir.ts +2 -2
  347. package/src/execution-loop/launch-gate.ts +158 -2
  348. package/src/fleet/host-doctor.ts +446 -0
  349. package/src/goals/judge.ts +20 -6
  350. package/src/graph-runner/runner.ts +12 -6
  351. package/src/graph-wizard/archetypes.ts +14 -8
  352. package/src/graph-wizard/generate.ts +77 -1
  353. package/src/grok.ts +13 -7
  354. package/src/harness/harness-cli-command.ts +102 -51
  355. package/src/harness/harness-stop.ts +93 -19
  356. package/src/index.ts +52 -179
  357. package/src/instance/current.ts +2 -6
  358. package/src/instance/resolve.ts +5 -6
  359. package/src/intake-plane/collect-github.ts +7 -2
  360. package/src/intake-plane/lens.ts +46 -4
  361. package/src/intake-plane/requirement-funnel.ts +53 -1
  362. package/src/intelligence-map/catalog-feed.ts +119 -0
  363. package/src/intelligence-map/model-watch-intake.ts +40 -0
  364. package/src/intelligence-map/model-watch-mission.ts +14 -1
  365. package/src/llm/open-weight-discipline.ts +21 -0
  366. package/src/llm/openai-sampling-fields.ts +89 -0
  367. package/src/llm/runtime-model-family.ts +61 -0
  368. package/src/llm/zai-coding-plan.ts +27 -1
  369. package/src/llm.ts +17 -97
  370. package/src/machines/machine-ledger.ts +31 -3
  371. package/src/maturity/cli-maturity.ts +13 -3
  372. package/src/maturity/feature-maturity.ts +1 -1
  373. package/src/msg/msg-store.ts +69 -7
  374. package/src/nexus/api/http-server.ts +22 -0
  375. package/src/oauth/codex-account-rotation.ts +4 -1
  376. package/src/oauth/codex-account-store.ts +20 -7
  377. package/src/oauth/codex-quota-policy.ts +33 -4
  378. package/src/ops/overview-collect.ts +3 -2
  379. package/src/ops/overview-owner.ts +29 -0
  380. package/src/plugin-hooks/shell-hook.ts +17 -2
  381. package/src/plugin-missions/evaluator-runner.ts +18 -2
  382. package/src/plugins/install/plugin-install.ts +11 -1
  383. package/src/preview/terminal.ts +15 -5
  384. package/src/project/project-store.ts +20 -0
  385. package/src/prompt-enhance/enhance.ts +11 -0
  386. package/src/release-loop/auto-start.ts +7 -5
  387. package/src/release-loop/checklist.ts +52 -5
  388. package/src/release-loop/feature-store.ts +10 -9
  389. package/src/release-loop/gate-shards.ts +4 -0
  390. package/src/release-loop/light-rc.ts +84 -13
  391. package/src/release-loop/merged-pr-checklist.ts +35 -5
  392. package/src/release-loop/rehearsal.ts +1 -1
  393. package/src/seat-loop/duty-ledger.ts +64 -0
  394. package/src/seat-loop/seat-loop.ts +5 -1
  395. package/src/self-dev/decompose.ts +37 -3
  396. package/src/self-dev/dev-pipeline.ts +32 -7
  397. package/src/self-dev/draft-residue.ts +16 -6
  398. package/src/self-dev/draft-sweep.ts +75 -18
  399. package/src/self-dev/fabric-decompose-adapter.ts +9 -2
  400. package/src/self-dev/orchestrate.ts +6 -2
  401. package/src/self-dev/run-supervisor.ts +72 -8
  402. package/src/self-implement/gate-cli.ts +29 -10
  403. package/src/self-implement/gate-remote.ts +4 -1
  404. package/src/self-implement/goal-author.ts +15 -29
  405. package/src/self-implement/goal-command-execution.ts +26 -0
  406. package/src/self-implement/goal-new-paths.ts +42 -0
  407. package/src/self-implement/host-regate.ts +124 -30
  408. package/src/self-implement/importer-test-index.ts +3 -1
  409. package/src/self-implement/l8-merge-queue.ts +80 -2
  410. package/src/self-implement/merge-train.ts +19 -0
  411. package/src/self-implement/off-diff-evidence.ts +40 -1
  412. package/src/self-implement/orchestrator.ts +90 -20
  413. package/src/self-implement/premise-review.ts +159 -0
  414. package/src/self-implement/pwa-import-graph.ts +194 -7
  415. package/src/self-implement/regate-detail.ts +79 -0
  416. package/src/self-implement/review-deferred-to-host.ts +21 -0
  417. package/src/self-implement/rework-budget-judgment.ts +23 -3
  418. package/src/self-implement/running-runs.ts +2 -2
  419. package/src/self-implement/scope-adjacency.ts +23 -0
  420. package/src/self-implement/seams.ts +42 -7
  421. package/src/self-implement/self-implement-runtime.ts +126 -21
  422. package/src/session/index.ts +14 -4
  423. package/src/session-runtime/index.ts +55 -11
  424. package/src/skills/tools/agent.ts +16 -1
  425. package/src/skills/tools/persistent-grounding.ts +11 -1
  426. package/src/skills/tools/shell.ts +33 -1
  427. package/src/steward/rejudge-tick.ts +142 -0
  428. package/src/task-agent/board.ts +92 -3
  429. package/src/task-agent/card-evidence.ts +88 -1
  430. package/src/task-agent/cover.ts +85 -1
  431. package/src/task-agent/live-moves.ts +14 -6
  432. package/src/task-agent/parent-host.ts +27 -3
  433. package/src/task-agent/rejudge-on-head.ts +370 -29
  434. package/src/task-agent/review-result-capture.ts +67 -2
  435. package/src/task-agent/shadow.ts +148 -21
  436. package/src/task-agent/task-hand.ts +22 -3
  437. package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -0
  438. package/src/task-orchestrator/surfaces/pod-host-acp-review.ts +122 -0
  439. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +23 -0
  440. package/src/task-orchestrator/surfaces/pod-pool.ts +53 -0
  441. package/src/task-orchestrator/surfaces/self-implement-pod.ts +236 -28
  442. package/src/tool-runtime/tool-search-runtime.ts +25 -0
  443. package/src/tui.ts +20 -1
  444. package/src/user-config.ts +21 -63
  445. package/src/ux-sim/fault-cred-expiry.ts +100 -0
  446. package/src/ux-sim/fault-pod-death.ts +74 -0
  447. package/src/ux-sim/fault-pool-cap.ts +81 -0
  448. package/src/version/packed-revision.json +1 -1
  449. package/src/webclone/qa-table.ts +22 -0
  450. package/apps/pwa/out/_next/static/chunks/0a09e062-34f747a17d8d8c2e.js +0 -1
  451. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +0 -77
  452. package/apps/pwa/out/_next/static/chunks/1325-dc3f3c21eb181cb4.js +0 -1
  453. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +0 -34
  454. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +0 -24
  455. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +0 -1
  456. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +0 -1
  457. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +0 -1
  458. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +0 -1
  459. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +0 -1
  460. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +0 -1
  461. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +0 -1
  462. package/apps/pwa/out/_next/static/chunks/1669-da843ed73aa301f5.js +0 -1
  463. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +0 -1
  464. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +0 -36
  465. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +0 -122
  466. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +0 -1
  467. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +0 -62
  468. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +0 -1
  469. package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +0 -1
  470. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +0 -1
  471. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +0 -1
  472. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +0 -1
  473. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +0 -1
  474. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +0 -149
  475. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +0 -1
  476. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +0 -1
  477. package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +0 -1
  478. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +0 -309
  479. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +0 -1
  480. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +0 -1
  481. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +0 -1
  482. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +0 -1
  483. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +0 -1
  484. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +0 -1
  485. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +0 -1
  486. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +0 -1
  487. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +0 -1
  488. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +0 -1
  489. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +0 -1
  490. package/apps/pwa/out/_next/static/chunks/5313.1697309c532b9856.js +0 -2
  491. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +0 -1
  492. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +0 -1
  493. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +0 -1
  494. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +0 -1
  495. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +0 -1
  496. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +0 -1
  497. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +0 -1
  498. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +0 -74
  499. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +0 -1
  500. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +0 -1
  501. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +0 -1
  502. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +0 -64
  503. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +0 -1
  504. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +0 -1
  505. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +0 -32
  506. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +0 -24
  507. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +0 -1
  508. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +0 -1
  509. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +0 -1
  510. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +0 -93
  511. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +0 -1
  512. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +0 -1
  513. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +0 -1
  514. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +0 -1
  515. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +0 -148
  516. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +0 -226
  517. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +0 -27
  518. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +0 -1
  519. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +0 -1
  520. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +0 -115
  521. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +0 -1
  522. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +0 -1
  523. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +0 -1
  524. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +0 -1
  525. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +0 -1
  526. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +0 -1
  527. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +0 -8
  528. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +0 -23
  529. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +0 -1
  530. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +0 -1
  531. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +0 -1
  532. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +0 -1
  533. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +0 -90
  534. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +0 -94
  535. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +0 -1
  536. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +0 -41
  537. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +0 -1
  538. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +0 -287
  539. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +0 -79
  540. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +0 -1
  541. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +0 -1
  542. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +0 -1
  543. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +0 -1
  544. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +0 -104
  545. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +0 -1
  546. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +0 -1
  547. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +0 -1
  548. package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +0 -1
  549. package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +0 -1
  550. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +0 -1
  551. package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +0 -1
  552. package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +0 -1
  553. package/apps/pwa/out/_next/static/chunks/app/consult/page-c0ab229673a8b0eb.js +0 -1
  554. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +0 -1
  555. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +0 -1
  556. package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +0 -1
  557. package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +0 -1
  558. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +0 -1
  559. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +0 -1
  560. package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +0 -1
  561. package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +0 -1
  562. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +0 -1
  563. package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +0 -1
  564. package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +0 -1
  565. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +0 -1
  566. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +0 -1
  567. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +0 -1
  568. package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +0 -1
  571. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +0 -1
  572. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +0 -1
  573. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +0 -1
  577. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +0 -1
  579. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +0 -1
  580. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +0 -1
  587. package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +0 -1
  588. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +0 -1
  591. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +0 -1
  595. package/apps/pwa/out/_next/static/chunks/framework-b2763b10dc6b3836.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +0 -1
  599. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +0 -1
  600. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +0 -1
  601. /package/apps/pwa/out/_next/static/{Q-7iofoxOEv1WX18S35of → Ev2jivDMTSoEc-5rIXdcy}/_ssgManifest.js +0 -0
@@ -12,15 +12,23 @@
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
- import { LIVE_MOVE_RESULT_EVENT, readTaskAgentState, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
17
+ import { LIVE_MOVE_RESULT_EVENT, cardPrNumber, readTaskAgentState, readTaskCard, updateTaskCard, type TaskCard, type TaskCardEvent } from './task-hand.js';
18
+ import type { RejudgeDeps } from './rejudge-on-head.js';
17
19
 
18
20
  export const REVIEW_RESULT_MISSING_EFFECT = 'review process produced no result';
19
21
  /** 결과 파일은 있는데 읽지 못했다(EACCES 등) — «결과 없음»과 가른다(결과가 있었을 수 있다). */
20
22
  export const REVIEW_RESULT_UNREADABLE_EFFECT = 'review result file unreadable';
23
+ /** Detached self review child: only this card and exact result file may trigger a completion tick. */
24
+ export const TA_REVIEW_COMPLETION_CARD_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_CARD';
25
+ export const TA_REVIEW_COMPLETION_STATE_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_STATE';
26
+ export const TA_REVIEW_COMPLETION_RESULT_ENV = 'ELANOUS_TA_REVIEW_COMPLETION_RESULT';
21
27
  /** 리뷰 한 판(1차 ⊕ 폴백 · ACP 300s 상한 여러 번)을 넉넉히 덮는 대기 상한 — 이 안에는 «아직»으로 본다. */
22
28
  export const REVIEW_RESULT_WAIT_MS = 90 * 60_000;
23
29
 
30
+ const reviewRejudgeInFlight = new Set<string>();
31
+
24
32
  const SHA40 = /^[0-9a-f]{40}$/i;
25
33
 
26
34
  /** 결과 파일 경로 — 카드 상태 파일 옆 `review-results/` · 카드 id 는 파일 이름에 안전한 글자만. */
@@ -63,7 +71,8 @@ export function parseReviewResultOutput(text: string): ParsedReviewResult | null
63
71
  ...(Number.isSafeInteger(prRaw) && prRaw > 0 ? { pr: prRaw } : {}),
64
72
  verdict: typeof v.verdict === 'string' ? v.verdict : null,
65
73
  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,
74
+ // PR-LAND-MUSTFIX-NONE — 저장된 결과(옛 판 리뷰 · 다른 경로)에 «(없음 — …)» 표지 줄이 남아 있어도 리뷰 출력과 «같은» 판정으로 0 으로 센다.
75
+ mustFix: Array.isArray(v.mustFix) && v.mustFix.every((fix) => typeof fix === 'string') ? v.mustFix.filter((fix) => !isNoneSentinelFinding(fix)).length : null,
67
76
  reviewRoute: typeof v.reviewRoute === 'string' ? v.reviewRoute : null,
68
77
  head: typeof v.headCommit === 'string' && SHA40.test(v.headCommit) ? v.headCommit : null,
69
78
  error: typeof v.error === 'string' ? v.error : null,
@@ -86,6 +95,8 @@ export function pendingReviewResults(card: TaskCard): ReviewRequest[] {
86
95
  export interface CaptureReviewResultsOptions {
87
96
  /** 이 카드들만 본다 — 없으면 상태 파일의 모든 카드. */
88
97
  cardIds?: readonly string[];
98
+ /** A detached completion callback may only harvest its own result file. */
99
+ resultPaths?: readonly string[];
89
100
  now?: () => Date;
90
101
  /** 시험 seam — 결과 파일 읽기(없으면 ENOENT 를 던진다). */
91
102
  readFile?: (path: string) => string;
@@ -121,6 +132,7 @@ export function captureReviewResults(statePath: string, opts: CaptureReviewResul
121
132
  if (!card) continue;
122
133
  for (const request of pendingReviewResults(card)) {
123
134
  const resultPath = request.resultPath!;
135
+ if (opts.resultPaths && !opts.resultPaths.includes(resultPath)) continue;
124
136
  let text: string | null = null;
125
137
  let readError: string | null = null;
126
138
  let unreadable = false;
@@ -182,6 +194,59 @@ export function captureReviewResults(statePath: string, opts: CaptureReviewResul
182
194
  return out;
183
195
  }
184
196
 
197
+ /** Run after the detached review child has fully written its JSON stdout. Never infer a card from PR alone. */
198
+ export async function rejudgeCompletedTaskReview(
199
+ env: Record<string, string | undefined> = process.env,
200
+ rejudge?: (cardId: string, statePath: string) => Promise<unknown>,
201
+ rejudgeDeps?: RejudgeDeps,
202
+ ): Promise<boolean> {
203
+ const cardId = env[TA_REVIEW_COMPLETION_CARD_ENV];
204
+ const statePath = env[TA_REVIEW_COMPLETION_STATE_ENV];
205
+ const resultPath = env[TA_REVIEW_COMPLETION_RESULT_ENV];
206
+ if (!cardId || !statePath || !resultPath) return false;
207
+ const before = readTaskCard(cardId, statePath);
208
+ const bound = before?.reviewRequests?.find((item) => item.resultPath === resultPath);
209
+ if (before?.status !== 'launched' || before.taLand !== true || !bound || cardPrNumber(before) !== bound.pr
210
+ || !SHA40.test(bound.head) || (before.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)) return false;
211
+ captureReviewResults(statePath, { cardIds: [cardId], resultPaths: [resultPath] });
212
+ const key = `${statePath}\0${cardId}\0${resultPath}`;
213
+ if (reviewRejudgeInFlight.has(key)) return false;
214
+ const card = readTaskCard(cardId, statePath);
215
+ const request = card?.reviewRequests?.find((item) => item.resultPath === resultPath);
216
+ if (card?.status !== 'launched' || card.taLand !== true || !request || cardPrNumber(card) !== request.pr
217
+ || !(card.history ?? []).some((item) => item.event === LIVE_MOVE_RESULT_EVENT && item.resultPath === resultPath && item.kind === 'review'
218
+ && item.pr === request.pr && SHA40.test(request.head) && SHA40.test(item.head ?? '')
219
+ && item.effect?.startsWith('review result captured') && item.reviewed === true && item.head?.toLowerCase() === request.head.toLowerCase())
220
+ || (card.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)) return false;
221
+ reviewRejudgeInFlight.add(key);
222
+ try {
223
+ const run = async (): Promise<unknown> => {
224
+ if (rejudgeDeps) {
225
+ const { rejudgeShadowCard } = await import('./rejudge-on-head.js');
226
+ return rejudgeShadowCard(cardId, statePath, rejudgeDeps, { pr: request.pr, head: request.head, kind: 'review', resultPath });
227
+ } else if (rejudge) return rejudge(cardId, statePath);
228
+ else {
229
+ const { rejudgeAsyncResultCard } = await import('./rejudge-on-head.js');
230
+ return rejudgeAsyncResultCard(cardId, statePath, {}, { pr: request.pr, head: request.head, kind: 'review', resultPath });
231
+ }
232
+ };
233
+ const { requireCompletedHeadRejudge } = await import('./rejudge-on-head.js');
234
+ try { requireCompletedHeadRejudge(await run(), request.pr, request.head); }
235
+ catch { requireCompletedHeadRejudge(await run(), request.pr, request.head); } // Bounded retry; no marker on failed outcomes.
236
+ updateTaskCard(statePath, cardId, (current) => current?.status === 'launched' && current.taLand === true && cardPrNumber(current) === request.pr
237
+ && (current.reviewRequests ?? []).some((item) => item.pr === request.pr && SHA40.test(item.head) && item.head.toLowerCase() === request.head.toLowerCase() && item.resultPath === resultPath)
238
+ && (current.history ?? []).some((item) => item.event === LIVE_MOVE_RESULT_EVENT && item.resultPath === resultPath && item.kind === 'review'
239
+ && item.pr === request.pr && SHA40.test(item.head ?? '') && item.head?.toLowerCase() === request.head.toLowerCase()
240
+ && item.reviewed === true && item.effect?.startsWith('review result captured'))
241
+ && !(current.history ?? []).some((item) => item.event === 'async-result-rejudge' && item.resultPath === resultPath)
242
+ ? { ...current, history: [...(current.history ?? []), { at: new Date().toISOString(), event: 'async-result-rejudge', kind: 'review', pr: request.pr, head: request.head, resultPath, effect: 'completion callback succeeded' }] }
243
+ : undefined);
244
+ } finally {
245
+ reviewRejudgeInFlight.delete(key);
246
+ }
247
+ return true;
248
+ }
249
+
185
250
  /**
186
251
  * 다음 수 판단의 입력 — 카드에 회수된 리뷰 결과 중 «그 머리(`head`)»의 «가장 최근» 결과가 실제로 돈(reviewed) pass 이고
187
252
  * 리뷰한 머리가 40자 sha 일 때만 `selfReview` 모양으로 돌려준다(슈퍼바이저가 나르는 `self-implement-cli` 의 규칙과 같다 ·
@@ -10,16 +10,22 @@
10
10
  * - 관측: `debug.log('task-agent', 'shadow-move', …)` → `elanous logs --category task-agent`.
11
11
  */
12
12
  import { lstatSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
13
+ import { randomUUID } from 'node:crypto';
13
14
  import { extname, join, relative, resolve } from 'node:path';
14
15
  import { debug } from '../debug/log.js';
15
- import { readTaskAgentState, readTaskCard, taskAgentStatePath, type CompletionKind, type TaskCard } from './task-hand.js';
16
+ import { readTaskAgentState, readTaskCard, taskAgentStatePath, TASK_CARD_PREFIX, type CompletionKind, type TaskCard } from './task-hand.js';
16
17
  import type { SupervisorJobResult, SupervisorStopReason } from '../self-dev/run-supervisor.js';
17
18
  import { executeNextAction, type DeliveryKind, type NextAction } from './actions.js';
18
19
  import { judgeNextMove, type TaskJudgeInput, type TaskJudgement } from './judge.js';
19
20
  import { HARNESS_RUN_ID_ENV } from '../harness/harness-space.js';
20
- import { recordLiveMoveHistory } from './live-move-history.js';
21
+ import { appendRunLedgerEntry, loadRunLedger } from '../self-implement/run-ledger.js';
22
+ import { collectWiringEvidence, readCardRunSnapshot, type WiringEvidenceDeps, type CardRunEvidenceDeps } from './card-evidence.js';
23
+ import { remoteLedgerMirrorDir } from './parent-host.js';
24
+ import { prodInstanceRoot } from '../instance/resolve.js';
25
+ import { liveMoveHistoryEntry, recordLiveMoveHistory } from './live-move-history.js';
26
+ import { updateTaskCard } from './task-hand.js';
21
27
  import { capturedSelfReview, captureReviewResults, hasCapturedPass } from './review-result-capture.js';
22
- import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
28
+ import { configuredTaskAgentLiveMoves, defaultPrHead, executeLiveDecisionCard, executeLiveGreenProposal, executeLiveLand, executeLiveReview, type LiveMoveDeps, type LiveMoveResult, type TaskAgentLiveMove } from './live-moves.js';
23
29
 
24
30
  export interface TaskAgentShadowInput {
25
31
  runId: string | null;
@@ -45,6 +51,8 @@ export interface TaskAgentShadowMove {
45
51
  pr: number | null;
46
52
  /** TA-JUDGE-LIVE-SAFE — `taskAgent.liveMoves` 가 이 수를 실제로 했을 때만 실린다(없으면 종전 그대로 그림자). */
47
53
  liveMove?: LiveMoveResult;
54
+ /** 원격 카드 결선이 미결일 때 런 원장 대기열 보존 결과. */
55
+ cardBinding?: 'pending' | 'queue-failed';
48
56
  }
49
57
 
50
58
  export interface TaskAgentShadowDeps {
@@ -60,10 +68,16 @@ export interface TaskAgentShadowDeps {
60
68
  live?: LiveMoveDeps;
61
69
  /** 카드 조회 상태 파일(시험 주입 · 운영 파일을 건드리지 않게). 기본 = `live.statePath` ⊕ `taskAgentStatePath()`. */
62
70
  statePath?: string;
71
+ /** TA-WIRING-CHECK — 배선 근거 수집 의존(시험 주입 · 기본 = gh pr diff 한 번 ⊕ 카드 런 원장). */
72
+ wiring?: Omit<WiringEvidenceDeps, 'card'>;
63
73
  /** Process env for the launched-run id (`ELANOUS_RUN_ID`) — test seam; default process.env. */
64
74
  env?: NodeJS.ProcessEnv;
75
+ /** Remote pending-move ledger seam; defaults to the run ledger. */
76
+ queueMove?: typeof appendRunLedgerEntry;
65
77
  }
66
78
 
79
+ export const REMOTE_CARD_MOVE_PENDING = 'task-agent-card-move-pending';
80
+
67
81
  /** 카드 조회 상태 파일 — 조회 경로 전부가 같은 파일을 본다. */
68
82
  function cardStatePath(deps: TaskAgentShadowDeps): string {
69
83
  return deps.statePath ?? deps.live?.statePath ?? taskAgentStatePath();
@@ -172,6 +186,13 @@ function shadowCompletion(card: TaskCard | undefined, lookupFailed: boolean): Co
172
186
  }
173
187
 
174
188
  export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, deps: TaskAgentShadowDeps = {}): Promise<TaskAgentShadowMove> {
189
+ const env = deps.env ?? process.env;
190
+ const remoteChild = !!env.ELANOUS_POD_NAME;
191
+ const hintedCard = env.ELANOUS_TASK_CARD_ID?.trim();
192
+ const pendingCardId = hintedCard?.startsWith(TASK_CARD_PREFIX) && hintedCard.length <= 63 && /^[A-Za-z0-9._-]+$/.test(hintedCard) ? hintedCard : null;
193
+ const parentRunId = env.ELANOUS_PARENT_RUN_ID?.trim() || null;
194
+ const matchesLaunchCard = (candidate: TaskCard | undefined): boolean => !!candidate && !!parentRunId
195
+ && candidate.id === pendingCardId && candidate.runId === parentRunId;
175
196
  // TA-REVIEW-RESULT-CAPTURE — 판단 «전»에 지난 live review 의 결과 파일을 회수한다(카드 원장을 아는 때만 · 던지지 않는다).
176
197
  // 대기 중인 요청이 없으면 아무것도 쓰지 않는다(결과 파일 없는 카드의 동작은 종전과 같다).
177
198
  const reviewLedger = cardLedgerPath(deps);
@@ -185,14 +206,22 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
185
206
  let card: TaskCard | undefined;
186
207
  let cardLookupFailed = false;
187
208
  try {
188
- card = successful ? (deps.readCard ? deps.readCard(successful.taskId) : readTaskCard(successful.taskId, cardStatePath(deps))) : undefined;
189
- if (!card && successful && !deps.readCard) {
209
+ // Pod 에 발사 카드 id 가 있으면 그 id 만 믿는다. 같은 문장을 가진 다른 카드가 있어도 묶지 않는다.
210
+ if (remoteChild) {
211
+ if (pendingCardId) {
212
+ const found = deps.readCard ? deps.readCard(pendingCardId) : readTaskCard(pendingCardId, cardStatePath(deps));
213
+ if (matchesLaunchCard(found)) card = found;
214
+ }
215
+ } else if (successful) {
216
+ card = deps.readCard ? deps.readCard(successful.taskId) : readTaskCard(successful.taskId, cardStatePath(deps));
217
+ }
218
+ if (!card && successful && !deps.readCard && !remoteChild) {
190
219
  const tasks = readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(cardStatePath(deps)).tasks ?? {};
191
220
  const matches = Object.values(tasks).filter(candidate => candidate.status === 'launched' && candidate.text === successful.feature);
192
221
  if (matches.length === 1) card = matches[0];
193
222
  }
194
223
  // TA-OWN-ALL-RUNS — 런 소유 카드: 입력 runId ⊕ 상속 ELANOUS_RUN_ID(Pod 자식의 부모 런) 중 카드 runId 와 «정확히» 같은 것만.
195
- if (!card && !deps.readCard) card = runCardFor(input.runId, deps);
224
+ if (!card && !deps.readCard && !remoteChild) card = runCardFor(input.runId, deps);
196
225
  } catch {
197
226
  // Card lookup is optional; preserve the original PR judgement when unavailable — but mark the completion kind as unmeasured.
198
227
  cardLookupFailed = true;
@@ -206,7 +235,7 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
206
235
  try {
207
236
  const reviewedPr = judgeInput.pr;
208
237
  const prRun = input.results.find((result) => result.prNumber === reviewedPr);
209
- const prCard = prRun ? (card && successful?.taskId === prRun.taskId ? card : liveCardFor([prRun], deps, input.runId)) : undefined;
238
+ const prCard = prRun ? (remoteChild ? card : card && successful?.taskId === prRun.taskId ? card : liveCardFor([prRun], deps, input.runId)) : undefined;
210
239
  // 회수한 판정은 «리뷰한 머리»의 것이다 — 지금 PR 머리의 결과만 입력으로 쓴다(A 의 pass 로 B 를 land 쪽으로 보내지 않게 ·
211
240
  // 여러 머리 결과가 역순으로 회수돼도 지금 머리 것을 고른다). 지금 머리 = 그 런 작업 트리에서 PR 머리 조회 ·
212
241
  // 작업 트리가 없으면(Pod) 런이 낸 머리. 못 정하면 쓰지 않는다(종전처럼 review 수 → 새 머리면 새 리뷰).
@@ -275,20 +304,23 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
275
304
  move.reason = wouldDo ?? judgement.reason;
276
305
  move.wouldDo = null;
277
306
  }
278
- const liveKind: TaskAgentLiveMove | null = move.move === 'review' || move.move === 'propose-green' || move.move === 'propose-land' ? move.move : null;
307
+ const liveKind: TaskAgentLiveMove | null = move.move === 'review' || move.move === 'propose-green' || move.move === 'propose-land' || move.move === 'decision-card' ? move.move : null;
279
308
  // 판단마다 해석한다 — 허용되지 않은 수를 판단할 때도 모르는 항목 경고가 남게.
280
309
  const liveMoves = deps.liveMoves ?? await configuredTaskAgentLiveMoves();
281
- const live = liveKind !== null && liveMoves.has(liveKind);
282
310
  // 카드 id 는 모든 판단 관측에 싣는다(그림자 일치율을 카드로 잇는다) — 읽기 전용 조회.
283
311
  // live 수는 «근거 결과»에 묶는다 — PR 수는 그 PR 을 낸 결과의 카드·작업 트리, 전달은 전달한 카드(다중 결과에서 남의 카드에 쓰지 않게).
284
312
  const prResult = typeof judgeInput.pr === 'number' ? input.results.find((result) => result.prNumber === judgeInput.pr) : undefined;
285
- const boundCard = delivery
313
+ const candidateBoundCard = delivery
286
314
  ? card
287
315
  : prResult
288
- ? (card && successful?.taskId === prResult.taskId ? card : liveCardFor([prResult], deps, input.runId))
289
- : undefined;
316
+ ? (card && (successful?.taskId === prResult.taskId || (remoteChild && pendingCardId === card.id)) ? card : liveCardFor([prResult], deps, input.runId))
317
+ : liveKind === 'decision-card' ? card ?? liveCardFor(input.results, deps, input.runId) : undefined;
318
+ const boundCard = remoteChild && !matchesLaunchCard(candidateBoundCard) ? undefined : candidateBoundCard;
290
319
  // PR 에 묶인 수는 그 PR 의 카드만 관측에 싣는다(못 찾으면 null — 다른 결과의 카드로 대체하지 않는다).
291
- const liveCard = prResult || delivery ? boundCard : card ?? (cardLookupFailed ? undefined : liveCardFor(input.results, deps, input.runId));
320
+ const candidateLiveCard = prResult || delivery ? boundCard : card ?? (cardLookupFailed ? undefined : liveCardFor(input.results, deps, input.runId));
321
+ const liveCard = remoteChild && !matchesLaunchCard(candidateLiveCard) ? undefined : candidateLiveCard;
322
+ // 원격 Pod 는 HQ 카드 파일을 갖지 않는다. id 를 전달받아도 현지 원장이 없으면 실행 수는 보류한다.
323
+ const live = liveKind !== null && liveMoves.has(liveKind) && (!remoteChild || boundCard !== undefined);
292
324
  let liveMove: LiveMoveResult | undefined;
293
325
  if (live) {
294
326
  if (liveKind === 'review') {
@@ -313,6 +345,17 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
313
345
  ...(prResult.prUrl ? { prUrl: prResult.prUrl } : {}),
314
346
  } } : {}),
315
347
  }, liveMoveDeps(deps));
348
+ } else if (liveKind === 'decision-card') {
349
+ // Supervisor results carry failure text and reviewer must-fix items, but no screen tail.
350
+ // A stop reason alone is not evidence: the executor correctly raises no card when both are absent.
351
+ const evidenceResults = prResult ? [prResult] : input.results;
352
+ const signature = evidenceResults.find((result) => result.error?.message?.trim())?.error?.message;
353
+ const mustFix = evidenceResults.flatMap((result) => result.reviewMustFix ?? []);
354
+ liveMove = await executeLiveDecisionCard(boundCard, {
355
+ runId: input.runId, stopReason: input.stopReason, reason: move.reason,
356
+ ...(prResult ? { pr: prResult.prNumber } : {}),
357
+ evidence: { ...(signature ? { signature } : {}), mustFix },
358
+ }, liveMoveDeps(deps));
316
359
  } else {
317
360
  const evidence: Record<string, string> = {};
318
361
  if (boundCard && !delivery && judgeInput.prState === 'MERGED' && prResult) evidence[boundCard.id] = `#${prResult.prNumber}`;
@@ -320,26 +363,62 @@ export async function recordTaskAgentShadowMove(input: TaskAgentShadowInput, dep
320
363
  liveMove = executeLiveGreenProposal(boundCard, evidence, liveMoveDeps(deps));
321
364
  }
322
365
  }
323
- // 판단한 수마다 live/shadow 를 남긴다 — OP 가 «오판 건수»·«그림자 일치율»을 카드·수 종류로 잰다.
324
- (deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'shadow-move', {
325
- ...move, completion: shadowCompletion(card, cardLookupFailed), card: liveCard?.id ?? null, live, liveExecuted: liveMove?.executed ?? false, ...(liveMove ? { liveOk: liveMove.ok } : {}),
326
- ...(reviewFromCapture ? { reviewSource: 'captured-review-result' } : {}),
327
- });
366
+ // TA-WIRING-CHECK — 병합 PR 은 판단한 «뒤» 배선 근거를 관측만 한다(move 불변 · 실패는 unknown 으로 남기고 던지지 않는다).
367
+ if (judgeInput.prState === 'MERGED' && typeof judgeInput.pr === 'number' && !delivery && liveCard) {
368
+ try {
369
+ const wiring = await collectWiringEvidence(judgeInput.pr, { ...deps.wiring, card: liveCard });
370
+ (deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'wiring-shadow', {
371
+ card: liveCard.id, pr: judgeInput.pr, required: wiring.required, liveRunRecorded: wiring.liveRunRecorded, unknown: wiring.unknown,
372
+ });
373
+ } catch { /* fail-soft — 관측일 뿐 판단을 막지 않는다 */ }
374
+ }
328
375
  // TA-LIVE-MOVE-CARD-HISTORY — live-move 수(review·propose-green·propose-land)는 실행이든 그림자든 그 카드 history 에 한 줄.
329
376
  // 결정·실행이 끝난 «뒤»에 덧붙이기만 한다(반환값·관측 무변경) · 실패는 관측만(live-move 를 막지 않는다).
330
- if (liveKind !== null) recordLiveMoveOnCard({
377
+ if (liveKind !== null && (liveKind !== 'decision-card' || live) && (!remoteChild || liveCard)) recordLiveMoveOnCard({
331
378
  liveKind, live, liveMove, card: live ? boundCard : liveCard, runId: input.runId,
332
379
  pr: prResult?.prNumber ?? (typeof judgeInput.pr === 'number' ? judgeInput.pr : undefined),
333
380
  shadowDetail: move.wouldDo ?? move.reason,
334
381
  }, deps);
335
- return liveMove ? { ...move, liveMove } : move;
382
+ let cardBinding: TaskAgentShadowMove['cardBinding'];
383
+ if (liveKind !== null && !liveCard && remoteChild) {
384
+ const inheritedRunId = parentRunId || env[HARNESS_RUN_ID_ENV]?.trim() || null;
385
+ const reason = !parentRunId ? 'parent run id absent; HQ binding required'
386
+ : pendingCardId ? 'card id carried but ledger unavailable' : 'card id absent; parent run lookup required';
387
+ try {
388
+ if (!input.runId) throw new Error('runId absent');
389
+ (deps.queueMove ?? appendRunLedgerEntry)({
390
+ timestamp: new Date().toISOString(), runId: input.runId, event: REMOTE_CARD_MOVE_PENDING,
391
+ data: { id: randomUUID(), card: pendingCardId, parentRunId: inheritedRunId, kind: liveKind, pr: move.pr,
392
+ detail: move.wouldDo ?? move.reason, reason, executorResult: 'shadow' },
393
+ });
394
+ cardBinding = 'pending';
395
+ } catch (error) {
396
+ cardBinding = 'queue-failed';
397
+ try {
398
+ (deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'card-binding-queue-failed',
399
+ { card: pendingCardId, runId: input.runId, parentRunId: inheritedRunId, kind: liveKind, reason: error instanceof Error ? error.message : String(error) });
400
+ } catch { /* queue failure remains visible in the return value */ }
401
+ }
402
+ if (cardBinding === 'pending') try {
403
+ (deps.log ?? ((c, e, d) => debug.log(c, e, d)))('task-agent', 'card-binding-pending',
404
+ { card: pendingCardId, runId: input.runId, parentRunId: inheritedRunId, kind: liveKind, reason });
405
+ } catch { /* queued evidence remains authoritative */ }
406
+ }
407
+ // 판단 관측은 원격 미결 수를 실제 원장에 기록한 결과까지 확정한 뒤 남긴다.
408
+ (deps.log ?? ((category, event, data) => debug.log(category, event, data)))('task-agent', 'shadow-move', {
409
+ ...move, completion: shadowCompletion(card, cardLookupFailed), card: liveCard?.id ?? pendingCardId,
410
+ live, liveExecuted: liveMove?.executed ?? false, ...(liveMove ? { liveOk: liveMove.ok } : {}),
411
+ ...(cardBinding ? { cardBinding } : {}),
412
+ ...(reviewFromCapture ? { reviewSource: 'captured-review-result' } : {}),
413
+ });
414
+ return { ...move, ...(liveMove ? { liveMove } : {}), ...(cardBinding ? { cardBinding } : {}) };
336
415
  }
337
416
 
338
417
  /**
339
418
  * 런 id 폴백 — 입력 runId(슈퍼바이저 · Pod 면 자식 런) → 상속 `ELANOUS_RUN_ID`(발사기가 넘긴 부모 런) 순으로,
340
419
  * 카드 runId 와 정확히 같고 그 카드가 하나뿐일 때만 쓴다. 못 찾으면 추측하지 않고 이유 한 줄을 남긴다(조용한 미스 0).
341
420
  */
342
- function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps): TaskCard | undefined {
421
+ export function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps): TaskCard | undefined {
343
422
  const own = runId?.trim() || undefined;
344
423
  const inherited = (deps.env ?? process.env)[HARNESS_RUN_ID_ENV]?.trim() || undefined;
345
424
  if (!own && !inherited) return undefined;
@@ -358,6 +437,54 @@ function runCardFor(runId: string | null | undefined, deps: TaskAgentShadowDeps)
358
437
  return undefined;
359
438
  }
360
439
 
440
+ /** HQ `tasks show` 가 원격 원장 거울의 미결 수를 카드에 회수한다. 부모→자식 원장 간선과 카드 id 를 함께 확인한다. */
441
+ export async function replayRemoteCardMoves(cardId: string, statePath: string, evidenceDeps: CardRunEvidenceDeps = {},
442
+ log: (category: string, event: string, data: Record<string, unknown>) => void = (c, e, d) => debug.log(c, e, d)): Promise<number> {
443
+ const card = readTaskCard(cardId, statePath);
444
+ if (!card?.runId || !card.parentHost) return 0;
445
+ // 원격 부모와 동일 runId 의 HQ 국소 원장은 발사 영수증만 있을 수 있다. 이 회수는 원격 거울을 우선한다.
446
+ const loadLedger = evidenceDeps.loadLedger ?? ((runId: string) =>
447
+ loadRunLedger(runId, remoteLedgerMirrorDir(prodInstanceRoot(), card.parentHost!.host)));
448
+ const snapshot = await readCardRunSnapshot(card, { ...evidenceDeps, loadLedger });
449
+ if (snapshot.readErrors?.length) {
450
+ log('task-agent', 'card-binding-replay-failed', { card: cardId, runId: card.runId, reason: snapshot.readErrors.join(' · ') });
451
+ return 0;
452
+ }
453
+ // 카드 id 가 빠진 옛 원격 줄은 부모 runId 의 유일 카드일 때만 역조회한다.
454
+ const matches = Object.values(readTaskAgentState<{ tasks?: Record<string, TaskCard> }>(statePath).tasks ?? {})
455
+ .filter((candidate) => candidate.runId === card.runId);
456
+ let written = 0;
457
+ for (const [childRunId, entries] of Object.entries(snapshot.children)) {
458
+ for (const entry of entries ?? []) {
459
+ if (entry.event !== REMOTE_CARD_MOVE_PENDING) continue;
460
+ const data = entry.data;
461
+ const id = data.id;
462
+ const kind = data.kind;
463
+ const linked = data.card === cardId || (data.card == null && matches.length === 1 && matches[0]?.id === cardId);
464
+ const parentMatches = data.parentRunId == null || data.parentRunId === card.runId;
465
+ if (!linked || !parentMatches || typeof id !== 'string' || !/^[a-f0-9-]{36}$/i.test(id)
466
+ || !['review', 'propose-green', 'propose-land', 'decision-card'].includes(String(kind))) {
467
+ log('task-agent', 'card-binding-replay-skipped', { card: cardId, childRunId, pendingId: typeof id === 'string' ? id : null,
468
+ reason: !linked ? 'card mismatch or ambiguous runId' : !parentMatches ? 'parent run mismatch' : 'invalid pending move' });
469
+ continue;
470
+ }
471
+ const at = entry.timestamp ?? '';
472
+ if (!Number.isFinite(Date.parse(at))) continue;
473
+ const pr = Number.isSafeInteger(data.pr) && (data.pr as number) > 0 ? data.pr as number : undefined;
474
+ updateTaskCard(statePath, cardId, (current) => {
475
+ if (!current || current.runId !== card.runId || current.history.some((item) => item.sourceId === id)) return undefined;
476
+ const item = liveMoveHistoryEntry(current, { at, kind: kind as TaskAgentLiveMove, executorResult: 'shadow',
477
+ shadowDetail: typeof data.detail === 'string' ? data.detail : 'remote card binding pending', runId: childRunId,
478
+ ...(pr ? { pr } : {}) });
479
+ written++;
480
+ return { ...current, history: [...current.history, { ...item, sourceId: id }] };
481
+ });
482
+ }
483
+ }
484
+ if (written) log('task-agent', 'card-binding-replayed', { card: cardId, parentRunId: card.runId, written });
485
+ return written;
486
+ }
487
+
361
488
  /**
362
489
  * 카드 history 에 live-move 한 줄 — 상태 파일은 카드를 읽은 곳과 같아야 한다: 주입한 경로(`live.statePath`) 또는
363
490
  * 기본 리더를 썼을 때의 기본 경로. 주입한 카드 리더(`readCard`)만 있고 경로가 없으면 그 카드의 원장을 모른다 — 적지 않는다.
@@ -18,6 +18,7 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
18
18
  import { withFileLockSync } from '../storage/file-lock.js';
19
19
  import { checkCompletionEvidence, deliverableReceiptEvidence } from './completion-evidence.js';
20
20
  import { judgeNextMove } from './judge.js';
21
+ import { loadRunLedger, runLedgerDir } from '../self-implement/run-ledger.js';
21
22
 
22
23
  export interface ResolveHandTextDeps {
23
24
  cwd: string;
@@ -94,6 +95,8 @@ export type CompletionKind = typeof COMPLETION_KINDS[number];
94
95
  */
95
96
  export interface TaskCardEvent {
96
97
  at: string; event: string; detail?: string; runId?: string; pr?: number;
98
+ /** 원격 미결 수를 HQ 에 한 번만 회수하기 위한 원장 사건 id. */
99
+ sourceId?: string;
97
100
  /** `closed-by-hand` 줄만 — 닫은 사유 · 닫은 자리(`closeTaskCard`). */
98
101
  reason?: string; by?: string;
99
102
  kind?: string; executed?: boolean; ok?: boolean; executorResult?: 'shadow' | 'live'; head?: string; effect?: string;
@@ -167,7 +170,9 @@ export interface TaskCard {
167
170
  */
168
171
  regates?: Array<{ pr: number; head: string; at: string; resultPath?: string; passed?: boolean; status?: string; baseCommit?: string; detail?: string;
169
172
  /** REJUDGE base-stale — 같은 머리를 새 base 위에서 다시 잰 재게이트면, land 가 낡았다고 거절한 앞 재게이트의 base(멱등 키 = 머리 ⊕ 이 base). */
170
- staleBase?: string }>;
173
+ staleBase?: string;
174
+ /** TA-READY-BEFORE-REGATE — draft 때문에 실패한 같은 머리를 ready 뒤 딱 한 번 다시 잰다. */
175
+ readyRetry?: true }>;
171
176
  /**
172
177
  * Live land attempts, claimed before invocation, once per PR head even if the command fails.
173
178
  * TA-LAND-RETRY-ON-INFRA — a failed attempt carries `class`/`reason`: `infra` (TA-side, allow-listed) leaves one more attempt on
@@ -316,7 +321,8 @@ export function launchArgs(card: Pick<TaskCard, 'text' | 'seat' | 'childLlm'>):
316
321
  * 이유에 «착지 미확인»을 단다(착지했다/안 했다를 단정하지 않는다).
317
322
  * 미션 카드는 스스로 발사하지 않는다 · 아직 안 뜬 조각의 선행이 덜 착지했으면 `wait after <id>`.
318
323
  */
319
- export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string>): TaskCardMove {
324
+ export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string>, deps: { ledgerDir?: string } = {}): TaskCardMove {
325
+ // Completion callbacks record a shadow decision; do not suggest the live CLI here.
320
326
  if (card.pieces) return { kind: 'wait', reason: `미션 — 조각 ${card.pieces.length}장이 선후대로 발사된다` };
321
327
  const unmet = (card.after ?? []).filter((id) => !landed?.has(id));
322
328
  if (card.status !== 'launched' && unmet.length > 0) return { kind: 'wait', reason: `after ${unmet.join(', ')}${landed ? '' : ' · 착지 미확인'}` };
@@ -324,6 +330,16 @@ export function nextMoveFor(card: TaskCard, landed?: ReadonlySet<string>): TaskC
324
330
  if (card.status === 'launch-failed') return { kind: 'launch', command: launchArgs(card), reason: '직전 발사 실패 — 다시 발사' };
325
331
  // live-move·hand-move 줄(관측 기록)은 실패 사유가 아니다 — 그 줄을 뺀 마지막 칸이 사유다(live-move 줄 없는 카드는 종전과 같다).
326
332
  if (card.status === 'failed') return { kind: 'wait', reason: card.history.filter((item) => item.event !== LIVE_MOVE_HISTORY_EVENT && item.event !== LIVE_MOVE_RESULT_EVENT && item.event !== HAND_MOVE_HISTORY_EVENT).at(-1)?.detail ?? '런 실패 — PR·수확 가지 없음' };
333
+ if (card.status === 'launched' && card.runId) {
334
+ try {
335
+ const ledger = loadRunLedger(card.runId, deps.ledgerDir ?? runLedgerDir());
336
+ const terminal = ledger?.filter((entry) => entry.event === 'run-status').at(-1);
337
+ if (terminal && ['succeeded', 'failed', 'cancelled', 'abandoned'].includes(String(terminal.data.runStatus))) {
338
+ if (cardPrNumber(card) === undefined) return { kind: 'wait', reason: `런 원장 종료 — ${terminal.data.runStatus} · PR 없음` };
339
+ return { kind: 'wait', reason: `런 원장 종료 — ${terminal.data.runStatus} · 그림자 재판정은 완료 훅이 기록` };
340
+ }
341
+ } catch { /* 원장 결손·손상은 종료로 단정하지 않는다. */ }
342
+ }
327
343
  return { kind: 'wait', reason: '발사됨 — 런 멈춤을 슈퍼바이저 그림자 판단(task-agent.shadow-move)이 받는다' };
328
344
  }
329
345
 
@@ -487,7 +503,10 @@ export async function handTask(opts: HandTaskOptions): Promise<HandTaskResult> {
487
503
  if (!opts.launcher) throw new Error('--live 인데 launcher 가 없다');
488
504
  const runId = mintRunId();
489
505
  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) };
506
+ const context: TaskLaunchContext = { runId, launchId, env: { [HARNESS_RUN_ID_ENV]: runId, ELANOUS_TASK_CARD_ID: card.id,
507
+ ...(card.checklistId ? { ELANOUS_POD_SLOT_ID: card.checklistId } : {}),
508
+ ...(card.seat ? { ELANOUS_POD_OWNER_KIND: 'seat', ELANOUS_POD_OWNER_ID: card.seat } : {}),
509
+ ...(card.taLand ? { [TA_LAND_ENV]: '1' } : {}) }, cardLabelContext: taskCardLabelContext(card) };
491
510
  let receipt: void | TaskLaunchReceipt;
492
511
  try {
493
512
  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
+ }