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
@@ -62,11 +62,39 @@ export class TaskNotificationQueue {
62
62
  * listens to both runner events and a separate `onTaskDone` hook.
63
63
  * Keyed by taskId. */
64
64
  private seen = new Set<string>();
65
+ /** Wake listeners — fired once per REAL enqueue (not on seen-dup).
66
+ * TUI-SEAT-READY ③ first shard: one completion event = one wake
67
+ * signal so an idle parent can open the next turn. Opening the turn
68
+ * itself is deliberately NOT wired here (next shard). */
69
+ private wakeListeners = new Set<(n: PendingTaskNotification) => void>();
70
+
71
+ /** Register a wake listener; returns an unsubscribe function.
72
+ * Listeners survive `clear()` — they belong to the wiring, not the
73
+ * queue contents. */
74
+ onEnqueue(listener: (n: PendingTaskNotification) => void): () => void {
75
+ this.wakeListeners.add(listener);
76
+ return () => { this.wakeListeners.delete(listener); };
77
+ }
65
78
 
66
79
  enqueue(n: PendingTaskNotification): void {
67
80
  if (this.seen.has(n.taskId)) return;
68
81
  this.seen.add(n.taskId);
69
82
  this.queue.push(n);
83
+ debug.log('agent.task-notification', 'wake', { taskId: n.taskId, size: this.queue.length });
84
+ for (const listener of this.wakeListeners) {
85
+ try {
86
+ listener(n);
87
+ } catch (error) {
88
+ // fail-soft — a throwing wake listener must not lose the
89
+ // queued notification or break sibling listeners.
90
+ try {
91
+ debug.log('agent.task-notification', 'wake-listener-failed', {
92
+ taskId: n.taskId,
93
+ reason: error instanceof Error ? error.message : String(error),
94
+ });
95
+ } catch { /* */ }
96
+ }
97
+ }
70
98
  }
71
99
 
72
100
  /** Return all pending notifications AND clear the queue. Parents
@@ -85,7 +113,8 @@ export class TaskNotificationQueue {
85
113
  return this.queue.length;
86
114
  }
87
115
 
88
- /** Forget everything — tests use this for isolation. */
116
+ /** Forget everything — tests use this for isolation. Listeners are
117
+ * preserved: clear() empties queue + seen, not the wake wiring. */
89
118
  clear(): void {
90
119
  this.queue = [];
91
120
  this.seen.clear();
@@ -1,7 +1,8 @@
1
1
  // ── ACP Claude Code 를 «구현» 실행기로 (CLAUDE-IMPL-LANE · `--child-llm-provider claude-acp`) ──
2
2
  //
3
3
  // acp-reviewer.ts 의 짝이다. 리뷰어는 read-only 라 읽기 툴만 허가하지만, 구현 실행기는 런 워크트리 안에서
4
- // 쓰기·실행을 허가해야 한다. 그래서 approver 가 «워크트리 밖 경로 쓰기»를 구조적으로 거부한다.
4
+ // 쓰기·실행을 허가해야 한다. 대표 대표 결정(10-12): ACP 세션 권한 모드는 호스트 설정(auto)을 그대로 두고
5
+ // 바꾸지 않으며, approver 가 불려도 «워크트리 밖 경로 쓰기»를 거부하지 않고 허가하되 insideWorktree 로 관측한다.
5
6
  // 자식은 claude 구독 ACP 어댑터(`claude-agent-acp`)이며 env 는 subscriptionReviewerSpawn 의 과금 스크럽
6
7
  // (ANTHROPIC_API_KEY 등 제거)을 그대로 쓴다 — 지우지 않으면 구독이 아니라 API 로 과금된다.
7
8
  import { isAbsolute, relative, resolve } from 'node:path';
@@ -23,6 +24,8 @@ export interface ImplementerPermissionRequest {
23
24
  export interface ImplementerPermissionDecision {
24
25
  tool: string;
25
26
  path: string | null;
27
+ /** 판정에 쓴 경로가 워크트리 안인가 — 경로가 없으면 null. 밖이어도 허가한다(대표 10-12); 이 칸이 그 관측이다. */
28
+ insideWorktree: boolean | null;
26
29
  decision: 'allow' | 'deny';
27
30
  }
28
31
 
@@ -37,18 +40,20 @@ function insideWorktree(worktree: string, target: string): boolean {
37
40
  return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
38
41
  }
39
42
 
40
- /** 허가 판정(순수 함수). 쓰기 계열(edit·delete·move)은 모든 경로가 워크트리 안일 때만 허가하고,
41
- * 실행(execute)은 cwd 가 워크트리라 허가한다. 읽기 계열은 허가, 그 외는 경로가 있고 전부 안쪽일 때만 허가(보수적). */
43
+ /** 허가 판정(순수 함수). 쓰기 계열(edit·delete·move)은 경로가 있으면 워크트리 안팎을 가리지 않고 허가한다
44
+ * (대표 10-12 — 밖 쓰기 거부를 걷었다 · insideWorktree 로 관측만 한다). 실행(execute)·읽기 계열은 허가,
45
+ * 그 외(모르는 kind)는 경로가 있을 때만 허가 — 경로 없는 쓰기·모르는 요청은 여전히 거부. */
42
46
  export function decideImplementerPermission(req: ImplementerPermissionRequest, worktree: string): ImplementerPermissionDecision {
43
47
  const paths = requestedPaths(req.rawInput);
44
48
  const outside = paths.find((p) => !insideWorktree(worktree, p));
45
49
  const tool = req.title.slice(0, 80);
46
50
  const shown = outside ?? paths[0] ?? null;
47
- const verdict = (allow: boolean): ImplementerPermissionDecision => ({ tool, path: shown, decision: allow ? 'allow' : 'deny' });
48
- if (req.kind && WRITE_TOOL_KINDS.has(req.kind)) return verdict(paths.length > 0 && outside === undefined);
51
+ const inside = paths.length === 0 ? null : outside === undefined;
52
+ const verdict = (allow: boolean): ImplementerPermissionDecision => ({ tool, path: shown, insideWorktree: inside, decision: allow ? 'allow' : 'deny' });
53
+ if (req.kind && WRITE_TOOL_KINDS.has(req.kind)) return verdict(paths.length > 0);
49
54
  if (req.kind === 'execute') return verdict(true);
50
55
  if (isReadOnlyReviewTool(req.kind, req.title)) return verdict(true);
51
- return verdict(paths.length > 0 && outside === undefined);
56
+ return verdict(paths.length > 0);
52
57
  }
53
58
 
54
59
  export interface AcpImplementerOpts {
@@ -96,7 +101,9 @@ export function makeAcpImplementer(opts: AcpImplementerOpts): (prompt: string) =
96
101
  permissionApprover: async (req) => {
97
102
  const verdict = decideImplementerPermission(req, opts.worktree);
98
103
  if (verdict.decision === 'allow') allowed++; else denied++;
99
- debug.log(OBS, 'permission', { ...verdict });
104
+ debug.log(OBS, 'permission', {
105
+ tool: verdict.tool, path: verdict.path, insideWorktree: verdict.insideWorktree, allowed: verdict.decision === 'allow',
106
+ });
100
107
  return verdict.decision === 'allow';
101
108
  },
102
109
  };
@@ -683,8 +683,9 @@ function isLongNoFindingBracket(text: string): boolean {
683
683
  return NO_FINDING_HEAD.test(remark) && !LONG_REMARK_DISSENT.test(remark);
684
684
  }
685
685
  /** must-fix 항목이 «지적 없음» 표지인가 — must-fix 를 세는 자리는 전부 `parseReviewResult` 를 거친다
686
- * (`self review --json` 의 `mustFix` → TA `parseReviewResultOutput` → `pr land --overlap-evidence` 의 `review-must-fix-N`). */
687
- function isNoneSentinelFinding(finding: string): boolean {
686
+ * (`self review --json` 의 `mustFix` → TA `parseReviewResultOutput` → `pr land --overlap-evidence` 의 `review-must-fix-N`).
687
+ * ⭐ export — `parseReviewResultOutput` 가 «같은» 판정으로 저장된 결과의 표지 줄을 다시 접는다(PR-LAND-MUSTFIX-NONE · 복제 금지). */
688
+ export function isNoneSentinelFinding(finding: string): boolean {
688
689
  const text = finding.trim();
689
690
  if (BARE_SENTINEL.test(text)) return true;
690
691
  const bracketed = BRACKETED_SENTINEL.exec(text);
@@ -765,6 +766,25 @@ function reviewedResultFromRaw(raw: string, runId: string | undefined, pass?: {
765
766
  return { verdict: 'pass', mustFix: [], shouldFix: [], reviewed: false, failureReason: NO_VERDICT_LINE_REASON };
766
767
  }
767
768
 
769
+ /** REVIEW-PROMPT-SIZE — llmReview 호출 하나(단일·청크 패스)마다 프롬프트·응답 크기를 남긴다.
770
+ * 관측이 리뷰를 막지 않는다(다른 review.* 관측과 같은 계약). */
771
+ function logReviewPromptSize(
772
+ prompt: string,
773
+ response: string,
774
+ pass: { pass: number; chunked: boolean },
775
+ runId: string | undefined,
776
+ ): void {
777
+ try {
778
+ debug.log('review.prompt-size', 'call', {
779
+ pass: pass.pass,
780
+ promptChars: prompt.length,
781
+ responseChars: response.length,
782
+ chunked: pass.chunked,
783
+ ...(runId !== undefined ? { runId } : {}),
784
+ });
785
+ } catch { /* Observation must not prevent the review. */ }
786
+ }
787
+
768
788
  function failureReasonText(error: unknown): string {
769
789
  if (error instanceof Error) return safeLogText(error.message, 400);
770
790
  if (typeof error === 'string') return safeLogText(error, 400);
@@ -916,10 +936,11 @@ export async function reviewPullRequest(
916
936
  + ' 「여기 안 보인다」를 결함으로 판정하지 마십시오.',
917
937
  ].filter(Boolean).join('\n'),
918
938
  };
919
- passResults.push(reviewedResultFromRaw(await llmReview(
920
- buildReviewPrompt(passInput, passBudget, '', passContext[index]?.budget),
921
- reviewImages.length > 0 && index === 0 ? reviewImages : undefined,
922
- ), input.reviewContext?.runId, { index, of: plan.passes.length }));
939
+ const passPrompt = buildReviewPrompt(passInput, passBudget, '', passContext[index]?.budget);
940
+ const passImages = reviewImages.length > 0 && index === 0 ? reviewImages : undefined;
941
+ const passRaw = await llmReview(passPrompt, passImages);
942
+ logReviewPromptSize(passPrompt, passRaw, { pass: index + 1, chunked: true }, input.reviewContext?.runId);
943
+ passResults.push(reviewedResultFromRaw(passRaw, input.reviewContext?.runId, { index, of: plan.passes.length }));
923
944
  }
924
945
  return {
925
946
  ...foldReviewResults(passResults),
@@ -943,10 +964,9 @@ export async function reviewPullRequest(
943
964
  } : {}),
944
965
  };
945
966
  }
946
- const raw = await llmReview(
947
- buildReviewPrompt(input, diffBudget, referencedContext.text, singleContextBudget),
948
- reviewImages.length > 0 ? reviewImages : undefined,
949
- );
967
+ const prompt = buildReviewPrompt(input, diffBudget, referencedContext.text, singleContextBudget);
968
+ const raw = await llmReview(prompt, reviewImages.length > 0 ? reviewImages : undefined);
969
+ logReviewPromptSize(prompt, raw, { pass: 1, chunked: false }, input.reviewContext?.runId);
950
970
  return {
951
971
  ...reviewedResultFromRaw(raw, input.reviewContext?.runId),
952
972
  diffBudget: {
@@ -60,8 +60,11 @@ interface ReviewObservationInput {
60
60
  readonly fallbackAttempted?: boolean;
61
61
  /** 폴백이 실제로 시도한 백엔드. */
62
62
  readonly fallbackBackend?: string;
63
+ /** Explicitly requested primary model and the ACP backend that actually completed review. */
64
+ readonly requestedModel?: string;
65
+ readonly actualBackend?: string;
63
66
  /** 폴백을 시도하지 않은 이유. */
64
- readonly fallbackNotAttemptedReason?: 'explicit-acp' | 'primary-review-succeeded';
67
+ readonly fallbackNotAttemptedReason?: 'explicit-acp' | 'primary-review-succeeded' | 'explicit-model';
65
68
  /** 1차가 왜 못 돌았나 — 폴백의 «사인». */
66
69
  readonly fallbackTriggerReason?: string;
67
70
  /** Each failed ACP fallback attempt, retained in order for diagnosis. */
@@ -80,7 +83,9 @@ interface ReviewObservation {
80
83
  readonly reviewRoute?: 'api' | 'acp' | 'acp-fallback';
81
84
  readonly fallbackAttempted?: boolean;
82
85
  readonly fallbackBackend?: string;
83
- readonly fallbackNotAttemptedReason?: 'explicit-acp' | 'primary-review-succeeded';
86
+ readonly requestedModel?: string;
87
+ readonly actualBackend?: string;
88
+ readonly fallbackNotAttemptedReason?: 'explicit-acp' | 'primary-review-succeeded' | 'explicit-model';
84
89
  readonly fallbackTriggerReason?: string;
85
90
  readonly fallbackFailures?: readonly { backend: string; reason: string }[];
86
91
  readonly skippedAcpFallbackBackends?: readonly { backend: string; reason: string }[];
@@ -168,6 +173,8 @@ export function buildReviewObservation(input: ReviewObservationInput): ReviewObs
168
173
  ...(input.reviewRoute ? { reviewRoute: input.reviewRoute } : {}),
169
174
  ...(input.fallbackAttempted !== undefined ? { fallbackAttempted: input.fallbackAttempted } : {}),
170
175
  ...(input.fallbackBackend ? { fallbackBackend: safeLogText(input.fallbackBackend) } : {}),
176
+ ...(input.requestedModel ? { requestedModel: safeLogText(input.requestedModel) } : {}),
177
+ ...(input.actualBackend ? { actualBackend: safeLogText(input.actualBackend) } : {}),
171
178
  ...(input.fallbackNotAttemptedReason ? { fallbackNotAttemptedReason: input.fallbackNotAttemptedReason } : {}),
172
179
  ...(input.fallbackTriggerReason ? { fallbackTriggerReason: safeLogText(input.fallbackTriggerReason) } : {}),
173
180
  ...(input.fallbackFailures?.length ? {
@@ -14,6 +14,9 @@
14
14
  //
15
15
  // index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
16
16
 
17
+ import { mkdtempSync, rmSync } from 'node:fs';
18
+ import { tmpdir } from 'node:os';
19
+ import { join } from 'node:path';
17
20
  import { tierModel } from '../llm/model-defaults.js';
18
21
  import { buildReviewObservation, safeLogText } from './review-observation.js';
19
22
  import { DEFAULT_REVIEW_BACKEND } from './acp-reviewer.js';
@@ -21,7 +24,7 @@ import { ACP_BACKENDS, canonicalizeBackendId } from '../acp/backend-registry.js'
21
24
  import { buildManualReviewIntent, intentFromPr, prIntentSectionCoverage, reviewIntentTruncationFromPr, reviewIntentTruncationObservation } from './review-intent.js';
22
25
  import { budgetReviewerContext, reviewDiffBudgetObservation, splitDiffByFile, type ReviewImage, type ReviewInput, type ReviewerContextItem, type ReviewResult } from './pr-reviewer.js';
23
26
  import type { ReferencedFileReader } from '../self-implement/goal-file-reader.js';
24
- import type { SubscriptionReviewerSpec } from '../user-config.js';
27
+ import { getUserConfig, type SubscriptionReviewerSpec } from '../user-config.js';
25
28
  import { listRunLedgers, lookupPrGoalAcceptance, lookupRunLedger, type PrGoalAcceptanceLookup, type RunLedgerEntry, type RunLedgerLookup } from '../self-implement/run-ledger.js';
26
29
 
27
30
  /** SUBSCRIPTION-EXHAUST-REROUTE — API reviewer when the configured `roleLlm.reviewer` lane is unavailable (off codex). */
@@ -34,6 +37,8 @@ export interface SelfReviewCliOpts {
34
37
  acpModel?: string | undefined;
35
38
  acpBackend?: string | undefined;
36
39
  configuredAcpBackend?: string | undefined;
40
+ /** ACP review backends excluded from automatic fallback by `acp.reviewDenyBackends`. */
41
+ reviewDenyBackends?: string[] | undefined;
37
42
  /** `roleLlm.reviewer` (same resolution as the harness). Used only when no explicit reviewer flag is given. */
38
43
  roleReviewer?: SubscriptionReviewerSpec | undefined;
39
44
  acpTimeout?: string | undefined;
@@ -75,13 +80,13 @@ export interface SelfReviewCliDeps {
75
80
  *
76
81
  * ⚠️ API 백엔드(`makeApiLlm`)는 이 인자를 안 받는다 — ACP 경로만 이미지를 나른다.
77
82
  */
78
- makeAcpLlm(o: { backend: string; model?: string; timeoutMs: number }): (prompt: string, images?: readonly ReviewImage[]) => Promise<string>;
83
+ makeAcpLlm(o: { backend: string; model?: string; timeoutMs: number; cwd?: string }): (prompt: string, images?: readonly ReviewImage[]) => Promise<string>;
79
84
  /**
80
85
  * Reviewer ACP lane selected by `roleLlm.reviewer` (no explicit flag). Returns the LLM when the
81
86
  * subscription is usable, or a reason code when it is not — the caller then reviews on the API
82
87
  * exactly as before. Absent seam = the lane is unavailable (`role-reviewer-seam-missing`).
83
88
  */
84
- makeRoleReviewerLlm?(spec: SubscriptionReviewerSpec, o: { timeoutMs: number }):
89
+ makeRoleReviewerLlm?(spec: SubscriptionReviewerSpec, o: { timeoutMs: number; cwd?: string }):
85
90
  | { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; backend: string }
86
91
  | { reason: string };
87
92
  /**
@@ -1117,10 +1122,11 @@ function roleAcpErrorReason(error: unknown): 'acp-handshake-timeout' | 'acp-erro
1117
1122
 
1118
1123
  type AcpFallbackSkip = { backend: string; reason: string };
1119
1124
 
1120
- function orderedAcpReviewFallbackBackends(configuredBackend: string | undefined): {
1125
+ function orderedAcpReviewFallbackBackends(configuredBackend: string | undefined, denyBackends: readonly string[] = []): {
1121
1126
  backends: string[];
1122
1127
  skipped: AcpFallbackSkip[];
1123
1128
  } {
1129
+ const denied = new Set(denyBackends.map((backend) => backend.trim().toLowerCase()).filter(Boolean));
1124
1130
  const candidates = [configuredBackend, ...Object.keys(ACP_BACKENDS)]
1125
1131
  .map((backend) => backend?.trim())
1126
1132
  .filter((backend): backend is string => Boolean(backend));
@@ -1132,6 +1138,10 @@ function orderedAcpReviewFallbackBackends(configuredBackend: string | undefined)
1132
1138
  const spec = ACP_BACKENDS[backend];
1133
1139
  if (!spec || seen.has(backend)) continue;
1134
1140
  seen.add(backend);
1141
+ if (denied.has(backend)) {
1142
+ skipped.push({ backend, reason: 'denied-by-acp.reviewDenyBackends' });
1143
+ continue;
1144
+ }
1135
1145
  if (spec.unsupportedReason) {
1136
1146
  skipped.push({ backend, reason: spec.unsupportedReason });
1137
1147
  continue;
@@ -1164,6 +1174,65 @@ export function renderReviewerContextStatus(loaded: LoadedReviewerContext, decom
1164
1174
  return `Reviewer context: ${loaded.items.length} loaded, ${loaded.failed.length} not loaded.${source}${truncation}${decompositionStatus}${labels ? `\n${labels}` : ''}${failures ? `\n${failures}` : ''}`;
1165
1175
  }
1166
1176
 
1177
+ /**
1178
+ * 머지된 PR 의 사후 리뷰 격리 — 리뷰어 cwd 가 main 최신이면 그 뒤 수리를 인용한다.
1179
+ * `merged` 는 그 PR 의 머지 커밋, `open` 은 종전(cwd 불변), `unpinnable` 은 MERGED 인데 머지 커밋을 못 구한 경우다.
1180
+ */
1181
+ type PrMergeState =
1182
+ | { kind: 'open' }
1183
+ | { kind: 'merged'; commit: string }
1184
+ | { kind: 'unpinnable'; reason: 'merge-commit-unknown' };
1185
+
1186
+ function readPrMergeState(pr: string, deps: SelfReviewCliDeps): PrMergeState {
1187
+ const view = deps.gh(['pr', 'view', pr, '--json', 'state,mergeCommit'], 15_000);
1188
+ if (view.status !== 0) return { kind: 'open' };
1189
+ try {
1190
+ const parsed = JSON.parse(view.stdout) as { state?: unknown; mergeCommit?: { oid?: unknown } | null };
1191
+ if (parsed?.state !== 'MERGED') return { kind: 'open' };
1192
+ const oid = parsed.mergeCommit?.oid;
1193
+ return typeof oid === 'string' && COMMIT_OID.test(oid)
1194
+ ? { kind: 'merged', commit: oid }
1195
+ : { kind: 'unpinnable', reason: 'merge-commit-unknown' };
1196
+ } catch {
1197
+ return { kind: 'open' };
1198
+ }
1199
+ }
1200
+
1201
+ interface ReviewWorktree {
1202
+ cwd: string;
1203
+ commit: string;
1204
+ /** 멱등 — 두 번 불러도 안전하다. */
1205
+ remove(): void;
1206
+ }
1207
+
1208
+ type ReviewWorktreeResult = ReviewWorktree | { reason: 'no-git-seam' | 'worktree-add-failed' };
1209
+
1210
+ function createDetachedReviewWorktree(commit: string, deps: SelfReviewCliDeps): ReviewWorktreeResult {
1211
+ const git = deps.git;
1212
+ if (!git) return { reason: 'no-git-seam' };
1213
+ const parent = mkdtempSync(join(tmpdir(), 'elanous-review-pin-'));
1214
+ const cwd = join(parent, 'wt');
1215
+ const add = () => git(['worktree', 'add', '--detach', cwd, commit], 120_000);
1216
+ let added = add();
1217
+ if (added.status !== 0) {
1218
+ git(['fetch', 'origin', commit], 120_000);
1219
+ added = add();
1220
+ }
1221
+ let removed = false;
1222
+ const remove = (): void => {
1223
+ if (removed) return;
1224
+ removed = true;
1225
+ git(['worktree', 'remove', '--force', cwd], 60_000);
1226
+ rmSync(parent, { recursive: true, force: true });
1227
+ // ⛔ `git worktree prune` 은 부르지 않는다 — 저장소 «전체»의 stale 메타데이터를 지워 남의 worktree 까지 건드린다.
1228
+ };
1229
+ if (added.status !== 0) {
1230
+ remove();
1231
+ return { reason: 'worktree-add-failed' };
1232
+ }
1233
+ return { cwd, commit, remove };
1234
+ }
1235
+
1167
1236
  /** `elanous self review <pr...>` 본문. read-only — 머지하지 않는다. */
1168
1237
  /**
1169
1238
  * `self review --json` stdout 한 줄 — 결과가 하나면 객체, 여럿이면 배열. index.ts 액션이 이것을 그대로 쓴다.
@@ -1177,6 +1246,20 @@ export async function runSelfReviewCliCommand(
1177
1246
  prArgs: string[],
1178
1247
  opts: SelfReviewCliOpts,
1179
1248
  deps: SelfReviewCliDeps,
1249
+ ): Promise<SelfReviewCliOutcome> {
1250
+ const pins: ReviewWorktree[] = [];
1251
+ try {
1252
+ return await runSelfReviewCliCommandPinned(prArgs, opts, deps, pins);
1253
+ } finally {
1254
+ for (const pin of pins) pin.remove();
1255
+ }
1256
+ }
1257
+
1258
+ async function runSelfReviewCliCommandPinned(
1259
+ prArgs: string[],
1260
+ opts: SelfReviewCliOpts,
1261
+ deps: SelfReviewCliDeps,
1262
+ pins: ReviewWorktree[],
1180
1263
  ): Promise<SelfReviewCliOutcome> {
1181
1264
  // 관측 sink는 모든 종료 경로보다 먼저 등록해 거부도 운영 로그에 남긴다.
1182
1265
  await deps.registerSink('self-review');
@@ -1201,7 +1284,12 @@ export async function runSelfReviewCliCommand(
1201
1284
  ? { backend: opts.configuredAcpBackend, source: 'config' as const }
1202
1285
  : { backend: DEFAULT_REVIEW_BACKEND, source: 'default' as const };
1203
1286
  const acpBackend = acpBackendResolution.backend;
1204
- const automaticFallbacks = orderedAcpReviewFallbackBackends(opts.configuredAcpBackend);
1287
+ const requestedModel = opts.model?.trim() || undefined;
1288
+ const rawReviewDenyBackends = (getUserConfig().raw?.acp as { reviewDenyBackends?: unknown } | undefined)?.reviewDenyBackends;
1289
+ const configuredReviewDenyBackends = Array.isArray(rawReviewDenyBackends)
1290
+ ? rawReviewDenyBackends.filter((backend): backend is string => typeof backend === 'string')
1291
+ : [];
1292
+ const automaticFallbacks = orderedAcpReviewFallbackBackends(opts.configuredAcpBackend, opts.reviewDenyBackends ?? configuredReviewDenyBackends);
1205
1293
  const fallbackAcpBackends = opts.acpBackend
1206
1294
  ? [canonicalizeBackendId(opts.acpBackend)]
1207
1295
  : automaticFallbacks.backends;
@@ -1224,6 +1312,14 @@ export async function runSelfReviewCliCommand(
1224
1312
  const envModel = deps.envModel();
1225
1313
  const roleFallbackModel = !useAcp && !opts.model && !envModel && reviewerSource === 'role-config'
1226
1314
  ? deps.roleFallbackModel?.()?.trim() || undefined : undefined;
1315
+ if (requestedModel && /^glm-\d+(?:\.\d+)?$/i.test(requestedModel)) {
1316
+ const canonical = requestedModel.toLowerCase() === 'glm-5.3' ? 'openrouter/z-ai/glm-5.3' : undefined;
1317
+ const suggestion = canonical ? ` 정본 모델 ID 후보: ${canonical}` : ' `local:<model>` 또는 공급자 정본 ID를 지정하세요.';
1318
+ const message = `모델 ID가 모호합니다: ${requestedModel}.${suggestion} 짧은 별칭을 공급자 정본 ID로 바꿔 다시 시도하세요.`;
1319
+ deps.log('model-rejected', { requestedModel: safeLogText(requestedModel), reason: 'ambiguous-model-id', ...(canonical ? { canonicalModelCandidate: canonical } : {}) }, { level: 'warn' });
1320
+ deps.error(message);
1321
+ return { results: opts.json ? [{ error: message, requestedModel }] : [], failed: 1 };
1322
+ }
1227
1323
  const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (opts.model || envModel || roleFallbackModel || tierModel('better'));
1228
1324
  let roleReviewer: { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; model: string } | undefined;
1229
1325
  let roleReviewerUnavailableReason: string | undefined;
@@ -1272,6 +1368,7 @@ export async function runSelfReviewCliCommand(
1272
1368
  // ⛔ `relation-unknown` 도 경고한다(위 주석 · 리뷰가 두 라운드 반복 지적) — 그 밖 unavailable 은 조용하다.
1273
1369
  // ⭐ 경고 여부 판정은 `localHeadWarningDetails` 한 곳에 있다(호출부에서 같은 함수를 두 번 부르지 않는다).
1274
1370
  const mismatchWarning = localHeadWarningDetails(localHeadComparison);
1371
+ const mergeState = readPrMergeState(pr, deps);
1275
1372
  const view = deps.gh(['pr', 'view', pr, '--json', 'title,body'], 15_000);
1276
1373
  let prView: { title?: string; body?: string } | undefined;
1277
1374
  if (view.status === 0) {
@@ -1399,6 +1496,36 @@ export async function runSelfReviewCliCommand(
1399
1496
  else deps.print(`\n━━ PR ${pr} (${primaryModel}) ━━\n${renderStaleRefusal(diffRead)}\n${reviewerContextStatus}`);
1400
1497
  continue;
1401
1498
  }
1499
+ // ⭐ 머지된 PR 만 머지 커밋 detached worktree 에서 리뷰한다 — main 최신이 아니라 그 PR 이 머지된 시점의 코드를 본다.
1500
+ // 열린 PR 은 종전 그대로(cwd = process.cwd() · 리뷰어 심이 cwd 를 받지 않는다).
1501
+ let reviewPin: ReviewWorktree | undefined;
1502
+ let reviewCwdPinFallbackReason: string | undefined;
1503
+ // cwd 를 받는 레인(ACP · role 리뷰어)일 때만 worktree 를 뜬다 — API 리뷰어는 cwd 를 안 받으므로 떠도 그 위에서 돌지 않는다.
1504
+ const pinLane = useAcp || Boolean(roleReviewer && opts.roleReviewer && deps.makeRoleReviewerLlm);
1505
+ let rolePinned = false;
1506
+ if (!pinLane) {
1507
+ // 비-ACP 레인 — 격리하지 않는다(종전 그대로 · reviewCwdCommit 없음).
1508
+ } else if (mergeState.kind === 'merged') {
1509
+ const made = createDetachedReviewWorktree(mergeState.commit, deps);
1510
+ if ('cwd' in made) {
1511
+ reviewPin = made;
1512
+ pins.push(made);
1513
+ } else reviewCwdPinFallbackReason = made.reason;
1514
+ } else if (mergeState.kind === 'unpinnable') reviewCwdPinFallbackReason = mergeState.reason;
1515
+ const reviewCwd = reviewPin?.cwd;
1516
+ const prAcpReviewLLM = reviewCwd && useAcp
1517
+ ? deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: acpTimeoutSec * 1000, cwd: reviewCwd })
1518
+ : acpReviewLLM;
1519
+ let prRoleReviewer = roleReviewer;
1520
+ if (reviewCwd && roleReviewer && opts.roleReviewer && deps.makeRoleReviewerLlm) {
1521
+ try {
1522
+ const pinned = deps.makeRoleReviewerLlm(opts.roleReviewer, { timeoutMs: acpTimeoutSec * 1000, cwd: reviewCwd });
1523
+ if ('llm' in pinned) { prRoleReviewer = { llm: pinned.llm, model: `acp:${pinned.backend}` }; rolePinned = true; }
1524
+ else reviewCwdPinFallbackReason = 'role-reviewer-cwd-unavailable';
1525
+ } catch {
1526
+ reviewCwdPinFallbackReason = 'role-reviewer-cwd-unavailable';
1527
+ }
1528
+ }
1402
1529
  const startedAt = deps.now();
1403
1530
  // Role-config lane builds the API reviewer only when it falls back (`made().api` stays 0 on ACP success).
1404
1531
  const responded: { provider?: string; model?: string } = {};
@@ -1406,7 +1533,7 @@ export async function runSelfReviewCliCommand(
1406
1533
  pinProvider: Boolean(opts.model?.trim()),
1407
1534
  onResolved: (provider, respondedModel) => { responded.provider = provider; responded.model = respondedModel; },
1408
1535
  });
1409
- const llmReview = roleReviewer ? undefined : (acpReviewLLM ?? makeApi());
1536
+ const llmReview = prRoleReviewer ? undefined : (prAcpReviewLLM ?? makeApi());
1410
1537
  // ⛔ evidenceNote 는 **별도 채널**이다 — phaseIntent 에 섞으면 의도 채널이 오염된다(실측: 그렇게
1411
1538
  // 했다가 intent 배선 테스트 3개가 즉시 깨졌다).
1412
1539
  // ⛔ 사람 `--intent`(phaseIntent) 와 골 acceptance 는 다른 인자 — 충돌하지 않고, 충돌해도 intent 가 이긴다.
@@ -1426,10 +1553,10 @@ export async function runSelfReviewCliCommand(
1426
1553
  let roleReview: ReviewResult | undefined;
1427
1554
  let roleReviewerFallbackReason = roleReviewerUnavailableReason;
1428
1555
  let roleReviewMs: number | undefined;
1429
- if (roleReviewer) {
1556
+ if (prRoleReviewer) {
1430
1557
  const roleStartedAt = deps.now();
1431
1558
  try {
1432
- const attempt = await deps.reviewPullRequest(reviewInput, roleReviewer.llm);
1559
+ const attempt = await deps.reviewPullRequest(reviewInput, prRoleReviewer.llm);
1433
1560
  if (attempt.reviewed === true) roleReview = attempt;
1434
1561
  // Code, not the reviewer's raw failure text (same rule as the throw path above).
1435
1562
  else roleReviewerFallbackReason = 'acp-review-not-completed';
@@ -1445,15 +1572,15 @@ export async function runSelfReviewCliCommand(
1445
1572
  }, { level: 'warn' });
1446
1573
  }
1447
1574
  }
1448
- let review = roleReview ?? await deps.reviewPullRequest(reviewInput, llmReview ?? acpReviewLLM ?? makeApi());
1449
- let selectedModel = roleReview && roleReviewer ? roleReviewer.model : model;
1575
+ let review = roleReview ?? await deps.reviewPullRequest(reviewInput, llmReview ?? prAcpReviewLLM ?? makeApi());
1576
+ let selectedModel = roleReview && prRoleReviewer ? prRoleReviewer.model : model;
1450
1577
  let reviewRoute: 'api' | 'acp' | 'acp-fallback' = useAcp || roleReview ? 'acp' : 'api';
1451
1578
  let fallbackAttempted = false;
1452
1579
  let fallbackBackend: string | undefined;
1453
1580
  let fallbackTriggerReason: string | undefined;
1454
- let fallbackNotAttemptedReason: 'explicit-acp' | 'primary-review-succeeded' | undefined;
1581
+ let fallbackNotAttemptedReason: 'explicit-acp' | 'primary-review-succeeded' | 'explicit-model' | undefined;
1455
1582
  const fallbackFailures: Array<{ backend: string; reason: string }> = [];
1456
- if (!useAcp && !roleReview && review.reviewed !== true) {
1583
+ if (!useAcp && !roleReview && !opts.acpModel?.trim() && (!requestedModel || Boolean(opts.acpBackend)) && review.reviewed !== true) {
1457
1584
  fallbackAttempted = true;
1458
1585
  fallbackTriggerReason = safeLogText(review.failureReason || 'reviewed=false', 400);
1459
1586
  for (const backend of fallbackAcpBackends) {
@@ -1462,11 +1589,12 @@ export async function runSelfReviewCliCommand(
1462
1589
  pr: safeLogText(pr),
1463
1590
  failureReason: fallbackTriggerReason,
1464
1591
  fallbackBackend: safeLogText(backend),
1592
+ requestedModel: safeLogText(primaryModel),
1465
1593
  }, { level: 'warn' });
1466
1594
  try {
1467
1595
  const fallbackReview = await deps.reviewPullRequest(
1468
1596
  reviewInput,
1469
- deps.makeAcpLlm({ backend, timeoutMs: acpTimeoutSec * 1000 }),
1597
+ deps.makeAcpLlm({ backend, timeoutMs: acpTimeoutSec * 1000, ...(reviewCwd ? { cwd: reviewCwd } : {}) }),
1470
1598
  );
1471
1599
  if (fallbackReview.reviewed === true) {
1472
1600
  review = fallbackReview;
@@ -1482,13 +1610,22 @@ export async function runSelfReviewCliCommand(
1482
1610
  }
1483
1611
  }
1484
1612
  }
1613
+ reviewPin?.remove();
1614
+ // reviewCwdCommit 은 «최종 판정을 낸 LLM 이 실제로 그 cwd 를 받았을 때만» 싣는다(role 실패 → API 폴백이면 안 싣는다).
1615
+ const reviewedOnPin = Boolean(reviewPin) && (roleReview ? rolePinned : reviewRoute === 'acp-fallback' ? true : reviewRoute === 'acp' && useAcp);
1616
+ if (reviewPin && !reviewedOnPin) reviewCwdPinFallbackReason ??= 'final-reviewer-not-pinned';
1617
+ const reviewCwdOutput = {
1618
+ ...(reviewPin && reviewedOnPin ? { reviewCwdCommit: reviewPin.commit } : {}),
1619
+ ...(reviewCwdPinFallbackReason ? { reviewCwdPinFallbackReason } : {}),
1620
+ };
1485
1621
  if (!fallbackAttempted) {
1486
- fallbackNotAttemptedReason = useAcp ? 'explicit-acp' : 'primary-review-succeeded';
1622
+ fallbackNotAttemptedReason = useAcp ? 'explicit-acp' : requestedModel && review.reviewed !== true ? 'explicit-model' : 'primary-review-succeeded';
1487
1623
  }
1488
1624
  const reviewProvenance = {
1489
1625
  reviewRoute,
1490
1626
  fallbackAttempted,
1491
1627
  ...(fallbackBackend ? { fallbackBackend } : {}),
1628
+ ...(fallbackBackend ? { requestedModel: primaryModel, actualBackend: `acp:${fallbackBackend}` } : {}),
1492
1629
  ...(fallbackNotAttemptedReason ? { fallbackNotAttemptedReason } : {}),
1493
1630
  ...(fallbackTriggerReason ? { fallbackTriggerReason } : {}),
1494
1631
  ...(fallbackFailures.length ? { fallbackFailures } : {}),
@@ -1522,20 +1659,21 @@ export async function runSelfReviewCliCommand(
1522
1659
  goalLoaded: goalAcceptance.goalLoaded,
1523
1660
  acceptanceChars: goalAcceptance.acceptanceChars,
1524
1661
  ...reviewerSelection,
1662
+ ...reviewCwdOutput,
1525
1663
  },
1526
1664
  { level: review.reviewed === false ? 'warn' : 'info' });
1527
1665
  // --acp 는 대표가 명시 요청한 리뷰 — fail-soft(reviewed=false)면 조용히 pass 하지 말고 표면화(관측=acp-review).
1528
1666
  if (useAcp && review.reviewed === false) {
1529
1667
  const err = 'ACP 리뷰 실행 실패(reviewed=false) — 관측: elanous logs --category acp-review';
1530
1668
  const contextOutput = reviewerContextOutput(reviewerContext, decompositionContext);
1531
- if (opts.json) results.push({ pr, error: err, ...review, verdict: null, ...reviewProvenance, ...respondedOutput, ...reviewerSelection, ...provenance, ...contextOutput });
1669
+ if (opts.json) results.push({ pr, error: err, ...review, verdict: null, ...reviewProvenance, ...respondedOutput, ...reviewerSelection, ...reviewCwdOutput, ...provenance, ...contextOutput });
1532
1670
  else deps.error(`PR ${pr}: ${err}\n${renderProvenance(diffRead)}\n${reviewerContextStatus}`);
1533
1671
  failed += 1;
1534
1672
  continue;
1535
1673
  }
1536
1674
  const contextOutput = reviewerContextOutput(reviewerContext, decompositionContext);
1537
1675
  const jsonReview = review.reviewed === true ? review : { ...review, verdict: null };
1538
- if (opts.json) results.push({ pr, model: selectedModel, ...jsonReview, ...reviewProvenance, ...respondedOutput, ...reviewerSelection, ...provenance, ...contextOutput, evidence: evidence.evidence, prDiffFiles: evidence.prDiffFiles, ...(evidence.authoredFiles !== undefined ? { authoredFiles: evidence.authoredFiles } : {}) });
1676
+ if (opts.json) results.push({ pr, model: selectedModel, ...jsonReview, ...reviewProvenance, ...respondedOutput, ...reviewerSelection, ...reviewCwdOutput, ...provenance, ...contextOutput, evidence: evidence.evidence, prDiffFiles: evidence.prDiffFiles, ...(evidence.authoredFiles !== undefined ? { authoredFiles: evidence.authoredFiles } : {}) });
1539
1677
  else deps.print(`\n━━ PR ${pr} (${selectedModel}) ━━\n${renderProvenance(diffRead)}\n${evidenceLine}\n${reviewerContextStatus}\n${deps.renderReview(review)}`);
1540
1678
  // REVIEW-ERROR-RC — 기본(API)·role 경로가 1차·폴백 모두 실패해 reviewed≠true 로 끝나도 «못 리뷰한 PR» 이다(verdict:null).
1541
1679
  if (review.reviewed !== true) failed += 1;
@@ -75,6 +75,66 @@ export function _setCreateGoalAuthorDecomposeStepsForTesting(fn?: CreateGoalAuth
75
75
  /** 진행 종료 스테이지(phase='end') — 그 외는 delta(start 제외). */
76
76
  const END_STAGES: readonly SelfImplementProgressStage[] = ['pr-opened', 'aborted', 'gate-failed', 'pr-declined'];
77
77
 
78
+ // ⭐ 결과 네 꼴(HARNESS-RESULT-CONTRACT · RFC-tui-tool-surface-on-graph-harness §4 · 0.2.26) —
79
+ // 종전 `{observed:true}` 한 비트는 모델이 «안 됐다 → 직접 편집»으로 읽었다(UX S1-02 · 47 도구).
80
+ // ⇒ launched / pending / observed-only / failed 네 꼴로 구조화해 «다음 행동»을 문면으로 고정한다.
81
+ // ⚠️ launched 꼴은 SelfImplementResult 필드를 **그대로 보존**한다 — runId 조인·원장 소비자 무손상.
82
+ export type SelfImplementLaunchedToolResult = SelfImplementResult & { runId: string; kind: 'launched'; message: string; next: string; missing: string[] };
83
+ export type SelfImplementPendingToolResult = Partial<SelfImplementResult> & { kind: 'pending'; message: string; next: string; missing: string[] };
84
+ export type SelfImplementObservedOnlyToolResult = { kind: 'observed-only'; observed: true; message: string; next: string; missing: ['runId', 'node'] };
85
+ export type SelfImplementFailedToolResult = Partial<SelfImplementResult> & { kind: 'failed'; reason: string; message: string; next: string; missing: string[] };
86
+ export type SelfImplementToolResult = SelfImplementLaunchedToolResult | SelfImplementPendingToolResult | SelfImplementObservedOnlyToolResult | SelfImplementFailedToolResult;
87
+
88
+ /** 하니스가 런을 맡았다 — 파일 편집은 하니스 몫이므로 모델의 직접 Write/Edit 을 문면으로 막는다. */
89
+ export function buildLaunchedToolResult(result: SelfImplementResult): SelfImplementLaunchedToolResult | SelfImplementPendingToolResult {
90
+ if (!result.runId) return buildPendingToolResult(result);
91
+ const runId = result.runId;
92
+ const node = result.node || null;
93
+ const missing = node ? [] : ['node'];
94
+ const query = `eln self run ${runId}`;
95
+ return {
96
+ ...result,
97
+ runId,
98
+ kind: 'launched',
99
+ next: query,
100
+ missing,
101
+ message: `하니스가 맡았습니다 · 런 ${runId} · 노드 ${node ?? '미관측'} · 다음 조회: ${query} · 이 턴에서 파일을 직접 편집하지 마세요`,
102
+ };
103
+ }
104
+
105
+ /** 완료 또는 접수는 관측했지만 실제 런 ID가 없어 발사를 단언할 수 없다. */
106
+ export function buildPendingToolResult(result: SelfImplementResult): SelfImplementPendingToolResult {
107
+ const { runId: _unconfirmedRunId, ...observed } = result;
108
+ return {
109
+ ...observed,
110
+ kind: 'pending',
111
+ next: 'eln self running-runs',
112
+ missing: ['runId', ...(result.node ? [] : ['node'])],
113
+ message: '하니스 응답을 받았지만 런 식별자는 아직 미관측입니다 · 진행 중 런 조회: eln self running-runs · 일치하는 런이 없으면 요청을 다시 보내세요 · 이 턴에서 파일을 직접 편집하지 마세요',
114
+ };
115
+ }
116
+
117
+ /** 관측 전용 — 런이 발사되지 «않았다»는 사실과 «구현 실패가 아니다»를 함께 말한다. */
118
+ export function buildObservedOnlyToolResult(): SelfImplementObservedOnlyToolResult {
119
+ return {
120
+ kind: 'observed-only',
121
+ observed: true,
122
+ missing: ['runId', 'node'],
123
+ next: '실제 발사를 원하면 관측 전용 모드를 끈 뒤 다시 요청하세요',
124
+ message: '관측 전용이라 런을 발사하지 않았습니다 · 코드도 안 바꿨습니다 · 이 결과를 구현 실패로 읽고 직접 Write/Edit 하지 마세요 · 실제 발사를 원하면 관측 전용 모드를 끈 뒤 다시 요청하세요',
125
+ };
126
+ }
127
+
128
+ /** 거부·실패 — 이유와 다음 행동을 구조화해 모델이 재시도·포기·인계를 판단하게 한다. */
129
+ export function buildFailedToolResult(reason: string, result?: SelfImplementResult): SelfImplementFailedToolResult {
130
+ const next = result?.runId ? `eln self run ${result.runId}` : '요청과 실패 이유를 확인한 뒤 다시 요청하세요';
131
+ return {
132
+ ...(result ?? {}), kind: 'failed', reason, next,
133
+ missing: [...(result?.runId ? [] : ['runId']), ...(result?.node ? [] : ['node'])],
134
+ message: `하니스가 발사되지 않았거나 실패했습니다: ${reason} · 다음: ${next} · 이 턴에서 파일을 직접 편집하지 마세요`,
135
+ };
136
+ }
137
+
78
138
  /**
79
139
  * ★ base seam 에 막(SurfaceUx) 배선을 얹는다(P0·테스트 가능). approvePr=ux.confirm(fail-closed)·
80
140
  * onProgress=ux.progress. 코어(runSelfImplement)·다른 seam(worktree/implement/gate/openPr)은 무손상.
@@ -180,9 +240,10 @@ export async function dispatchSelfImplement(
180
240
  authorGoal: SelfImplementGoalAuthor = writeAuthoredGoal,
181
241
  runCli: RunSelfImplementCliFn = runSelfImplementCliCommand,
182
242
  seamsFactory?: SelfImplementSeamsFactory,
183
- ): Promise<unknown> {
243
+ ): Promise<SelfImplementToolResult> {
184
244
  const feature = typeof args.feature === 'string' ? args.feature.trim() : '';
185
- if (!feature) return { error: 'SelfImplement: `feature` is required' };
245
+ if (!feature) return buildFailedToolResult('SelfImplement: `feature` is required');
246
+ try {
186
247
  const base = typeof args.base === 'string' && args.base.trim() ? args.base.trim() : undefined;
187
248
  const draft = typeof args.draft === 'boolean' ? args.draft : true;
188
249
  const entry = resolveDispatchEntry(ctx);
@@ -216,7 +277,7 @@ export async function dispatchSelfImplement(
216
277
  debug.log('daemon-tools.self-implement', 'runtime.observe-only-decision', { surface: ux.surface, observeOnly: observeOnly.enabled, observeOnlySource: observeOnly.source });
217
278
  if (observeOnly.enabled) {
218
279
  debug.log('daemon-tools.self-implement', 'runtime.observed', { surface: ux.surface, observeOnly: observeOnly.enabled, observeOnlySource: observeOnly.source });
219
- return { observed: true };
280
+ return buildObservedOnlyToolResult();
220
281
  }
221
282
 
222
283
  let goalFile: string | undefined;
@@ -298,5 +359,12 @@ export async function dispatchSelfImplement(
298
359
  // ⭐ runId 를 반드시 싣는다 — 관측이 전부 runId 로 키잉되므로(`self run <runId>`·`logs --grep`)
299
360
  // 이게 없으면 **이 경계에서 조인이 끊긴다**(N3 재측정 2026-07-28: 계약은 섰는데 로그가 못 따라갔다).
300
361
  debug.log('daemon-tools.self-implement', 'done', { runId: result.runId, stage: result.stage, ok: result.ok, pr: result.prUrl ?? null });
301
- return result;
362
+ return !result.ok
363
+ ? buildFailedToolResult(result.detail ?? result.stage, result)
364
+ : result.runId ? buildLaunchedToolResult(result) : buildPendingToolResult(result);
365
+ } catch (error) {
366
+ const reason = error instanceof Error ? error.message : String(error);
367
+ debug.log('daemon-tools.self-implement', 'failed', { reason, stage: 'dispatch' });
368
+ return buildFailedToolResult(reason);
369
+ }
302
370
  }