elanous 0.2.22 → 0.2.24

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 (803) hide show
  1. package/NOTICE +7 -0
  2. package/README.md +32 -22
  3. package/apps/pwa/out/404/index.html +1 -1
  4. package/apps/pwa/out/404.html +1 -1
  5. package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_buildManifest.js +1 -1
  6. package/apps/pwa/out/_next/static/chunks/{119fc678.6f591cdb84ca5791.js → 0673cc54.8e2ef1c23e49e190.js} +1 -1
  7. package/apps/pwa/out/_next/static/chunks/{a9f2b54d-40c16bd0efdb04b8.js → 0a09e062-34f747a17d8d8c2e.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/{f8626309.a4e5d362b1d55e59.js → 0e3acd34.d42b2ef87fdf4234.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/1168.a0fb3d9db76c00bd.js +77 -0
  10. package/apps/pwa/out/_next/static/chunks/{7175-350f4ce2873bc038.js → 1325-dc3f3c21eb181cb4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/1357.a843c41d2cd7ec31.js +34 -0
  12. package/apps/pwa/out/_next/static/chunks/1430.53f49882b17607c2.js +24 -0
  13. package/apps/pwa/out/_next/static/chunks/1459-be6509b3419d8a9f.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/{6767.8e6c5f6e744fcd9f.js → 1505.5826671109111e75.js} +2 -2
  15. package/apps/pwa/out/_next/static/chunks/153.0a4e3cd516930491.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/1572.7bc291352e241a45.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1593-d07ad068c120dfb0.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/1608.b7c900baa56cab32.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/1615-4d8156febaac4b35.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1646.e03f0fbc26bc72f6.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/{7327-2d69fb321ba73389.js → 1669-da843ed73aa301f5.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/176.13ba0659e3e96fd4.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1990.9c60f495ef33c070.js +36 -0
  24. package/apps/pwa/out/_next/static/chunks/2042e469.f86158dd5c1e51a1.js +122 -0
  25. package/apps/pwa/out/_next/static/chunks/2528.0af5c0e1fad88df6.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/2543-28ec6aeb80a5e1e1.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2561.43c99d6ee914ee6a.js +62 -0
  28. package/apps/pwa/out/_next/static/chunks/2638.b39ab2f674caa1a5.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/272-0eed0fb0aab716b6.js +1 -0
  30. package/apps/pwa/out/_next/static/chunks/{7899.597af4a9996c907f.js → 2721.bc9a8f36bd85c07a.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/2778.67e0c1d484189ccf.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/2841.10ff309f6a3168af.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/2886-9639f97d523d752a.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/2978.57fb87ce21cc5a85.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3664.15f968c39d15bd28.js +149 -0
  36. package/apps/pwa/out/_next/static/chunks/3786-935eb3fcde90e496.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/3813.df4a01ae89c6f63f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/3961-aaae04ed1d32622f.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3992.f79c70480e8c4077.js +309 -0
  40. package/apps/pwa/out/_next/static/chunks/40-413e8641de9ed1e5.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/4054-521f11a503daed64.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/4315.e7356f34c7d8ec79.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4489-bf629de6f04f7681.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/4540.557733cc88c6a82b.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/462.0275b4338c5b6337.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/4658-7ed9266098a787e4.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/4945-0f4046cfc3228ea3.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/{d70879db.c66c56a95a91efc6.js → 4c5e95ce.83e9b16add6fcd8c.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/5105-18b4165c5d3a86b0.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/5205-6992210fe31f45f4.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/5287-72898b126d722457.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{6158.566c890adc06a459.js → 5313.1697309c532b9856.js} +2 -2
  53. package/apps/pwa/out/_next/static/chunks/{79b78388.663188133449d707.js → 53746282.1be36038d1abd949.js} +1 -1
  54. package/apps/pwa/out/_next/static/chunks/5474.991b90688c3cb321.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/5544-871146192d095594.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/5578.ac963634373b28c6.js +286 -0
  57. package/apps/pwa/out/_next/static/chunks/5935.d5e8ca3e096772e8.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/5967-c0a80f8ffe5d4050.js +1 -0
  59. package/apps/pwa/out/_next/static/chunks/{1268.0840ff91e083fcbd.js → 5974.360f8441eb0ac1ec.js} +1 -1
  60. package/apps/pwa/out/_next/static/chunks/6006.84e8b418a7a0db97.js +1 -0
  61. package/apps/pwa/out/_next/static/chunks/6013-1267ba7454d6764b.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/6038-1e0f7ee1086da4cf.js +1 -0
  63. package/apps/pwa/out/_next/static/chunks/617.709dd0019fe99796.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/6261.fb9bf94947094636.js +74 -0
  65. package/apps/pwa/out/_next/static/chunks/6411.1966866fae31ffa9.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/6481-b829d99aa8d158f5.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/6541.2b7daa043100d0fa.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6571-926ddf024a6ad5df.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/6597.2d7a6d77ab485b27.js +64 -0
  70. package/apps/pwa/out/_next/static/chunks/67.5dd2dc543c2fa3de.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/{9832.2ab2e818013574c7.js → 6702.ebbd165d5e4a4a14.js} +1 -1
  72. package/apps/pwa/out/_next/static/chunks/6777-312496b0d774719b.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/681.0116f7036cfb4e8d.js +32 -0
  74. package/apps/pwa/out/_next/static/chunks/6871.30b2bf23b3126e36.js +24 -0
  75. package/apps/pwa/out/_next/static/chunks/6882.737d366d54e29d83.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/7035.54c2c535164b1c9b.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/7086-8bfa7e8f796a03d9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/7126.5e5599f251726b67.js +93 -0
  79. package/apps/pwa/out/_next/static/chunks/7203-47ff0740a293e284.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/7268.017f49dafb5f0ff3.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/7355.5d65a87e9567ae08.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7392.4018c2a62177f296.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/{6110.1297d4093fdfbb0d.js → 740.90b31555290236a9.js} +2 -2
  84. package/apps/pwa/out/_next/static/chunks/7471.3a3d1be50559cfb8.js +148 -0
  85. package/apps/pwa/out/_next/static/chunks/7500.73489a345cef2201.js +226 -0
  86. package/apps/pwa/out/_next/static/chunks/{9070.067c106528ec1ae6.js → 7518.49161e8f5814abdb.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/7565.c2f72a15c1ed0396.js +27 -0
  88. package/apps/pwa/out/_next/static/chunks/7651.6d1c984d3d8587a4.js +1 -0
  89. package/apps/pwa/out/_next/static/chunks/7713.7ab863ed59b2d661.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7793.d7cd2026767ddd54.js +115 -0
  91. package/apps/pwa/out/_next/static/chunks/7837.c7c267e5dceadb11.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7891.09266382daf70d1c.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7905.b230b9d06cb4ad5d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7990-cbf6a01bcbdcb7e6.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/8119-819c549e0c197786.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8186-74ea19a3700d04a8.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/{8194.484f51e273d9abd2.js → 8264.00e434fbd02e9311.js} +16 -16
  98. package/apps/pwa/out/_next/static/chunks/8267-e7b3262b735ae106.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8386.86518e55b75f7cf5.js +8 -0
  100. package/apps/pwa/out/_next/static/chunks/{088d8e8a.8069543d082bec12.js → 83cfc5c8.349535543c1548b6.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/8437.ba6eeeb29590042f.js +23 -0
  102. package/apps/pwa/out/_next/static/chunks/{1948.5f35b39eef222a94.js → 8438.ee7f0df3b3f6fcb4.js} +1 -1
  103. package/apps/pwa/out/_next/static/chunks/8469-1500be57e582296f.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8483-7164cecdaf178ca6.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{4588.ad3364cb7fb97ada.js → 8532.a86e99acf9b761cb.js} +2 -2
  106. package/apps/pwa/out/_next/static/chunks/8569.b853a8daa8f31d12.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8722-4c940f02c496ad36.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/887-41d0dcf5af48c628.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/8925-2abfb48af477fb7f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/{88729267.9c6c000157c83f2f.js → 89849432.9eaa2f4c9c010965.js} +3 -3
  111. package/apps/pwa/out/_next/static/chunks/9039.da86361496797522.js +90 -0
  112. package/apps/pwa/out/_next/static/chunks/905.d5745a25884754d4.js +94 -0
  113. package/apps/pwa/out/_next/static/chunks/9089-d909f3d4478b0628.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/9096.dc5c7a267f83790c.js +41 -0
  115. package/apps/pwa/out/_next/static/chunks/93.a567257b6bdb7fe4.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9320.419acb9665b46597.js +287 -0
  117. package/apps/pwa/out/_next/static/chunks/9356.b8ceda6634612ff8.js +79 -0
  118. package/apps/pwa/out/_next/static/chunks/94.e9e1043b35cd3eed.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9400-7498ea90b2e6ee8f.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/{3522-1de1319d028ac89c.js → 9502-32c5dc22e8f120f5.js} +3 -3
  121. package/apps/pwa/out/_next/static/chunks/9930-58644af9c813d6e1.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9932.367cf4725fedd6e2.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/9935.1628b904cdc8ce0e.js +104 -0
  124. package/apps/pwa/out/_next/static/chunks/{7630.2b9a68659053ff4e.js → 9976.8f28864317639fe6.js} +16 -16
  125. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-a2aa8709d193ee0d.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/approvals/page-3b9fc39362473ae7.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f2b62c19ca68fef8.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/board/page-d7602d489edf5f37.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/botlab/page-24282bf9f90031a5.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/bots/page-8b7c5ab6b5bc8d64.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/ceo/page-4eb84d454f8c3415.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/chat/page-b2e494bdad57fcb5.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/consult/{page-80ed511e02c81412.js → page-c0ab229673a8b0eb.js} +1 -1
  134. package/apps/pwa/out/_next/static/chunks/app/control/page-3e2b45f3c36dbac4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/decisions/page-c22aa511b28743ad.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/design-check/page-26345242e4049f55.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/editor/page-bf88c0f558d8ef54.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/exec/page-52fec523e5b5d3ad.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/field/page-67723dfdcde92b31.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/healthz/route-a2aa8709d193ee0d.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/inside/page-22725e2570f1126b.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/intake/page-1891335950d68b70.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/layout-3267af1ebdc73cf5.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live/page-c314b75c11234998.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/live-run/page-9f9c85415f61782b.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/loops/page-c1d4276059085587.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/market/page-833aab587f26ad4c.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8526c17ae38e6a50.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/morning/page-f998637a8402115c.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/not-found-b7bb53828b17b335.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/observatory/page-1b1850de0257e46d.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6f23159fedb41f67.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1d809a87139dd024.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-da9e570234d481fd.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b92caddb5c715f30.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/page-8ce3a38e210b810a.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/reflection/page-57ffeeb6019440fd.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-abbb417bf514630b.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2c2b3f29cec1efa4.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-9369279f72fc7b51.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/settings/page-64861f14039499c3.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-ddc4c93efd8ab94b.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/layout-a2aa8709d193ee0d.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/page-901a1391b81053bc.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/share/page-68d9bbaac9841a58.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b5c0c996f329371e.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/tasks/page-89881ccbcf728978.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/term/page-0e87a803b3d7165e.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/today/page-58d4e5cb30ef4871.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/trace/page-02ce4c3b5f39e4d2.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/vault/page-e620d1bb8eadcec2.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-acf868c64d77f950.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workflows/page-54fa605fa6dba457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workspace/page-bc79f0833533fa84.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d5c4398eea03d8f3.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/b4e12462-5fab4a813a63dadd.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/cd39fa05.fac4545f42a3ef70.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/{f6b7c9ba.64a895b8b2fedbdc.js → ce383d63.d2ede338788ed18e.js} +1 -1
  179. package/apps/pwa/out/_next/static/chunks/{framework-5c169757551134ed.js → framework-b2763b10dc6b3836.js} +1 -1
  180. package/apps/pwa/out/_next/static/chunks/main-app-27893e93b0ec193d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/main-f280047194e1daf8.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_app-e90eff2d0b70564c.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/pages/_error-70f2d654b3435d34.js +1 -0
  184. package/apps/pwa/out/_next/static/chunks/webpack-4794f053bd5e4230.js +1 -0
  185. package/apps/pwa/out/_next/static/css/72becfd42807b50d.css +1 -0
  186. package/apps/pwa/out/_next/static/css/d0a48dc099ed86cf.css +1 -0
  187. package/apps/pwa/out/approvals/index.html +1 -1
  188. package/apps/pwa/out/approvals/index.txt +23 -23
  189. package/apps/pwa/out/autopilot/index.html +1 -1
  190. package/apps/pwa/out/autopilot/index.txt +23 -23
  191. package/apps/pwa/out/board/index.html +1 -1
  192. package/apps/pwa/out/board/index.txt +23 -23
  193. package/apps/pwa/out/botlab/index.html +1 -1
  194. package/apps/pwa/out/botlab/index.txt +22 -22
  195. package/apps/pwa/out/bots/index.html +1 -1
  196. package/apps/pwa/out/bots/index.txt +22 -22
  197. package/apps/pwa/out/ceo/index.html +1 -1
  198. package/apps/pwa/out/ceo/index.txt +23 -23
  199. package/apps/pwa/out/chat/index.html +1 -1
  200. package/apps/pwa/out/chat/index.txt +22 -22
  201. package/apps/pwa/out/consult/index.html +1 -1
  202. package/apps/pwa/out/consult/index.txt +23 -23
  203. package/apps/pwa/out/control/index.html +1 -1
  204. package/apps/pwa/out/control/index.txt +23 -23
  205. package/apps/pwa/out/decisions/index.html +1 -1
  206. package/apps/pwa/out/decisions/index.txt +22 -22
  207. package/apps/pwa/out/design-check/index.html +1 -1
  208. package/apps/pwa/out/design-check/index.txt +23 -23
  209. package/apps/pwa/out/editor/index.html +1 -1
  210. package/apps/pwa/out/editor/index.txt +24 -23
  211. package/apps/pwa/out/exec/index.html +1 -1
  212. package/apps/pwa/out/exec/index.txt +23 -23
  213. package/apps/pwa/out/field/index.html +1 -1
  214. package/apps/pwa/out/field/index.txt +23 -23
  215. package/apps/pwa/out/healthz +1 -1
  216. package/apps/pwa/out/index.html +1 -1
  217. package/apps/pwa/out/index.txt +22 -22
  218. package/apps/pwa/out/inside/index.html +1 -1
  219. package/apps/pwa/out/inside/index.txt +22 -22
  220. package/apps/pwa/out/intake/index.html +1 -1
  221. package/apps/pwa/out/intake/index.txt +23 -23
  222. package/apps/pwa/out/live/index.html +1 -1
  223. package/apps/pwa/out/live/index.txt +23 -23
  224. package/apps/pwa/out/live-run/index.html +1 -1
  225. package/apps/pwa/out/live-run/index.txt +24 -23
  226. package/apps/pwa/out/loops/index.html +1 -1
  227. package/apps/pwa/out/loops/index.txt +22 -22
  228. package/apps/pwa/out/market/index.html +1 -1
  229. package/apps/pwa/out/market/index.txt +22 -22
  230. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  231. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  232. package/apps/pwa/out/morning/index.html +1 -1
  233. package/apps/pwa/out/morning/index.txt +23 -23
  234. package/apps/pwa/out/observatory/index.html +1 -1
  235. package/apps/pwa/out/observatory/index.txt +23 -23
  236. package/apps/pwa/out/ops/checklist/index.html +1 -1
  237. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  238. package/apps/pwa/out/ops/release/index.html +1 -1
  239. package/apps/pwa/out/ops/release/index.txt +22 -22
  240. package/apps/pwa/out/ops/seats/index.html +1 -1
  241. package/apps/pwa/out/ops/seats/index.txt +22 -22
  242. package/apps/pwa/out/outputs/index.html +1 -1
  243. package/apps/pwa/out/outputs/index.txt +22 -22
  244. package/apps/pwa/out/reflection/index.html +1 -1
  245. package/apps/pwa/out/reflection/index.txt +23 -23
  246. package/apps/pwa/out/scheduler/index.html +1 -1
  247. package/apps/pwa/out/scheduler/index.txt +23 -23
  248. package/apps/pwa/out/sessions/index.html +1 -1
  249. package/apps/pwa/out/sessions/index.txt +22 -22
  250. package/apps/pwa/out/settings/devices/index.html +1 -1
  251. package/apps/pwa/out/settings/devices/index.txt +23 -23
  252. package/apps/pwa/out/settings/index.html +1 -1
  253. package/apps/pwa/out/settings/index.txt +23 -23
  254. package/apps/pwa/out/setup/done/index.html +1 -1
  255. package/apps/pwa/out/setup/done/index.txt +23 -23
  256. package/apps/pwa/out/setup/index.html +1 -1
  257. package/apps/pwa/out/setup/index.txt +23 -23
  258. package/apps/pwa/out/share/index.html +1 -1
  259. package/apps/pwa/out/share/index.txt +23 -23
  260. package/apps/pwa/out/showroom/index.html +1 -1
  261. package/apps/pwa/out/showroom/index.txt +22 -22
  262. package/apps/pwa/out/tasks/index.html +1 -1
  263. package/apps/pwa/out/tasks/index.txt +23 -23
  264. package/apps/pwa/out/term/index.html +1 -1
  265. package/apps/pwa/out/term/index.txt +23 -23
  266. package/apps/pwa/out/today/index.html +1 -1
  267. package/apps/pwa/out/today/index.txt +23 -23
  268. package/apps/pwa/out/trace/index.html +1 -1
  269. package/apps/pwa/out/trace/index.txt +23 -23
  270. package/apps/pwa/out/vault/index.html +1 -1
  271. package/apps/pwa/out/vault/index.txt +23 -23
  272. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  273. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  274. package/apps/pwa/out/workflows/index.html +1 -1
  275. package/apps/pwa/out/workflows/index.txt +23 -23
  276. package/apps/pwa/out/workspace/index.html +1 -1
  277. package/apps/pwa/out/workspace/index.txt +23 -23
  278. package/apps/pwa/out/worktrees/index.html +1 -1
  279. package/apps/pwa/out/worktrees/index.txt +23 -23
  280. package/catalog/models/anthropic/claude-haiku-5-5.yaml +32 -0
  281. package/catalog/models/anthropic/claude-opus-5-5.yaml +5 -0
  282. package/catalog/models/anthropic/claude-sonnet-5-5.yaml +31 -0
  283. package/catalog/models/anthropic/claude-sonnet-5.yaml +8 -2
  284. package/catalog/models/openai/gpt-6-astra.yaml +6 -0
  285. package/catalog/models/openai/gpt-6-luna.yaml +6 -0
  286. package/catalog/models/openai/gpt-6-sol.yaml +6 -0
  287. package/catalog/models/openrouter/deepseek-v4-pro-0813.yaml +39 -0
  288. package/catalog/models/openrouter/deepseek-v4.1-flash.yaml +38 -0
  289. package/catalog/models/openrouter/glm-5.3-flash.yaml +35 -0
  290. package/catalog/providers/openrouter.yaml +2 -0
  291. package/graphs/implement-loop.yaml +31 -0
  292. package/graphs/log-horizon/log-horizon-watch.yaml +25 -0
  293. package/graphs/log-horizon/recipes.yaml +3 -0
  294. package/graphs/ops/harness-gc.yaml +17 -0
  295. package/graphs/ops/recipes.yaml +3 -0
  296. package/graphs/overlays/README.md +1 -1
  297. package/graphs/overlays/stop-heal-ladder.yaml +105 -0
  298. package/graphs/release/recipes.yaml +1 -1
  299. package/graphs/release/release-loop.yaml +6 -2
  300. package/graphs/release-rehearsal/recipes.yaml +12 -0
  301. package/graphs/release-rehearsal/release-rehearsal.yaml +17 -0
  302. package/package.json +4 -1
  303. package/scripts/add-api-key.sh +1 -1
  304. package/scripts/bench-report.ts +82 -3
  305. package/scripts/ci-typecheck-changed.ts +80 -14
  306. package/scripts/fleet/bedrock-pod-secret.ts +122 -0
  307. package/scripts/fleet/node-setup-linux.sh +97 -0
  308. package/scripts/fleet/node-setup.sh +11 -0
  309. package/scripts/fleet/zai-pod-secret.ts +86 -0
  310. package/scripts/hq/hq-fence-wrapper.sh +148 -0
  311. package/scripts/land-global-checks.ts +3 -0
  312. package/scripts/lib/typecheck-ratchet.ts +51 -0
  313. package/scripts/measure-log-diet-2.ts +213 -0
  314. package/scripts/measure-tsc-affected-roots.ts +289 -0
  315. package/scripts/openai-relay-server.ts +5 -1
  316. package/scripts/release-loop/docs-node.ts +258 -43
  317. package/scripts/release-loop/gate-executor.ts +28 -0
  318. package/scripts/release-loop/gate-method.ts +59 -0
  319. package/scripts/release-loop/gate-node.ts +335 -33
  320. package/scripts/release-loop/gate-wall.ts +208 -0
  321. package/scripts/release-loop/known-issues-node.ts +53 -8
  322. package/scripts/release-loop/publish-at.ts +14 -0
  323. package/scripts/release-loop/publish-node.ts +17 -2
  324. package/scripts/release-loop/resume-release.ts +40 -4
  325. package/scripts/release-loop/resume.ts +94 -0
  326. package/scripts/release-loop/shard-plan.ts +3 -11
  327. package/scripts/release-loop/tui-node-checks.ts +22 -0
  328. package/scripts/release-loop/unattended-release.ts +29 -7
  329. package/scripts/rhythm/daily.ts +51 -2
  330. package/scripts/rhythm/weekly.ts +3 -2
  331. package/scripts/tsc-baseline-cache.ts +147 -0
  332. package/scripts/tsc-main-safety-net.ts +189 -0
  333. package/scripts/usage-rollup.ts +64 -8
  334. package/src/acp/codex-plugins.ts +48 -6
  335. package/src/agent/monad-agent-turn.ts +67 -5
  336. package/src/agent/run-context.ts +20 -0
  337. package/src/agent/tool-profile.ts +28 -2
  338. package/src/agent-mission/acp-judge.ts +8 -2
  339. package/src/agent-mission/capabilities-cli.ts +16 -1
  340. package/src/agent-mission/driver.ts +19 -4
  341. package/src/agent-mission/pr-review-watch.ts +6 -2
  342. package/src/agent-mission/resource-ladder.ts +8 -3
  343. package/src/agent-mission/review-loop.ts +41 -7
  344. package/src/agent-substrate/acp-implementer.ts +139 -0
  345. package/src/agent-substrate/acp-reviewer.ts +17 -8
  346. package/src/agent-substrate/pr-reviewer.ts +191 -28
  347. package/src/agent-substrate/review-intent.ts +6 -4
  348. package/src/agent-substrate/self-review-cli.ts +155 -21
  349. package/src/agent-substrate/shard-boundary-intent.ts +92 -26
  350. package/src/ask-user-question/pending-questions.ts +8 -2
  351. package/src/autopilot/build/llm-conflict-merge.ts +216 -12
  352. package/src/autopilot/codebase-grounding.ts +44 -0
  353. package/src/autopilot/llm-control-brain.ts +13 -1
  354. package/src/autopilot/mission-codebase-gate.ts +8 -77
  355. package/src/autopilot/mission-critique.ts +18 -5
  356. package/src/autopilot/mission-feasibility-negotiate.ts +11 -10
  357. package/src/autopilot/mission-trace.ts +12 -1
  358. package/src/autopilot/pr-manager.ts +12 -3
  359. package/src/autopilot/system-lookback-run.ts +16 -10
  360. package/src/bench/bench.ts +183 -0
  361. package/src/boot/acp-server.ts +4 -7
  362. package/src/boot/acp-socket-path.ts +7 -0
  363. package/src/briefing/brief-items.ts +21 -13
  364. package/src/budget/fetchers/grok.ts +15 -5
  365. package/src/budget/llm-cost.ts +37 -5
  366. package/src/budget/types.ts +8 -2
  367. package/src/budget/unified-usage.ts +88 -6
  368. package/src/chat/index.ts +12 -3
  369. package/src/cli/agent-cli.ts +20 -0
  370. package/src/cli/bench-cli.ts +34 -0
  371. package/src/cli/brief-cli.ts +27 -21
  372. package/src/cli/cli-user-error.ts +9 -2
  373. package/src/cli/guardian-cli.ts +26 -1
  374. package/src/cli/image-cli.ts +101 -0
  375. package/src/cli/log-event-names.ts +7 -0
  376. package/src/cli/logs-cli.ts +1 -0
  377. package/src/cli/mcp-login.ts +111 -37
  378. package/src/cli/plugin-cli.ts +21 -1
  379. package/src/cli/pod-cli.ts +26 -0
  380. package/src/cli/pr-cli.ts +90 -5
  381. package/src/cli/pr-land-overlap-evidence.ts +279 -0
  382. package/src/cli/release-cli.ts +63 -12
  383. package/src/cli/rfc-status.ts +52 -2
  384. package/src/cli/self-update.ts +277 -10
  385. package/src/cli/skills-cli.ts +12 -3
  386. package/src/cli/tasks-cli.ts +241 -30
  387. package/src/cli/usage-cli.ts +91 -8
  388. package/src/context-bus/context-first.ts +51 -2
  389. package/src/context-bus/context-now-surfaces.ts +13 -2
  390. package/src/context-bus/long-term-memory.ts +3 -1
  391. package/src/context-bus/nightly-condense.ts +3 -2
  392. package/src/core-turn/run-goal-loop.ts +87 -2
  393. package/src/dashboard/ad-run-setup-bindings.ts +279 -0
  394. package/src/dashboard/chat-fold.ts +20 -0
  395. package/src/dashboard/first-screen-band.ts +151 -1
  396. package/src/dashboard/index.ts +45 -281
  397. package/src/dashboard/slash-runtime/dashboard-handlers.ts +5 -3
  398. package/src/dashboard/stale-install-check.ts +24 -2
  399. package/src/dashboard/turn-stream-formatter.ts +25 -0
  400. package/src/debug/log-diet.ts +190 -0
  401. package/src/debug/log.ts +70 -17
  402. package/src/display/coordinator.ts +25 -2
  403. package/src/domains/coo-admin-tool.ts +27 -0
  404. package/src/domains/cron-match.ts +1 -0
  405. package/src/domains/outbound-alert.ts +17 -6
  406. package/src/domains/release-tool.ts +158 -10
  407. package/src/domains/schedule-registry.ts +10 -7
  408. package/src/domains/schedule-runner.ts +1 -0
  409. package/src/elanous-config-dir.ts +2 -2
  410. package/src/elanous-daemon.ts +3 -3
  411. package/src/error-report/report.ts +21 -4
  412. package/src/execution-loop/launch-gate.ts +1 -1
  413. package/src/expression/i18n/messages.en.ts +5 -0
  414. package/src/expression/i18n/messages.ja.ts +5 -0
  415. package/src/expression/i18n/messages.ko.ts +5 -0
  416. package/src/expression/i18n/messages.zh.ts +5 -0
  417. package/src/expression/i18n/types.ts +8 -0
  418. package/src/github/pr-labels.ts +2 -0
  419. package/src/graph-runner/graph-cli.ts +42 -1
  420. package/src/graph-runner/runner.ts +218 -8
  421. package/src/grok/usage.ts +23 -2
  422. package/src/grounding/ref-index.ts +253 -0
  423. package/src/harness/dispatch-backpressure.ts +267 -0
  424. package/src/harness/harness-clean.ts +199 -78
  425. package/src/harness/harness-cli-command.ts +229 -35
  426. package/src/harness/harness-gc.ts +331 -0
  427. package/src/harness/harness-seams.ts +2 -20
  428. package/src/harness/harness-stop.ts +4 -2
  429. package/src/harness/harness-substrate-default.ts +214 -8
  430. package/src/harness/launch-registry.ts +6 -0
  431. package/src/harness/nested-elanous-policy.ts +4 -2
  432. package/src/harness/worktree-branch-prefix.ts +9 -0
  433. package/src/hq/fence-wrapper.ts +7 -0
  434. package/src/hq/fence.ts +187 -0
  435. package/src/hq/hq.ts +33 -2
  436. package/src/hq/lease.ts +13 -0
  437. package/src/hq/seats.ts +133 -21
  438. package/src/images/image-ledger.ts +179 -0
  439. package/src/index.ts +250 -69
  440. package/src/instance/child-scope.ts +32 -1
  441. package/src/instance/dev-project.ts +133 -0
  442. package/src/instance/resolve.ts +24 -0
  443. package/src/instance/spawn-elanous.ts +45 -0
  444. package/src/intake-plane/collect-github.ts +19 -1
  445. package/src/intake-plane/digest.ts +45 -20
  446. package/src/intake-plane/lens.ts +36 -8
  447. package/src/intake-plane/ref-prefetch.ts +110 -0
  448. package/src/intelligence-map/model-alias.ts +6 -0
  449. package/src/intelligence-map/model-catalog.ts +113 -0
  450. package/src/knowledge/kgs/pack.ts +5 -2
  451. package/src/knowledge/kgs/sqlite-store.ts +15 -0
  452. package/src/knowledge/tools/knowledge-query.ts +20 -2
  453. package/src/knowledge/write.ts +234 -2
  454. package/src/llm/bedrock-eventstream.ts +215 -0
  455. package/src/llm/bedrock-provider.ts +248 -0
  456. package/src/llm/bedrock.ts +491 -0
  457. package/src/llm/openrouter-byok-cost.ts +96 -0
  458. package/src/llm/openrouter-deepseek.ts +151 -0
  459. package/src/llm/openrouter-upstream-pins.config.ts +25 -0
  460. package/src/llm/provider-credentials.ts +3 -1
  461. package/src/llm/zai-coding-plan.ts +700 -0
  462. package/src/llm.ts +383 -41
  463. package/src/loops/budget.ts +150 -0
  464. package/src/loops/checker.ts +148 -9
  465. package/src/loops/orchestrator/resync-shadow.ts +34 -7
  466. package/src/loops/orchestrator/seat-share.ts +6 -49
  467. package/src/loops/orchestrator/traffic.ts +5 -81
  468. package/src/market/signed-index.ts +42 -0
  469. package/src/maturity/feature-maturity.ts +2 -2
  470. package/src/mcp/mcp-oauth.ts +136 -17
  471. package/src/model-tier/llm-tier-map.ts +52 -4
  472. package/src/models/prompts.ts +23 -1
  473. package/src/mss/logging/horizon-watch.ts +168 -0
  474. package/src/mss/logging/log-store.ts +262 -26
  475. package/src/native-tool-catalog.ts +1 -1
  476. package/src/nexus/api/consult-requests.ts +7 -10
  477. package/src/nexus/api/discord-trigger-bot.ts +6 -3
  478. package/src/nexus/api/error-reports.ts +30 -8
  479. package/src/nexus/api/http-server.ts +8 -0
  480. package/src/nexus/api/loop-resources.ts +42 -0
  481. package/src/nexus/api/missions.ts +73 -2
  482. package/src/nexus/api/ops-api.ts +18 -0
  483. package/src/nexus/api/outbound-report.ts +8 -3
  484. package/src/nexus/api/telegram-trigger-bot.ts +6 -3
  485. package/src/nexus/index.ts +17 -75
  486. package/src/nexus/outbound/format.ts +2 -0
  487. package/src/nexus/outbound/router.ts +198 -13
  488. package/src/nexus/tools-kind.ts +78 -0
  489. package/src/oauth/codex-account-rotation.ts +55 -20
  490. package/src/oauth/codex-account-store.ts +451 -23
  491. package/src/oauth/fallback-chain.ts +75 -15
  492. package/src/onboarding/first-run.ts +37 -18
  493. package/src/onboarding/web-first.ts +20 -2
  494. package/src/onboarding.ts +2 -1
  495. package/src/ops/machine-heartbeat.ts +185 -0
  496. package/src/ops/overview-cache.ts +175 -0
  497. package/src/ops/overview.ts +8 -0
  498. package/src/plugins/adapters/claude-package.ts +4 -12
  499. package/src/plugins/core/capability-policy.ts +141 -0
  500. package/src/plugins/core/host.ts +21 -8
  501. package/src/plugins/core/manifest.ts +19 -2
  502. package/src/plugins/core/trust-store.ts +15 -0
  503. package/src/plugins/core/types.ts +12 -0
  504. package/src/plugins/install/market-fetch.ts +68 -16
  505. package/src/plugins/install/plugin-install.ts +187 -16
  506. package/src/plugins/maker/plugin-maker.ts +25 -20
  507. package/src/plugins/maker/wizard-generate.ts +16 -2
  508. package/src/policy/llm-policy.ts +14 -1
  509. package/src/process/pid-liveness.ts +1 -1
  510. package/src/prompt-cache/openai.ts +13 -6
  511. package/src/prompt-cache/openrouter.ts +94 -0
  512. package/src/prompt-cache/types.ts +5 -0
  513. package/src/prompt-enhance/enhance.ts +69 -5
  514. package/src/prompt-library/family-prompt-coverage.ts +1 -0
  515. package/src/prompt-library/universal-preamble.ts +2 -2
  516. package/src/registry/discovery/openrouter-live-resolve.ts +122 -0
  517. package/src/registry/loader.ts +6 -1
  518. package/src/release-loop/checklist.ts +24 -9
  519. package/src/release-loop/feature-store.ts +3 -0
  520. package/src/release-loop/gate-shards.ts +48 -4
  521. package/src/release-loop/landed-to-green.ts +81 -0
  522. package/src/release-loop/light-rc.ts +11 -1
  523. package/src/release-loop/merged-pr-checklist.ts +10 -0
  524. package/src/release-loop/placement.ts +107 -23
  525. package/src/release-loop/rehearsal.ts +317 -0
  526. package/src/release-loop/release-schedule.ts +13 -1
  527. package/src/release-loop/rubric-types.ts +1 -0
  528. package/src/release-loop/rubric.ts +2 -2
  529. package/src/requirements/requirement-ledger.ts +536 -0
  530. package/src/retro/daily.ts +26 -12
  531. package/src/seat-loop/seat-loop.ts +66 -11
  532. package/src/seat-loop/traffic-signal.ts +44 -0
  533. package/src/self-dev/ask-launch-flow.ts +2 -2
  534. package/src/self-dev/dev-cli.ts +109 -11
  535. package/src/self-dev/dev-pipeline.ts +11 -8
  536. package/src/self-dev/draft-residue.ts +475 -0
  537. package/src/self-dev/draft-sweep.ts +254 -10
  538. package/src/self-dev/draft-triage-rules.ts +27 -1
  539. package/src/self-dev/graph-journey-route.ts +6 -0
  540. package/src/self-dev/launch-preflight-text.ts +549 -0
  541. package/src/self-dev/launch-preflight.ts +10 -545
  542. package/src/self-dev/orchestrate-cli.ts +82 -5
  543. package/src/self-dev/orchestrate-summary-line.ts +13 -0
  544. package/src/self-dev/orchestrate.ts +49 -141
  545. package/src/self-dev/review-provider-fallback.ts +115 -19
  546. package/src/self-dev/run-store.ts +1 -3
  547. package/src/self-dev/run-supervisor.ts +190 -36
  548. package/src/self-dev/run-types.ts +191 -0
  549. package/src/self-dev/shard-aggregate.ts +61 -13
  550. package/src/self-dev/shard-plan.ts +5 -1
  551. package/src/self-dev/shard-run.ts +23 -5
  552. package/src/self-dev/supervisor-verdict-edges.ts +3 -4
  553. package/src/self-implement/blocked-draft-policy.ts +3 -19
  554. package/src/self-implement/budget-gate.ts +53 -13
  555. package/src/self-implement/child-context-composition.ts +139 -0
  556. package/src/self-implement/child-llm-preference.ts +13 -5
  557. package/src/self-implement/claude-acp-implement.ts +67 -0
  558. package/src/self-implement/draft-on-stop-mode.ts +18 -0
  559. package/src/self-implement/flex-signals.ts +59 -0
  560. package/src/self-implement/follow-up-goals.ts +114 -38
  561. package/src/self-implement/frozen-merges.ts +8 -3
  562. package/src/self-implement/gate-baseline-reap.ts +157 -0
  563. package/src/self-implement/gate-baseline.ts +78 -16
  564. package/src/self-implement/gate-cli.ts +12 -2
  565. package/src/self-implement/gate-remote.ts +17 -6
  566. package/src/self-implement/goal-author-decompose.ts +10 -2
  567. package/src/self-implement/goal-author.ts +48 -13
  568. package/src/self-implement/goal-digest.ts +19 -0
  569. package/src/self-implement/graph-overlay-condition.ts +32 -0
  570. package/src/self-implement/graph-overlay-yaml.ts +41 -7
  571. package/src/self-implement/graph-templates.ts +33 -1
  572. package/src/self-implement/graph-yaml.ts +56 -0
  573. package/src/self-implement/headless-elanous-driver.ts +11 -9
  574. package/src/self-implement/heal-intake.ts +5 -1
  575. package/src/self-implement/host-regate.ts +120 -29
  576. package/src/self-implement/l8-merge-queue.ts +67 -5
  577. package/src/self-implement/merge-train.ts +131 -0
  578. package/src/self-implement/off-diff-evidence.ts +9 -0
  579. package/src/self-implement/orchestrator.ts +271 -25
  580. package/src/self-implement/review-finding-recurrence.ts +28 -0
  581. package/src/self-implement/rework-policy.ts +2 -1
  582. package/src/self-implement/round-summary-card.ts +63 -0
  583. package/src/self-implement/run-ledger.ts +4 -3
  584. package/src/self-implement/run-step-projection.ts +147 -0
  585. package/src/self-implement/run-stop.ts +1 -1
  586. package/src/self-implement/running-runs.ts +75 -5
  587. package/src/self-implement/seams.ts +83 -4
  588. package/src/self-implement/self-implement-cli.ts +12 -5
  589. package/src/self-implement/stop-autoheal.ts +69 -2
  590. package/src/self-implement/train-gate-remote.ts +158 -0
  591. package/src/session-runtime/index.ts +10 -1
  592. package/src/session-runtime/retry-api.ts +11 -1
  593. package/src/session-runtime/retry-policy.ts +2 -1
  594. package/src/skills/gift-install.ts +119 -0
  595. package/src/skills/runner.ts +59 -2
  596. package/src/skills/skill-feedback.ts +31 -1
  597. package/src/skills/skill-tier.ts +1 -0
  598. package/src/smart-wizard/capability-index.ts +231 -0
  599. package/src/smart-wizard/rung.ts +74 -0
  600. package/src/steward/launch.ts +22 -10
  601. package/src/steward/triage-budget.ts +62 -0
  602. package/src/steward/triage.ts +87 -24
  603. package/src/storage/file-lock.ts +8 -1
  604. package/src/task-agent/actions.ts +66 -5
  605. package/src/task-agent/card-evidence.ts +59 -13
  606. package/src/task-agent/completion-evidence.ts +5 -0
  607. package/src/task-agent/cover.ts +101 -3
  608. package/src/task-agent/judge.ts +20 -3
  609. package/src/task-agent/land-order-ledger.ts +95 -0
  610. package/src/task-agent/land-worktree.ts +201 -0
  611. package/src/task-agent/live-move-history.ts +219 -0
  612. package/src/task-agent/live-moves.ts +451 -34
  613. package/src/task-agent/parent-host.ts +117 -8
  614. package/src/task-agent/rejudge-on-head.ts +352 -0
  615. package/src/task-agent/review-prior-fix.ts +146 -0
  616. package/src/task-agent/review-result-capture.ts +218 -0
  617. package/src/task-agent/run-adopt.ts +136 -0
  618. package/src/task-agent/shadow.ts +154 -14
  619. package/src/task-agent/task-hand.ts +186 -14
  620. package/src/task-orchestrator/surfaces/pod-account-broker.ts +38 -5
  621. package/src/task-orchestrator/surfaces/pod-bedrock-child.ts +74 -0
  622. package/src/task-orchestrator/surfaces/pod-child-default.ts +50 -0
  623. package/src/task-orchestrator/surfaces/pod-child-providers.ts +42 -0
  624. package/src/task-orchestrator/surfaces/pod-command-job.ts +6 -3
  625. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +94 -7
  626. package/src/task-orchestrator/surfaces/pod-image-source.ts +212 -0
  627. package/src/task-orchestrator/surfaces/pod-lease.ts +110 -17
  628. package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +32 -3
  629. package/src/task-orchestrator/surfaces/pod-pool.ts +86 -18
  630. package/src/task-orchestrator/surfaces/pod-zai-child.ts +101 -0
  631. package/src/task-orchestrator/surfaces/self-implement-pod.ts +463 -50
  632. package/src/task-orchestrator/surfaces/self-implement.ts +25 -3
  633. package/src/telegram-service.ts +5 -1
  634. package/src/telegram.ts +17 -4
  635. package/src/time/format.ts +13 -4
  636. package/src/tool-runtime/goal-author-runtime.ts +1 -0
  637. package/src/tool-runtime/self-cognition-catalog.ts +23 -0
  638. package/src/tool-runtime/self-cognition-runtimes.ts +2 -24
  639. package/src/typecheck-ratchet.ts +1 -0
  640. package/src/user-config.ts +180 -32
  641. package/src/ux-sim/slash-menu-frames.ts +168 -0
  642. package/src/version/packed-revision.json +1 -1
  643. package/src/web-terminal/preview-tap-registry.ts +5 -2
  644. package/src/workflow-runtime/triggers/registry.ts +59 -0
  645. package/src/workflow-runtime/triggers/scheduler.ts +1 -0
  646. package/src/workflow-runtime/triggers/webhook-source.ts +35 -5
  647. package/apps/pwa/out/_next/static/chunks/1109.78a7a3288c0259d9.js +0 -148
  648. package/apps/pwa/out/_next/static/chunks/115.1c6690b8604f81c4.js +0 -32
  649. package/apps/pwa/out/_next/static/chunks/1262.76a3f08e67c5f816.js +0 -309
  650. package/apps/pwa/out/_next/static/chunks/1307-08b716476f1d50af.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/1358d292.5c87f12cad6eaa91.js +0 -122
  652. package/apps/pwa/out/_next/static/chunks/1438.27a1a7b8f2308004.js +0 -149
  653. package/apps/pwa/out/_next/static/chunks/1442.02d85cd88f4c1eac.js +0 -79
  654. package/apps/pwa/out/_next/static/chunks/1501-1aad662d82ba43f7.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/1584.9e2dd53da6e6d4b1.js +0 -24
  656. package/apps/pwa/out/_next/static/chunks/1586.b989b0614afb77e6.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/1609.2ad355062870151f.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/1612-f6df0fc0eed7157b.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/1923.37f1d5fe7ebe3860.js +0 -27
  661. package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/1993.3fd074a2a246234e.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/2140.d2daf9ee96e295d1.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/2212.0359851457473efc.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/224.583e562365a52f74.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/2328.0f37465646bafa7d.js +0 -36
  670. package/apps/pwa/out/_next/static/chunks/2372.bf71372184991937.js +0 -286
  671. package/apps/pwa/out/_next/static/chunks/2489-d238d3e2eb5b2bf5.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/2549-a8515c86f9e8cb96.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/2655.72cc6a97276c5acc.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/2743-ef6e8c3ced74cce5.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/2840-5458ad50c49cac6a.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/2856.f75d5baef7f49b74.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/3344.0de4b0ec5a454b7a.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/335.a13f339e97893437.js +0 -94
  684. package/apps/pwa/out/_next/static/chunks/3394.646348f34b2500be.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/3443.6276909b53d72d53.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/3495.abd4254d808bf2dc.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/3721.ba5b82db0d9a5572.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/3857-5985236d9307f676.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/3919.9ff7dc25afefee33.js +0 -74
  692. package/apps/pwa/out/_next/static/chunks/3998.bd9a69d9b50e9bd2.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/4003.ab6db1dc266576c9.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/4216.e8ac94b9fe6b96ab.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/4327.c44dc2b55cb43ee5.js +0 -34
  697. package/apps/pwa/out/_next/static/chunks/4401.94257d497b6d26bc.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/4559.17ca2cdbaa8d414f.js +0 -115
  699. package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/4706.97e734bd4c9816ca.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/4795-f372490b178583fc.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/4982.6e44352f751b9a1b.js +0 -77
  703. package/apps/pwa/out/_next/static/chunks/5342.49c5c5a530e62b50.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/5360-08a80abdf3a4da99.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/5431.66c58ab1327ee0b7.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/5633-d6852385000738ef.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/5717.bcfcb96e701b82e0.js +0 -90
  708. package/apps/pwa/out/_next/static/chunks/5755-30d102586789bf7f.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/5957.3f1a4012388dd962.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/5977-5b9e8a45a5b0c823.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/602.9bf02ac8e9502598.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/6020.3a1b347e2d2dfacc.js +0 -8
  713. package/apps/pwa/out/_next/static/chunks/6375.fce1d174ba6d0324.js +0 -64
  714. package/apps/pwa/out/_next/static/chunks/6546.92a828aef441271f.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/658.957fdb0a8c6c6c8e.js +0 -287
  716. package/apps/pwa/out/_next/static/chunks/6706.323590aabb8b1293.js +0 -226
  717. package/apps/pwa/out/_next/static/chunks/6747.b67947f293a4c02d.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/6868.000b24a3045c5574.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/6946.bba74e9c96050f30.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/7033.a558f1b2f6912a53.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/7065.46029c26c53eac50.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/7087.6fae577d09249bc1.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/722.de8d9801e0f6d414.js +0 -41
  725. package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/7497.57981e9d7a75a52a.js +0 -24
  728. package/apps/pwa/out/_next/static/chunks/7672.4af122ad892117c7.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/771.6ab889a233e7dae7.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/8096.f7da0776cfde6300.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/8769.815ca69879f608b4.js +0 -104
  738. package/apps/pwa/out/_next/static/chunks/8857-aa1cc4ac90af4d40.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/8f835b4f.048eeb02299e3e12.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/9068.5f2764fccf86c1b2.js +0 -93
  741. package/apps/pwa/out/_next/static/chunks/9103-60fbef33e66f0a46.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/9247-55bcfbb0e8057f59.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/9451.ebfb0dcc9c02250f.js +0 -23
  745. package/apps/pwa/out/_next/static/chunks/9559.e648369b1d57cf9a.js +0 -62
  746. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/approvals/page-88459e0903da2803.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-d85c43f46f58716b.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/board/page-4e645600579ae952.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/botlab/page-87edbfd19117823b.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/bots/page-7f0c2b7801ac6a54.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/ceo/page-bf1f030a9d1adffd.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/chat/page-cbaf66b1e1804adf.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/control/page-9f5610caaa06178c.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/decisions/page-ec8f3575e339de74.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/design-check/page-86d753e460f1a989.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/editor/page-4166a7d51cf0a57d.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/exec/page-2a19c5cd3b562580.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/field/page-b6a09cde2e07521a.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/inside/page-f7eae1518ca0c353.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/intake/page-456a8573ad811381.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/layout-8462d6a543cbb2d9.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/live/page-2974cdfb87c0f9c9.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f927ffa25f3c86d1.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/loops/page-abd86cd832aaa011.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/market/page-79daf68f6256adaa.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-8c3f168fc3f91939.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/morning/page-786fb4504d0f2fa9.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/not-found-75209f14597dcb8f.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/observatory/page-bf30affe3a85af7e.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1187a44b7515434b.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-3d0910185a66ed54.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-f401ee1dd5a26e25.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5dfe7604fd842784.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/page-76cf838050a8d681.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7ec8e289b4c14df6.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-8c8ac17d52be2a79.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/sessions/page-d359ab048d63a9d9.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-b8b345c880bf78d1.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/settings/page-f151cc10ad026940.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-9875f103057da433.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/setup/page-9789328af9a9aa62.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/share/page-bf495a1e284f4e00.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/showroom/page-a263d94bca4be22a.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/tasks/page-3962eab8ec58d16e.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/term/page-9abcfac07e02a542.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/today/page-bee49f927c333abb.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/trace/page-bac2d56dcb02d955.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/vault/page-937cbcc13176295c.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d09495594f7f480d.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/workflows/page-69cb93d1a2e57e0e.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/app/workspace/page-72ec543928d67c3e.js +0 -1
  795. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-82906eeda0186a7b.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/f6231284-45726550aba08fca.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/webpack-f2b4016b9b981bc8.js +0 -1
  802. package/apps/pwa/out/_next/static/css/f2bd5257e6af88d8.css +0 -1
  803. /package/apps/pwa/out/_next/static/{aBi6EyMtLsrl7J8eH4kF7 → Q-7iofoxOEv1WX18S35of}/_ssgManifest.js +0 -0
@@ -11,6 +11,7 @@ import { runGitCommand } from '../git-fs/runner.js';
11
11
  import * as llm from '../llm.js';
12
12
  import type { LLMMessage } from '../llm.js';
13
13
  import { debug } from '../debug/log.js';
14
+ import { resolveRoleLlm } from '../user-config.js';
14
15
  import { releasePathHold, releasePathHoldShouldPost, releasePathHoldComment, releasePathHoldCommentsArgs, releasePrFilePaths, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
15
16
  import { runAgentMission, resolveBackend, type AgentMissionResult, type EvidenceMode } from './driver.js';
16
17
  import { judgeWithAcp, prepareJudgeDiff } from './acp-judge.js';
@@ -31,6 +32,8 @@ export interface ReviewClassification {
31
32
  asks: string[];
32
33
  reason: string;
33
34
  classificationSource: ReviewClassificationSource;
35
+ /** TA-LAND-MUSTFIX-ZERO — 분류 JSON 의 asks 가 없거나 배열이 아니거나 문자열 아닌 원소가 섞였다. `asks: []` 는 그때 «0» 이 아니라 «모름». */
36
+ asksUnreadable?: true;
34
37
  }
35
38
 
36
39
  export interface ReviewLoopOpts {
@@ -115,6 +118,16 @@ function gh(args: string[]): string {
115
118
  return execFileSync('gh', args, { encoding: 'utf8', timeout: 60000, maxBuffer: 20 * 1024 * 1024, env: process.env });
116
119
  }
117
120
 
121
+ /** TA-LAND-MUSTFIX-ZERO — 자동 병합 «직전» must-fix 관문(#25941 `canAuto` 와 같은 축).
122
+ * 남은 지적(asks)이 있으면 `review-warn-with-must-fix` · 목록 자체가 배열이 아니면 «0» 이 아니라
123
+ * «모름» = `review-must-fix-unknown`(fail-closed). 막을 때 `review-loop` 범주에 `auto-merge-blocked` 를 남긴다. */
124
+ function reviewMergeMustFixBlock(pr: string, stage: 'initial-ok' | 'final-judge', asks: unknown, unreadable: boolean, round?: number): 'review-warn-with-must-fix' | 'review-must-fix-unknown' | null {
125
+ const known = Array.isArray(asks) && !unreadable;
126
+ const reason = !known ? 'review-must-fix-unknown' : (asks as unknown[]).length > 0 ? 'review-warn-with-must-fix' : null;
127
+ if (reason) debug.log('review-loop', 'auto-merge-blocked', { pr, stage, reason, mustFixCount: known ? (asks as unknown[]).length : null, ...(round !== undefined ? { round } : {}) });
128
+ return reason;
129
+ }
130
+
118
131
  /** Check every page of the PR file list immediately before an unattended review-loop merge. */
119
132
  function holdReleasePathBeforeReviewMerge(pr: string, runGh: (args: string[]) => string): boolean {
120
133
  let paths: string[];
@@ -254,10 +267,16 @@ export async function judgeAndFinalize(
254
267
  debug.log('review-loop', 'judge-start', { pr, round, diffChars: preparedDiff.totalChars, judgeBackend: judgeBackendResolution.backend, judgeBackendSource: judgeBackendResolution.source });
255
268
  const judge = opts.judge ?? judgeWithAcp;
256
269
  const j = await judge({ diff, context: `반영한 지적:\n${asks.join('\n')}${reviewerContext}`, gatePassed: true, cwd, backend: judgeBackendResolution.backend, ...(opts.judgeModel ? { model: opts.judgeModel } : {}) });
257
- debug.log('review-loop', 'judge-verdict', { pr, round, verdict: j.verdict, asks: j.asks.length });
270
+ debug.log('review-loop', 'judge-verdict', { pr, round, verdict: j.verdict, asks: Array.isArray(j.asks) ? j.asks.length : null });
258
271
  const diffScope = `심판 diff 범위: 본 ${preparedDiff.judgeChars}자 / 전체 ${preparedDiff.totalChars}자`;
259
272
 
260
273
  if (j.verdict === 'merge') {
274
+ // TA-LAND-MUSTFIX-ZERO — 심판이 «merge» 라도 남긴 asks(미해결 지적)가 있으면 자동 병합하지 않는다 → HITL.
275
+ const mustFixBlock = opts.autoMerge ? reviewMergeMustFixBlock(pr, 'final-judge', j.asks, j.asksUnreadable === true, round) : null;
276
+ if (mustFixBlock) {
277
+ try { runGh(['pr', 'comment', pr, '--body', `🛑 ACP Claude Code 2차 최종심판: **MERGE** 이나 미해결 지적이 남아 자동 병합하지 않음(${mustFixBlock} · 라운드 ${round}) → 대표 결정 필요.\n${diffScope}\n사유: ${j.reason}`]); } catch { /* noop */ }
278
+ return { pr, branch, verdict: 'reinforce', asks: Array.isArray(j.asks) ? j.asks : asks, action: 'parked', reworkOk: true, pushed: lastPushed, rounds: round, detail: `2차 심판 MERGE ⊕ ${mustFixBlock} → HITL: ${j.reason}` };
279
+ }
261
280
  if (opts.autoMerge) {
262
281
  if (holdReleasePathBeforeReviewMerge(pr, runGh)) return { pr, branch, verdict: 'reinforce', asks, action: 'parked', reworkOk: true, pushed: lastPushed, rounds: round, detail: 'OP approval required: release-path hold or PR file inspection unavailable' };
263
282
  const approve = opts.approve ?? approvePr;
@@ -279,7 +298,7 @@ export async function judgeAndFinalize(
279
298
  try { runGh(['pr', 'comment', pr, '--body', `🛑 ACP Claude Code 2차 최종심판: **${j.verdict.toUpperCase()}** (라운드 ${round}) → 대표 결정 필요.\n${diffScope}\n사유: ${j.reason}`]); } catch { /* noop */ }
280
299
  return { pr, branch, verdict: 'reinforce', asks, action: 'parked', reworkOk: true, pushed: lastPushed, rounds: round, detail: `2차 심판 ${j.verdict} → HITL: ${j.reason}` };
281
300
  }
282
- return { rework: j.asks.length > 0 ? j.asks : asks };
301
+ return { rework: Array.isArray(j.asks) && j.asks.length > 0 ? j.asks : asks };
283
302
  }
284
303
 
285
304
  export interface LatestReviewSource {
@@ -421,15 +440,21 @@ asks: reinforce 일 때 codex 가 반영할 **구체 지적 목록**(각 한 줄
421
440
  JSON 만: {"verdict":"...","asks":["..."],"reason":"..."}`;
422
441
  const messages: LLMMessage[] = [{ role: 'system', content: sys }, { role: 'user', content: body.slice(0, 6000) }];
423
442
  let raw = '';
424
- try { raw = await llm.streamLLM(messages, () => {}, { maxTokens: 700, temperature: 0.1 }); }
425
- catch (e) { return { verdict: 'ambiguous', asks: [], reason: `분류 오류: ${describeThrownValue(e)}`, classificationSource: 'llm-call-failure' }; }
443
+ try {
444
+ const resolved = resolveRoleLlm('classify');
445
+ const provider = llm.PROVIDERS[resolved.provider];
446
+ if (!provider) throw new Error(`Unknown classify provider: ${resolved.provider}`);
447
+ debug.log('llm.role-pin', 'resolved', { site: 'classify-review', role: 'classify', model: resolved.model, provider: resolved.provider, source: resolved.source });
448
+ raw = await llm.streamLLM(messages, () => {}, { model: resolved.model, provider, usageRole: 'classify', maxTokens: 700, temperature: 0.1 });
449
+ } catch (e) { return { verdict: 'ambiguous', asks: [], reason: `분류 오류: ${describeThrownValue(e)}`, classificationSource: 'llm-call-failure' }; }
426
450
  const jm = raw.match(/\{[\s\S]*\}/);
427
451
  if (!jm) return { verdict: 'ambiguous', asks: [], reason: 'JSON 파싱 실패', classificationSource: 'llm' };
428
452
  try {
429
453
  const d = JSON.parse(jm[0]) as { verdict?: string; asks?: unknown; reason?: string };
430
454
  const verdict = (['ok', 'reinforce', 'reject', 'ambiguous'] as const).includes(d.verdict as ReviewVerdict) ? (d.verdict as ReviewVerdict) : 'ambiguous';
431
455
  const asks = Array.isArray(d.asks) ? d.asks.filter((x): x is string => typeof x === 'string') : [];
432
- return { verdict, asks, reason: typeof d.reason === 'string' ? d.reason : '', classificationSource: 'llm' };
456
+ const asksUnreadable = !Array.isArray(d.asks) || asks.length !== d.asks.length;
457
+ return { verdict, asks, reason: typeof d.reason === 'string' ? d.reason : '', classificationSource: 'llm', ...(asksUnreadable ? { asksUnreadable: true as const } : {}) };
433
458
  } catch { return { verdict: 'ambiguous', asks: [], reason: 'JSON 파싱 실패', classificationSource: 'llm' }; }
434
459
  }
435
460
 
@@ -497,15 +522,24 @@ export async function runReviewLoop(pr: string, opts: ReviewLoopOpts = {}): Prom
497
522
  debug.log('review-loop', 'classified', {
498
523
  pr,
499
524
  verdict: cls.verdict,
500
- asks: cls.asks.length,
525
+ asks: Array.isArray(cls.asks) ? cls.asks.length : null, // 목록 없음 = null(«0» 아님) — 아래 must-fix 관문이 막는다
501
526
  source: opts.injectedReview ? 'injected' : 'gh',
502
527
  reason: cls.reason,
503
528
  classificationSource: cls.classificationSource,
504
529
  });
505
530
 
506
- let asks = cls.asks;
531
+ let asks = Array.isArray(cls.asks) ? cls.asks : []; // 목록 없음·못 읽음은 아래 자동 병합 관문이 cls 로 막는다 · rework/명확화 소비처만 `[]` 로 읽는다
507
532
 
508
533
  if (cls.verdict === 'ok') {
534
+ // TA-LAND-MUSTFIX-ZERO — 1차 «ok» 에 지적(asks)이 남았거나 목록을 못 읽으면 자동 병합 경로로 가지 않는다(승인도 안 함) → HITL.
535
+ // light·heavy 둘 다 — heavy 는 심판에 asks 를 안 넘기므로(`[]`) 여기서 막지 않으면 심판 merge 가 1차 must-fix 를 덮는다.
536
+ // 관문은 «이 경로가 실제로 자동 병합할 때»만 — light 는 autoMergeOnOk||autoMerge, heavy 는 심판 merge 의 autoMerge 뿐(autoMergeOnOk 만이면 종전대로 심판 → ready-to-merge).
537
+ const autoMergesHere = effectiveFinalJudge ? opts.autoMerge === true : (opts.autoMergeOnOk || opts.autoMerge);
538
+ const mustFixBlock = autoMergesHere ? reviewMergeMustFixBlock(pr, 'initial-ok', cls.asks, cls.asksUnreadable === true) : null;
539
+ if (mustFixBlock) {
540
+ try { runGh(['pr', 'comment', pr, '--body', `🛑 1차 리뷰 ok 이나 미해결 지적이 남아 자동 병합하지 않음(${mustFixBlock}) → 대표 결정 필요.`]); } catch { /* noop */ }
541
+ return { pr, branch, verdict: 'ok', asks: Array.isArray(cls.asks) ? cls.asks : [], action: 'parked', detail: `${depth}·1차 ok ⊕ ${mustFixBlock} → HITL(자동 병합 안 함)` };
542
+ }
509
543
  // light: 1차 clean 으로 충분 → approve + 머지. heavy: 1차 ok 여도 2차 심판 머스트.
510
544
  if (!effectiveFinalJudge) {
511
545
  if ((opts.autoMergeOnOk || opts.autoMerge) && holdReleasePathBeforeReviewMerge(pr, runGh)) {
@@ -0,0 +1,139 @@
1
+ // ── ACP Claude Code 를 «구현» 실행기로 (CLAUDE-IMPL-LANE · `--child-llm-provider claude-acp`) ──
2
+ //
3
+ // acp-reviewer.ts 의 짝이다. 리뷰어는 read-only 라 읽기 툴만 허가하지만, 구현 실행기는 런 워크트리 안에서
4
+ // 쓰기·실행을 허가해야 한다. 그래서 approver 가 «워크트리 밖 경로 쓰기»를 구조적으로 거부한다.
5
+ // 자식은 claude 구독 ACP 어댑터(`claude-agent-acp`)이며 env 는 subscriptionReviewerSpawn 의 과금 스크럽
6
+ // (ANTHROPIC_API_KEY 등 제거)을 그대로 쓴다 — 지우지 않으면 구독이 아니라 API 로 과금된다.
7
+ import { isAbsolute, relative, resolve } from 'node:path';
8
+ import { AcpAgent, type AcpAgentOpts } from '../acp/client.js';
9
+ import { debug } from '../debug/log.js';
10
+ import { subscriptionReviewerSpawn } from '../self-dev/review-provider-fallback.js';
11
+ import type { SubscriptionReviewerSpec } from '../user-config.js';
12
+ import { isReadOnlyReviewTool } from './acp-reviewer.js';
13
+
14
+ const WRITE_TOOL_KINDS = new Set(['edit', 'delete', 'move']);
15
+ const PATH_INPUT_KEYS = ['file_path', 'filePath', 'path', 'notebook_path', 'destination', 'source'] as const;
16
+
17
+ export interface ImplementerPermissionRequest {
18
+ title: string;
19
+ kind?: string;
20
+ rawInput?: unknown;
21
+ }
22
+
23
+ export interface ImplementerPermissionDecision {
24
+ tool: string;
25
+ path: string | null;
26
+ decision: 'allow' | 'deny';
27
+ }
28
+
29
+ function requestedPaths(rawInput: unknown): string[] {
30
+ if (!rawInput || typeof rawInput !== 'object') return [];
31
+ const input = rawInput as Record<string, unknown>;
32
+ return PATH_INPUT_KEYS.flatMap((key) => (typeof input[key] === 'string' && input[key] ? [input[key] as string] : []));
33
+ }
34
+
35
+ function insideWorktree(worktree: string, target: string): boolean {
36
+ const rel = relative(resolve(worktree), resolve(worktree, target));
37
+ return rel === '' || (!rel.startsWith('..') && !isAbsolute(rel));
38
+ }
39
+
40
+ /** 허가 판정(순수 함수). 쓰기 계열(edit·delete·move)은 모든 경로가 워크트리 안일 때만 허가하고,
41
+ * 실행(execute)은 cwd 가 워크트리라 허가한다. 읽기 계열은 허가, 그 외는 경로가 있고 전부 안쪽일 때만 허가(보수적). */
42
+ export function decideImplementerPermission(req: ImplementerPermissionRequest, worktree: string): ImplementerPermissionDecision {
43
+ const paths = requestedPaths(req.rawInput);
44
+ const outside = paths.find((p) => !insideWorktree(worktree, p));
45
+ const tool = req.title.slice(0, 80);
46
+ 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);
49
+ if (req.kind === 'execute') return verdict(true);
50
+ if (isReadOnlyReviewTool(req.kind, req.title)) return verdict(true);
51
+ return verdict(paths.length > 0 && outside === undefined);
52
+ }
53
+
54
+ export interface AcpImplementerOpts {
55
+ /** 런 워크트리 — ACP 자식의 cwd 이자 쓰기 허용 경계. */
56
+ worktree: string;
57
+ /** 자식 env 의 원천(기본 process.env). 과금 키는 subscriptionReviewerSpawn 이 제거한다. */
58
+ env?: NodeJS.ProcessEnv;
59
+ /** cct 실행기가 `teamclaude env --no-mitm` 에서 읽은 프록시 주소. */
60
+ proxyBaseUrl?: string;
61
+ spec?: SubscriptionReviewerSpec;
62
+ /** 모델 별칭 — 지정 시 session/set_model 로 고정. */
63
+ model?: string;
64
+ /** 이어갈 ACP 세션 id — 주면 newSession 대신 loadSession 으로 이어간다. */
65
+ resumeSessionId?: string;
66
+ /** 구현 1턴 최대 대기(ms). 초과 시 cancel → throw. 기본 1_800_000. */
67
+ timeoutMs?: number;
68
+ /** spawn → initialize → session 준비까지의 단일 기한(ms). 기본 60_000. */
69
+ handshakeTimeoutMs?: number;
70
+ /** 테스트용 ACP 에이전트 생성기. */
71
+ createAgent?: (opts: AcpAgentOpts) => AcpAgent;
72
+ }
73
+
74
+ export interface AcpImplementerResult {
75
+ text: string;
76
+ sessionId: string;
77
+ allowed: number;
78
+ denied: number;
79
+ }
80
+
81
+ const OBS = 'agent-substrate.acp-implementer';
82
+
83
+ export function makeAcpImplementer(opts: AcpImplementerOpts): (prompt: string) => Promise<AcpImplementerResult> {
84
+ return async (prompt) => {
85
+ const spawn = subscriptionReviewerSpawn(opts.spec ?? { provider: 'claude-acp' }, opts.env ?? process.env, opts.proxyBaseUrl);
86
+ const timeoutMs = opts.timeoutMs ?? 1_800_000;
87
+ const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? 60_000;
88
+ let allowed = 0;
89
+ let denied = 0;
90
+ const agentOpts: AcpAgentOpts = {
91
+ backendId: 'claude',
92
+ backendSpec: spawn.backendSpec,
93
+ env: spawn.env,
94
+ cwd: opts.worktree,
95
+ log: (message) => debug.log(OBS, 'agent-log', { message }),
96
+ permissionApprover: async (req) => {
97
+ const verdict = decideImplementerPermission(req, opts.worktree);
98
+ if (verdict.decision === 'allow') allowed++; else denied++;
99
+ debug.log(OBS, 'permission', { ...verdict });
100
+ return verdict.decision === 'allow';
101
+ },
102
+ };
103
+ const agent = opts.createAgent ? opts.createAgent(agentOpts) : new AcpAgent(agentOpts);
104
+ let handshakeTimer: ReturnType<typeof setTimeout> | undefined;
105
+ const withinHandshake = <T>(step: Promise<T>): Promise<T> => Promise.race([step, new Promise<never>((_, reject) => {
106
+ handshakeTimer = setTimeout(() => reject(new Error(`ACP handshake timeout (${handshakeTimeoutMs}ms)`)), handshakeTimeoutMs);
107
+ })]).finally(() => { if (handshakeTimer) clearTimeout(handshakeTimer); });
108
+ let timer: ReturnType<typeof setTimeout> | undefined;
109
+ let timedOut = false;
110
+ let text = '';
111
+ try {
112
+ await withinHandshake(agent.start());
113
+ let sid: string;
114
+ if (opts.resumeSessionId) {
115
+ await withinHandshake(agent.loadSession({ sessionId: opts.resumeSessionId, cwd: opts.worktree }));
116
+ sid = opts.resumeSessionId;
117
+ } else {
118
+ sid = await withinHandshake(agent.newSession());
119
+ }
120
+ if (opts.model) await withinHandshake(agent.selectSessionModel(sid, opts.model));
121
+ debug.log(OBS, 'start', { cwd: opts.worktree, model: opts.model ?? '(default)', resumed: Boolean(opts.resumeSessionId) });
122
+ timer = setTimeout(() => { timedOut = true; agent.cancel(sid).catch(() => { /* noop */ }); }, timeoutMs);
123
+ await agent.prompt(sid, [{ type: 'text', text: prompt }], (u) => {
124
+ if (u.sessionUpdate === 'agent_message_chunk' && u.content.type === 'text' && u.content.text) text += u.content.text;
125
+ });
126
+ if (timedOut) throw new Error(`ACP 구현 타임아웃(${timeoutMs}ms)`);
127
+ debug.log(OBS, 'done', { chars: text.length, allowed, denied });
128
+ return { text, sessionId: sid, allowed, denied };
129
+ } catch (e) {
130
+ debug.log(OBS, 'error', { message: (e as Error).message, allowed, denied }, { level: 'error' });
131
+ throw e;
132
+ } finally {
133
+ if (timer) clearTimeout(timer);
134
+ try { await agent.stop(); } catch (e) {
135
+ debug.log(OBS, 'stop-fail', { message: (e as Error).message }, { level: 'error' });
136
+ }
137
+ }
138
+ };
139
+ }
@@ -33,6 +33,8 @@ export interface AcpReviewerOpts {
33
33
  model?: string;
34
34
  /** 리뷰 1턴 최대 대기(ms). 초과 시 cancel→throw(부분 리뷰로 오판 pass 방지). 기본 300000. */
35
35
  timeoutMs?: number;
36
+ /** One deadline for spawn → initialize → session/new → model select (ms). A child that never answers ACP must not hang the review. Default min(timeoutMs, 60000). */
37
+ handshakeTimeoutMs?: number;
36
38
  }
37
39
 
38
40
  /**
@@ -152,13 +154,20 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
152
154
  let text = '';
153
155
  let timedOut = false;
154
156
  let timer: ReturnType<typeof setTimeout> | undefined;
157
+ const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? Math.min(timeoutMs, 60_000);
158
+ const handshakeDeadline = Date.now() + handshakeTimeoutMs;
159
+ let handshakeTimer: ReturnType<typeof setTimeout> | undefined;
160
+ const withinHandshake = <T>(step: Promise<T>): Promise<T> => Promise.race([step, new Promise<never>((_, reject) => {
161
+ handshakeTimer = setTimeout(() => {
162
+ debug.log('acp-review', 'handshake-timeout', { backend, handshakeTimeoutMs }, { level: 'error' });
163
+ reject(new Error(`ACP handshake timeout (${handshakeTimeoutMs}ms)`));
164
+ }, Math.max(0, handshakeDeadline - Date.now()));
165
+ })]).finally(() => { if (handshakeTimer) clearTimeout(handshakeTimer); });
155
166
  try {
156
- agent = opts.createAgent
157
- ? opts.createAgent({ backendId: requestedBackend, ...agentOpts })
158
- : opts.backendSpec
159
- ? new AcpAgent({ backendId: requestedBackend, ...agentOpts })
160
- : await reviewManager!.getAgent(requestedBackend, agentOpts);
161
- if (injected || opts.backendSpec) await agent.start();
167
+ if (opts.createAgent) agent = opts.createAgent({ backendId: requestedBackend, ...agentOpts });
168
+ else if (opts.backendSpec) agent = new AcpAgent({ backendId: requestedBackend, ...agentOpts });
169
+ else agent = await withinHandshake(reviewManager!.getAgent(requestedBackend, agentOpts));
170
+ if (injected || opts.backendSpec) await withinHandshake(agent.start());
162
171
  if (!capabilitiesObserved) {
163
172
  try {
164
173
  debug.log('acp-review', 'capabilities', {
@@ -172,9 +181,9 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
172
181
  // Observability must not interrupt a review.
173
182
  }
174
183
  }
175
- const sid = await agent.newSession();
184
+ const sid = await withinHandshake(agent.newSession());
176
185
  if (opts.model) {
177
- const picked = await agent.selectSessionModel(sid, opts.model);
186
+ const picked = await withinHandshake(agent.selectSessionModel(sid, opts.model));
178
187
  debug.log('acp-review', 'model', { requested: opts.model, picked: picked?.name ?? null, backend });
179
188
  }
180
189
  timer = setTimeout(() => { timedOut = true; agent!.cancel(sid).catch(() => { /* noop */ }); }, timeoutMs);
@@ -430,14 +430,38 @@ function referencedRepositoryPaths(prDiff: string): string[] {
430
430
 
431
431
  const REVIEWER_CONTEXT_MAX_CHARS = 12_000;
432
432
 
433
+ /** Decode the a-side of a diff header, including Git's quoted UTF-8 octal paths. */
434
+ function reviewerContextDiffPath(chunk: string): string | undefined {
435
+ const header = /^diff --git ("(?:\\.|[^"\\])*"|a\/[^ \n]+) (?:"(?:\\.|[^"\\])*"|b\/[^ \n]+)(?:\r?\n|$)/.exec(chunk);
436
+ if (!header) return undefined;
437
+ const token = header[1]!;
438
+ if (!token.startsWith('"')) return token.slice(2);
439
+ const bytes: number[] = [];
440
+ const escapes: Record<string, number> = { a: 7, b: 8, t: 9, n: 10, v: 11, f: 12, r: 13, '"': 34, '\\': 92 };
441
+ const body = token.slice(1, -1);
442
+ for (let i = 0; i < body.length; i += 1) {
443
+ // Decode by code point so astral characters (emoji) keep both surrogate halves.
444
+ const codePoint = body.codePointAt(i)!;
445
+ const char = String.fromCodePoint(codePoint);
446
+ if (char !== '\\') { bytes.push(...Buffer.from(char, 'utf8')); if (codePoint > 0xffff) i += 1; continue; }
447
+ const octal = body.slice(i + 1, i + 4);
448
+ if (/^[0-7]{3}$/.test(octal)) { bytes.push(parseInt(octal, 8)); i += 3; continue; }
449
+ const next = body[++i]!;
450
+ if (escapes[next] !== undefined) bytes.push(escapes[next]);
451
+ else bytes.push(...Buffer.from(next, 'utf8'));
452
+ }
453
+ const path = Buffer.from(bytes).toString('utf8');
454
+ return path.startsWith('a/') ? path.slice(2) : undefined;
455
+ }
456
+
433
457
  /** Bound each ordered human-supplied item independently so an early large item cannot evict later context. */
434
- export function budgetReviewerContext(
435
- items: readonly ReviewerContextItem[] = [],
436
- maxChars = REVIEWER_CONTEXT_MAX_CHARS,
437
- ): ReviewerContextBudget {
458
+ function budgetReviewerContextWithParts(
459
+ items: readonly ReviewerContextItem[],
460
+ maxChars: number,
461
+ ): { budget: ReviewerContextBudget; partsByItem: (string | undefined)[] } {
438
462
  const fullText = items.map((item) => `### ${item.label}\n${item.body}`).join('\n\n');
439
463
  if (items.length === 0) {
440
- return { text: '', itemCount: 0, shownChars: 0, totalChars: 0, truncated: false, fullyIncludedItems: 0, truncatedItems: 0, omittedItems: 0 };
464
+ return { budget: { text: '', itemCount: 0, shownChars: 0, totalChars: 0, truncated: false, fullyIncludedItems: 0, truncatedItems: 0, omittedItems: 0 }, partsByItem: [] };
441
465
  }
442
466
  const separatorChars = (items.length - 1) * 2;
443
467
  const itemBudget = Math.max(0, Math.floor((maxChars - separatorChars) / items.length));
@@ -489,17 +513,27 @@ export function budgetReviewerContext(
489
513
  const omittedItems = items.length - parts.length;
490
514
  const text = parts.join('\n\n');
491
515
  return {
492
- text,
493
- itemCount: items.length,
494
- shownChars: text.length,
495
- totalChars: fullText.length,
496
- truncated: text.length < fullText.length,
497
- fullyIncludedItems,
498
- truncatedItems,
499
- omittedItems,
516
+ budget: {
517
+ text,
518
+ itemCount: items.length,
519
+ shownChars: text.length,
520
+ totalChars: fullText.length,
521
+ truncated: text.length < fullText.length,
522
+ fullyIncludedItems,
523
+ truncatedItems,
524
+ omittedItems,
525
+ },
526
+ partsByItem,
500
527
  };
501
528
  }
502
529
 
530
+ export function budgetReviewerContext(
531
+ items: readonly ReviewerContextItem[] = [],
532
+ maxChars = REVIEWER_CONTEXT_MAX_CHARS,
533
+ ): ReviewerContextBudget {
534
+ return budgetReviewerContextWithParts(items, maxChars).budget;
535
+ }
536
+
503
537
  function reviewerContextSection(
504
538
  items: readonly ReviewerContextItem[] | undefined,
505
539
  budget = items?.length ? budgetReviewerContext(items) : undefined,
@@ -609,10 +643,65 @@ export function buildReviewPrompt(
609
643
  ].join('\n');
610
644
  }
611
645
 
646
+ /** «지적 없음» 표지 — 일부 모델(GLM-5.3 실측)이 빈 섹션 대신 `- (없음 — …)` / `- none` 을 항목으로 쓴다.
647
+ * ⭐ 표지 «만»인 항목을 0건으로 접는다. 두 모양뿐이다:
648
+ * ① 낱말 하나(`none`·`없음`·`N/A`·`해당 없음` · 끝 마침표 허용)
649
+ * ② 항목 «전체»가 괄호에 싸인 표지 — 설명이 붙으면 그 설명이 «지적이 없다»는 말일 때만
650
+ * (`(없음 — 블로커 수준의 결함은 발견되지 않음)` · `(none — no blockers)`).
651
+ * ⛔ 그 밖은 «지적»으로 남긴다 — `없음 — 인증 검사가 없어 …` · `(none: the new export is never called)` ·
652
+ * `none of the tests …`. 표지 낱말로 시작하는 실제 블로커를 지우면 PASS/WARN 리뷰에서 블로커가 사라진다. */
653
+ const NONE_WORD = String.raw`(?:없음|해당\s*없음|n\/a|none|nothing)`;
654
+ const BARE_SENTINEL = new RegExp(String.raw`^${NONE_WORD}\s*[.。]?$`, 'i');
655
+ const BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*${NONE_WORD}(?:\s*[—–\-:.,;·]\s*([^)\])】]*))?\s*[)\])】]$`, 'i');
656
+ // ⭐ 설명 «전체»가 「지적 없음」 한 문장일 때만 — 일부만 맞아도 접으면 `(none: no blockers are checked because …)` 같은 지적이 사라진다.
657
+ const NO_FINDING_REMARK = new RegExp([
658
+ String.raw`^(?:(?:블로커|차단)\s*)?(?:수준의?\s*)?(?:결함|문제|이슈|지적|블로커)(?:은|는|이|가)?\s*(?:발견되지\s*않(?:음|았(?:다|습니다)?)|없(?:음|다|습니다))[.。]?$`,
659
+ String.raw`^(?:no|zero)\s+(?:blocking\s+)?(?:blockers?|issues?|problems?|findings?|must-?fix(?:es)?)(?:\s+found)?\.?$`,
660
+ String.raw`^nothing\s+(?:blocking|to\s+fix)\.?$`,
661
+ // REVIEW-MUSTFIX-NONE-SENTINEL — `(없음 — 수용기준 충족)` · `(none — acceptance criteria met)` (GLM 실측 6건). «미충족» 은 ^ 앵커로 안 맞는다.
662
+ String.raw`^수용\s*기준(?:을|이)?\s*(?:(?:모두|전부)\s*)?충족(?:함|됨|했다|합니다)?[.。]?$`,
663
+ String.raw`^(?:all\s+)?acceptance\s+criteria\s+(?:are\s+)?(?:all\s+)?met\.?$`,
664
+ ].join('|'), 'i');
665
+ // REVIEW-MUSTFIX-NONE-SENTINEL 후속 — GLM 이 괄호 안에 «무소견 머리 + 긴 근거»를 쓴다(10-11 TC `pr land` 가 `review-must-fix-1` 로 거부):
666
+ // `(없음 — 수용기준 충족: 머리말에 … 반영됨 …)` · `(없음 — 수용기준 3항 모두 충족: … (\`'failed'\` 반환) · …)`(근거 안에 괄호가 또 있다).
667
+ // ⭐ 길이 무관 0 은 «머리»가 무소견 서술이고 바로 구분자가 올 때만 — 머리가 결함 서술이면(`(없음 — 하지만 X 가 깨진다)`) 지적으로 남긴다.
668
+ // ⛔ 근거에 역접·미충족(`하지만`·`다만`·`미충족`·`but`·`except`·`not met` …)이 있으면 보수적으로 지적으로 남긴다.
669
+ const LONG_BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*${NONE_WORD}\s*[—–\-:·]\s*([\s\S]+?)\s*[)\])】]$`, 'i');
670
+ const NO_FINDING_HEAD = new RegExp('^(?:' + [
671
+ String.raw`수용\s*기준(?:\s*\d+\s*(?:항|개|건)(?:목)?)?(?:을|이)?\s*(?:(?:모두|전부)\s*)?충족(?:함|됨|했다|합니다)?`,
672
+ String.raw`(?:all\s+)?acceptance\s+criteria\s+(?:are\s+)?(?:all\s+)?met`,
673
+ String.raw`must-?fix\s*(?:항목)?(?:은|는|이|가)?\s*(?:없(?:음|다|습니다)|0\s*건)`,
674
+ String.raw`(?:no|zero)\s+(?:blocking\s+)?(?:blockers?|must-?fix(?:es)?)(?:\s+found)?`,
675
+ String.raw`(?:(?:블로커|차단)\s*)?(?:수준의?\s*)?(?:결함|블로커)(?:은|는|이|가)?\s*(?:발견되지\s*않(?:음|았(?:다|습니다)?)|없(?:음|다|습니다))`,
676
+ ].join('|') + String.raw`)\s*(?:[::—–\-·,;.。(]|$)`, 'i');
677
+ const LONG_REMARK_DISSENT = /하지만|그러나|다만|(?<![가-힣])단(?:,|\s)|미\s*충족|불\s*충족|충족하지|충족되지|\bbut\b|\bhowever\b|\bexcept\b|\balthough\b|\bnot\s+(?:yet\s+)?met\b|\bunmet\b/i;
678
+ /** 괄호 안이 «없음 + 구분자 + 무소견 머리 …» 인가 — 길이 무관(근거 안 괄호도 허용). `isNoneSentinelFinding` 의 갈래. */
679
+ function isLongNoFindingBracket(text: string): boolean {
680
+ const m = LONG_BRACKETED_SENTINEL.exec(text.trim());
681
+ if (!m) return false;
682
+ const remark = m[1]!.trim();
683
+ return NO_FINDING_HEAD.test(remark) && !LONG_REMARK_DISSENT.test(remark);
684
+ }
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 {
688
+ const text = finding.trim();
689
+ if (BARE_SENTINEL.test(text)) return true;
690
+ const bracketed = BRACKETED_SENTINEL.exec(text);
691
+ if (bracketed) {
692
+ const remark = bracketed[1]?.trim();
693
+ if (!remark || NO_FINDING_REMARK.test(remark)) return true;
694
+ }
695
+ return isLongNoFindingBracket(text);
696
+ }
697
+
612
698
  /** critic 응답 파싱 → ReviewResult. 순수함수. VERDICT + MUST-FIX/SHOULD-FIX/REQUIREMENTS 섹션 분해.
613
699
  * verdict=FAIL 인데 must-fix 미기재면 첫 finding 을 must 로 승격(블로커 근거 보존). */
700
+ /** ⭐ `VERDICT: PASS|WARN|FAIL` 판정 줄 — `parseReviewResult` 와 `reviewedResultFromRaw` 가 «같은» 정규식을 쓴다(존재 판정이 갈리면 안 된다). */
701
+ const VERDICT_LINE = /VERDICT:\s*(PASS|WARN|FAIL)/i;
702
+
614
703
  export function parseReviewResult(text: string): ReviewResult {
615
- const vm = /VERDICT:\s*(PASS|WARN|FAIL)/i.exec(text);
704
+ const vm = VERDICT_LINE.exec(text);
616
705
  const verdict = (vm ? vm[1]!.toLowerCase() : 'pass') as ReviewVerdict;
617
706
  const lines = text.split('\n').map((l) => l.trim());
618
707
  const mustFix: string[] = [];
@@ -628,7 +717,7 @@ export function parseReviewResult(text: string): ReviewResult {
628
717
  if (l.startsWith('- ')) {
629
718
  const f = l.slice(2).trim();
630
719
  if (!f) continue;
631
- if (section === 'must') mustFix.push(f);
720
+ if (section === 'must') { if (!isNoneSentinelFinding(f)) mustFix.push(f); }
632
721
  else if (section === 'should') shouldFix.push(f);
633
722
  else if (section === 'requirements') requirements.push(f);
634
723
  else fallbackFinding ??= f;
@@ -648,6 +737,34 @@ export function parseReviewResult(text: string): ReviewResult {
648
737
  };
649
738
  }
650
739
 
740
+ /** 판정 줄 없는 응답의 사유 값 — 기존 «리뷰 못 함» 경로(`reviewed:false` ⊕ `failureReason`)를 그대로 탄다. */
741
+ export const NO_VERDICT_LINE_REASON = 'no-verdict-line';
742
+
743
+ /**
744
+ * ⛔⭐⭐ REVIEW-NO-VERDICT-FAILCLOSED(2026-10-10) — 리뷰어 응답 «하나»를 결과로 접는다.
745
+ * `parseReviewResult` 는 `VERDICT:` 줄이 없으면 `pass` 로 기본값을 둔다. 종전 호출부는 거기에
746
+ * `reviewed: true` 를 붙여서, 자격 없는 리뷰어의 219자 오류 문구가 «지적 0 인 PASS» 로 접혔다
747
+ * (실물: run-dbe7b7df · PR #25906 · codex-app-server 17초).
748
+ * ⇒ 판정 줄이 없으면 «리뷰 못 함»(`reviewed:false` · `failureReason=no-verdict-line`)이다 —
749
+ * catch 경로와 «같은 모양»이라 소비처(orchestrator·seams·renderReview·fold)가 이미 «통과 판정 아님»으로 다룬다.
750
+ * ⭐ 판정 줄이 «있는» 응답은 `parseReviewResult(raw)` ⊕ `reviewed:true` 그대로 — 바이트 동일.
751
+ * ⛔ 계약: `reviewed:false` 일 때 `verdict` 는 «의미 없는 자리값»(`pass`)이다 — catch·미주입 경로와 같다.
752
+ * 소비처는 `reviewed` 를 «먼저» 본다(`renderReview`·`self-review-cli`·`review-adapter`·orchestrator).
753
+ */
754
+ function reviewedResultFromRaw(raw: string, runId: string | undefined, pass?: { index: number; of: number }): ReviewResult {
755
+ if (VERDICT_LINE.test(raw)) return { ...parseReviewResult(raw), reviewed: true };
756
+ try {
757
+ debug.log('review.verdict', NO_VERDICT_LINE_REASON, {
758
+ chars: raw.length,
759
+ head: safeLogText(raw, 80),
760
+ ...(pass ? { pass: pass.index + 1, passes: pass.of } : {}),
761
+ // ⛔ backend 는 안 남긴다 — 이 함수는 어느 백엔드로 불렸는지 «모른다»(catch 주석 `#7495` 와 같은 이유).
762
+ ...(runId !== undefined ? { runId } : {}),
763
+ });
764
+ } catch { /* Observation must not prevent the review. */ }
765
+ return { verdict: 'pass', mustFix: [], shouldFix: [], reviewed: false, failureReason: NO_VERDICT_LINE_REASON };
766
+ }
767
+
651
768
  function failureReasonText(error: unknown): string {
652
769
  if (error instanceof Error) return safeLogText(error.message, 400);
653
770
  if (typeof error === 'string') return safeLogText(error, 400);
@@ -675,7 +792,56 @@ export async function reviewPullRequest(
675
792
  if (!llmReview) return { verdict: 'pass', mustFix: [], shouldFix: [], reviewed: false }; // 리뷰어 미주입=미검토.
676
793
  try {
677
794
  const diffBudget = budgetedDiff(input.prDiff);
678
- const reviewerContextBudget = input.reviewerContext?.length ? budgetReviewerContext(input.reviewerContext) : undefined;
795
+ // Existing caller: self-review-cli.ts runSelfReviewCliCommand → deps.reviewPullRequest(reviewInput, llmReview).
796
+ const plan = planReviewChunks(input.prDiff);
797
+ const chunked = plan.passes.length > 1;
798
+ const contextItems = input.reviewerContext ?? [];
799
+ const passPaths = chunked ? plan.passes.map((pass) => new Set(
800
+ splitDiffByFile(pass).flatMap((chunk) => {
801
+ // self-review-cli.ts runSelfReviewCliCommand → deps.reviewPullRequest(reviewInput, llmReview) → this pass.
802
+ const path = reviewerContextDiffPath(chunk);
803
+ return path === undefined ? [] : [path];
804
+ }),
805
+ )) : [];
806
+ const matchedLabels = new Set(passPaths.flatMap((paths) => [...paths]));
807
+ const passContext = chunked && contextItems.length ? passPaths.map((paths, passIndex) => {
808
+ const indices = contextItems.flatMap((item, index) =>
809
+ item.image ? (passIndex === 0 ? [index] : [])
810
+ : !matchedLabels.has(item.label) || paths.has(item.label) ? [index] : []);
811
+ const { budget, partsByItem } = budgetReviewerContextWithParts(indices.map((index) => contextItems[index]!), REVIEWER_CONTEXT_MAX_CHARS);
812
+ return { indices, budget, partsByItem };
813
+ }) : [];
814
+ const chunkContextBudget = passContext.length ? (() => {
815
+ const shownByItem: Array<number | undefined> = contextItems.map(() => undefined);
816
+ const status: Array<'omitted' | 'truncated' | 'full' | undefined> = contextItems.map(() => undefined);
817
+ for (const { indices, partsByItem } of passContext) {
818
+ indices.forEach((itemIndex, position) => {
819
+ const part = partsByItem[position];
820
+ // Count each item once at its narrowest pass: a loss in any pass must show in shownChars.
821
+ const shown = part?.length ?? 0;
822
+ shownByItem[itemIndex] = Math.min(shownByItem[itemIndex] ?? shown, shown);
823
+ const full = `### ${contextItems[itemIndex]!.label}\n${contextItems[itemIndex]!.body}`;
824
+ if (part !== full) status[itemIndex] = part === undefined && status[itemIndex] !== 'truncated' ? 'omitted' : 'truncated';
825
+ else if (status[itemIndex] === undefined) status[itemIndex] = 'full';
826
+ });
827
+ }
828
+ const shownCount = shownByItem.filter((length) => (length ?? 0) > 0).length;
829
+ const fullyIncludedItems = status.filter((value) => value === 'full').length;
830
+ const truncatedItems = status.filter((value) => value === 'truncated').length;
831
+ const omittedItems = contextItems.length - fullyIncludedItems - truncatedItems;
832
+ return {
833
+ itemCount: contextItems.length,
834
+ // Same scale as totalChars (items joined by "\n\n"): each item counts once at its narrowest
835
+ // shown part, so shownChars === totalChars exactly when no item lost anything in any pass.
836
+ // perPassShownChars in the budget log keeps the raw per-pass sizes.
837
+ shownChars: shownByItem.reduce<number>((sum, length) => sum + (length ?? 0), 0) + Math.max(0, shownCount - 1) * 2,
838
+ totalChars: contextItems.map((item) => `### ${item.label}\n${item.body}`).join('\n\n').length,
839
+ truncated: truncatedItems > 0 || omittedItems > 0,
840
+ fullyIncludedItems, truncatedItems, omittedItems,
841
+ };
842
+ })() : undefined;
843
+ const singleContextBudget = !chunked && contextItems.length ? budgetReviewerContext(contextItems) : undefined;
844
+ const reviewerContextBudget = chunkContextBudget ?? singleContextBudget;
679
845
  if (reviewerContextBudget) {
680
846
  try {
681
847
  debug.log('review.images', 'reviewer-context-budget', {
@@ -686,6 +852,7 @@ export async function reviewPullRequest(
686
852
  fullyIncludedItems: reviewerContextBudget.fullyIncludedItems,
687
853
  truncatedItems: reviewerContextBudget.truncatedItems,
688
854
  omittedItems: reviewerContextBudget.omittedItems,
855
+ ...(chunked ? { passes: plan.passes.length, perPassShownChars: passContext.map(({ budget }) => budget.shownChars) } : {}),
689
856
  ...(input.reviewContext?.runId !== undefined ? { runId: input.reviewContext.runId } : {}),
690
857
  ...(input.reviewContext?.round !== undefined ? { round: input.reviewContext.round } : {}),
691
858
  });
@@ -716,8 +883,7 @@ export async function reviewPullRequest(
716
883
  // *"64,000자는 **분할 리뷰 도입을 전제로 한 조각별 고정 예산**"*. 부품(`splitDiffByFile`)도
717
884
  // 서 있었다. 없던 것은 「조각들을 리뷰하고 결과를 «접는» 자」 하나였다.
718
885
  // ⛔ 상한을 «올리는» 것이 아니다 — 조각마다 상한을 «지킨다».
719
- const plan = planReviewChunks(input.prDiff);
720
- if (plan.passes.length > 1) {
886
+ if (chunked) {
721
887
  try {
722
888
  debug.log('review.diff-plan', 'chunked', {
723
889
  passes: plan.passes.length, files: plan.files, coversAll: plan.coversAll,
@@ -740,6 +906,7 @@ export async function reviewPullRequest(
740
906
  const passInput: ReviewInput = {
741
907
  ...input,
742
908
  prDiff: passDiff,
909
+ reviewerContext: passContext[index]?.indices.map((itemIndex) => contextItems[itemIndex]!),
743
910
  // ⭐ 리뷰어에게 «자기가 몇 분의 몇을 보는지» 알린다 — 이것 없이는 조각 리뷰어가
744
911
  // "다른 파일이 안 보인다"를 SCOPE/미배선 결함으로 오판한다(규칙 (7) 오작동).
745
912
  evidenceNote: [
@@ -749,13 +916,10 @@ export async function reviewPullRequest(
749
916
  + ' 「여기 안 보인다」를 결함으로 판정하지 마십시오.',
750
917
  ].filter(Boolean).join('\n'),
751
918
  };
752
- passResults.push({
753
- ...parseReviewResult(await llmReview(
754
- buildReviewPrompt(passInput, passBudget, '', reviewerContextBudget),
755
- reviewImages.length > 0 && index === 0 ? reviewImages : undefined,
756
- )),
757
- reviewed: true,
758
- });
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 }));
759
923
  }
760
924
  return {
761
925
  ...foldReviewResults(passResults),
@@ -780,12 +944,11 @@ export async function reviewPullRequest(
780
944
  };
781
945
  }
782
946
  const raw = await llmReview(
783
- buildReviewPrompt(input, diffBudget, referencedContext.text, reviewerContextBudget),
947
+ buildReviewPrompt(input, diffBudget, referencedContext.text, singleContextBudget),
784
948
  reviewImages.length > 0 ? reviewImages : undefined,
785
949
  );
786
950
  return {
787
- ...parseReviewResult(raw),
788
- reviewed: true,
951
+ ...reviewedResultFromRaw(raw, input.reviewContext?.runId),
789
952
  diffBudget: {
790
953
  truncated: diffBudget.truncated,
791
954
  shownChars: diffBudget.shownChars,
@@ -16,7 +16,7 @@ import { parseGoalType, type GoalType } from '../self-implement/goal-author.js';
16
16
  import type { DesignCheckOutcome } from '../design/design-check.js';
17
17
  import type { DesignGateResult } from '../design/design-gate.js';
18
18
  import type { PriorDraftFinding } from '../self-implement/prior-draft-findings.js';
19
- import { parseShardIdentity, shardBoundaryBlock, withoutShardIdentity } from './shard-boundary-intent.js';
19
+ import { parseShardIdentity, shardReviewContractBlock, withoutShardIdentity } from './shard-boundary-intent.js';
20
20
 
21
21
  export interface ReviewIntentInput {
22
22
  /** 무엇을 왜 — 골 원문. */
@@ -603,7 +603,9 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
603
603
  // 그 안의 수용기준을 다시 목록으로 붙이면 **같은 내용이 두 번** 들어가 4000자 예산을 먹고,
604
604
  // 후순위 블록(스코프 경계)이 불필요하게 잘린다.
605
605
  const identity = parseShardIdentity(i.goal);
606
- const shardBoundary = identity ? { title: '조각 경계', text: `조각 경계\n${shardBoundaryBlock(identity)}` } : undefined;
606
+ // This is the phaseIntent consumed by defaultSeams.reviewDiff → reviewPullRequest;
607
+ // the same block is retained by the orchestrator's PR-body review-intent section.
608
+ const shardBoundary = identity ? { title: '샤드 계약 — 리뷰 범위', text: shardReviewContractBlock(i.goal, identity, boundaries, i.changedFiles) } : undefined;
607
609
  const authoredLiteGoal = isLightweightGoal(i.goal);
608
610
  const liteGoal = authoredLiteGoal && Boolean(i.goalFile?.trim());
609
611
  const goalBody = liteGoal ? '' : stripExtractedSections(identity ? withoutShardIdentity(i.goal) : i.goal).trim();
@@ -629,8 +631,8 @@ export function buildReviewIntent(i: Readonly<ReviewIntentInput>): string {
629
631
  const context = lightweightGoalContext(i.goal, i.goalFile!.trim());
630
632
  const boundaryBlock = listBlock('의도적 스코프 경계', boundaries);
631
633
  const liteBlocks = [
632
- acceptanceBlock, context, boundaryBlock, priorFindings, applied,
633
- runFacts, goalType, shardBoundary, preexisting, importerTestsNotRun,
634
+ acceptanceBlock, context, boundaryBlock, shardBoundary, priorFindings, applied,
635
+ runFacts, goalType, preexisting, importerTestsNotRun,
634
636
  gateEvidence, designCheck, designGate, shardSiblings, coverage, claims,
635
637
  listBlock('검증 못 한 경계 후보 (결정 아님 — 이것만으로 must-fix 를 면제하지도, 만들지도 말 것)', unverifiedBoundaryCandidates),
636
638
  ].filter((block): block is Block => Boolean(block));