elanous 0.2.34 → 0.2.36

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 (802) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{abb4b98b.163e0f56e84ae35d.js → 053a429e.9a63436527cc751c.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/109.f196abf3484bb97f.js +287 -0
  5. package/apps/pwa/out/_next/static/chunks/1201.afbfc5b1c5e5cbe4.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1517.9275b89572098ff3.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1574.ad11f8db8396ab45.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1614.7a8c5c40aee0261f.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/1871-f1eb29d8dbb4065b.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/190.285c832bd9626f8c.js +64 -0
  11. package/apps/pwa/out/_next/static/chunks/2193.0ea24c4a7aa1d004.js +36 -0
  12. package/apps/pwa/out/_next/static/chunks/223-ad865c1e80491d78.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/2265-f0d90b6dbec05f81.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2267.eb4a62a209f09ec4.js +149 -0
  15. package/apps/pwa/out/_next/static/chunks/2341-86cd06c0cf01aa33.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/2352.9abc42422bade876.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/2397-c1653a816061842d.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/2500.cbc1257b774aae52.js +1 -0
  19. package/apps/pwa/out/_next/static/chunks/{6086.913a69e6fa3e4a8b.js → 2683.c9773a0c589b031b.js} +4 -4
  20. package/apps/pwa/out/_next/static/chunks/2709.8e1889034255fc5f.js +24 -0
  21. package/apps/pwa/out/_next/static/chunks/{5576-82d3703636d5c4b9.js → 275-02ea4c2a33980422.js} +3 -3
  22. package/apps/pwa/out/_next/static/chunks/{ffdc3a04.b9c23c1b28dd4a96.js → 2812ca6a.3b9f4a7a08885744.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/284.ac77c0db55bfd3a8.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/2941.3c3546f96bc6efa7.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/2976.b000698a3c6512dc.js +24 -0
  26. package/apps/pwa/out/_next/static/chunks/{9550.d5f76828f972058c.js → 2986.45d7652e4f13557e.js} +2 -2
  27. package/apps/pwa/out/_next/static/chunks/3031-85328a92fcce4da6.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/{8817.61bb7ffbba502ecb.js → 3136.30aaaa5fa03662a3.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/{9131-fce7256c4180c4a5.js → 3148-98efd4869d660a87.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/{3498.cf2a15a8a9e5b926.js → 3155.2587a55196ecb394.js} +3 -3
  31. package/apps/pwa/out/_next/static/chunks/3277.785db1cf09f98601.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3320-f9c77381f85a2c0a.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/{3103.84470c8445962f04.js → 3324.a09703033abcbd2f.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/3386-91049feabff9a94e.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/339.80afb7e8839372af.js +8 -0
  36. package/apps/pwa/out/_next/static/chunks/3410.7f9af5ab77cbe65f.js +115 -0
  37. package/apps/pwa/out/_next/static/chunks/{3819.163d4777f0a597f6.js → 3538.a445e50bb359d068.js} +2 -2
  38. package/apps/pwa/out/_next/static/chunks/3540c645.2595a6af01a97672.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/3621.581b2054cc14bee4.js +286 -0
  40. package/apps/pwa/out/_next/static/chunks/3676.8c28d16fd84ca843.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/{3414.172ad4ca2d9b08e8.js → 3727.7949ccaacaa71242.js} +2 -2
  42. package/apps/pwa/out/_next/static/chunks/375-b84540853523fe52.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3757-180308bc61021b05.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/379.ee262e37586fe1ae.js +74 -0
  45. package/apps/pwa/out/_next/static/chunks/3840-5825d56d46976a92.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/3969-81054381eaec4c4c.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/{9b48c871.204d5d13e7809bd0.js → 3a3d9966.cc4d4585a2708e7c.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/4067-bf9aa60547972937.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4116.a84a92a2492c080e.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4176.e5729c93c29151eb.js +104 -0
  51. package/apps/pwa/out/_next/static/chunks/4227-e6c84686bc8946ca.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/{6740.43de73fc427c9fe2.js → 4286.b70c4520306817e8.js} +1 -1
  53. package/apps/pwa/out/_next/static/chunks/4304.e9b2512834a9e23e.js +23 -0
  54. package/apps/pwa/out/_next/static/chunks/4327.b9e08a71c0009348.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{8548.036c344973968847.js → 4615.8525eb0add35eba6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/4946.bd106eafd668f248.js +148 -0
  57. package/apps/pwa/out/_next/static/chunks/{3411-f87314c6c66ebc73.js → 5085-bce4904931767ca6.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/5125.2eb9968b83767193.js +93 -0
  59. package/apps/pwa/out/_next/static/chunks/5128-75b733fd74a9a1eb.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/{3110.0a7065f25c841818.js → 528.38ce20ef8aa251ff.js} +16 -16
  61. package/apps/pwa/out/_next/static/chunks/5489f3fe.4bb1458b09f6dead.js +122 -0
  62. package/apps/pwa/out/_next/static/chunks/{1644.35dd25240ae24e4b.js → 552.b7d061ad91eeac51.js} +2 -2
  63. package/apps/pwa/out/_next/static/chunks/5560-2a4648f6a30f16e7.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{3837.722e053fb9f321ad.js → 5711.957b095705c12560.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/{2124.ed5bf480cea7f85b.js → 575.d929793a53f27c4b.js} +1 -1
  66. package/apps/pwa/out/_next/static/chunks/5772-e29e14f8ff127122.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5887.5b2f5b44ce0f7e9a.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/5899-4c112a2d908cf97f.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{7562.948255cbc3e79d33.js → 599.c39c571b6733f2a2.js} +2 -2
  70. package/apps/pwa/out/_next/static/chunks/6041.1b65efb796ebc2a5.js +79 -0
  71. package/apps/pwa/out/_next/static/chunks/6057-765c0a26028c86b2.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6142.f289e0d039f453a6.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6199-6bcd61d2a3910e04.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/6236.cdf7293e710a9b2d.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/6387-237e079dac9a3ae6.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/6448-b6d272d074276e14.js +1 -0
  77. package/apps/pwa/out/_next/static/chunks/6466-92e65a48490b68a9.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/6566.926a1d1b7c911442.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6580-cdc0e4a634ce4708.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/6659-b242dc31b20b3f29.js +1 -0
  81. package/apps/pwa/out/_next/static/chunks/6690.c5d9b321b1f79384.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/671-e9b6ad0c771c5514.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/6862.bcbf89dd0f4496b3.js +27 -0
  84. package/apps/pwa/out/_next/static/chunks/6912-7b375ee48732c767.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/{5446.edf141cff9ef647d.js → 6925.562d532110879886.js} +1 -1
  86. package/apps/pwa/out/_next/static/chunks/{7005.1623d2aea78eb85f.js → 6943.c6b24124853a47b2.js} +1 -1
  87. package/apps/pwa/out/_next/static/chunks/727.7deb87749b0a343a.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{8368.014caa8de2f5af34.js → 7481.39f7a4654907bf6e.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7545.b1aa42cd15503319.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7551-416d298c2dc4a9ab.js +1 -0
  91. package/apps/pwa/out/_next/static/chunks/{2554.3b5e200f5f5cfcd6.js → 771.c3cdb6c1f7f47c02.js} +16 -16
  92. package/apps/pwa/out/_next/static/chunks/7784.1f0ac4a16d190cf4.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7870-309de463786ac1fc.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/7888-e29b151bb6a3bb8b.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/{3121.779fafe3e44612c5.js → 7891.03f910124a737985.js} +1 -1
  96. package/apps/pwa/out/_next/static/chunks/7905-6ba78d9234608f79.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/8037.e254fd797aa224d1.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8207.f527886b7c464529.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/856.50bda61439d465e6.js +62 -0
  100. package/apps/pwa/out/_next/static/chunks/{9a8cb466.cc9fc9e6e46038aa.js → 873d6c12.09bd499f57171543.js} +1 -1
  101. package/apps/pwa/out/_next/static/chunks/{7431.3051e9b8a4372d2d.js → 8904.7d51af2dc033965c.js} +2 -2
  102. package/apps/pwa/out/_next/static/chunks/9031-92e9b487edb681ee.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/9060.5410d9f6a95f6287.js +90 -0
  104. package/apps/pwa/out/_next/static/chunks/914.8abefd48d579547b.js +94 -0
  105. package/apps/pwa/out/_next/static/chunks/9187-c87a2207d4ac5d46.js +1 -0
  106. package/apps/pwa/out/_next/static/chunks/{1895-60ed0e341c658bd4.js → 9250-072df22eaadaa6b5.js} +1 -1
  107. package/apps/pwa/out/_next/static/chunks/9289.3e92f278821e18e0.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/9319.7816d3cc741cd34f.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/9327-e016bb9f1674d24f.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/9365.3de48bf75193ff9a.js +77 -0
  111. package/apps/pwa/out/_next/static/chunks/9383.5b5e9aa56b5fea97.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9387-cb929573ef436f39.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/9489.c27becacc3283dec.js +1 -0
  114. package/apps/pwa/out/_next/static/chunks/{2547.dd27303624cb4da8.js → 9514.131c52cc75fe6439.js} +1 -1
  115. package/apps/pwa/out/_next/static/chunks/9536.28962663c7734376.js +1 -0
  116. package/apps/pwa/out/_next/static/chunks/9686-12286f5bbf15a5a0.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/9776.289d40cc5a4c342a.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9789.60f723d18097ec30.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/989.f0c17523c5e61f65.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9972-1df393aa8d4f7d52.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/9f31e478.fefcbcd3c388ebc5.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-96750aba7430959f.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4105e5bbbb043024.js +1 -0
  124. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5d4fa75c2acb113e.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/board/page-a79a9bdb3b2142bf.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/botlab/page-f1c2047484992a35.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/bots/page-15ffc49b2d8c70e2.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/ceo/page-67d53a3fc8734135.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/chat/page-e30c8dc696491336.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/consult/page-2136e04fa77696e2.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/control/page-fecd2814790c2e12.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/decisions/page-280aa4a98fc5bb44.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/design-check/page-c14e96b65fb4b883.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/editor/page-187dac74825ed6bf.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/exec/page-6bc7246ea8c92448.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/field/{page-4fb31eb476dcbad3.js → page-083747f1d4518f61.js} +1 -1
  137. package/apps/pwa/out/_next/static/chunks/app/healthz/route-96750aba7430959f.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/inside/page-15ca95a16ec96e1f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/intake/page-a8ac031b3810eb64.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/layout-8835f93110494cda.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/live/page-e2de2e59111c9aad.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/live-run/page-f2b2e4bf6e981450.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/loops/page-5b92b7f75df20948.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/market/page-468eddf2b1a84ecb.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-2af16e62c12f22df.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/morning/page-18b40867a77a5793.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/not-found-fe934f2979f5a4a2.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/observatory/page-3eec435537357170.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ff88cbfd2aa99fc8.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a5b39fb780c70ab5.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ae465dde1d1b3933.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/outputs/page-e7abc34a48a6f71e.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/page-cab9674fde9ead26.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/reflection/page-1da49bc8712284d0.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-5e8aa657551ac912.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/sessions/page-fcc36f36c6dc1fe2.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-d22db22f2a7296ca.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/settings/page-d12dc7b1773878f0.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-99debec9ea7fbec0.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/setup/layout-96750aba7430959f.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/page-2a088a78bad7e924.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/share/page-2e8ed57db7e69993.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/showroom/page-4b3a16213c2ae8fe.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/tasks/page-f098747ddf38c98b.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/term/page-c15958835534404b.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/today/page-68279e3c843c1fd7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/trace/page-a34a74453367a39d.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/vault/page-8767a7db2155a5bd.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-bd5976683460d7f2.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b7364835e7f2ef54.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workspace/page-311af16b3ee0ffca.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-fb670757274ae990.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/{5014f970-22bef0b5210f7d60.js → ccae1c4b-0cf414f5eff1b10d.js} +1 -1
  174. package/apps/pwa/out/_next/static/chunks/{4fa33ebd.21c1bd5b294496e6.js → ceba0382.650712b56b85b582.js} +1 -1
  175. package/apps/pwa/out/_next/static/chunks/da5ecc5c-b005ad8cac737d57.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/f9a61e4d.1fc2c1dbdd49fe46.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/framework-6d497cbf1eef04c6.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/main-app-012f5edec932f337.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-da5aeb809edc94a2.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/pages/_app-5ee319af6f749dfe.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_error-4bc84653a718d6c6.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/webpack-8a96cf6775c73d6e.js +1 -0
  183. package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_buildManifest.js +1 -1
  184. package/apps/pwa/out/approvals/index.html +1 -1
  185. package/apps/pwa/out/approvals/index.txt +22 -22
  186. package/apps/pwa/out/autopilot/index.html +1 -1
  187. package/apps/pwa/out/autopilot/index.txt +22 -22
  188. package/apps/pwa/out/board/index.html +1 -1
  189. package/apps/pwa/out/board/index.txt +22 -22
  190. package/apps/pwa/out/botlab/index.html +1 -1
  191. package/apps/pwa/out/botlab/index.txt +21 -21
  192. package/apps/pwa/out/bots/index.html +1 -1
  193. package/apps/pwa/out/bots/index.txt +21 -21
  194. package/apps/pwa/out/ceo/index.html +1 -1
  195. package/apps/pwa/out/ceo/index.txt +22 -22
  196. package/apps/pwa/out/chat/index.html +1 -1
  197. package/apps/pwa/out/chat/index.txt +21 -21
  198. package/apps/pwa/out/consult/index.html +1 -1
  199. package/apps/pwa/out/consult/index.txt +22 -22
  200. package/apps/pwa/out/control/index.html +1 -1
  201. package/apps/pwa/out/control/index.txt +22 -22
  202. package/apps/pwa/out/decisions/index.html +1 -1
  203. package/apps/pwa/out/decisions/index.txt +21 -21
  204. package/apps/pwa/out/design-check/index.html +1 -1
  205. package/apps/pwa/out/design-check/index.txt +22 -22
  206. package/apps/pwa/out/editor/index.html +1 -1
  207. package/apps/pwa/out/editor/index.txt +22 -22
  208. package/apps/pwa/out/exec/index.html +1 -1
  209. package/apps/pwa/out/exec/index.txt +22 -22
  210. package/apps/pwa/out/field/index.html +1 -1
  211. package/apps/pwa/out/field/index.txt +22 -22
  212. package/apps/pwa/out/healthz +1 -1
  213. package/apps/pwa/out/index.html +1 -1
  214. package/apps/pwa/out/index.txt +21 -21
  215. package/apps/pwa/out/inside/index.html +1 -1
  216. package/apps/pwa/out/inside/index.txt +21 -21
  217. package/apps/pwa/out/intake/index.html +1 -1
  218. package/apps/pwa/out/intake/index.txt +22 -22
  219. package/apps/pwa/out/live/index.html +1 -1
  220. package/apps/pwa/out/live/index.txt +22 -22
  221. package/apps/pwa/out/live-run/index.html +1 -1
  222. package/apps/pwa/out/live-run/index.txt +22 -22
  223. package/apps/pwa/out/loops/index.html +1 -1
  224. package/apps/pwa/out/loops/index.txt +21 -21
  225. package/apps/pwa/out/market/index.html +1 -1
  226. package/apps/pwa/out/market/index.txt +21 -21
  227. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  228. package/apps/pwa/out/missions/placeholder/index.txt +21 -21
  229. package/apps/pwa/out/morning/index.html +1 -1
  230. package/apps/pwa/out/morning/index.txt +22 -22
  231. package/apps/pwa/out/observatory/index.html +1 -1
  232. package/apps/pwa/out/observatory/index.txt +22 -22
  233. package/apps/pwa/out/ops/checklist/index.html +1 -1
  234. package/apps/pwa/out/ops/checklist/index.txt +21 -21
  235. package/apps/pwa/out/ops/release/index.html +1 -1
  236. package/apps/pwa/out/ops/release/index.txt +21 -21
  237. package/apps/pwa/out/ops/seats/index.html +1 -1
  238. package/apps/pwa/out/ops/seats/index.txt +21 -21
  239. package/apps/pwa/out/outputs/index.html +1 -1
  240. package/apps/pwa/out/outputs/index.txt +21 -21
  241. package/apps/pwa/out/reflection/index.html +1 -1
  242. package/apps/pwa/out/reflection/index.txt +22 -22
  243. package/apps/pwa/out/scheduler/index.html +1 -1
  244. package/apps/pwa/out/scheduler/index.txt +22 -22
  245. package/apps/pwa/out/sessions/index.html +1 -1
  246. package/apps/pwa/out/sessions/index.txt +21 -21
  247. package/apps/pwa/out/settings/devices/index.html +1 -1
  248. package/apps/pwa/out/settings/devices/index.txt +22 -22
  249. package/apps/pwa/out/settings/index.html +1 -1
  250. package/apps/pwa/out/settings/index.txt +22 -22
  251. package/apps/pwa/out/setup/done/index.html +1 -1
  252. package/apps/pwa/out/setup/done/index.txt +22 -22
  253. package/apps/pwa/out/setup/index.html +1 -1
  254. package/apps/pwa/out/setup/index.txt +22 -22
  255. package/apps/pwa/out/share/index.html +1 -1
  256. package/apps/pwa/out/share/index.txt +22 -22
  257. package/apps/pwa/out/showroom/index.html +1 -1
  258. package/apps/pwa/out/showroom/index.txt +21 -21
  259. package/apps/pwa/out/tasks/index.html +1 -1
  260. package/apps/pwa/out/tasks/index.txt +22 -22
  261. package/apps/pwa/out/term/index.html +1 -1
  262. package/apps/pwa/out/term/index.txt +22 -22
  263. package/apps/pwa/out/today/index.html +1 -1
  264. package/apps/pwa/out/today/index.txt +22 -22
  265. package/apps/pwa/out/trace/index.html +1 -1
  266. package/apps/pwa/out/trace/index.txt +22 -22
  267. package/apps/pwa/out/vault/index.html +1 -1
  268. package/apps/pwa/out/vault/index.txt +22 -22
  269. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  270. package/apps/pwa/out/workflows/chat-ui/index.txt +22 -22
  271. package/apps/pwa/out/workflows/index.html +1 -1
  272. package/apps/pwa/out/workflows/index.txt +22 -22
  273. package/apps/pwa/out/workspace/index.html +1 -1
  274. package/apps/pwa/out/workspace/index.txt +22 -22
  275. package/apps/pwa/out/worktrees/index.html +1 -1
  276. package/apps/pwa/out/worktrees/index.txt +22 -22
  277. package/bin/elanous.mjs +3 -2
  278. package/catalog/providers/opengateway.yaml +25 -0
  279. package/docs/goal-context/01-goal-authoring-checks.md +8 -0
  280. package/docs/goal-context/03-verification-menu.md +24 -0
  281. package/docs/goal-context/04-mock-scenarios.md +100 -0
  282. package/docs/goal-context/05-authoring-lessons.jsonl +47 -0
  283. package/docs/goal-context/README.md +7 -0
  284. package/graphs/catalog/catalog.yaml +1 -1
  285. package/graphs/default-loop.yaml +63 -4
  286. package/graphs/document-loop.yaml +51 -3
  287. package/graphs/implement-loop.yaml +77 -4
  288. package/graphs/journey/ta-journey.yaml +11 -1
  289. package/graphs/journey/units/author-dialogue/author-dialogue.yaml +42 -0
  290. package/graphs/journey/units/author-dialogue/observe.ts +96 -0
  291. package/graphs/journey/units/author-dialogue/recipes.yaml +10 -0
  292. package/graphs/operate-loop.yaml +51 -3
  293. package/graphs/release/recipes.yaml +6 -0
  294. package/graphs/release/release-loop.yaml +17 -4
  295. package/graphs/research-loop.yaml +137 -3
  296. package/graphs/test-diet/test-diet.yaml +3 -0
  297. package/graphs/wizard/recipes.yaml +44 -0
  298. package/graphs/wizard/wizard-loop.yaml +44 -0
  299. package/graphs/work/research-report.yaml +2 -0
  300. package/package.json +1 -1
  301. package/scripts/ci-typecheck-changed.ts +139 -5
  302. package/scripts/coord-role-pack.ts +19 -6
  303. package/scripts/first10-gate.ts +416 -0
  304. package/scripts/fleet/wsl-node-setup.sh +432 -0
  305. package/scripts/hq/standby-snapshot.ts +17 -12
  306. package/scripts/release-loop/docs-land-node.ts +21 -5
  307. package/scripts/release-loop/docs-node.ts +204 -8
  308. package/scripts/release-loop/gate-baseline-receipt.ts +155 -0
  309. package/scripts/release-loop/gate-node.ts +427 -72
  310. package/scripts/release-loop/gate-partial.ts +65 -11
  311. package/scripts/release-loop/gate-radius-live.ts +177 -0
  312. package/scripts/release-loop/gate-radius-shadow.ts +1 -1
  313. package/scripts/release-loop/node-verdict.ts +14 -1
  314. package/scripts/release-loop/npm-publish-node.ts +66 -12
  315. package/scripts/release-loop/probe-pod-host-dirs-live.ts +5 -0
  316. package/scripts/release-loop/pwa-remote.ts +166 -0
  317. package/scripts/release-loop/pwa-scenarios-node.ts +19 -3
  318. package/scripts/release-loop/resume-cap.ts +14 -34
  319. package/scripts/release-loop/resume-release.ts +78 -15
  320. package/scripts/release-loop/traffic-node.ts +59 -0
  321. package/scripts/release-loop/traffic-transition.ts +159 -0
  322. package/scripts/release-loop/unattended-release.ts +2 -0
  323. package/scripts/rhythm/daily.ts +137 -3
  324. package/scripts/test-diet/lib.ts +6 -1
  325. package/scripts/test-diet/node.ts +194 -13
  326. package/scripts/ux-sim.ts +92 -0
  327. package/skills/README.md +1 -0
  328. package/src/acp/core-turn-bridge.ts +48 -6
  329. package/src/agent/delegate-hint.ts +16 -0
  330. package/src/agent/runner.ts +82 -2
  331. package/src/agent/self-ambient-cache.ts +8 -0
  332. package/src/agent/task-notification.ts +56 -10
  333. package/src/agent/types.ts +4 -0
  334. package/src/agent-substrate/acp-reviewer.ts +39 -4
  335. package/src/agent-substrate/pr-reviewer.ts +72 -3
  336. package/src/agent-substrate/review-intent.ts +29 -2
  337. package/src/agent-substrate/review-observation.ts +3 -0
  338. package/src/agent-substrate/self-review-cli.ts +229 -28
  339. package/src/autopilot/mission-codebase-gate.ts +141 -12
  340. package/src/autopilot/pr-manager.ts +240 -41
  341. package/src/boot/daemon-tools/self-implement.ts +1 -0
  342. package/src/budget/run-usage-rollup.ts +1 -0
  343. package/src/budget/usage-outcomes.ts +8 -4
  344. package/src/capture/tui-self-report.ts +102 -0
  345. package/src/chat/goal-continue-verdict.ts +41 -0
  346. package/src/chat/index.ts +30 -6
  347. package/src/chat/internal-turn-origin.ts +1 -0
  348. package/src/chat/paste-fold.ts +86 -0
  349. package/src/chat/pickers/modal-runtime.ts +10 -27
  350. package/src/chat/tool-render/block.ts +32 -0
  351. package/src/chat/tool-render/dispatch.ts +2 -20
  352. package/src/chat/tool-render/result-text.ts +98 -0
  353. package/src/chat/turn-typeahead.ts +70 -7
  354. package/src/cli/agent-cli.ts +13 -2
  355. package/src/cli/config-audit.ts +119 -0
  356. package/src/cli/doctor-cli.ts +26 -1
  357. package/src/cli/guardian-cli.ts +10 -0
  358. package/src/cli/herdr-cli.ts +34 -0
  359. package/src/cli/light-entry-route.ts +50 -7
  360. package/src/cli/log-event-names.ts +2 -0
  361. package/src/cli/make-cli.ts +247 -11
  362. package/src/cli/msg-cli.ts +117 -3
  363. package/src/cli/pod-cli.ts +77 -3
  364. package/src/cli/pr-cli.ts +34 -18
  365. package/src/cli/pr-land-base-read.ts +11 -2
  366. package/src/cli/pr-land-heavy-remote.ts +6 -3
  367. package/src/cli/pr-land-overlap-evidence.ts +23 -4
  368. package/src/cli/pr-land-pod-shadow-job.ts +3 -0
  369. package/src/cli/pr-land-recovery.ts +117 -1
  370. package/src/cli/pty-takeover-cli.ts +8 -7
  371. package/src/cli/release-checklist-read-cli.ts +79 -0
  372. package/src/cli/release-cli.ts +92 -106
  373. package/src/cli/release-single-flight.ts +1 -1
  374. package/src/cli/remote-resolve.ts +1 -1
  375. package/src/cli/root-tui-entry.ts +48 -0
  376. package/src/cli/sim-cli.ts +22 -0
  377. package/src/cli/tasks-card-show.ts +162 -0
  378. package/src/cli/tasks-cli.ts +1065 -338
  379. package/src/cli/tasks-read-cli.ts +197 -0
  380. package/src/cli/usage-cli.ts +13 -11
  381. package/src/clipboard/history.ts +179 -13
  382. package/src/config.ts +8 -1
  383. package/src/core-turn/run-core-turn.ts +4 -2
  384. package/src/core-turn/run-goal-loop.ts +73 -16
  385. package/src/core-turn/types.ts +6 -1
  386. package/src/dashboard/chat/acp-chat.ts +8 -0
  387. package/src/dashboard/context/keys.ts +8 -31
  388. package/src/dashboard/index.ts +280 -59
  389. package/src/dashboard/input/agent-wake.ts +7 -1
  390. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +146 -3
  391. package/src/dashboard/input/chat-main-slash-command.ts +4 -2
  392. package/src/dashboard/input/goal-continue.ts +210 -0
  393. package/src/dashboard/input/goal-interim.ts +2 -0
  394. package/src/dashboard/input/internal-turn.ts +2 -8
  395. package/src/dashboard/input/seat-autowake.ts +9 -7
  396. package/src/dashboard/input/turn-autoheal.ts +52 -0
  397. package/src/dashboard/render/theme-resolver.ts +33 -4
  398. package/src/dashboard/seat-boot-preamble.ts +132 -5
  399. package/src/dashboard/slash-runtime/chat-persona.ts +65 -8
  400. package/src/dashboard/slash-runtime/dashboard-handlers.ts +3 -2
  401. package/src/dashboard/slash-runtime/model-choices.ts +15 -0
  402. package/src/dashboard/stale-install-check.ts +3 -99
  403. package/src/debug/batch-queue.ts +119 -0
  404. package/src/debug/tui-log-tag.ts +67 -0
  405. package/src/display/agent-surface.ts +7 -0
  406. package/src/domains/schedule-registry.ts +16 -2
  407. package/src/domains/standalone-log-sink.ts +15 -2
  408. package/src/esc-abort-gate.ts +69 -0
  409. package/src/git-fs/idle-refresh.ts +76 -0
  410. package/src/git-fs/index.ts +18 -7
  411. package/src/git-fs/worktree.ts +137 -5
  412. package/src/graph-kinds/registry.ts +2 -2
  413. package/src/graph-runner/graph-cli.ts +18 -0
  414. package/src/graph-runner/runner.ts +173 -21
  415. package/src/graph-wizard/generate.ts +108 -4
  416. package/src/graph-wizard/steps.ts +15 -0
  417. package/src/grok/credential.ts +10 -3
  418. package/src/grounding/proactive-ground.ts +86 -0
  419. package/src/harness/control-inbox.ts +49 -1
  420. package/src/harness/harness-cli-command.ts +163 -35
  421. package/src/harness/harness-incidents.ts +85 -1
  422. package/src/harness/launch-utterance-ledger.ts +208 -0
  423. package/src/harness/pod-control-send.ts +33 -5
  424. package/src/harness/self-send-remote.ts +69 -0
  425. package/src/harness/self-send-routing-guard.ts +6 -0
  426. package/src/harness/self-send-target.ts +4 -3
  427. package/src/impl-discipline/detector.ts +16 -4
  428. package/src/impl-discipline/system-prompt.ts +11 -0
  429. package/src/impl-discipline/types.ts +2 -2
  430. package/src/index.ts +822 -154
  431. package/src/input-core/context-key-runtime.ts +21 -0
  432. package/src/intake-plane/already-built-hint.ts +4 -2
  433. package/src/intake-plane/requirement-funnel.ts +29 -1
  434. package/src/light-cli.ts +32 -11
  435. package/src/llm/opengateway-models.ts +11 -0
  436. package/src/llm/provider-credentials.ts +14 -0
  437. package/src/llm/provider-detect.ts +8 -1
  438. package/src/llm/runtime-model-family.ts +2 -1
  439. package/src/llm-wellformed.ts +70 -0
  440. package/src/llm.ts +247 -59
  441. package/src/loops/msg-wake.ts +35 -39
  442. package/src/loops/orchestrator/inbox.ts +59 -11
  443. package/src/loops/orchestrator/knowhow-pack.ts +364 -0
  444. package/src/loops/orchestrator/tick.ts +5 -1
  445. package/src/maturity/feature-maturity.ts +1 -1
  446. package/src/model-tier/llm-tier-map.ts +15 -1
  447. package/src/models/prompts.ts +17 -2
  448. package/src/msg/msg-post-office.ts +116 -0
  449. package/src/mss/logging/log-store.ts +79 -22
  450. package/src/native-tool-catalog.ts +15 -1
  451. package/src/nexus/api/decisions-route.ts +38 -18
  452. package/src/nexus/api/graph-wizard-api.ts +20 -2
  453. package/src/nexus/api/loop-resources.ts +13 -1
  454. package/src/nexus/boot/register-mcp-clients.ts +263 -38
  455. package/src/nexus/onboarding/first-boot-wizard.ts +56 -8
  456. package/src/oauth/codex.ts +7 -0
  457. package/src/onboarding/first-run.ts +37 -6
  458. package/src/onboarding/web-first.ts +43 -11
  459. package/src/ops/overview-collect.ts +30 -9
  460. package/src/ops/overview.ts +22 -9
  461. package/src/persona/loader.ts +11 -0
  462. package/src/persona/types.ts +8 -0
  463. package/src/pr-tool/census.ts +261 -27
  464. package/src/prompt-library/session-guidance.ts +14 -0
  465. package/src/provider-summary.ts +8 -0
  466. package/src/pty-shell/herdr-agent-report.ts +118 -9
  467. package/src/pty-shell/herdr-prompt.ts +266 -0
  468. package/src/pty-shell/pty-control-ipc.ts +151 -8
  469. package/src/pty-shell/pty-manifest.ts +7 -0
  470. package/src/pty-shell/pty-special-keys.ts +42 -2
  471. package/src/pty-shell/stale-install-check.ts +99 -0
  472. package/src/pty-shell/tui-run-state.ts +14 -2
  473. package/src/release-loop/auto-start.ts +20 -2
  474. package/src/release-loop/checklist.ts +100 -4
  475. package/src/release-loop/landed-but-yellow.ts +129 -5
  476. package/src/release-loop/light-rc.ts +1 -0
  477. package/src/release-loop/rehearsal.ts +37 -21
  478. package/src/repl/index.ts +192 -17
  479. package/src/repl/ops-msg-bridge.ts +32 -0
  480. package/src/seat-loop/knowhow-lint.ts +1 -1
  481. package/src/self-dev/ask-launch-flow.ts +44 -5
  482. package/src/self-dev/cli-help-text.ts +17 -0
  483. package/src/self-dev/decompose-proposal.ts +172 -20
  484. package/src/self-dev/decompose.ts +61 -0
  485. package/src/self-dev/dev-cli.ts +48 -12
  486. package/src/self-dev/dev-pipeline.ts +8 -2
  487. package/src/self-dev/draft-residue.ts +37 -1
  488. package/src/self-dev/draft-sweep.ts +137 -11
  489. package/src/self-dev/draft-triage-rules.ts +138 -0
  490. package/src/self-dev/fleet-reduce.ts +3 -2
  491. package/src/self-dev/glm-credential-guard.ts +77 -0
  492. package/src/self-dev/graph-front-nodes.ts +112 -0
  493. package/src/self-dev/graph-journey-nodes.ts +2 -0
  494. package/src/self-dev/graph-journey-route.ts +12 -2
  495. package/src/self-dev/harness-run-cli.ts +3 -15
  496. package/src/self-dev/orchestrate-cli-text.ts +10 -0
  497. package/src/self-dev/orchestrate-cli.ts +68 -3
  498. package/src/self-dev/orchestrate.ts +116 -17
  499. package/src/self-dev/review-provider-fallback.ts +35 -1
  500. package/src/self-dev/run-supervisor.ts +55 -2
  501. package/src/self-dev/run-types.ts +1 -1
  502. package/src/self-dev/self-orchestrate-runtime.ts +1 -11
  503. package/src/self-dev/shard-aggregate.ts +42 -5
  504. package/src/self-dev/shard-run.ts +8 -1
  505. package/src/self-health/autoheal.ts +153 -0
  506. package/src/self-health/signatures.ts +6 -0
  507. package/src/self-implement/blocked-draft-policy.ts +20 -0
  508. package/src/self-implement/classify-shadow.ts +3 -7
  509. package/src/self-implement/device-first.ts +116 -0
  510. package/src/self-implement/doctor-visit.ts +257 -2
  511. package/src/self-implement/evidence-command-budget.ts +80 -0
  512. package/src/self-implement/gate-baseline.ts +56 -17
  513. package/src/self-implement/gate-cli.ts +1 -0
  514. package/src/self-implement/gate-remote.ts +31 -20
  515. package/src/self-implement/goal-author-cli.ts +1 -0
  516. package/src/self-implement/goal-author-decompose.ts +534 -45
  517. package/src/self-implement/goal-author.ts +282 -7
  518. package/src/self-implement/goal-elaborate.ts +449 -0
  519. package/src/self-implement/goal-refine.ts +273 -0
  520. package/src/self-implement/graph-overlay-yaml.ts +14 -3
  521. package/src/self-implement/graph-variant.ts +40 -6
  522. package/src/self-implement/headless-elanous-driver.ts +19 -3
  523. package/src/self-implement/off-diff-evidence.ts +58 -6
  524. package/src/self-implement/orchestrator.ts +370 -62
  525. package/src/self-implement/pod-warm-pool-profile.ts +1 -0
  526. package/src/self-implement/pwa-import-graph.ts +1 -1
  527. package/src/self-implement/rework-budget-judgment.ts +5 -8
  528. package/src/self-implement/rework-policy.ts +30 -0
  529. package/src/self-implement/run-ledger.ts +108 -0
  530. package/src/self-implement/run-stop.ts +10 -1
  531. package/src/self-implement/run-ttl.ts +38 -24
  532. package/src/self-implement/running-runs.ts +29 -1
  533. package/src/self-implement/scope-adjacency.ts +115 -0
  534. package/src/self-implement/seams.ts +187 -28
  535. package/src/self-implement/stop-autoheal.ts +87 -1
  536. package/src/self-implement/wiring-check.ts +358 -0
  537. package/src/session-runtime/index.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +5 -0
  539. package/src/shell-env-bootstrap.ts +11 -4
  540. package/src/skills/runner.ts +4 -2
  541. package/src/skills/tools/agent.ts +408 -40
  542. package/src/skills/tools/msg-ask.ts +100 -0
  543. package/src/skills/tools/ops-ledger.ts +2 -1
  544. package/src/skills/tools/schedule-wakeup.ts +23 -4
  545. package/src/skills/tools/shell.ts +61 -6
  546. package/src/skills/tools/terminal-modal-inject.ts +1 -2
  547. package/src/skills/tools/terminal-modal.ts +10 -8
  548. package/src/skills/url-router.ts +41 -1
  549. package/src/smart-wizard/run.ts +66 -0
  550. package/src/status/bar.ts +34 -6
  551. package/src/status/status-provider-info.ts +37 -6
  552. package/src/steward/hold-hygiene.ts +24 -6
  553. package/src/steward/rejudge-tick.ts +10 -2
  554. package/src/steward/ta-repair-event-collect.ts +17 -6
  555. package/src/steward/triage-budget.ts +194 -0
  556. package/src/steward/triage.ts +20 -3
  557. package/src/task-agent/actions.ts +72 -2
  558. package/src/task-agent/green-sweep.ts +4 -0
  559. package/src/task-agent/land-queue.ts +21 -8
  560. package/src/task-agent/live-moves.ts +182 -10
  561. package/src/task-agent/mission.ts +30 -0
  562. package/src/task-agent/parent-host.ts +123 -3
  563. package/src/task-agent/rejudge-on-head.ts +15 -0
  564. package/src/task-agent/repair-cycle.ts +138 -32
  565. package/src/task-agent/repair-next-move.ts +31 -3
  566. package/src/task-agent/repair-outcomes.ts +29 -0
  567. package/src/task-agent/repair-worker.ts +14 -4
  568. package/src/task-agent/shadow.ts +48 -4
  569. package/src/task-agent/task-card-prefix.ts +2 -0
  570. package/src/task-agent/task-hand.ts +525 -57
  571. package/src/task-agent/task-parent-role-llm.ts +36 -0
  572. package/src/task-agent/tier-split.ts +196 -0
  573. package/src/task-agent/work-order-build.ts +2 -0
  574. package/src/task-agent/work-order.ts +3 -2
  575. package/src/task-orchestrator/generator-prompt.ts +60 -11
  576. package/src/task-orchestrator/surfaces/pod-account-broker.ts +42 -0
  577. package/src/task-orchestrator/surfaces/pod-child-providers.ts +1 -1
  578. package/src/task-orchestrator/surfaces/pod-child-reuse.ts +146 -0
  579. package/src/task-orchestrator/surfaces/pod-command-job.ts +130 -11
  580. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +215 -3
  581. package/src/task-orchestrator/surfaces/pod-image-source.ts +89 -1
  582. package/src/task-orchestrator/surfaces/pod-launch-history.ts +133 -0
  583. package/src/task-orchestrator/surfaces/pod-lease.ts +17 -8
  584. package/src/task-orchestrator/surfaces/pod-manifest-test-normalize.ts +19 -2
  585. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -4
  586. package/src/task-orchestrator/surfaces/pod-provenance.ts +82 -0
  587. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +18 -3
  588. package/src/task-orchestrator/surfaces/pod-si-warm-entry.ts +16 -0
  589. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +224 -0
  590. package/src/task-orchestrator/surfaces/pod-si-warm-protocol.ts +201 -0
  591. package/src/task-orchestrator/surfaces/pod-si-warm-provider.ts +444 -0
  592. package/src/task-orchestrator/surfaces/pod-si-warm-runner.ts +387 -0
  593. package/src/task-orchestrator/surfaces/pod-si-warm-transport.ts +157 -0
  594. package/src/task-orchestrator/surfaces/pod-source-receive.ts +18 -0
  595. package/src/task-orchestrator/surfaces/pod-warm-provenance.ts +81 -0
  596. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +6 -2
  597. package/src/task-orchestrator/surfaces/pod-warm-worker-protocol.ts +7 -0
  598. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +521 -40
  599. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +3 -0
  600. package/src/task-orchestrator/surfaces/self-implement-pod.ts +759 -50
  601. package/src/task-orchestrator/surfaces/self-implement.ts +65 -2
  602. package/src/tool-runtime/index.ts +15 -2
  603. package/src/tool-runtime/mcp-proxy-bootstrap.ts +29 -0
  604. package/src/tool-runtime/ops-ledger-runtimes.ts +10 -2
  605. package/src/tty-foreground.ts +155 -0
  606. package/src/tui/README.md +2 -0
  607. package/src/tui/chat/background-job-status.ts +54 -0
  608. package/src/tui/chat/goal-interim.ts +173 -0
  609. package/src/tui/chat/log-view.ts +267 -0
  610. package/src/tui/chat/self-health-status.ts +232 -0
  611. package/src/tui/entry.ts +695 -0
  612. package/src/tui/input/composer.ts +151 -0
  613. package/src/tui/seat-mail-boot.ts +59 -0
  614. package/src/tui/slash/compact-command.ts +7 -0
  615. package/src/tui/slash/compact.ts +94 -0
  616. package/src/tui/slash/new-session.ts +35 -0
  617. package/src/tui/slash/resume.ts +75 -0
  618. package/src/tui-client/local-chat-turn.ts +282 -0
  619. package/src/tui-client/local-harness-command.ts +63 -0
  620. package/src/tui-client/local-provider-command.ts +184 -0
  621. package/src/tui-client/next-dashboard-runtime.ts +8 -0
  622. package/src/tui-client/next-loop-command.ts +70 -0
  623. package/src/tui-client/next-wakeup.ts +191 -0
  624. package/src/tui.ts +37 -0
  625. package/src/ui/modal-adapter.ts +2 -2
  626. package/src/user-config.ts +4 -2
  627. package/src/ux-sim/classic-tui-seat-scenarios.ts +516 -0
  628. package/src/ux-sim/cli-config-audit-device.ts +121 -0
  629. package/src/ux-sim/dashboard-event-loop-stall-monitor-device.ts +238 -0
  630. package/src/ux-sim/event-monkey.ts +379 -0
  631. package/src/ux-sim/fake-bin.ts +87 -7
  632. package/src/ux-sim/fake-herdr.ts +238 -0
  633. package/src/ux-sim/fake-llm.ts +111 -6
  634. package/src/ux-sim/fault-glm-no-credential.ts +116 -0
  635. package/src/ux-sim/fault-nextmove-dispatch.ts +367 -0
  636. package/src/ux-sim/fault-pod-codex-503.ts +211 -0
  637. package/src/ux-sim/fault-scope-escape-lift.ts +216 -0
  638. package/src/ux-sim/fault-tui-400-autoheal.ts +297 -0
  639. package/src/ux-sim/goal-device.ts +619 -0
  640. package/src/ux-sim/in-process-cli.ts +22 -5
  641. package/src/ux-sim/mock-authoring-first-run-child.ts +35 -0
  642. package/src/ux-sim/mock-authoring-first-run.ts +97 -0
  643. package/src/ux-sim/mock-seat-pty-frame-child.ts +29 -0
  644. package/src/ux-sim/mock-seat-pty-frame.ts +297 -0
  645. package/src/ux-sim/mock-seat-pty-sequence-child.ts +21 -0
  646. package/src/ux-sim/mock-seat-pty-sequence.ts +206 -0
  647. package/src/ux-sim/next-tui-seat-scenarios.ts +631 -0
  648. package/src/ux-sim/onboarding-first-run-device.ts +269 -0
  649. package/src/ux-sim/pty-key-modifiers-device.ts +85 -0
  650. package/src/ux-sim/subagent-tools-device.ts +81 -0
  651. package/src/ux-sim/task-orchestrator-surfaces-self-implement-pod-device.ts +250 -0
  652. package/src/ux-sim/tty-foreground-steal-child.ts +21 -0
  653. package/src/version/packed-revision.json +1 -1
  654. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +0 -79
  655. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +0 -94
  658. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +0 -23
  660. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +0 -115
  662. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +0 -8
  663. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/2987-30cf9c2eb7b8bdd5.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/3001-5a52788c813b6113.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +0 -104
  681. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +0 -286
  682. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +0 -149
  683. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +0 -148
  684. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +0 -64
  685. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +0 -74
  688. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/5028-f0722e6114c313e7.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/5249.96a848656b582a93.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +0 -62
  695. package/apps/pwa/out/_next/static/chunks/5489.ec2dd1b5272a19dc.js +0 -24
  696. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +0 -77
  708. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +0 -90
  711. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +0 -287
  717. package/apps/pwa/out/_next/static/chunks/7448.478958ffbbba0ac0.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +0 -27
  722. package/apps/pwa/out/_next/static/chunks/7952.b192c31b6a0e00cc.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +0 -36
  725. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +0 -93
  738. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +0 -24
  740. package/apps/pwa/out/_next/static/chunks/9739.8d5f36ac67a3b236.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +0 -1
  763. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +0 -1
  764. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +0 -1
  765. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +0 -1
  766. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +0 -1
  767. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +0 -1
  768. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +0 -1
  769. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +0 -1
  770. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +0 -1
  771. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +0 -1
  772. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +0 -1
  773. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +0 -1
  774. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +0 -1
  775. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +0 -1
  776. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +0 -1
  777. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +0 -1
  778. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-398c0faa173203f7.js +0 -1
  779. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +0 -1
  780. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +0 -1
  781. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +0 -1
  782. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +0 -1
  783. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +0 -1
  784. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +0 -1
  785. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +0 -1
  786. package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +0 -1
  787. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +0 -1
  788. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +0 -1
  789. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +0 -1
  790. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +0 -1
  791. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +0 -1
  792. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +0 -1
  793. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +0 -1
  794. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +0 -122
  795. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +0 -1
  796. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +0 -1
  797. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +0 -1
  798. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +0 -1
  799. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +0 -1
  800. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +0 -1
  801. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +0 -1
  802. /package/apps/pwa/out/_next/static/{L04y73dlwKeTW-GetaTF3 → uC-N0emedeNOFuaBQFv-I}/_ssgManifest.js +0 -0
@@ -14,26 +14,38 @@
14
14
  //
15
15
  // index.ts 의 액션은 옵션 파싱과 실제 의존 배선만 남는다(얇은 껍데기).
16
16
 
17
- import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
18
18
  import { homedir, tmpdir } from 'node:os';
19
19
  import { dirname, join } from 'node:path';
20
20
  import { effectiveInstanceRoot } from '../instance/resolve.js';
21
21
  import { tierModel } from '../llm/model-defaults.js';
22
22
  import { buildReviewObservation, safeLogText } from './review-observation.js';
23
- import { DEFAULT_REVIEW_BACKEND } from './acp-reviewer.js';
23
+ import { DEFAULT_REVIEW_BACKEND, defaultAcpReviewTimeoutSec } from './acp-reviewer.js';
24
+ import { ZAI_OPENROUTER_FALLBACK_MODEL } from '../llm/zai-coding-plan.js';
25
+ import { debug } from '../debug/log.js';
24
26
  import { ACP_BACKENDS, canonicalizeBackendId } from '../acp/backend-registry.js';
25
27
  import { buildManualReviewIntent, intentFromPr, prIntentSectionCoverage, reviewIntentTruncationFromPr, reviewIntentTruncationObservation } from './review-intent.js';
26
28
  import { budgetReviewerContext, reviewDiffBudgetObservation, splitDiffByFile, type ReviewImage, type ReviewInput, type ReviewerContextItem, type ReviewResult } from './pr-reviewer.js';
27
29
  import type { ReferencedFileReader } from '../self-implement/goal-file-reader.js';
28
- import { getUserConfig, type SubscriptionReviewerSpec } from '../user-config.js';
30
+ import { getUserConfig, type LLMProviderName, type RoleLlmSpec, type SubscriptionReviewerSpec } from '../user-config.js';
29
31
  import { listRunLedgers, lookupPrGoalAcceptance, lookupRunLedger, type PrGoalAcceptanceLookup, type RunLedgerEntry, type RunLedgerLookup } from '../self-implement/run-ledger.js';
30
32
 
31
33
  /** SUBSCRIPTION-EXHAUST-REROUTE — API reviewer when the configured `roleLlm.reviewer` lane is unavailable (off codex). */
32
34
  export const ROLE_REVIEWER_FALLBACK_MODEL = 'openrouter/z-ai/glm-5.3';
33
35
 
36
+ /** Only an explicit provider+model role setting selects the API review model. */
37
+ export function apiReviewModelFromRoleSpec(spec: RoleLlmSpec | undefined): string | undefined {
38
+ const model = spec?.model?.trim();
39
+ if (!spec?.provider || !model) return undefined;
40
+ return spec.provider === 'openrouter' && !model.startsWith('openrouter/') ? `openrouter/${model}` : model;
41
+ }
42
+
34
43
  export interface SelfReviewCliOpts {
35
44
  intent?: string | undefined;
36
45
  model?: string | undefined;
46
+ /** Explicit `roleLlm.review` provider+model, normalized by the CLI entry. */
47
+ configuredReviewModel?: string | undefined;
48
+ configuredReviewProvider?: LLMProviderName | undefined;
37
49
  acp?: boolean | undefined;
38
50
  acpModel?: string | undefined;
39
51
  acpBackend?: string | undefined;
@@ -73,7 +85,7 @@ export interface SelfReviewCliDeps {
73
85
  * 라우터 폴백(grok 등)으로 조용히 넘어가지 않고 실패를 오류로 낸다.
74
86
  * `o.onResolved` — streamLLM 이 «실제로 응답한» provider·model 을 알린다.
75
87
  */
76
- makeApiLlm(model: string, o?: { pinProvider?: boolean; onResolved?: (provider: string, model: string) => void }): (prompt: string) => Promise<string>;
88
+ makeApiLlm(model: string, o?: { pinProvider?: boolean; providerName?: LLMProviderName; onResolved?: (provider: string, model: string) => void }): (prompt: string) => Promise<string>;
77
89
  /** `--acp` 경로 리뷰어 LLM(독립 프로세스). */
78
90
  /**
79
91
  * ⭐ `P4b` — 두 번째 인자가 **멀티미디어 통로**다.
@@ -127,27 +139,36 @@ export interface SelfReviewCliOutcome {
127
139
  }
128
140
 
129
141
  /** Saved results are round evidence only when their PR, exact head and reviewed status agree. */
130
- export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
142
+ function savedReviewRecords(pr: string, root = effectiveInstanceRoot()): Array<{ head: string; reviewedAt: number }> {
131
143
  const dir = join(root, 'review-results');
132
144
  let names: string[];
133
145
  try { names = readdirSync(dir); } catch { return []; }
134
146
  // Manual review saves in the operating house also use head10; the JSON's full head is authoritative.
135
147
  const matching = new RegExp(`^.+-${pr}-([a-f0-9]{7,40})\\.json$`, 'i');
136
- const heads = new Set<string>();
148
+ const records = new Map<string, { head: string; reviewedAt: number }>();
137
149
  for (const name of names) {
138
150
  const match = matching.exec(name);
139
151
  if (!match) continue;
140
152
  try {
141
- const raw: unknown = JSON.parse(readFileSync(join(dir, name), 'utf8'));
153
+ const recordPath = join(dir, name);
154
+ const raw: unknown = JSON.parse(readFileSync(recordPath, 'utf8'));
142
155
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) continue;
143
156
  const result = raw as Record<string, unknown>;
144
157
  const head = result.headCommit;
145
158
  if (String(result.pr) !== pr || result.reviewed !== true || typeof head !== 'string'
146
159
  || !COMMIT_OID.test(head) || !head.toLowerCase().startsWith(match[1]!.toLowerCase())) continue;
147
- heads.add(head.toLowerCase());
160
+ const normalized = head.toLowerCase();
161
+ const existing = records.get(normalized);
162
+ const reviewedAt = typeof result.reviewedAt === 'number' && Number.isFinite(result.reviewedAt)
163
+ ? result.reviewedAt : statSync(recordPath).mtimeMs;
164
+ if (!existing || reviewedAt > existing.reviewedAt) records.set(normalized, { head: normalized, reviewedAt });
148
165
  } catch { /* corrupt or partial result is not a completed round */ }
149
166
  }
150
- return [...heads];
167
+ return [...records.values()];
168
+ }
169
+
170
+ export function savedReviewHeads(pr: string, root = effectiveInstanceRoot()): string[] {
171
+ return savedReviewRecords(pr, root).map(({ head }) => head);
151
172
  }
152
173
 
153
174
  function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string | null {
@@ -166,14 +187,42 @@ function normalizeReviewPrArg(input: string, deps: SelfReviewCliDeps): string |
166
187
  } catch { return null; }
167
188
  }
168
189
 
190
+ function readCapOverride(pr: string): { head: string; reason: string } | undefined {
191
+ try {
192
+ const value = JSON.parse(readFileSync(join(effectiveInstanceRoot(), 'review-results', `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
193
+ if (String(value.pr) !== pr || typeof value.head !== 'string' || !COMMIT_OID.test(value.head)
194
+ || typeof value.reason !== 'string' || !value.reason.trim()) return undefined;
195
+ return { head: value.head.toLowerCase(), reason: value.reason };
196
+ } catch { return undefined; }
197
+ }
198
+
169
199
  function claimCapOverride(pr: string, head: string, reason: string, now: number): boolean {
170
200
  const dir = join(effectiveInstanceRoot(), 'review-results');
171
201
  try {
172
202
  mkdirSync(dir, { recursive: true });
173
- // wx is atomic across concurrent CLI processes; a PR receives one recorded exception.
174
- writeFileSync(join(dir, `cap-override-${pr}.json`), JSON.stringify({ pr, head, reason, claimedAt: now }) + '\n', { flag: 'wx' });
203
+ const normalizedHead = head.toLowerCase();
204
+ const authorizationPath = join(dir, `cap-override-${pr}.json`);
205
+ // The first over-cap review creates the durable, PR-scoped authorization record atomically.
206
+ writeFileSync(authorizationPath, JSON.stringify({ pr, head: normalizedHead, reason, claimedAt: now, use: 'initial-authorization' }) + '\n', { flag: 'wx' });
175
207
  return true;
176
- } catch { return false; }
208
+ } catch {
209
+ // An OP authorization applies to later heads of this PR while the allowlist remains active.
210
+ // Keep the initial claim immutable, and atomically record each additional head separately so
211
+ // retries of the same head cannot spend the grant twice.
212
+ try {
213
+ const authorization = JSON.parse(readFileSync(join(dir, `cap-override-${pr}.json`), 'utf8')) as Record<string, unknown>;
214
+ const authorizedHead = authorization.head;
215
+ if (String(authorization.pr) !== pr || typeof authorization.reason !== 'string' || !authorization.reason.trim()
216
+ || authorization.reason !== reason
217
+ || typeof authorizedHead !== 'string' || !COMMIT_OID.test(authorizedHead)
218
+ || authorizedHead.toLowerCase() === head.toLowerCase()) return false;
219
+ const normalizedHead = head.toLowerCase();
220
+ writeFileSync(join(dir, `cap-override-${pr}-head-${normalizedHead}.json`), JSON.stringify({
221
+ pr, head: normalizedHead, reason, claimedAt: now, use: 'subsequent-head', authorizationHead: authorizedHead.toLowerCase(),
222
+ }) + '\n', { flag: 'wx' });
223
+ return true;
224
+ } catch { return false; }
225
+ }
177
226
  }
178
227
 
179
228
  /** OP owns this list. Missing, unreadable, or malformed traffic never grants a review exception. */
@@ -1331,6 +1380,34 @@ export function selfReviewJsonLine(results: readonly unknown[]): string {
1331
1380
  return JSON.stringify(results.length === 1 ? results[0] : results) + '\n';
1332
1381
  }
1333
1382
 
1383
+ // Normalize only whole-item forms whose complete text is an explicit no-finding
1384
+ // sentinel. Any extra clause stays in mustFix (fail-closed).
1385
+ const NO_FINDING_REVIEW_NOTE_ALLOWLIST: readonly RegExp[] = [
1386
+ /^(?:없음|해당\s*없음|none|nothing|n\/a)[.!。]?$/i,
1387
+ /^\((?:없음|해당\s*없음|none|nothing|n\/a)\)[.!。]?$/i,
1388
+ /^\(이 조각에서 확인된 코어 결함 없음\s*[—–-]\s*명시 intent 기준 mustFix 는 비움\)$/i,
1389
+ /^\(이 조각에서 검증된 (?:차단 )?결함은 발견되지 않음(?:\s*\(mustFix \[\]\))?\)$/i,
1390
+ ];
1391
+
1392
+ function isNoFindingReviewNote(finding: string): boolean {
1393
+ const wholeItem = finding.trim();
1394
+ return NO_FINDING_REVIEW_NOTE_ALLOWLIST.some((form) => form.test(wholeItem));
1395
+ }
1396
+
1397
+ function normalizeSavedReviewMustFix(result: Record<string, unknown>): { result: Record<string, unknown>; count: number } {
1398
+ if (!Array.isArray(result.mustFix)) return { result, count: 0 };
1399
+ const noFindingNotes = result.mustFix.filter((finding): finding is string =>
1400
+ typeof finding === 'string' && isNoFindingReviewNote(finding));
1401
+ if (noFindingNotes.length === 0) return { result, count: 0 };
1402
+ const retained = result.mustFix.filter((finding) =>
1403
+ typeof finding !== 'string' || !isNoFindingReviewNote(finding));
1404
+ const existingNotes = Array.isArray(result.noFindingNotes) ? result.noFindingNotes : [];
1405
+ return {
1406
+ result: { ...result, mustFix: retained, noFindingNotes: [...existingNotes, ...noFindingNotes] },
1407
+ count: noFindingNotes.length,
1408
+ };
1409
+ }
1410
+
1334
1411
  export async function runSelfReviewCliCommand(
1335
1412
  prArgs: string[],
1336
1413
  opts: SelfReviewCliOpts,
@@ -1371,7 +1448,9 @@ async function runSelfReviewCliCommandPinned(
1371
1448
  return { results: [], failed: 1 };
1372
1449
  }
1373
1450
 
1374
- const useAcp = opts.acp === true;
1451
+ // An explicit API model is the caller's reviewer choice even when a default ACP lane supplied both flags.
1452
+ const requestedModel = opts.model?.trim() || undefined;
1453
+ const useAcp = opts.acp === true && !requestedModel;
1375
1454
  const acpModel = opts.acpModel?.trim() || undefined;
1376
1455
  const acpBackendResolution = opts.acpBackend
1377
1456
  ? { backend: opts.acpBackend, source: 'cli' as const }
@@ -1379,7 +1458,6 @@ async function runSelfReviewCliCommandPinned(
1379
1458
  ? { backend: opts.configuredAcpBackend, source: 'config' as const }
1380
1459
  : { backend: DEFAULT_REVIEW_BACKEND, source: 'default' as const };
1381
1460
  const acpBackend = acpBackendResolution.backend;
1382
- const requestedModel = opts.model?.trim() || undefined;
1383
1461
  const rawReviewDenyBackends = (getUserConfig().raw?.acp as { reviewDenyBackends?: unknown } | undefined)?.reviewDenyBackends;
1384
1462
  const denyCheckedAt = Date.now();
1385
1463
  const configuredReviewDenyBackends = validateReviewDenyBackends(rawReviewDenyBackends, denyCheckedAt);
@@ -1396,11 +1474,15 @@ async function runSelfReviewCliCommandPinned(
1396
1474
  ? [canonicalizeBackendId(opts.acpBackend)]
1397
1475
  : automaticFallbacks.backends;
1398
1476
  const skippedAcpFallbackBackends = opts.acpBackend ? [] : automaticFallbacks.skipped;
1399
- const acpTimeoutSec = Number.isFinite(Number(opts.acpTimeout)) && Number(opts.acpTimeout) > 0
1400
- ? Number(opts.acpTimeout) : 300;
1477
+ // ACP-REVIEW-VIA-TEAMCLAUDE: no `--acp-timeout` = the backend's default (claude 600s · others 300s).
1478
+ const explicitAcpTimeoutSec = Number.isFinite(Number(opts.acpTimeout)) && Number(opts.acpTimeout) > 0
1479
+ ? Number(opts.acpTimeout) : undefined;
1480
+ const acpTimeoutSecFor = (backend: string): number => explicitAcpTimeoutSec ?? defaultAcpReviewTimeoutSec(backend);
1481
+ const acpTimeoutSec = explicitAcpTimeoutSec ?? 300;
1482
+ const primaryAcpTimeoutSec = acpTimeoutSecFor(acpBackend);
1401
1483
  let acpReviewLLM: ((prompt: string, images?: readonly ReviewImage[]) => Promise<string>) | null = null;
1402
1484
  if (useAcp) {
1403
- acpReviewLLM = deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: acpTimeoutSec * 1000 });
1485
+ acpReviewLLM = deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: primaryAcpTimeoutSec * 1000 });
1404
1486
  }
1405
1487
  // ⭐ Reviewer selection source. An explicit flag always wins byte-for-byte; only without one does
1406
1488
  // `roleLlm.reviewer` (the harness's reviewer row) pick the ACP lane. Worst case = today's API review.
@@ -1422,7 +1504,11 @@ async function runSelfReviewCliCommandPinned(
1422
1504
  deps.error(message);
1423
1505
  return { results: opts.json ? [{ error: message, requestedModel }] : [], failed: 1 };
1424
1506
  }
1425
- const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (opts.model || envModel || roleFallbackModel || tierModel('better'));
1507
+ const configuredReviewModel = opts.configuredReviewModel?.trim() || undefined;
1508
+ // REVIEW-MODEL-ALIAS-PROVIDER: provider pinning needs GLM's OpenRouter model id, not the bare alias.
1509
+ const explicitApiModel = requestedModel?.toLowerCase() === 'glm' ? ROLE_REVIEWER_FALLBACK_MODEL : opts.model;
1510
+ const model = useAcp ? `acp:${acpBackend}${acpModel ? `/${acpModel}` : ''}` : (explicitApiModel || envModel || configuredReviewModel || roleFallbackModel || tierModel('better'));
1511
+ const configuredReviewSelected = !opts.model?.trim() && !envModel && Boolean(configuredReviewModel);
1426
1512
  let roleReviewer: { llm: (prompt: string, images?: readonly ReviewImage[]) => Promise<string>; model: string } | undefined;
1427
1513
  let roleReviewerUnavailableReason: string | undefined;
1428
1514
  let roleReviewerAvailabilityMs: number | undefined;
@@ -1444,7 +1530,7 @@ async function runSelfReviewCliCommandPinned(
1444
1530
  deps.log('role-reviewer-fallback', {
1445
1531
  reviewerSource, roleReviewerProvider: opts.roleReviewer.provider, roleReviewerAvailabilityMs,
1446
1532
  stage: 'availability', reason: roleReviewerUnavailableReason, fallbackModel: safeLogText(model),
1447
- fallbackModelSource: roleFallbackModel ? 'role-fallback' : 'default',
1533
+ fallbackModelSource: configuredReviewSelected ? 'role-review-config' : roleFallbackModel ? 'role-fallback' : 'default',
1448
1534
  }, { level: 'warn' });
1449
1535
  }
1450
1536
  }
@@ -1463,16 +1549,17 @@ async function runSelfReviewCliCommandPinned(
1463
1549
  const previousHeads = savedReviewHeads(pr);
1464
1550
  const previousRoundCount = previousHeads.length;
1465
1551
  const reason = opts.overCapReason?.trim();
1552
+ const authorization = previousRoundCount >= 5 ? readCapOverride(pr) : undefined;
1466
1553
  deps.observeDoctorReview?.('round-counted', { pr, previousRoundCount, round: previousRoundCount + 1 });
1467
1554
  const opAllowed = previousRoundCount >= 5 && opAllowsReviewOverCap(pr);
1468
1555
  if (previousRoundCount >= 5) {
1469
1556
  deps.observeDoctorReview?.('cap-attempt', { pr, previousRoundCount, round: previousRoundCount + 1, reasonProvided: Boolean(reason), opAllowed }, { level: 'warn' });
1470
1557
  }
1471
- if (previousRoundCount >= 5 && (!reason || !opAllowed)) {
1558
+ if (previousRoundCount >= 5 && (!opAllowed || (!authorization && !reason))) {
1472
1559
  const refusalHead = prHeadCommit(pr, deps).value;
1473
1560
  const message = !opAllowed
1474
1561
  ? `PR ${pr}: r5 상한 초과 리뷰는 OP traffic.json reviewOverCapAllow 허용 목록에 있어야 합니다.`
1475
- : `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. 새 리뷰는 --over-cap-reason <사유>로 PR당 한 번만 허용됩니다.`;
1562
+ : `PR ${pr}: 저장된 서로 다른 head 리뷰 ${previousRoundCount}개로 r5 상한에 도달했습니다. OP 허용 상태와 --over-cap-reason <사유>가 필요합니다.`;
1476
1563
  deps.observeDoctorReview?.('cap-refused', { pr, head: refusalHead, previousRoundCount, round: previousRoundCount + 1, reason: opAllowed ? 'missing-reason' : 'not-op-allowlisted' }, { level: 'warn' });
1477
1564
  deps.error(message);
1478
1565
  if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: refusalHead });
@@ -1480,9 +1567,69 @@ async function runSelfReviewCliCommandPinned(
1480
1567
  continue;
1481
1568
  }
1482
1569
  const diffRead = readDiffAtHead(pr, deps);
1483
- if (previousRoundCount >= 5 && reason) {
1484
- // Claim only the exact SHA-pinned diff that the reviewer will see; never spend the sole
1485
- // exception on a separately read head that may move before readDiffAtHead.
1570
+ if (previousRoundCount >= 5 && authorization && diffRead.headCommit.toLowerCase() === authorization.head) {
1571
+ const message = `PR ${pr}: 동일 head는 이미 승인 소모 기록이 있습니다.`;
1572
+ deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'same-head-already-used' }, { level: 'warn' });
1573
+ deps.error(message);
1574
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1575
+ failed += 1;
1576
+ continue;
1577
+ }
1578
+ if (previousRoundCount >= 5 && authorization && reason && reason !== authorization.reason) {
1579
+ const message = `PR ${pr}: 기존 PR 승인의 사유와 일치하지 않습니다.`;
1580
+ deps.observeDoctorReview?.('cap-refused', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason: 'authorization-reason-mismatch' }, { level: 'warn' });
1581
+ deps.error(message);
1582
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1583
+ failed += 1;
1584
+ continue;
1585
+ }
1586
+ let mergeOnlyDeltaRange: { base: string; head: string } | undefined;
1587
+ if (previousRoundCount >= 5 && authorization) {
1588
+ const git = deps.git;
1589
+ if (!git || diffRead.source !== 'sha-pinned' || diffRead.headCommitState !== 'known'
1590
+ || diffRead.currentHeadCommitState !== 'known' || diffRead.stale || diffRead.diff.status !== 0) {
1591
+ const message = `PR ${pr}: 후속 head의 merge-only 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1592
+ deps.error(message);
1593
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1594
+ failed += 1;
1595
+ continue;
1596
+ }
1597
+ const savedRecords = savedReviewRecords(pr);
1598
+ const latestReviewed = savedRecords.reduce<(typeof savedRecords)[number] | undefined>(
1599
+ (latest, record) => !latest || record.reviewedAt > latest.reviewedAt ? record : latest, undefined,
1600
+ );
1601
+ const classificationBase = latestReviewed?.head ?? authorization.head;
1602
+ const ancestry = git(['merge-base', '--is-ancestor', classificationBase, diffRead.headCommit], 10_000);
1603
+ const parents = git(['rev-list', '--parents', '-n', '1', diffRead.headCommit], 10_000);
1604
+ const parentFields = parents.stdout.trim().split(/\s+/);
1605
+ const headIsMerge = parentFields.length > 2;
1606
+ const deltaHead = headIsMerge ? parentFields[1] : diffRead.headCommit;
1607
+ if ((ancestry.status !== 0 && ancestry.status !== 1) || parents.status !== 0 || parentFields[0]?.toLowerCase() !== diffRead.headCommit.toLowerCase()
1608
+ || !COMMIT_OID.test(deltaHead) || classificationBase === diffRead.headCommit.toLowerCase()) {
1609
+ const message = `PR ${pr}: 후속 head ancestry 또는 parent 정보를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1610
+ deps.error(message);
1611
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1612
+ failed += 1;
1613
+ continue;
1614
+ }
1615
+ // A non-ancestor head can be a force-push rewind or rebase. It is still
1616
+ // reviewed from the pinned full PR diff; only a proven descendant can
1617
+ // qualify for the merge-only delta path.
1618
+ if (ancestry.status === 0) {
1619
+ // Non-merge commits brought in from main are reachable but are not on
1620
+ // this first-parent line. A merge-only head ends at its first parent;
1621
+ // a later PR commit remains in the candidate range.
1622
+ const commits = git(['rev-list', '--first-parent', '--no-merges', `${classificationBase}..${deltaHead}`], 10_000);
1623
+ if (commits.status !== 0) {
1624
+ const message = `PR ${pr}: 후속 head의 PR 변경 여부를 확인할 수 없어 상한 예외 리뷰를 거부합니다.`;
1625
+ deps.error(message);
1626
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1627
+ failed += 1;
1628
+ continue;
1629
+ }
1630
+ if (commits.stdout.trim() === '') mergeOnlyDeltaRange = { base: classificationBase, head: diffRead.headCommit.toLowerCase() };
1631
+ }
1632
+ } else if (previousRoundCount >= 5 && reason) {
1486
1633
  const claimable = diffRead.source === 'sha-pinned' && diffRead.headCommitState === 'known'
1487
1634
  && diffRead.currentHeadCommitState === 'known' && !diffRead.stale && diffRead.diff.status === 0;
1488
1635
  if (!claimable || !claimCapOverride(pr, diffRead.headCommit, reason, deps.now())) {
@@ -1495,6 +1642,25 @@ async function runSelfReviewCliCommandPinned(
1495
1642
  }
1496
1643
  deps.observeDoctorReview?.('cap-override', { pr, head: diffRead.headCommit, previousRoundCount, round: previousRoundCount + 1, reason }, { level: 'warn' });
1497
1644
  }
1645
+ if (mergeOnlyDeltaRange) {
1646
+ const delta = deps.git?.(['diff', '--no-ext-diff', `${mergeOnlyDeltaRange.base}...${mergeOnlyDeltaRange.head}`], 25_000);
1647
+ if (!delta || delta.status !== 0) {
1648
+ const message = `PR ${pr}: merge-only 후속 head의 delta diff를 고정할 수 없습니다.`;
1649
+ deps.error(message);
1650
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1651
+ failed += 1;
1652
+ continue;
1653
+ }
1654
+ diffRead.diff = delta;
1655
+ diffRead.baseCommit = mergeOnlyDeltaRange.base;
1656
+ }
1657
+ if (previousRoundCount >= 5 && authorization && !claimCapOverride(pr, diffRead.headCommit, authorization.reason, deps.now())) {
1658
+ const message = `PR ${pr}: 후속 head 승인 사용 기록을 남기지 못했습니다.`;
1659
+ deps.error(message);
1660
+ if (opts.json || opts.save !== undefined) results.push({ pr, error: message, reviewed: false, refusal: 'cap-refused', previousRoundCount, headCommit: diffRead.headCommit });
1661
+ failed += 1;
1662
+ continue;
1663
+ }
1498
1664
  const localHeadComparison = compareLocalHead(pr, { value: diffRead.headCommit, state: diffRead.headCommitState }, deps);
1499
1665
  const { diff } = diffRead;
1500
1666
  const baseReviewerContext = hasProvidedReviewerContext
@@ -1668,7 +1834,7 @@ async function runSelfReviewCliCommandPinned(
1668
1834
  } else if (mergeState.kind === 'unpinnable') reviewCwdPinFallbackReason = mergeState.reason;
1669
1835
  const reviewCwd = reviewPin?.cwd;
1670
1836
  const prAcpReviewLLM = reviewCwd && useAcp
1671
- ? deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: acpTimeoutSec * 1000, cwd: reviewCwd })
1837
+ ? deps.makeAcpLlm({ backend: acpBackend, ...(acpModel ? { model: acpModel } : {}), timeoutMs: primaryAcpTimeoutSec * 1000, cwd: reviewCwd })
1672
1838
  : acpReviewLLM;
1673
1839
  let prRoleReviewer = roleReviewer;
1674
1840
  if (reviewCwd && roleReviewer && opts.roleReviewer && deps.makeRoleReviewerLlm) {
@@ -1684,7 +1850,8 @@ async function runSelfReviewCliCommandPinned(
1684
1850
  // Role-config lane builds the API reviewer only when it falls back (`made().api` stays 0 on ACP success).
1685
1851
  const responded: { provider?: string; model?: string } = {};
1686
1852
  const makeApi = () => deps.makeApiLlm(model, {
1687
- pinProvider: Boolean(opts.model?.trim()),
1853
+ pinProvider: Boolean(opts.model?.trim() || configuredReviewSelected),
1854
+ ...(configuredReviewSelected && opts.configuredReviewProvider ? { providerName: opts.configuredReviewProvider } : {}),
1688
1855
  onResolved: (provider, respondedModel) => { responded.provider = provider; responded.model = respondedModel; },
1689
1856
  });
1690
1857
  const llmReview = prRoleReviewer ? undefined : (prAcpReviewLLM ?? makeApi());
@@ -1748,7 +1915,7 @@ async function runSelfReviewCliCommandPinned(
1748
1915
  try {
1749
1916
  const fallbackReview = await deps.reviewPullRequest(
1750
1917
  reviewInput,
1751
- deps.makeAcpLlm({ backend, timeoutMs: acpTimeoutSec * 1000, ...(reviewCwd ? { cwd: reviewCwd } : {}) }),
1918
+ deps.makeAcpLlm({ backend, timeoutMs: acpTimeoutSecFor(backend) * 1000, ...(reviewCwd ? { cwd: reviewCwd } : {}) }),
1752
1919
  );
1753
1920
  if (fallbackReview.reviewed === true) {
1754
1921
  review = fallbackReview;
@@ -1764,6 +1931,34 @@ async function runSelfReviewCliCommandPinned(
1764
1931
  }
1765
1932
  }
1766
1933
  }
1934
+ // OP #25981: an explicit ACP claude review that ends without a verdict («Autocompact is thrashing …» ·
1935
+ // reviewed:false · no JSON) goes once to GLM on the same head — never a claude retry (subscription quota).
1936
+ // An explicit `--acp-model` is the operator's model choice: it is not silently swapped for GLM.
1937
+ // GLM that throws or also ends without a verdict keeps the claude result, and says so (`glmReviewed`).
1938
+ let claudeFallbackGlm: { reason: string; model: string; glmReviewed: boolean; glmFailureReason?: string } | undefined;
1939
+ if (useAcp && !roleReview && !acpModel && canonicalizeBackendId(acpBackend) === 'claude' && review.reviewed !== true) {
1940
+ const reason = safeLogText(review.failureReason || 'reviewed=false', 400);
1941
+ debug.log('review.acp', 'claude-fallback-glm', { reason }, { level: 'warn' });
1942
+ fallbackAttempted = true;
1943
+ fallbackTriggerReason = reason;
1944
+ let glmFailureReason: string | undefined;
1945
+ try {
1946
+ const glmReview = await deps.reviewPullRequest(reviewInput, deps.makeApiLlm(ZAI_OPENROUTER_FALLBACK_MODEL, {
1947
+ pinProvider: true,
1948
+ onResolved: (provider, respondedModel) => { responded.provider = provider; responded.model = respondedModel; },
1949
+ }));
1950
+ if (glmReview.reviewed === true) {
1951
+ review = glmReview;
1952
+ selectedModel = ZAI_OPENROUTER_FALLBACK_MODEL;
1953
+ reviewRoute = 'api';
1954
+ } else glmFailureReason = safeLogText(glmReview.failureReason || 'reviewed=false', 400);
1955
+ } catch (error) {
1956
+ glmFailureReason = safeLogText(error instanceof Error ? error.message : String(error), 400);
1957
+ }
1958
+ if (glmFailureReason !== undefined) fallbackFailures.push({ backend: ZAI_OPENROUTER_FALLBACK_MODEL, reason: glmFailureReason });
1959
+ claudeFallbackGlm = { reason, model: ZAI_OPENROUTER_FALLBACK_MODEL, glmReviewed: glmFailureReason === undefined,
1960
+ ...(glmFailureReason !== undefined ? { glmFailureReason } : {}) };
1961
+ }
1767
1962
  reviewPin?.remove();
1768
1963
  // reviewCwdCommit 은 «최종 판정을 낸 LLM 이 실제로 그 cwd 를 받았을 때만» 싣는다(role 실패 → API 폴백이면 안 싣는다).
1769
1964
  const reviewedOnPin = Boolean(reviewPin) && (roleReview ? rolePinned : reviewRoute === 'acp-fallback' ? true : reviewRoute === 'acp' && useAcp);
@@ -1783,6 +1978,7 @@ async function runSelfReviewCliCommandPinned(
1783
1978
  ...(fallbackBackend ? { requestedModel: primaryModel, actualBackend: `acp:${fallbackBackend}` } : {}),
1784
1979
  ...(fallbackNotAttemptedReason ? { fallbackNotAttemptedReason } : {}),
1785
1980
  ...(fallbackTriggerReason ? { fallbackTriggerReason } : {}),
1981
+ ...(claudeFallbackGlm ? { claudeFallbackGlm } : {}),
1786
1982
  ...(fallbackFailures.length ? { fallbackFailures } : {}),
1787
1983
  ...(skippedAcpFallbackBackends.length ? { skippedAcpFallbackBackends } : {}),
1788
1984
  };
@@ -1838,10 +2034,15 @@ async function runSelfReviewCliCommandPinned(
1838
2034
  if (review.reviewed === true) failed += 1;
1839
2035
  } else {
1840
2036
  const path = join(effectiveInstanceRoot(), 'review-results', `${opts.save}-${pr}-${diffRead.headCommit.slice(0, 12)}.json`);
1841
- const result = results.at(-1);
2037
+ const rawResult = results.at(-1);
2038
+ const normalized = rawResult && typeof rawResult === 'object'
2039
+ ? normalizeSavedReviewMustFix(rawResult)
2040
+ : { result: rawResult, count: 0 };
2041
+ const result = normalized.result;
1842
2042
  try {
1843
2043
  mkdirSync(dirname(path), { recursive: true });
1844
2044
  writeFileSync(path, selfReviewJsonLine([result]));
2045
+ if (normalized.count > 0) deps.log('mustfix-normalized', { pr, head: diffRead.headCommit, count: normalized.count });
1845
2046
  } catch (error) {
1846
2047
  failed += 1;
1847
2048
  deps.error(`PR ${pr}: --save 실패: ${error instanceof Error ? error.message : String(error)}`);
@@ -28,6 +28,116 @@ import { llmUsageCostFields } from '../budget/llm-cost.js';
28
28
 
29
29
  const execFileAsync = promisify(execFile);
30
30
 
31
+ /** git 서브프로세스 대역 — term grep 동시성 계약을 실제 git 없이 재기 위한 교체점. */
32
+ export type ExecFileLike = (
33
+ file: string,
34
+ args: readonly string[],
35
+ options: { cwd?: string; encoding: 'utf-8'; maxBuffer: number },
36
+ ) => Promise<{ stdout: string; stderr?: string }>;
37
+
38
+ const defaultExecFile: ExecFileLike = execFileAsync as unknown as ExecFileLike;
39
+ let execFileImpl: ExecFileLike = defaultExecFile;
40
+
41
+ /** 테스트 seam — null/미지정이면 실제 git 서브프로세스로 되돌린다. */
42
+ export function setExecFileForTest(fn?: ExecFileLike | null): void {
43
+ execFileImpl = fn ?? defaultExecFile;
44
+ }
45
+
46
+ /** term 별 git grep 동시 실행 상한(기본 3 · OP 06:3x 실측 13개 동시 부하 101 을 막는다). */
47
+ export const TERM_GREP_CONCURRENCY = 3;
48
+ let termGrepConcurrency: number = TERM_GREP_CONCURRENCY;
49
+
50
+ /** 테스트 seam — 상한 없음(Infinity)과 결과 불변을 비교하기 위해 올린다. */
51
+ export function setTermGrepConcurrencyForTest(value?: number | null): void {
52
+ termGrepConcurrency = value ?? TERM_GREP_CONCURRENCY;
53
+ }
54
+
55
+ /** 상한 클램프 — 풀 크기와 관측값이 같은 규칙을 쓰게 한 곳에 둔다. */
56
+ function effectiveConcurrency(concurrency: number, width: number): number {
57
+ const limit = Number.isFinite(concurrency) ? Math.max(1, Math.floor(concurrency)) : width;
58
+ return Math.max(1, Math.min(limit, width));
59
+ }
60
+
61
+ /** 동시 실행 상한 풀 — 결과 순서는 입력 순서 그대로(순위 계산이 순서에 의존하지 않게). */
62
+ async function mapWithConcurrency<T, R>(
63
+ items: readonly T[],
64
+ concurrency: number,
65
+ worker: (item: T) => Promise<R>,
66
+ ): Promise<R[]> {
67
+ const results = new Array<R>(items.length);
68
+ const size = effectiveConcurrency(concurrency, items.length);
69
+ let cursor = 0;
70
+ await Promise.all(
71
+ Array.from({ length: size }, async () => {
72
+ for (let index = cursor++; index < items.length; index = cursor++) {
73
+ results[index] = await worker(items[index]!);
74
+ }
75
+ }),
76
+ );
77
+ return results;
78
+ }
79
+
80
+ /** cwd seam 복원의 **단일 소유** — `process.chdir` 로 되돌리는 곳은 이 묶음(acquire/release) 하나뿐이다.
81
+ *
82
+ * ⛔ 왜 «생산» 이 소유하나: 한 번의 grounding 런은 persistent 코드 채널·skill 도구처럼 **임의 코드**를
83
+ * 지나고(`dispatchTool` → shell·pty), 그 코드가 cwd 를 옮긴 채 끝날 수 있다. 되돌리기를 «각 의존성» 에
84
+ * 맡기면 런이 마감(타임아웃)·예외로 끝나는 순간 그 되돌리기가 통째로 빠지고, 다음 런의 seam
85
+ * (`deps.cwd ?? process.cwd()`)이 **엉뚱한 트리를 저장소 루트로 읽어** 조용히 0건 grounding 을 낸다
86
+ * (#29343 r3 지적: 타임아웃 뒤 cwd seam 오염).
87
+ *
88
+ * ⛔ 소유는 «런마다» 가 아니라 «겹친 런 묶음» 하나다 — cwd 는 프로세스 전역이므로 런별 스냅샷은 겹침에서
89
+ * 깨진다(A 가 임시 트리로 옮긴 사이 B 가 시작하면 B 가 그 임시 트리를 «시작 자리» 로 저장하고, A 가 되돌린
90
+ * 뒤 B 가 다시 임시 트리로 되돌린다). ⇒ 첫 런이 시작 자리를 한 번 스냅샷하고, 겹쳐 들어온 런은 그 값을
91
+ * seam 으로 «물려받으며», 마지막으로 나가는 런만 되돌린다. 마감으로 «버려진» 런도 본문이 끝날 때까지
92
+ * holder 로 남으므로, 마감 뒤에 재개된 본문이 cwd 를 옮겨도 그 뒤의 런은 오염된 자리를 seam 으로 읽지 않고
93
+ * 본문이 끝나는 순간 되돌려진다.
94
+ * ⛔ 복원 보장의 «경계»: 복원은 런의 수명 안에서만 소유한다. 호출자가 마감으로 버렸는데 본문이 «끝나지
95
+ * 않으면» 전역 cwd 는 그 본문이 끝날 때까지 옮겨진 채 남는다 — 이 함수에는 호출자의 마감 신호가 들어오지
96
+ * 않고, 진행 중인 본문 밑의 cwd 를 남이 바꾸면 그 본문을 깨뜨린다. 그 사이 보장되는 것은 «겹쳐 들어온
97
+ * grounding 런의 seam 이 오염된 자리를 읽지 않는다» 이고, 본문이 끝나는 순간 마지막 holder 가 되돌린다
98
+ * (mission-codebase-gate.test.ts «마감 뒤 재개» 시험이 이 경계를 그대로 잰다).
99
+ * ⛔ 되돌리기 실패는 grounding 결과를 바꾸지 않되 «조용히 삼키지» 않는다 — `mission.grounding`
100
+ * `cwd-restore-failed` 로 남긴다(기존 이벤트 형식은 그대로). */
101
+ interface CwdSeamOwner { root: string; holders: number }
102
+ let cwdSeamOwner: CwdSeamOwner | null = null;
103
+
104
+ /** 소유 토큰 — `owned=false` 면 이 런은 묶음에 들지 않았다(시작 자리를 못 읽었다) ⇒ 되돌릴 것도 없다.
105
+ * ⛔ 절대 throw 하지 않는다: 지워진 cwd 에서도 `deps.cwd` 를 받은 호출은 예전처럼 진행해야 한다. */
106
+ interface CwdSeamLease { root: string | null; owned: boolean }
107
+
108
+ function acquireCwdSeam(): CwdSeamLease {
109
+ if (!cwdSeamOwner) {
110
+ let root: string;
111
+ try { root = process.cwd(); } catch { return { root: null, owned: false }; }
112
+ cwdSeamOwner = { root, holders: 0 };
113
+ }
114
+ cwdSeamOwner.holders += 1;
115
+ return { root: cwdSeamOwner.root, owned: true };
116
+ }
117
+
118
+ function releaseCwdSeam(lease: CwdSeamLease): void {
119
+ if (!lease.owned) return;
120
+ const owner = cwdSeamOwner;
121
+ if (!owner) return;
122
+ owner.holders -= 1;
123
+ if (owner.holders > 0) return;
124
+ cwdSeamOwner = null;
125
+ let current: string | null = null;
126
+ try { current = process.cwd(); } catch { /* 지워진 자리 — 아래에서 되돌린다 */ }
127
+ if (current === owner.root) return;
128
+ try {
129
+ process.chdir(owner.root);
130
+ } catch (e) {
131
+ try {
132
+ debug.log('mission.grounding', 'cwd-restore-failed', {
133
+ root: owner.root,
134
+ current,
135
+ error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200),
136
+ }, { level: 'warn' });
137
+ } catch { /* 관측 실패가 grounding 을 바꾸지 않는다 */ }
138
+ }
139
+ }
140
+
31
141
  function logLlmUsage(site: 'codebase-gate-injected' | 'codebase-gate-dynamic', model: string, usage: LLMUsage): void {
32
142
  try {
33
143
  debug.log('llm.usage', 'llm-usage', {
@@ -215,28 +325,37 @@ export function commonTermCoverageWeight(matchLines: number): number {
215
325
  }
216
326
 
217
327
  async function searchRepository(terms: string[], limit: number, cwd: string | undefined, paths: string[], commonPaths = paths): Promise<string[]> {
218
- if (!terms.length) return [];
328
+ // 같은 키워드는 한 번만 실행한다 — 실행·랭킹이 같은 목록을 쓰므로 결과는 결정적이다.
329
+ const uniqueTerms = [...new Set(terms)];
330
+ if (!uniqueTerms.length) return [];
219
331
  const fileTerms = new Map<string, Set<string>>(); // file → 매칭된 서로 다른 term
220
332
  const fileLines = new Map<string, number>(); // file → 총 매칭 라인 수
221
333
  const fileTermLines = new Map<string, Map<string, number>>(); // file → term별 매칭 라인 수
222
334
  const tooCommon = new Set<string>(); // 200+ 파일 매칭 = 밀도 감쇠 대상
223
- const trackedPaths = await execFileAsync('git', ['ls-files', '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
335
+ const trackedPaths = await execFileImpl('git', ['ls-files', '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
224
336
  .then(({ stdout }) => stdout.split('\n').filter(Boolean))
225
337
  .catch(() => [] as string[]);
226
- const pathMatches = new Map(terms.map((term) => [term, trackedPaths.filter((file) => file.toLowerCase().includes(term)).length]));
227
- // term별 git grep 을 병렬 실행(순차 spawnSync ~16초 → 병렬 ~2초). git grep=현재 워킹트리
228
- // 파일 검색(history 아님)·gitignore/바이너리 자동 제외. 호출자가 코드와 문서를 분리한다.
229
- const perTerm = await Promise.all(terms.map(async (t) => {
338
+ const pathMatches = new Map(uniqueTerms.map((term) => [term, trackedPaths.filter((file) => file.toLowerCase().includes(term)).length]));
339
+ // term별 git grep 을 동시 실행 상한 풀(기본 3)로 돌린다 — 무제한 병렬은 mbp 1분 부하 101·git grep
340
+ // 13개 동시(OP 06:3x 실측)를 만들었다. git grep=현재 워킹트리 파일 검색(history 아님)·
341
+ // gitignore/바이너리 자동 제외. 호출자가 코드와 문서를 분리한다.
342
+ const termGrepStartedAt = Date.now();
343
+ const perTerm = await mapWithConcurrency(uniqueTerms, termGrepConcurrency, async (t) => {
230
344
  try {
231
345
  // -c: file:count. -i 무시·-I 바이너리제외. term 하나씩(어느 term 이 걸렸는지 추적).
232
- const { stdout } = await execFileAsync('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 });
346
+ const { stdout } = await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...paths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 });
233
347
  const rows = stdout.split('\n').filter(Boolean);
234
- const commonRows = commonPaths === paths ? rows : await execFileAsync('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...commonPaths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
348
+ const commonRows = commonPaths === paths ? rows : await execFileImpl('git', ['grep', '-c', '-i', '-I', '-e', t, '--', ...commonPaths], { ...(cwd ? { cwd } : {}), encoding: 'utf-8', maxBuffer: 8_000_000 })
235
349
  .then(({ stdout }) => stdout.split('\n').filter(Boolean))
236
350
  .catch(() => [] as string[]);
237
351
  return { t, rows, commonCount: commonRows.length };
238
352
  } catch { return { t, rows: [] as string[], commonCount: 0 }; } // git grep no-match = exit 1(throw) → 빈 결과
239
- }));
353
+ });
354
+ debug.log('grounding.search', 'term-grep-batch', {
355
+ terms: uniqueTerms.length,
356
+ concurrency: effectiveConcurrency(termGrepConcurrency, uniqueTerms.length),
357
+ ms: Date.now() - termGrepStartedAt,
358
+ });
240
359
  for (const { t, rows, commonCount } of perTerm) {
241
360
  if (commonCount > 200) {
242
361
  tooCommon.add(t);
@@ -260,7 +379,7 @@ async function searchRepository(terms: string[], limit: number, cwd: string | un
260
379
  const cover = [...ts].reduce((total, term) => total + (tooCommon.has(term)
261
380
  ? commonTermCoverageWeight(termLines?.get(term) ?? 0)
262
381
  : 1), 0);
263
- const nameTerms = terms.filter((t) => f.toLowerCase().includes(t));
382
+ const nameTerms = uniqueTerms.filter((t) => f.toLowerCase().includes(t));
264
383
  const nameWeight = nameTerms.reduce((total, term) => {
265
384
  const matches = pathMatches.get(term) ?? 0;
266
385
  // 경로상 유일한 식별자는 강한 +25를 유지하고, 공유 조각은 매칭 경로 수에 반비례해 감쇠한다.
@@ -531,8 +650,12 @@ export async function groundMissionInCodebase(
531
650
  goal: string, deps: { cwd?: string; seedPaths?: readonly string[]; searchTerms?: SearchTermFn; skillIndex?: SkillIndexFn; pickSkills?: SkillPickFn; recallMemory?: RecallMemoryFn; recallSelf?: RecallSelfFn; refDigest?: RefDigestFn; persistent?: PersistentGroundingDeps | false } & CapsuleGroundingDeps = {},
532
651
  ): Promise<CodebaseGrounding> {
533
652
  // 호출자가 준 root를 모든 저장소 채널과 corpus 관측에 공유한다. 미지정 호출은 기존처럼 프로세스 cwd를 쓴다.
653
+ // ⛔ seam 은 «읽기» 만 하지 않는다 — 시작 자리를 소유자(acquireCwdSeam)에게서 받고 finally 에서 돌려준다.
654
+ // 겹친 런은 첫 런의 스냅샷을 물려받으므로, 다른 런이 옮겨 놓은 cwd 를 시작 자리로 읽지 않는다.
655
+ const cwdLease = acquireCwdSeam();
534
656
  const cwdSource = deps.cwd === undefined ? 'process' : 'caller';
535
- const searchRoot = deps.cwd ?? process.cwd();
657
+ // 시작 자리를 못 읽었으면(지워진 cwd) 소유하지 않는다 — caller root 는 그대로 쓰고, 미지정이면 예전처럼 process.cwd() 가 판정한다.
658
+ const searchRoot = deps.cwd ?? cwdLease.root ?? process.cwd();
536
659
  const startedAt = performance.now();
537
660
  let searchTermsElapsedMs = 0;
538
661
  let persistentElapsedMs = 0;
@@ -695,7 +818,13 @@ export async function groundMissionInCodebase(
695
818
  debug.log('mission.grounding', 'corpus', { grounded: false, reason: 'error', cwd: searchRoot, cwdSource, error: e instanceof Error ? e.message.slice(0, 200) : String(e).slice(0, 200), persistentEvidence: null, persistentStopReason: null, codeChannel: 'failed' }, { level: 'warn' });
696
819
  return { grounded: false, context: '', files: [], persistentEvidence: [], skillFacts: [], codeFacts: [], memoryFacts: [], documentFacts: [], refFacts: [], ptyFacts: [] };
697
820
  } finally {
698
- observeTiming();
821
+ // 정상·예외·타임아웃 어느 경로로 끝났든 소유를 돌려준다 — 마지막 holder 가 시작 자리로 되돌린다.
822
+ // 되돌리기를 관측보다 «먼저» 둔다: 관측이 무엇을 하든 복원이 빠지지 않는다.
823
+ try {
824
+ releaseCwdSeam(cwdLease);
825
+ } finally {
826
+ observeTiming();
827
+ }
699
828
  }
700
829
  }
701
830