elanous 0.2.31 → 0.2.34

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 (715) 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/{LSXfY0u9QtfDbejY0Ukf_ → L04y73dlwKeTW-GetaTF3}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/1162.c69abda138c7ce43.js +79 -0
  5. package/apps/pwa/out/_next/static/chunks/1449-1fede62af84c3e43.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1598-13fc845935e816df.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1639.62c5e16fa20d242f.js +94 -0
  8. package/apps/pwa/out/_next/static/chunks/{4174.92ed04922709ac9e.js → 1644.35dd25240ae24e4b.js} +2 -2
  9. package/apps/pwa/out/_next/static/chunks/1661-adb8b2babc9aaf8c.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/{2940-619bfd8ef337c611.js → 1895-60ed0e341c658bd4.js} +1 -1
  11. package/apps/pwa/out/_next/static/chunks/{5525.86debf231e181813.js → 2124.ed5bf480cea7f85b.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/2147.107c0fc6146fb15a.js +23 -0
  13. package/apps/pwa/out/_next/static/chunks/2202-ef1c9b000c3074fc.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/2247.1e326638ee43e672.js +115 -0
  15. package/apps/pwa/out/_next/static/chunks/2268.56e1e3d58180abae.js +8 -0
  16. package/apps/pwa/out/_next/static/chunks/2469-606819c812414021.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/{6092.a7f99e68b188ca66.js → 2547.dd27303624cb4da8.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/{2213.2ccbada92c33ea0f.js → 2554.3b5e200f5f5cfcd6.js} +16 -16
  19. package/apps/pwa/out/_next/static/chunks/2593.e53c1620c0bb3599.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/2690.e96671114222676a.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/2898-79ee1a5cc0cd9d13.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/298.26099a9f65e5c8ff.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/{5173-233188df2f42c626.js → 2987-30cf9c2eb7b8bdd5.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/2992.51fc2a7295bd8139.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3541-ce3a5424ed5ad7f1.js → 3001-5a52788c813b6113.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/3014-291245fba9df7b5b.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/3068.ee78201f0251a18d.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/3083.cd399a17e9365f78.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/3103.84470c8445962f04.js +34 -0
  30. package/apps/pwa/out/_next/static/chunks/{6433.fc573af22bbc9ab7.js → 3110.0a7065f25c841818.js} +17 -17
  31. package/apps/pwa/out/_next/static/chunks/3117-e1c474683fd1f824.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/3121.779fafe3e44612c5.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/3251-2c17bd5a91f8de2e.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/326.3fb32322bb2ddf6d.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/3411-f87314c6c66ebc73.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/{6157.0c9af021de4fb31b.js → 3414.172ad4ca2d9b08e8.js} +2 -2
  37. package/apps/pwa/out/_next/static/chunks/3421-7ff7fbaa156985a7.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/{4745.67d6f99c245af3f7.js → 3498.cf2a15a8a9e5b926.js} +3 -3
  39. package/apps/pwa/out/_next/static/chunks/381.f55dc63ea87735e6.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3819.163d4777f0a597f6.js +32 -0
  41. package/apps/pwa/out/_next/static/chunks/{5543.a438b8ab5a13ea47.js → 3837.722e053fb9f321ad.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/4129-ab0a6189f1778633.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/4361.93d14ba594b3a035.js +104 -0
  44. package/apps/pwa/out/_next/static/chunks/4364.7a7eb19cceb67d2f.js +286 -0
  45. package/apps/pwa/out/_next/static/chunks/4406.d71f506f7c3ee9d3.js +149 -0
  46. package/apps/pwa/out/_next/static/chunks/4461.2ad1514180ae7e29.js +148 -0
  47. package/apps/pwa/out/_next/static/chunks/4479.bd309cbe0e3842ee.js +64 -0
  48. package/apps/pwa/out/_next/static/chunks/4522-05966f777d66d13b.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/4543-9a3e9812e845de65.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/4557.f8f1d84a0d90d590.js +74 -0
  51. package/apps/pwa/out/_next/static/chunks/4589-79b11542179ef58c.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/4633-9f8f9f88ffbb8f5c.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/4831.23af4d10c0697b5e.js +1 -0
  54. package/apps/pwa/out/_next/static/chunks/4983.5951b85724f61f2a.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/{b313b242.cb1265eea908db61.js → 4fa33ebd.21c1bd5b294496e6.js} +1 -1
  56. package/apps/pwa/out/_next/static/chunks/{997ce8a5-2ad501927003b41b.js → 5014f970-22bef0b5210f7d60.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/{2112-e4efc21a6505d5bc.js → 5028-f0722e6114c313e7.js} +1 -1
  58. package/apps/pwa/out/_next/static/chunks/{2898.fd781bc7cf01a7b7.js → 5249.96a848656b582a93.js} +1 -1
  59. package/apps/pwa/out/_next/static/chunks/5311.16e0ffbfa5468b80.js +62 -0
  60. package/apps/pwa/out/_next/static/chunks/{9407.e49124dedf0f5e72.js → 5446.edf141cff9ef647d.js} +1 -1
  61. package/apps/pwa/out/_next/static/chunks/{9002.e5658224e3dc1b6f.js → 5489.ec2dd1b5272a19dc.js} +1 -1
  62. package/apps/pwa/out/_next/static/chunks/{1335-6731f392c35216eb.js → 5576-82d3703636d5c4b9.js} +3 -3
  63. package/apps/pwa/out/_next/static/chunks/559.df87695df637920c.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/5618-5c88f2f70178c4ad.js +1 -0
  65. package/apps/pwa/out/_next/static/chunks/5764.05487bf0b73ddb6b.js +1 -0
  66. package/apps/pwa/out/_next/static/chunks/5930.e678826c3f831aab.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/5dfb57f7.f2e3305326202474.js +1 -0
  68. package/apps/pwa/out/_next/static/chunks/6053-d893974de92e6198.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/{2985.39ccdecd36848b12.js → 6086.913a69e6fa3e4a8b.js} +4 -4
  70. package/apps/pwa/out/_next/static/chunks/6200-cefd6f33f59d765e.js +1 -0
  71. package/apps/pwa/out/_next/static/chunks/6314-edeba650ae686ac9.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/6316-bc9a9b74d7842d79.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/6476-13b9779b73528008.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/666-04db3ac4c8e3c66f.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/670.682e55106ef915a6.js +77 -0
  76. package/apps/pwa/out/_next/static/chunks/{7862.30a8d6482bb238eb.js → 6740.43de73fc427c9fe2.js} +1 -1
  77. package/apps/pwa/out/_next/static/chunks/6816.b7ba9d0a1a4a46a7.js +1 -0
  78. package/apps/pwa/out/_next/static/chunks/690-fbbcc777f189af37.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/6989.0d3d4020e5cb3df6.js +90 -0
  80. package/apps/pwa/out/_next/static/chunks/{2871.0bca6137343b3f76.js → 7005.1623d2aea78eb85f.js} +1 -1
  81. package/apps/pwa/out/_next/static/chunks/7193-cf355cca5ba6c5d5.js +1 -0
  82. package/apps/pwa/out/_next/static/chunks/7217-d17393fe7af78fa6.js +1 -0
  83. package/apps/pwa/out/_next/static/chunks/7232.24edbd938a69c8d0.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/7295cd1e.b4b557908888eeee.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/7323.adb02de21991883c.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/7386.5d8e7e42e818dfb6.js +287 -0
  87. package/apps/pwa/out/_next/static/chunks/{7502.ccd5b8065545edd0.js → 7431.3051e9b8a4372d2d.js} +2 -2
  88. package/apps/pwa/out/_next/static/chunks/{3583.a05e88cc8d594628.js → 7448.478958ffbbba0ac0.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/7537.ba2208c5c656b8a3.js +1 -0
  90. package/apps/pwa/out/_next/static/chunks/7562.948255cbc3e79d33.js +41 -0
  91. package/apps/pwa/out/_next/static/chunks/7596-962ae6db6cfc9c83.js +1 -0
  92. package/apps/pwa/out/_next/static/chunks/7671.cff51beac212a2ba.js +1 -0
  93. package/apps/pwa/out/_next/static/chunks/7883.3916734ee16d3e58.js +27 -0
  94. package/apps/pwa/out/_next/static/chunks/{9989.3694300e5f000b14.js → 7952.b192c31b6a0e00cc.js} +1 -1
  95. package/apps/pwa/out/_next/static/chunks/801.5b24e81eded22d1b.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/8176.8c9a8613f5a01ac1.js +36 -0
  97. package/apps/pwa/out/_next/static/chunks/819e78a6.fa3dd7f7da19bf61.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/8220-78978450c3183d8d.js +1 -0
  99. package/apps/pwa/out/_next/static/chunks/8221-eb60b5bc692a3361.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/826.e9a26064f474949e.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/{5307.60f2209e809bd627.js → 8368.014caa8de2f5af34.js} +1 -1
  102. package/apps/pwa/out/_next/static/chunks/8459-a351487a4480f584.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/8482-75823d513a4ce151.js +1 -0
  104. package/apps/pwa/out/_next/static/chunks/8488.8da515248cda3f3a.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{9221.7d22eaf353a2d4e7.js → 8548.036c344973968847.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8584.388a1779d9b203af.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8637.a55e098e61ffefb8.js +1 -0
  108. package/apps/pwa/out/_next/static/chunks/8817.61bb7ffbba502ecb.js +1 -0
  109. package/apps/pwa/out/_next/static/chunks/{9398-6aed28f0a96d0d6f.js → 9131-fce7256c4180c4a5.js} +1 -1
  110. package/apps/pwa/out/_next/static/chunks/9207-8e6a12db30373f32.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/9263-00ae932c62696a86.js +1 -0
  112. package/apps/pwa/out/_next/static/chunks/9318.caafc3a130e8769c.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/932.da3fb55951882562.js +93 -0
  114. package/apps/pwa/out/_next/static/chunks/9433.002f8426ac75b6b7.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/9464.dd631a5a14b1d660.js +24 -0
  116. package/apps/pwa/out/_next/static/chunks/{3278.2e5d15b53a4091c8.js → 9550.d5f76828f972058c.js} +2 -2
  117. package/apps/pwa/out/_next/static/chunks/{2534.e85ae21ad0dac829.js → 9739.8d5f36ac67a3b236.js} +1 -1
  118. package/apps/pwa/out/_next/static/chunks/9743.beeabb9d5f86abe4.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9843-a23d3f32dc43f715.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/994-28211077c7c587d5.js +1 -0
  121. package/apps/pwa/out/_next/static/chunks/{7a1887c4.f36b88fba31da8fd.js → 9a8cb466.cc9fc9e6e46038aa.js} +1 -1
  122. package/apps/pwa/out/_next/static/chunks/{0bb0ff36.b8d418980951e5ba.js → 9b48c871.204d5d13e7809bd0.js} +7 -7
  123. package/apps/pwa/out/_next/static/chunks/{409f1e57.d0649fc47691ebfe.js → abb4b98b.163e0f56e84ae35d.js} +1 -1
  124. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-3b4c947f174e33d8.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/app/approvals/page-369d5ce99483f859.js +1 -0
  126. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-63c0ed0eb26e5fce.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/board/page-62802c6003bc85cc.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/botlab/page-ecb41560d4e77be9.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/bots/page-7b65ad8130c93e95.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8755477c15a9060c.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/chat/page-5725447dd972c471.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/consult/page-b979de0591a69375.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/control/page-6d0796bf4633751a.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/decisions/page-59c31dc0394e67b4.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/design-check/page-12dfc95f6cc5c718.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/editor/page-25788244e66aa4dd.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/exec/page-a2555dc705466322.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/field/page-4fb31eb476dcbad3.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/healthz/route-3b4c947f174e33d8.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/inside/page-578729adbeaa40cb.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/intake/page-a1d20fffbec35205.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/layout-4a558f94516b8004.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/live/page-9e3834705b86145e.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d7bff0f0905a662c.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/loops/page-cb1c5fe746ea4014.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/market/page-9ee320507356582a.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-66fd183b74835886.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/morning/page-3272a064a01a9927.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/not-found-f281b7a7f6ef2529.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/observatory/page-d45a65f8b7124fcd.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-e9c1fe684dd19a66.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-b8322932fc6e34de.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-82c66d9af2290575.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/outputs/page-63c6752009c97b05.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/page-bb33d42ebc358aec.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7e4c9379197d7214.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-38bf1e9a7001732b.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/sessions/page-2e5b752012389d56.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-0a07363b130182a1.js → page-398c0faa173203f7.js} +1 -1
  160. package/apps/pwa/out/_next/static/chunks/app/settings/page-002f53a965b6445c.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-7f75997f61a26269.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/setup/layout-3b4c947f174e33d8.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/setup/page-05631753294f23fb.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/share/page-edd700fd2cc3d7f8.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/showroom/page-105f83ecb4594365.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/tasks/page-5823e87d2017f19c.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/term/page-df3445b207ceceab.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/today/page-b51ca09566c03de7.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/trace/page-8aacd5ded5dbac60.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/vault/page-bae3365a0b3c6a8e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ed52b48ff1aa7fd.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/workflows/page-b6f8cad35fe00946.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/workspace/page-6d25ceda500d2457.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-b6401a5f2c962fe8.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/ebf6cf5e.0d2f887b040e80fb.js +122 -0
  176. package/apps/pwa/out/_next/static/chunks/f09ec7d7-d29abe23edcbb193.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/{ebc7d829.264a0bcb6c750b50.js → ffdc3a04.b9c23c1b28dd4a96.js} +1 -1
  178. package/apps/pwa/out/_next/static/chunks/framework-9322cb8a56ac081c.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-2fbab294e49a1561.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-f36729f56621a8f3.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-2a62e450b47c6114.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-5e17f7b445f34d43.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-b4263e2190ea7adf.js +1 -0
  184. package/apps/pwa/out/_next/static/css/b5d88eba78a3d7bf.css +1 -0
  185. package/apps/pwa/out/approvals/index.html +1 -1
  186. package/apps/pwa/out/approvals/index.txt +23 -23
  187. package/apps/pwa/out/autopilot/index.html +1 -1
  188. package/apps/pwa/out/autopilot/index.txt +23 -23
  189. package/apps/pwa/out/board/index.html +1 -1
  190. package/apps/pwa/out/board/index.txt +23 -23
  191. package/apps/pwa/out/botlab/index.html +1 -1
  192. package/apps/pwa/out/botlab/index.txt +22 -22
  193. package/apps/pwa/out/bots/index.html +1 -1
  194. package/apps/pwa/out/bots/index.txt +22 -22
  195. package/apps/pwa/out/ceo/index.html +1 -1
  196. package/apps/pwa/out/ceo/index.txt +23 -23
  197. package/apps/pwa/out/chat/index.html +1 -1
  198. package/apps/pwa/out/chat/index.txt +22 -22
  199. package/apps/pwa/out/consult/index.html +1 -1
  200. package/apps/pwa/out/consult/index.txt +23 -23
  201. package/apps/pwa/out/control/index.html +1 -1
  202. package/apps/pwa/out/control/index.txt +23 -23
  203. package/apps/pwa/out/decisions/index.html +1 -1
  204. package/apps/pwa/out/decisions/index.txt +22 -22
  205. package/apps/pwa/out/design-check/index.html +1 -1
  206. package/apps/pwa/out/design-check/index.txt +23 -23
  207. package/apps/pwa/out/editor/index.html +1 -1
  208. package/apps/pwa/out/editor/index.txt +23 -23
  209. package/apps/pwa/out/exec/index.html +1 -1
  210. package/apps/pwa/out/exec/index.txt +23 -23
  211. package/apps/pwa/out/field/index.html +1 -1
  212. package/apps/pwa/out/field/index.txt +23 -23
  213. package/apps/pwa/out/healthz +1 -1
  214. package/apps/pwa/out/index.html +1 -1
  215. package/apps/pwa/out/index.txt +22 -22
  216. package/apps/pwa/out/inside/index.html +1 -1
  217. package/apps/pwa/out/inside/index.txt +22 -22
  218. package/apps/pwa/out/intake/index.html +1 -1
  219. package/apps/pwa/out/intake/index.txt +23 -23
  220. package/apps/pwa/out/live/index.html +1 -1
  221. package/apps/pwa/out/live/index.txt +26 -23
  222. package/apps/pwa/out/live-run/index.html +1 -1
  223. package/apps/pwa/out/live-run/index.txt +23 -23
  224. package/apps/pwa/out/loops/index.html +1 -1
  225. package/apps/pwa/out/loops/index.txt +22 -22
  226. package/apps/pwa/out/market/index.html +1 -1
  227. package/apps/pwa/out/market/index.txt +22 -22
  228. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  229. package/apps/pwa/out/missions/placeholder/index.txt +22 -22
  230. package/apps/pwa/out/morning/index.html +1 -1
  231. package/apps/pwa/out/morning/index.txt +23 -23
  232. package/apps/pwa/out/observatory/index.html +1 -1
  233. package/apps/pwa/out/observatory/index.txt +23 -23
  234. package/apps/pwa/out/ops/checklist/index.html +1 -1
  235. package/apps/pwa/out/ops/checklist/index.txt +22 -22
  236. package/apps/pwa/out/ops/release/index.html +1 -1
  237. package/apps/pwa/out/ops/release/index.txt +22 -22
  238. package/apps/pwa/out/ops/seats/index.html +1 -1
  239. package/apps/pwa/out/ops/seats/index.txt +22 -22
  240. package/apps/pwa/out/outputs/index.html +1 -1
  241. package/apps/pwa/out/outputs/index.txt +22 -22
  242. package/apps/pwa/out/reflection/index.html +1 -1
  243. package/apps/pwa/out/reflection/index.txt +23 -23
  244. package/apps/pwa/out/scheduler/index.html +1 -1
  245. package/apps/pwa/out/scheduler/index.txt +23 -23
  246. package/apps/pwa/out/sessions/index.html +1 -1
  247. package/apps/pwa/out/sessions/index.txt +22 -22
  248. package/apps/pwa/out/settings/devices/index.html +1 -1
  249. package/apps/pwa/out/settings/devices/index.txt +23 -23
  250. package/apps/pwa/out/settings/index.html +1 -1
  251. package/apps/pwa/out/settings/index.txt +23 -23
  252. package/apps/pwa/out/setup/done/index.html +1 -1
  253. package/apps/pwa/out/setup/done/index.txt +23 -23
  254. package/apps/pwa/out/setup/index.html +1 -1
  255. package/apps/pwa/out/setup/index.txt +23 -23
  256. package/apps/pwa/out/share/index.html +1 -1
  257. package/apps/pwa/out/share/index.txt +23 -23
  258. package/apps/pwa/out/showroom/index.html +1 -1
  259. package/apps/pwa/out/showroom/index.txt +22 -22
  260. package/apps/pwa/out/tasks/index.html +1 -1
  261. package/apps/pwa/out/tasks/index.txt +23 -23
  262. package/apps/pwa/out/term/index.html +1 -1
  263. package/apps/pwa/out/term/index.txt +23 -23
  264. package/apps/pwa/out/today/index.html +1 -1
  265. package/apps/pwa/out/today/index.txt +23 -23
  266. package/apps/pwa/out/trace/index.html +1 -1
  267. package/apps/pwa/out/trace/index.txt +23 -23
  268. package/apps/pwa/out/vault/index.html +1 -1
  269. package/apps/pwa/out/vault/index.txt +23 -23
  270. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  271. package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
  272. package/apps/pwa/out/workflows/index.html +1 -1
  273. package/apps/pwa/out/workflows/index.txt +23 -23
  274. package/apps/pwa/out/workspace/index.html +1 -1
  275. package/apps/pwa/out/workspace/index.txt +23 -23
  276. package/apps/pwa/out/worktrees/index.html +1 -1
  277. package/apps/pwa/out/worktrees/index.txt +23 -23
  278. package/bin/elanous.mjs +9 -2
  279. package/docs/goal-context/README.md +1 -0
  280. package/graphs/default-loop.yaml +20 -3
  281. package/graphs/document-loop.yaml +21 -2
  282. package/graphs/implement-loop.yaml +11 -0
  283. package/graphs/journey/SCENARIOS.md +33 -0
  284. package/graphs/journey/recipes.yaml +1 -0
  285. package/graphs/journey/ta-journey.yaml +84 -0
  286. package/graphs/journey/units/author/author.yaml +20 -0
  287. package/graphs/journey/units/author/recipes.yaml +2 -0
  288. package/graphs/journey/units/green/green.yaml +20 -0
  289. package/graphs/journey/units/green/recipes.yaml +2 -0
  290. package/graphs/journey/units/pr/pr.yaml +20 -0
  291. package/graphs/journey/units/pr/recipes.yaml +2 -0
  292. package/graphs/journey/units/remember/recipes.yaml +2 -0
  293. package/graphs/journey/units/remember/remember.yaml +20 -0
  294. package/graphs/operate-loop.yaml +21 -2
  295. package/graphs/overlays/stop-heal-ladder.yaml +1 -1
  296. package/graphs/release-rehearsal/recipes.yaml +1 -1
  297. package/graphs/release-rehearsal/release-rehearsal.yaml +2 -2
  298. package/graphs/research-loop.yaml +23 -2
  299. package/graphs/units/dispatch-pod/dispatch-pod.yaml +50 -0
  300. package/graphs/units/dispatch-pod/recipes.yaml +14 -0
  301. package/graphs/units/entry/entry.yaml +50 -0
  302. package/graphs/units/entry/recipes.yaml +14 -0
  303. package/graphs/units/harvest/harvest.yaml +25 -0
  304. package/graphs/units/harvest/recipes.yaml +4 -0
  305. package/graphs/units/land/land.yaml +45 -0
  306. package/graphs/units/land/recipes.yaml +3 -0
  307. package/graphs/units/recipes.yaml +7 -0
  308. package/graphs/units/recover.yaml +39 -0
  309. package/graphs/units/reflect/recipes.yaml +3 -0
  310. package/graphs/units/reflect/reflect.yaml +15 -0
  311. package/graphs/units/task-agent-recover-review.yaml +17 -0
  312. package/graphs/units/task-agent-recover-wait.yaml +17 -0
  313. package/graphs/units/verbs/make-doc.yaml +34 -0
  314. package/graphs/units/verbs/recipes.yaml +33 -0
  315. package/graphs/units/verbs/verify.yaml +55 -0
  316. package/graphs/work/recipes.yaml +2 -0
  317. package/graphs/work/research-report.yaml +28 -0
  318. package/package.json +1 -1
  319. package/scripts/ci-typecheck-changed.ts +95 -17
  320. package/scripts/docs/generate-graph-anatomy.ts +19 -2
  321. package/scripts/graph-harvest-unit.ts +22 -0
  322. package/scripts/graph-units/journey-stub.ts +6 -0
  323. package/scripts/graph-units/land-enqueue.ts +78 -0
  324. package/scripts/graph-units/recover-plan.ts +15 -0
  325. package/scripts/graph-units/reflect-node.ts +88 -0
  326. package/scripts/graph-units/ta-journey-observe.ts +109 -0
  327. package/scripts/graph-units/verbs/headless-goal-loop.ts +152 -0
  328. package/scripts/graph-units/verbs/verify-stage.ts +75 -0
  329. package/scripts/graph-units/verbs-envelope.ts +139 -0
  330. package/scripts/hq/standby-snapshot.ts +25 -0
  331. package/scripts/measure-si-task-cpu.ts +143 -0
  332. package/scripts/public-export.ts +43 -1
  333. package/scripts/ratchets/test-interference-patterns.allowlist.txt +0 -2
  334. package/scripts/ratchets/train-side-invariants.sh +45 -0
  335. package/scripts/release-loop/auto-approve-node.ts +30 -16
  336. package/scripts/release-loop/gate-closure.ts +5 -1
  337. package/scripts/release-loop/gate-diff.ts +1 -1
  338. package/scripts/release-loop/gate-node.ts +498 -31
  339. package/scripts/release-loop/gate-partial.ts +3 -3
  340. package/scripts/release-loop/gate-radius-shadow.ts +138 -0
  341. package/scripts/release-loop/gate-traffic-mode.ts +128 -0
  342. package/scripts/release-loop/gate-triage-node.ts +5 -2
  343. package/scripts/release-loop/known-issues-0.2.33-approved.json +194 -0
  344. package/scripts/release-loop/known-issues-node.ts +77 -8
  345. package/scripts/release-loop/preflight.ts +93 -7
  346. package/scripts/release-loop/prepare-node.ts +102 -4
  347. package/scripts/release-loop/publish-node.ts +60 -9
  348. package/scripts/release-loop/resume-cap.ts +56 -0
  349. package/scripts/release-loop/resume-release.ts +114 -15
  350. package/scripts/release-loop/resume.ts +24 -1
  351. package/scripts/release-loop/tui-sim-node.ts +8 -2
  352. package/scripts/release-loop/unattended-release.ts +8 -2
  353. package/src/acp/core-turn-bridge.ts +36 -9
  354. package/src/acp/elanous-extensions.ts +3 -0
  355. package/src/acp/reasoning-thought-buffer.ts +45 -0
  356. package/src/acp/server.ts +3 -0
  357. package/src/acp/tool-trace.ts +186 -11
  358. package/src/agent/self-ambient-cache.ts +156 -0
  359. package/src/agent/self-ambient.ts +8 -1
  360. package/src/agent/task-notification.ts +5 -0
  361. package/src/agent-substrate/acp-reviewer.ts +52 -12
  362. package/src/agent-substrate/pr-reviewer.ts +3 -1
  363. package/src/agent-substrate/review-finding-key.ts +53 -0
  364. package/src/agent-substrate/self-review-cli.ts +126 -5
  365. package/src/ask-user-question/pending-questions.ts +1 -1
  366. package/src/ask-user-question/tool.ts +22 -0
  367. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  368. package/src/autopilot/pr-manager.ts +213 -46
  369. package/src/capture/frame-state-detect.ts +39 -0
  370. package/src/capture/tui-self-report.ts +134 -6
  371. package/src/chat/index.ts +61 -15
  372. package/src/chat/pickers/modal-runtime.ts +6 -0
  373. package/src/chat/pickers/modals.ts +8 -2
  374. package/src/chat/tool-render/dispatch.ts +62 -10
  375. package/src/cli/ask-bare.ts +1 -0
  376. package/src/cli/control-cli.ts +24 -7
  377. package/src/cli/guardian-cli.ts +10 -0
  378. package/src/cli/import-cli.ts +12 -0
  379. package/src/cli/light-entry-route.ts +35 -0
  380. package/src/cli/llm-detect-cli.ts +23 -1
  381. package/src/cli/log-event-names.ts +10 -0
  382. package/src/cli/msg-cli.ts +1 -0
  383. package/src/cli/pod-cli.ts +14 -3
  384. package/src/cli/pr-cli.ts +140 -41
  385. package/src/cli/pr-land-base-read.ts +36 -0
  386. package/src/cli/pr-land-heavy-remote.ts +81 -25
  387. package/src/cli/pr-land-overlap-evidence.ts +200 -18
  388. package/src/cli/pr-land-pod-shadow-job.ts +26 -3
  389. package/src/cli/pr-land-recovery.ts +64 -0
  390. package/src/cli/pr-land-refusal.ts +20 -5
  391. package/src/cli/pty-takeover-cli.ts +94 -19
  392. package/src/cli/release-cli.ts +120 -33
  393. package/src/cli/release-run-if-ready.ts +29 -28
  394. package/src/cli/release-single-flight.ts +178 -0
  395. package/src/cli/seat-cli.ts +37 -0
  396. package/src/cli/setup-cli.ts +40 -1
  397. package/src/cli/sim-cli.ts +18 -0
  398. package/src/cli/tasks-cli.ts +149 -5
  399. package/src/context-bus/ops-events.ts +6 -2
  400. package/src/control/control-status.ts +8 -3
  401. package/src/control-plane/ledger.ts +5 -3
  402. package/src/control-plane/server.ts +5 -3
  403. package/src/core-turn/run-core-turn.ts +1 -0
  404. package/src/core-turn/run-goal-loop.ts +21 -0
  405. package/src/core-turn/short-question.ts +5 -1
  406. package/src/core-turn/types.ts +3 -0
  407. package/src/dashboard/acp-active-model.ts +42 -1
  408. package/src/dashboard/background-jobs-status.ts +66 -0
  409. package/src/dashboard/index.ts +153 -111
  410. package/src/dashboard/input/agent-wake.ts +242 -0
  411. package/src/dashboard/input/chat-main-entry-runtime.ts +5 -0
  412. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +3 -0
  413. package/src/dashboard/input/dashboard-plain-turn-stream.ts +4 -0
  414. package/src/dashboard/input/external-input-host.ts +23 -9
  415. package/src/dashboard/input/mouse-wiring.ts +108 -11
  416. package/src/dashboard/input/seat-autowake.ts +56 -3
  417. package/src/dashboard/log-click-runtime.ts +118 -2
  418. package/src/dashboard/seat-boot-preamble.ts +1 -1
  419. package/src/dashboard/slash-runtime/ask-clarification.ts +48 -0
  420. package/src/dashboard/slash-runtime/dashboard-delegated-slashes.ts +68 -0
  421. package/src/dashboard/slash-runtime/dashboard-handlers.ts +62 -322
  422. package/src/dashboard/slash-runtime/dashboard-log-slash.ts +208 -0
  423. package/src/dashboard/turn-preamble.ts +163 -41
  424. package/src/dashboard/turn-session-layers.ts +4 -2
  425. package/src/dashboard/turn-start-segments.ts +222 -0
  426. package/src/dashboard/turn-stream-formatter.ts +34 -1
  427. package/src/dashboard/turn-stream-runtime.ts +2 -0
  428. package/src/dashboard/turn-typeahead-prompt-zone.ts +67 -0
  429. package/src/display/prompt-row-owner.ts +146 -0
  430. package/src/display/resize-listener.ts +33 -2
  431. package/src/domains/guardian-tick.ts +54 -2
  432. package/src/domains/outbound-alert.ts +3 -2
  433. package/src/extractors.ts +3 -1
  434. package/src/fold-stack.ts +4 -2
  435. package/src/git-fs/index.ts +263 -36
  436. package/src/git-fs/retry.ts +4 -0
  437. package/src/git-fs/runner.ts +2 -0
  438. package/src/graph-runner/runner.ts +114 -44
  439. package/src/grok/credential.ts +5 -0
  440. package/src/harness/gate-reserve.ts +87 -0
  441. package/src/harness/harness-cli-command.ts +39 -10
  442. package/src/harness/harness-incidents.ts +17 -0
  443. package/src/harness/harness-pod-dispatch.ts +38 -1
  444. package/src/harness/harness-queue.ts +15 -0
  445. package/src/harness/harness-salvage-cli.ts +14 -2
  446. package/src/index.ts +198 -12
  447. package/src/input/external-input-queue.ts +34 -9
  448. package/src/intake-plane/already-built-hint.ts +89 -0
  449. package/src/knowhow/pack.ts +199 -0
  450. package/src/light-cli.ts +95 -0
  451. package/src/llm/route-decision.ts +36 -0
  452. package/src/llm/tool-loop-steered-rejection.ts +8 -0
  453. package/src/llm-request-shape.ts +209 -0
  454. package/src/llm.ts +221 -276
  455. package/src/loops/budget.ts +95 -0
  456. package/src/loops/msg-wake.ts +8 -2
  457. package/src/loops/orchestrator/tick.ts +24 -2
  458. package/src/loops/orchestrator/traffic.ts +132 -1
  459. package/src/maturity/feature-maturity.ts +1 -1
  460. package/src/mss/logging/log-store.ts +4 -5
  461. package/src/mss/logging/render-categories.ts +5 -0
  462. package/src/nexus/api/graphs-api.ts +22 -3
  463. package/src/nexus/api/http-server.ts +1 -1
  464. package/src/nexus/api/ops-api.ts +12 -0
  465. package/src/oauth/claude-pty-maturity.ts +66 -0
  466. package/src/oauth/codex-access-mirror.ts +55 -0
  467. package/src/oauth/fallback-chain.ts +1 -1
  468. package/src/onboarding/first-run.ts +5 -3
  469. package/src/onboarding/non-interactive.ts +64 -13
  470. package/src/onboarding.ts +10 -2
  471. package/src/ops/overview-collect.ts +36 -1
  472. package/src/ops/overview.ts +70 -2
  473. package/src/pr-tool/census.ts +41 -8
  474. package/src/pr-tool/inflight-registry.ts +296 -0
  475. package/src/prompt-library/gpt6-family-addendum.ts +14 -1
  476. package/src/pty-shell/herdr-agent-report.ts +442 -0
  477. package/src/pty-shell/pty-control-ipc.ts +5 -5
  478. package/src/pty-shell/pty-manifest.ts +12 -3
  479. package/src/pty-shell/pty-write-outcome.ts +24 -6
  480. package/src/pty-shell/tui-run-state.ts +151 -6
  481. package/src/release-loop/checklist.ts +79 -5
  482. package/src/release-loop/feature-store.ts +19 -2
  483. package/src/release-loop/placement.ts +10 -3
  484. package/src/release-loop/rehearsal.ts +205 -25
  485. package/src/release-loop/rubric.ts +16 -2
  486. package/src/seat-loop/traffic-signal.ts +2 -1
  487. package/src/self-dev/ask-launch-flow.ts +13 -0
  488. package/src/self-dev/draft-residue.ts +243 -24
  489. package/src/self-dev/draft-sweep.ts +52 -3
  490. package/src/self-dev/graph-journey-nodes.ts +10 -6
  491. package/src/self-dev/graph-journey-route.ts +60 -6
  492. package/src/self-dev/orchestrate.ts +79 -3
  493. package/src/self-dev/run-supervisor.ts +107 -12
  494. package/src/self-dev/run-types.ts +5 -1
  495. package/src/self-dev/shard-plan.ts +11 -3
  496. package/src/self-dev/shard-run.ts +103 -10
  497. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  498. package/src/self-implement/follow-up-placement.ts +79 -0
  499. package/src/self-implement/gate-artifacts.ts +15 -4
  500. package/src/self-implement/gate-baseline.ts +145 -10
  501. package/src/self-implement/gate-cli.ts +7 -2
  502. package/src/self-implement/gate-remote.ts +35 -6
  503. package/src/self-implement/goal-author-identity.ts +66 -0
  504. package/src/self-implement/goal-author-preservation-obligation.ts +35 -0
  505. package/src/self-implement/goal-author.ts +4 -120
  506. package/src/self-implement/graph-overlay-yaml.ts +17 -2
  507. package/src/self-implement/graph-unit-flatten.ts +103 -0
  508. package/src/self-implement/graph-unit-resolver.ts +107 -0
  509. package/src/self-implement/graph-yaml.ts +151 -1
  510. package/src/self-implement/headless-elanous-driver.ts +1 -0
  511. package/src/self-implement/host-regate.ts +36 -4
  512. package/src/self-implement/knowhow-pack.ts +103 -0
  513. package/src/self-implement/orchestrator.ts +109 -11
  514. package/src/self-implement/pod-warm-pool-profile.ts +45 -0
  515. package/src/self-implement/review-mustfix-class.ts +203 -0
  516. package/src/self-implement/run-ledger.ts +16 -14
  517. package/src/self-implement/run-stop.ts +8 -2
  518. package/src/self-implement/seams.ts +32 -1
  519. package/src/self-implement/stop-autoheal.ts +25 -1
  520. package/src/session/chat.ts +27 -0
  521. package/src/session-runtime/index.ts +22 -267
  522. package/src/session-runtime/retry-policy.ts +2 -1
  523. package/src/shell-runner/background-surface.ts +15 -5
  524. package/src/skills/tools/agent.ts +39 -6
  525. package/src/skills/tools/list-dir.ts +11 -0
  526. package/src/skills/tools/schedule-wakeup.ts +457 -0
  527. package/src/skills/tools/shell.ts +245 -3
  528. package/src/status/bar.ts +26 -0
  529. package/src/steward/digest-delivery.ts +118 -0
  530. package/src/steward/hold-hygiene.ts +120 -0
  531. package/src/steward/release-day.ts +7 -3
  532. package/src/steward/triage.ts +47 -4
  533. package/src/surface/shell-runner-boot.ts +5 -2
  534. package/src/task-agent/harvest-unit.ts +141 -0
  535. package/src/task-agent/live-moves.ts +98 -12
  536. package/src/task-agent/parent-host.ts +93 -3
  537. package/src/task-agent/postland-card.ts +80 -1
  538. package/src/task-agent/rejudge-on-head.ts +112 -26
  539. package/src/task-agent/repair-branch-cas.ts +4 -1
  540. package/src/task-agent/repair-cycle.ts +16 -3
  541. package/src/task-agent/run-identity.ts +4 -3
  542. package/src/task-agent/shadow.ts +12 -2
  543. package/src/task-agent/task-hand.ts +76 -5
  544. package/src/task-agent/work-order-build.ts +22 -0
  545. package/src/task-orchestrator/surfaces/pod-account-broker.ts +39 -3
  546. package/src/task-orchestrator/surfaces/pod-command-job.ts +67 -12
  547. package/src/task-orchestrator/surfaces/pod-lease.ts +98 -0
  548. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  549. package/src/task-orchestrator/surfaces/pod-lifecycle-stages.ts +86 -8
  550. package/src/task-orchestrator/surfaces/pod-pool.ts +76 -18
  551. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +10 -6
  552. package/src/task-orchestrator/surfaces/pod-source-receive.ts +54 -4
  553. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +548 -0
  554. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +389 -0
  555. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  556. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +158 -3
  557. package/src/task-orchestrator/surfaces/self-implement-pod.ts +230 -43
  558. package/src/task-orchestrator/surfaces/self-implement.ts +83 -2
  559. package/src/tool-runtime/truncation-store.ts +4 -0
  560. package/src/tui/chat/execution-badge.ts +5 -1
  561. package/src/tui/input-lag-probe.ts +230 -0
  562. package/src/tui-client/dashboard-session.ts +10 -1
  563. package/src/tui.ts +4 -0
  564. package/src/user-config/coercion.ts +36 -0
  565. package/src/user-config.ts +18 -41
  566. package/src/ux-sim/scenario.ts +314 -0
  567. package/src/version/packed-revision.json +1 -1
  568. package/apps/pwa/out/_next/static/chunks/1034-8b639cee57b8e4a8.js +0 -1
  569. package/apps/pwa/out/_next/static/chunks/1085-6c2d35526f11f840.js +0 -1
  570. package/apps/pwa/out/_next/static/chunks/1220.1ff7d5cdc34b1ae5.js +0 -27
  571. package/apps/pwa/out/_next/static/chunks/1247.5884ec81b39fe2e7.js +0 -287
  572. package/apps/pwa/out/_next/static/chunks/1302.87681521a7a4661e.js +0 -62
  573. package/apps/pwa/out/_next/static/chunks/1324-59dae3002413623b.js +0 -1
  574. package/apps/pwa/out/_next/static/chunks/1343-f40b5870ac1eda5a.js +0 -1
  575. package/apps/pwa/out/_next/static/chunks/146-b6cd56be11dda017.js +0 -1
  576. package/apps/pwa/out/_next/static/chunks/1654.32de4b324981a188.js +0 -23
  577. package/apps/pwa/out/_next/static/chunks/1834-50625904996a8fa8.js +0 -1
  578. package/apps/pwa/out/_next/static/chunks/1849.1ce38efa6c527d9a.js +0 -149
  579. package/apps/pwa/out/_next/static/chunks/1913.7cc6fb6055b1ed3f.js +0 -41
  580. package/apps/pwa/out/_next/static/chunks/2001.6c7e0fd02190886c.js +0 -1
  581. package/apps/pwa/out/_next/static/chunks/2030.41fae98c7e907304.js +0 -1
  582. package/apps/pwa/out/_next/static/chunks/2099-08b2f2dfba742c9b.js +0 -1
  583. package/apps/pwa/out/_next/static/chunks/2134.ecee03a550ee7250.js +0 -1
  584. package/apps/pwa/out/_next/static/chunks/2236.66061832181cb745.js +0 -1
  585. package/apps/pwa/out/_next/static/chunks/2422.b0bd272e7020d7e6.js +0 -1
  586. package/apps/pwa/out/_next/static/chunks/3040.92ff9ffc9f971cb9.js +0 -115
  587. package/apps/pwa/out/_next/static/chunks/3144.6861096c7b4edef7.js +0 -64
  588. package/apps/pwa/out/_next/static/chunks/3267c0e6.d34854e7b3984a6e.js +0 -1
  589. package/apps/pwa/out/_next/static/chunks/3771.e928edf2867d28c0.js +0 -1
  590. package/apps/pwa/out/_next/static/chunks/3902.e1e71aaac850a045.js +0 -34
  591. package/apps/pwa/out/_next/static/chunks/4063-03284b5de59965f3.js +0 -1
  592. package/apps/pwa/out/_next/static/chunks/4111.2bfedbb233ad206b.js +0 -1
  593. package/apps/pwa/out/_next/static/chunks/4300-c7ec4eeabbb5f3f7.js +0 -1
  594. package/apps/pwa/out/_next/static/chunks/4483.646d5065199e1b55.js +0 -36
  595. package/apps/pwa/out/_next/static/chunks/4519.28199ff26b2fd80d.js +0 -1
  596. package/apps/pwa/out/_next/static/chunks/4581.ef2443578054544f.js +0 -1
  597. package/apps/pwa/out/_next/static/chunks/4608-8d894e9cbe4f08bf.js +0 -1
  598. package/apps/pwa/out/_next/static/chunks/4639.ae48a01d1bb50a93.js +0 -286
  599. package/apps/pwa/out/_next/static/chunks/4739.08742ac668aada67.js +0 -77
  600. package/apps/pwa/out/_next/static/chunks/4882-16cef71d6a1a32be.js +0 -1
  601. package/apps/pwa/out/_next/static/chunks/4999.c064a4000c2a9e94.js +0 -79
  602. package/apps/pwa/out/_next/static/chunks/5260-69f35419bca263e7.js +0 -1
  603. package/apps/pwa/out/_next/static/chunks/5272.b92d1b72a15c25fe.js +0 -1
  604. package/apps/pwa/out/_next/static/chunks/5304.04d24756f242a094.js +0 -148
  605. package/apps/pwa/out/_next/static/chunks/5415-997980f828667736.js +0 -1
  606. package/apps/pwa/out/_next/static/chunks/5458-16cd7a2b51b74c8c.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/5572-42c9084f27ca761e.js +0 -1
  608. package/apps/pwa/out/_next/static/chunks/5661-80470aac963d9f36.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/5723.421338408b5c30c4.js +0 -74
  610. package/apps/pwa/out/_next/static/chunks/5809.64c3664267c50bce.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/6000.64bc21ac8627f2f5.js +0 -94
  612. package/apps/pwa/out/_next/static/chunks/6013.39459b9c68eabf5f.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/607-06466dff012b03ef.js +0 -1
  614. package/apps/pwa/out/_next/static/chunks/60fb96c9.360b01d8d4927b7b.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/6192.a190b989b81e9743.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/6323.8672b4817a306928.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/6444.7d1fdcb9b09ae71c.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/6517.4147878ac06d584d.js +0 -90
  619. package/apps/pwa/out/_next/static/chunks/6532.e34302010b2f0b68.js +0 -32
  620. package/apps/pwa/out/_next/static/chunks/6544cb48.a87fe20ddf137be2.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/6546.74bc4ed82f19016d.js +0 -104
  622. package/apps/pwa/out/_next/static/chunks/6684-e7523ce7c2fad075.js +0 -1
  623. package/apps/pwa/out/_next/static/chunks/6726.ebdc82feb161431e.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/6739.00fb6f892e5e392b.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/6745.934c4921bf15513a.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/6767.ea607cf0c20a25af.js +0 -24
  627. package/apps/pwa/out/_next/static/chunks/6843.67bfd020da0926c5.js +0 -93
  628. package/apps/pwa/out/_next/static/chunks/6948.1062d4594652b5bf.js +0 -1
  629. package/apps/pwa/out/_next/static/chunks/7138-eaf841fc1dc03463.js +0 -1
  630. package/apps/pwa/out/_next/static/chunks/7174-cda29ee13d7790e7.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/7304-3c07583f4e405f4f.js +0 -1
  632. package/apps/pwa/out/_next/static/chunks/7371.80c05c653b08e907.js +0 -1
  633. package/apps/pwa/out/_next/static/chunks/7391.ebae168025c91b6a.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/7557.e325503a090a4310.js +0 -8
  635. package/apps/pwa/out/_next/static/chunks/7569-9ce9432c7f10989f.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/7886-55854585fadeded1.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/7947-d0759430f8042240.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/8018.a32663f04a6fc5f9.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/8215-1661812b6e9ad71f.js +0 -1
  641. package/apps/pwa/out/_next/static/chunks/8260-19c921a51ca8ec3e.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/8440.3a5cf5c85aa76db8.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/8519-4599be2249161e68.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/8547.b028b90c5c01ace6.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/8587-cbe02a953a7f4990.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/877-2b977259c4b15655.js +0 -1
  647. package/apps/pwa/out/_next/static/chunks/9019-0a4b40c50c7314fb.js +0 -1
  648. package/apps/pwa/out/_next/static/chunks/9138.b6e80031afb1d973.js +0 -1
  649. package/apps/pwa/out/_next/static/chunks/9188-d36e4fc869ddc166.js +0 -1
  650. package/apps/pwa/out/_next/static/chunks/9230.44f5039e796e4ab4.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/9279-d28c5b7754d010ae.js +0 -1
  652. package/apps/pwa/out/_next/static/chunks/939.336acce73e98482c.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/9610.c07cce4bfcc14ed7.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/9667-ce78c2ce91050ff9.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-339fabb3499da0e1.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-3535a4a69f1fafaa.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2ebb8fd59b9461f9.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/app/ceo/page-5a503541353e60a8.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/app/chat/page-6025101384e361a5.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +0 -1
  664. package/apps/pwa/out/_next/static/chunks/app/control/page-a645f00a06483e9a.js +0 -1
  665. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/app/design-check/page-e9bab7413b028b28.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/app/exec/page-e547e6ce55f1fb33.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/app/field/page-d27e1b9850fd54bf.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/app/healthz/route-339fabb3499da0e1.js +0 -1
  671. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +0 -1
  672. package/apps/pwa/out/_next/static/chunks/app/intake/page-0fec29c7ba01894b.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/app/layout-339a07410cd6f36b.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/app/loops/page-2fd93ed8c9f16580.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/app/market/page-9b564dbff0fefc35.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +0 -1
  679. package/apps/pwa/out/_next/static/chunks/app/morning/page-814ba51385225776.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/app/not-found-397d479626e5a459.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/app/observatory/page-af1bba4e3251b728.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ad3be5e7d3fdce9.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4da93ad35d4a8d28.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +0 -1
  687. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-3a658d5fa6d16a25.js +0 -1
  689. package/apps/pwa/out/_next/static/chunks/app/sessions/page-0157de6e85f8bb6b.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/app/settings/page-841d73d4ac44ed49.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-6f43a3d1146e6377.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/app/setup/layout-339fabb3499da0e1.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/app/setup/page-521ee23ac8c0abfa.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/app/share/page-a9992ee285efaa83.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/app/showroom/page-3d48e85fa89ec04f.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/app/today/page-233c71cd5f68f0d7.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/app/trace/page-70151d78de2f375e.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/app/vault/page-dcac33a3e2cb72c0.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-149dc1caba411bb9.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0448145ccd5c45c1.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +0 -1
  705. package/apps/pwa/out/_next/static/chunks/e5012ffe.f727e23c231f4342.js +0 -122
  706. package/apps/pwa/out/_next/static/chunks/ea695e3c-1f1d70d740cf3031.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/framework-906af9bd029e166c.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/main-a24847f9f684d469.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/main-app-7bdcd8aa7c8397d3.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/pages/_app-6ba46a5066fc226d.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/pages/_error-a8dc6d07591f2a25.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/webpack-f13df28c15c55eee.js +0 -1
  713. package/apps/pwa/out/_next/static/css/3f5fc6f96e2cf7b2.css +0 -1
  714. package/src/cli/g6a-registration-probe.ts +0 -16
  715. /package/apps/pwa/out/_next/static/{LSXfY0u9QtfDbejY0Ukf_ → L04y73dlwKeTW-GetaTF3}/_ssgManifest.js +0 -0
@@ -1,4 +1,4 @@
1
- import { appendMessage } from '../session/index.js';
1
+ import { appendMessage, onSessionCreated } from '../session/index.js';
2
2
  // ⛔ 메시지 «모양»은 `session/chat.ts` 가 갖는다 — 여기서 베끼지 않는다.
3
3
  // 같은 계약을 두 벌로 두면 한쪽만 자라고, 그때 「어느 표면의 기록인가」가 갈린다.
4
4
  import { buildToolTraceMessage } from '../session/chat.js';
@@ -24,9 +24,13 @@ import { debug } from '../debug/log.js';
24
24
  * Goodhart 시험이었다. ⇒ 주입 가능한 함수로 떼어 **실행으로** 문다. */
25
25
  /** ⛔ 이 저장소 «밖»으로 열지 않는다 — 소비처가 이 파일과 그 시험뿐이다(리뷰 must-fix:
26
26
  * 쓰이지 않는 공개 표면). 시험은 리터럴로 넘기므로 이름을 export 할 필요가 없다. */
27
+ type TraceMessage = ReturnType<typeof buildToolTraceMessage>;
28
+ type AppendFn = (sessionId: string, msg: TraceMessage) => unknown;
29
+ type FailureObserver = (info: { sessionId: string; tool: string; id: string; reason: string }) => void;
30
+
27
31
  interface AcpToolTraceDeps {
28
32
  /** 시험 주입점. 기본은 실제 세션 저장소. */
29
- readonly append?: (sessionId: string, msg: ReturnType<typeof buildToolTraceMessage>) => unknown;
33
+ readonly append?: AppendFn;
30
34
  /** ⛔⭐ 메시지 «모양»을 만드는 자리 — 기본은 `session/chat.ts` 의 공유 빌더.
31
35
  *
32
36
  * 📏 무인 리뷰 must-fix(PR #11120): 산출 필드(`role`/`toolName`/…)만 검사하면
@@ -35,7 +39,166 @@ interface AcpToolTraceDeps {
35
39
  * ⇒ 주입점으로 열어 **「공유 빌더를 쓴다」를 시험이 «실행으로» 확인**할 수 있게 한다. */
36
40
  readonly buildMessage?: typeof buildToolTraceMessage;
37
41
  /** 실패를 «이름으로» 남기는 자리. 기본은 관측 로그. */
38
- readonly observeFailure?: (info: { sessionId: string; tool: string; id: string; reason: string }) => void;
42
+ readonly observeFailure?: FailureObserver;
43
+ /** 지연·회수·상한을 남기는 자리(`trace-persist-deferred|flushed|dropped`). 기본은 관측 로그. */
44
+ readonly observe?: (event: TraceDeferEvent, data: Record<string, unknown>) => void;
45
+ /** 「세션이 원장에 생겼다」를 듣는 자리. 기본은 `session/index.ts` 의 `onSessionCreated`. */
46
+ readonly subscribeSessionCreated?: (listener: (meta: { readonly id: string }) => void) => () => void;
47
+ }
48
+
49
+ type TraceDeferEvent = 'trace-persist-deferred' | 'trace-persist-flushed' | 'trace-persist-dropped';
50
+
51
+ /** ⛔⭐⭐ **「세션이 아직 원장에 없다」는 실패가 아니라 «순서»다 — 지연 기록한다.**
52
+ *
53
+ * 📏 2026-10-16 실측(TUI 결함 #30·#64 · `eln logs --category acp.tool` 12h):
54
+ * `trace-persist-failed «session not found: elanous-session-ndusg6»` 7건이 **13:12:03~15Z 한 턴**에 몰렸고,
55
+ * 그 세션 파일의 첫 줄은 **13:12:48Z**(턴 «끝»)였다.
56
+ * 🔑 원인(호출부): ACP 서버는 세션 id 를 «메모리에만» 민팅하고(`acpServerRegisterSession` · `server.ts`),
57
+ * 원장 채택은 **턴이 «끝난 뒤»** 에 일어난다 — `persistCompletedTuiAcpTurn`(서버 · origin 메타가 있을 때) 또는
58
+ * 대시보드의 `adoptChatSession`(SESSION-RESUME-ISOLATED · 턴 완료 뒤). 그런데 툴 흔적은 «턴 도중»
59
+ * `pushToolResult` → 이 함수에서 쓴다. ⇒ ***새 세션의 «첫 턴» 도구 흔적은 전부 잃었다***
60
+ * (`/session new`·ACP 갱신마다 새 id 라 첫 턴이 반복된다).
61
+ * ⇒ 그 오류면 메시지를 세션별로 붙잡아 두고, 세션이 원장에 생기는 순간(`onSessionCreated`) 또는
62
+ * 같은 세션의 다음 호출 때 «원래 시각(ts) 그대로» 붙인다. 경고는 세션당 «한 번»(지연) ⊕ 회수 때 «수»로.
63
+ * ⛔ 출처(`source`)를 짐작해 여기서 세션을 «만들지» 않는다 — 같은 ACP 경로를 PWA 도 타므로
64
+ * TUI 로 낙인찍으면 남의 세션 속성을 틀리게 박는다. 만드는 일은 원래 주인(턴 완료 채택)에게 둔다. */
65
+ /* ⚠️ 상한은 «메모리 바닥»만 지킨다 — 영영 채택되지 않는 세션(턴 도중 종료)이 쌓이지 않게.
66
+ * 세션당 100 을 넘으면 그 뒤 흔적은 버리고, 세션 32 를 넘으면 가장 오래 기다린 세션을 통째로 버린다.
67
+ * 어느 쪽이든 `trace-persist-dropped` 를 «한 줄» 남길 뿐 버린 «수»를 세거나 간격을 두지 않는다
68
+ * (버림 계수·보고 방식은 연결 골 `ASK-ACP-TRACE-EVICTION-ACCOUNTING` 이 정한다).
69
+ * 축출된 id 가 다시 오면 「한 번」 경고부터 다시 시작한다 — id 는 base36 무작위 6자라 드물다. */
70
+ const MAX_PENDING_PER_SESSION = 100;
71
+ const MAX_PENDING_SESSIONS = 32;
72
+ const SESSION_NOT_FOUND = /^session not found: /;
73
+
74
+ interface PendingSession {
75
+ readonly entries: Array<{
76
+ readonly append: AppendFn;
77
+ readonly msg: TraceMessage;
78
+ readonly tool: string;
79
+ readonly id: string;
80
+ readonly observeFailure: FailureObserver | undefined;
81
+ }>;
82
+ /** 세션당 상한에 한 번 닿았나 — `trace-persist-dropped` 를 세션당 한 줄만 남기려고. */
83
+ capped: boolean;
84
+ readonly observe: (event: TraceDeferEvent, data: Record<string, unknown>) => void;
85
+ }
86
+
87
+ const pendingBySession = new Map<string, PendingSession>();
88
+ let unsubscribeCreated: (() => void) | null = null;
89
+
90
+ const defaultObserve = (event: TraceDeferEvent, data: Record<string, unknown>): void => {
91
+ debug.log('acp.tool', event, data);
92
+ };
93
+
94
+ const safeObserve = (fn: () => void): void => {
95
+ // ⛔ 관측 자체가 던져도 턴을 깨지 않는다 — 그러면 fail-soft 가 무의미해진다.
96
+ try { fn(); } catch { /* 관측은 마지막 방어선이다 */ }
97
+ };
98
+
99
+ const errorReason = (err: unknown): string =>
100
+ err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
101
+
102
+ function observeFailureOf(
103
+ sessionId: string,
104
+ call: { readonly tool: string; readonly id: string },
105
+ reason: string,
106
+ observeFailure: FailureObserver | undefined,
107
+ ): void {
108
+ const observe = observeFailure
109
+ ?? ((info) => { debug.log('acp.tool', 'trace-persist-failed', info); });
110
+ safeObserve(() => observe({ sessionId, tool: call.tool, id: call.id, reason }));
111
+ }
112
+
113
+ /** 붙잡아 둔 흔적을 원래 순서대로 붙인다. 세션이 여전히 없으면 그대로 둔다(`'missing'`). */
114
+ function flushPending(sessionId: string): 'missing' | 'flushed' | 'none' {
115
+ const p = pendingBySession.get(sessionId);
116
+ if (!p) return 'none';
117
+ let flushed = 0;
118
+ let failed = 0;
119
+ while (p.entries.length > 0) {
120
+ const entry = p.entries[0]!;
121
+ try {
122
+ entry.append(sessionId, entry.msg);
123
+ flushed += 1;
124
+ } catch (err) {
125
+ const reason = errorReason(err);
126
+ // ⛔ 회수 «도중» 세션이 사라져도(이미 몇 행을 붙인 뒤라도) 그 행과 나머지는 «지연» 그대로 둔다 — 실패가 아니다.
127
+ if (SESSION_NOT_FOUND.test(reason)) {
128
+ // ⭐ 그때까지 붙인 행 수는 «지금» 남긴다 — 다음 회수 보고는 그 뒤의 행만 센다.
129
+ if (flushed > 0 || failed > 0) {
130
+ safeObserve(() => p.observe('trace-persist-flushed', { sessionId, flushed, failed, partial: true }));
131
+ }
132
+ return 'missing';
133
+ }
134
+ failed += 1;
135
+ // ⛔ 회수 중 실패도 «같은» `trace-persist-failed` 로 — `flushed.failed` 합계에만 묻으면 실패가 안 보인다.
136
+ observeFailureOf(sessionId, { tool: entry.tool, id: entry.id }, reason, entry.observeFailure);
137
+ }
138
+ p.entries.shift();
139
+ }
140
+ pendingBySession.delete(sessionId);
141
+ safeObserve(() => p.observe('trace-persist-flushed', { sessionId, flushed, failed }));
142
+ if (pendingBySession.size === 0 && unsubscribeCreated) {
143
+ const off = unsubscribeCreated;
144
+ unsubscribeCreated = null;
145
+ try { off(); } catch { /* 구독 해제 실패는 무해 — 다음 지연이 다시 건다 */ }
146
+ }
147
+ return 'flushed';
148
+ }
149
+
150
+ function deferTrace(
151
+ sessionId: string,
152
+ call: { readonly id: string; readonly name: string },
153
+ append: AppendFn,
154
+ msg: TraceMessage,
155
+ reason: string,
156
+ deps: AcpToolTraceDeps,
157
+ ): void {
158
+ let p = pendingBySession.get(sessionId);
159
+ if (!p) {
160
+ if (pendingBySession.size >= MAX_PENDING_SESSIONS) {
161
+ // 가장 오래 기다린 세션부터 버린다 — 원장에 영영 안 생긴 세션(턴 도중 종료)이 쌓이지 않게.
162
+ const [oldestId, oldest] = pendingBySession.entries().next().value as [string, PendingSession];
163
+ pendingBySession.delete(oldestId);
164
+ safeObserve(() => oldest.observe('trace-persist-dropped', { sessionId: oldestId, reason: 'pending-session-cap' }));
165
+ }
166
+ p = { entries: [], capped: false, observe: deps.observe ?? defaultObserve };
167
+ pendingBySession.set(sessionId, p);
168
+ // ⭐ 경고는 세션당 «한 번» — 호출마다 같은 줄을 찍던 것이 결함 #64 의 다른 반쪽이다.
169
+ safeObserve(() => p!.observe('trace-persist-deferred', { sessionId, tool: call.name, id: call.id, reason }));
170
+ }
171
+ if (p.entries.length < MAX_PENDING_PER_SESSION) {
172
+ p.entries.push({ append, msg, tool: call.name, id: call.id, observeFailure: deps.observeFailure });
173
+ } else if (!p.capped) {
174
+ p.capped = true;
175
+ safeObserve(() => p!.observe('trace-persist-dropped', {
176
+ sessionId, tool: call.name, id: call.id, reason: 'pending-per-session-cap',
177
+ }));
178
+ }
179
+ if (!unsubscribeCreated) {
180
+ const subscribe = deps.subscribeSessionCreated ?? onSessionCreated;
181
+ try {
182
+ unsubscribeCreated = subscribe((meta) => {
183
+ if (!pendingBySession.has(meta.id)) return;
184
+ // ⭐ 채택 «직후» 같은 동기 구간에서 user/assistant 가 이어 붙는다(`persistCompletedTuiAcpTurn`).
185
+ // 마이크로태스크로 미뤄 그 뒤에 붙인다 — 그래야 「마지막 user 뒤의 tool 행」(다음 턴 관찰)이 산다.
186
+ queueMicrotask(() => { try { flushPending(meta.id); } catch { /* fail-soft */ } });
187
+ });
188
+ } catch { unsubscribeCreated = null; }
189
+ }
190
+ }
191
+
192
+ /** 시험 전용 — 모듈 상태(지연 큐·구독)를 비운다. */
193
+ export function _resetAcpToolTraceStateForTest(): void {
194
+ pendingBySession.clear();
195
+ if (unsubscribeCreated) { try { unsubscribeCreated(); } catch { /* 무해 */ } }
196
+ unsubscribeCreated = null;
197
+ }
198
+
199
+ /** 시험·관측용 — 세션별로 붙잡아 둔 흔적 수. */
200
+ export function pendingAcpToolTraceCount(sessionId: string): number {
201
+ return pendingBySession.get(sessionId)?.entries.length ?? 0;
39
202
  }
40
203
 
41
204
  /** 한 번의 툴 호출을 감사 기록으로 남긴다.
@@ -44,8 +207,9 @@ interface AcpToolTraceDeps {
44
207
  * (`session/chat.ts` 가 세운 규율).
45
208
  * ⚠️ **그러나 «조용히 삼키지 않는다»** — 실패하면 이름을 대고 관측에 남긴다.
46
209
  * ***조용한 실패야말로 16차가 내내 잡던 형태고, 이 PR 초판이 또 만들었다.***
210
+ * ⭐ 「세션이 아직 원장에 없다」면 지연 기록한다(위 `MAX_PENDING_*` 주석) — 이때도 `false` 다.
47
211
  *
48
- * @returns 저장을 시도해 «성공»했으면 `true`. ⛔ 「안 했다」와 「했는데 실패했다」는 다른 값이다. */
212
+ * @returns 지금 저장에 «성공»했으면 `true`. ⛔ 「안 했다」와 「했는데 실패했다」·「미뤘다」는 다른 값이다. */
49
213
  export function persistAcpToolTrace(
50
214
  sessionId: string,
51
215
  call: { readonly id: string; readonly name: string; readonly result?: unknown },
@@ -56,14 +220,25 @@ export function persistAcpToolTrace(
56
220
  // ⛔ 모양은 «공유 빌더»가 만든다 — 여기서 손으로 조립하지 않는다(계약을 두 벌로 두지 않는다).
57
221
  const build = deps.buildMessage ?? buildToolTraceMessage;
58
222
  try {
59
- append(sessionId, build(call.name, args, call.result));
60
- return true;
223
+ const msg = build(call.name, args, call.result);
224
+ // 앞서 미뤄 둔 흔적이 있으면 먼저 붙인다(순서 보존). 여전히 세션이 없으면 이것도 뒤에 줄 세운다.
225
+ if (pendingBySession.has(sessionId) && flushPending(sessionId) === 'missing') {
226
+ deferTrace(sessionId, call, append, msg, 'session not found (pending)', deps);
227
+ return false;
228
+ }
229
+ try {
230
+ append(sessionId, msg);
231
+ return true;
232
+ } catch (err) {
233
+ const reason = errorReason(err);
234
+ if (SESSION_NOT_FOUND.test(reason)) {
235
+ deferTrace(sessionId, call, append, msg, reason, deps);
236
+ return false;
237
+ }
238
+ throw err;
239
+ }
61
240
  } catch (err) {
62
- const reason = err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
63
- const observe = deps.observeFailure
64
- ?? ((info) => { debug.log('acp.tool', 'trace-persist-failed', info); });
65
- // ⛔ 관측 자체가 던져도 턴을 깨지 않는다 — 그러면 fail-soft 가 무의미해진다.
66
- try { observe({ sessionId, tool: call.name, id: call.id, reason }); } catch { /* 관측은 마지막 방어선이다 */ }
241
+ observeFailureOf(sessionId, { tool: call.name, id: call.id }, errorReason(err), deps.observeFailure);
67
242
  return false;
68
243
  }
69
244
  }
@@ -0,0 +1,156 @@
1
+ // ── TUI 자기인지 ambient 캐시 — 턴 시작이 이벤트 루프를 막지 않게 (TUI-TYPING-LAG · 2026-10-14) ──
2
+ //
3
+ // 실측(격리 TUI · bun --cpu-prof): 턴마다 `elanousSelfAmbientBaseParts()`(ops 스캔·crontab·`ps`)가
4
+ // 메인 스레드에서 동기로 돌았고, 한 턴에 «두 번»(대시보드 preamble ⊕ ACP buildTurnMessages) 돌아
5
+ // 그 동안 키 입력이 0.4~9s 멈췄다. 이 캐시는 «요청과 무관한» 부분만 담는다:
6
+ // · 신선(< FRESH_MS) → 그대로 쓴다.
7
+ // · 오래됨(< STALE_MAX_MS) → 그대로 쓰고 워커에서 다시 잰다(다음 턴용).
8
+ // · 없음/너무 오래됨 → 종전대로 동기 계산(첫 턴 내용 보존). TUI 는 부팅 때 데우고 5s 주기
9
+ // 틱(`refreshSelfAmbientCache({}, { ifOlderThanMs })` · src/dashboard/index.ts)으로 계속 데워
10
+ // 두므로, 워커가 실패(백오프)하지 않는 한 오래 쉰 뒤 첫 턴도 이 길로 안 온다.
11
+ // 관측 = `self-ambient.cache` (hit · stale-hit · sync · worker-refreshed · worker-failed).
12
+
13
+ import { isMainThread, parentPort, workerData, Worker } from 'node:worker_threads';
14
+ import { debug } from '../debug/log.js';
15
+ import { effectiveInstanceRoot } from '../instance/resolve.js';
16
+ import { setElanousConfigDir } from '../elanous-config-dir.js';
17
+ import { elanousSelfAmbientBaseParts } from './self-ambient.js';
18
+
19
+ export const SELF_AMBIENT_FRESH_MS = 30_000;
20
+ export const SELF_AMBIENT_STALE_MAX_MS = 10 * 60_000;
21
+ const WORKER_TIMEOUT_MS = 60_000;
22
+
23
+ interface CacheEntry { at: number; version: number; parts: string[] }
24
+
25
+ export interface SelfAmbientCacheDeps {
26
+ now?: () => number;
27
+ computeSync?: () => string[];
28
+ computeInWorker?: (stateRoot: string | undefined, selectedRoot: string) => Promise<string[]>;
29
+ universeKey?: () => { stateRoot: string | undefined; selectedRoot: string };
30
+ log?: (category: string, event: string, data: Record<string, unknown>) => void;
31
+ }
32
+
33
+ const entries = new Map<string, CacheEntry>();
34
+ /** Monotonic store sequence — orders async worker stores against synchronous ones.
35
+ * A millisecond `at` clock ties within the same millisecond and let a worker's older
36
+ * result overwrite a newer synchronous computation; the version never ties. */
37
+ let storeSeq = 0;
38
+ const inFlight = new Map<string, Promise<void>>();
39
+ /** A failed worker is not retried (by ticks or stale turn reads) for this long; the turn path keeps
40
+ * serving the stale entry, or falls back to sync once it is too old. */
41
+ const WORKER_FAILURE_BACKOFF_MS = 60_000;
42
+ const lastFailureAt = new Map<string, number>();
43
+
44
+ function resolveDeps(deps: SelfAmbientCacheDeps): Required<SelfAmbientCacheDeps> {
45
+ return {
46
+ now: deps.now ?? Date.now,
47
+ computeSync: deps.computeSync ?? elanousSelfAmbientBaseParts,
48
+ computeInWorker: deps.computeInWorker ?? computeBasePartsInWorker,
49
+ universeKey: deps.universeKey ?? (() => ({ stateRoot: process.env.ELANOUS_STATE_DIR, selectedRoot: effectiveInstanceRoot() })),
50
+ log: deps.log ?? ((category, event, data) => debug.log(category, event, data)),
51
+ };
52
+ }
53
+
54
+ /** Start (or join) a background refresh. Resolves when the cache has been updated or the refresh failed.
55
+ * `ifOlderThanMs` turns it into a keep-warm tick: a younger entry is left alone. */
56
+ export function refreshSelfAmbientCache(deps: SelfAmbientCacheDeps = {}, opts: { ifOlderThanMs?: number } = {}): Promise<void> {
57
+ const d = resolveDeps(deps);
58
+ const { stateRoot, selectedRoot } = d.universeKey();
59
+ const key = JSON.stringify([selectedRoot, stateRoot ?? null]);
60
+ const cached = entries.get(key);
61
+ if (cached && opts.ifOlderThanMs !== undefined && d.now() - cached.at < opts.ifOlderThanMs) return Promise.resolve();
62
+ if (d.now() - (lastFailureAt.get(key) ?? -Infinity) < WORKER_FAILURE_BACKOFF_MS) return Promise.resolve();
63
+ const running = inFlight.get(key);
64
+ if (running) return running;
65
+ const startedAt = d.now();
66
+ const startedVersion = storeSeq;
67
+ // A worker that fails to even start (sync throw) is the same fail-soft failure as one that rejects.
68
+ let started: Promise<string[]>;
69
+ try { started = d.computeInWorker(stateRoot, selectedRoot); }
70
+ catch (error) { started = Promise.reject(error); }
71
+ const refresh = started
72
+ .then((parts) => {
73
+ // A newer entry (e.g. a synchronous first-turn computation that overlapped this worker) is kept.
74
+ // Judged by the monotonic store version, not the millisecond clock: a store that landed in the
75
+ // same millisecond as this worker's start is still newer.
76
+ const current = entries.get(key);
77
+ if (current && current.version > startedVersion) return;
78
+ entries.set(key, { at: startedAt, version: ++storeSeq, parts });
79
+ d.log('self-ambient.cache', 'worker-refreshed', { ms: d.now() - startedAt, parts: parts.length });
80
+ }, (error: unknown) => {
81
+ lastFailureAt.set(key, d.now());
82
+ d.log('self-ambient.cache', 'worker-failed', { ms: d.now() - startedAt, reason: error instanceof Error ? error.message : String(error) });
83
+ })
84
+ .finally(() => { inFlight.delete(key); });
85
+ inFlight.set(key, refresh);
86
+ return refresh;
87
+ }
88
+
89
+ /** Request-independent ambient parts for the TUI turn preamble, served from the cache when possible. */
90
+ export function cachedSelfAmbientBaseParts(deps: SelfAmbientCacheDeps = {}): string[] {
91
+ const d = resolveDeps(deps);
92
+ const { stateRoot, selectedRoot } = d.universeKey();
93
+ const key = JSON.stringify([selectedRoot, stateRoot ?? null]);
94
+ const at = d.now();
95
+ const cached = entries.get(key);
96
+ const ageMs = cached ? at - cached.at : null;
97
+ if (cached && ageMs! < SELF_AMBIENT_FRESH_MS) {
98
+ d.log('self-ambient.cache', 'hit', { ageMs });
99
+ return [...cached.parts];
100
+ }
101
+ if (cached && ageMs! < SELF_AMBIENT_STALE_MAX_MS) {
102
+ d.log('self-ambient.cache', 'stale-hit', { ageMs });
103
+ void refreshSelfAmbientCache(deps);
104
+ return [...cached.parts];
105
+ }
106
+ const parts = d.computeSync();
107
+ entries.set(key, { at, version: ++storeSeq, parts });
108
+ d.log('self-ambient.cache', 'sync', { ms: d.now() - at, ageMs, parts: parts.length });
109
+ return [...parts];
110
+ }
111
+
112
+ export function _resetSelfAmbientCacheForTest(): void {
113
+ storeSeq = 0;
114
+ entries.clear();
115
+ inFlight.clear();
116
+ lastFailureAt.clear();
117
+ }
118
+
119
+ function computeBasePartsInWorker(stateRoot: string | undefined, selectedRoot: string): Promise<string[]> {
120
+ const worker = new Worker(new URL(import.meta.url), { workerData: { kind: 'self-ambient' } });
121
+ return new Promise((resolve, reject) => {
122
+ let settled = false;
123
+ const timeout = setTimeout(() => finish(new Error(`self-ambient worker timed out after ${WORKER_TIMEOUT_MS}ms`)), WORKER_TIMEOUT_MS);
124
+ // A background warm-up must never keep a finished CLI or test process alive.
125
+ timeout.unref?.();
126
+ worker.unref?.();
127
+ const finish = (error?: Error, parts?: string[]): void => {
128
+ if (settled) return;
129
+ settled = true;
130
+ clearTimeout(timeout);
131
+ void worker.terminate();
132
+ if (error) reject(error);
133
+ else resolve(parts!);
134
+ };
135
+ worker.on('message', (message: { parts?: string[]; error?: string }) => {
136
+ if (message.error) finish(new Error(message.error));
137
+ else if (message.parts) finish(undefined, message.parts);
138
+ });
139
+ worker.on('error', error => finish(error instanceof Error ? error : new Error(String(error))));
140
+ worker.on('exit', code => { if (!settled) finish(new Error(`self-ambient worker exited before answering: ${code}`)); });
141
+ // Pin the caller's universe: a programmatic config override is not inherited by workers.
142
+ worker.postMessage({ stateRoot, selectedRoot });
143
+ });
144
+ }
145
+
146
+ const selfAmbientWorkerPort = parentPort;
147
+ if (!isMainThread && selfAmbientWorkerPort && workerData?.kind === 'self-ambient') {
148
+ selfAmbientWorkerPort.on('message', ({ stateRoot, selectedRoot }: { stateRoot?: string; selectedRoot: string }) => {
149
+ try {
150
+ if (stateRoot === undefined) delete process.env.ELANOUS_STATE_DIR;
151
+ else process.env.ELANOUS_STATE_DIR = stateRoot;
152
+ setElanousConfigDir(selectedRoot);
153
+ selfAmbientWorkerPort.postMessage({ parts: elanousSelfAmbientBaseParts() });
154
+ } catch (error) { selfAmbientWorkerPort.postMessage({ error: error instanceof Error ? error.message : String(error) }); }
155
+ });
156
+ }
@@ -184,11 +184,18 @@ export function investigationRecallAmbient(taskText: string): string {
184
184
  /** 자기인지 ambient — 최근 자기 구현/변경 + 최근 자율행동 + 자율 시스템 이상 + 미션 사건 사실
185
185
  * (+ taskText 주면 조사문맥 관련 회상·축B). 매 턴 fresh · 각각 fail-soft(없음이면 빈 문자열). */
186
186
  export function elanousSelfAmbientParts(taskText?: string): string[] {
187
+ const parts = elanousSelfAmbientBaseParts();
188
+ if (taskText) { try { parts.push(investigationRecallAmbient(taskText)); } catch { /* fail-soft */ } }
189
+ return parts.filter(Boolean);
190
+ }
191
+
192
+ /** The request-independent ambient parts (store scans · `ps` · crontab). Split out so the
193
+ * TUI can compute them off its event loop (`self-ambient-cache.ts`). */
194
+ export function elanousSelfAmbientBaseParts(): string[] {
187
195
  const parts: string[] = [];
188
196
  try { parts.push(recentSelfChangesContext()); } catch { /* fail-soft */ }
189
197
  try { parts.push(recentAutonomyContext()); } catch { /* fail-soft */ }
190
198
  try { parts.push(opsHealthContext()); } catch { /* fail-soft */ }
191
199
  try { parts.push(missionIncidentAmbient()); } catch { /* fail-soft */ }
192
- if (taskText) { try { parts.push(investigationRecallAmbient(taskText)); } catch { /* fail-soft */ } }
193
200
  return parts.filter(Boolean);
194
201
  }
@@ -113,6 +113,11 @@ export class TaskNotificationQueue {
113
113
  return this.queue.length;
114
114
  }
115
115
 
116
+ /** Is this task's notification still queued (not yet drained into a turn)? */
117
+ has(taskId: string): boolean {
118
+ return this.queue.some((n) => n.taskId === taskId);
119
+ }
120
+
116
121
  /** Forget everything — tests use this for isolation. Listeners are
117
122
  * preserved: clear() empties queue + seen, not the wake wiring. */
118
123
  clear(): void {
@@ -55,6 +55,9 @@ export interface AcpReviewerOpts {
55
55
  */
56
56
  export const DEFAULT_REVIEW_BACKEND = 'codex';
57
57
 
58
+ /** Stable failureReason prefix carried through reviewPullRequest's fail-soft result. */
59
+ export const GROK_ACP_REVIEW_TIMEOUT = 'ACP_REVIEW_TIMEOUT:grok:';
60
+
58
61
  // ACP ToolKind(zToolKind) 중 read-only(부작용 없음) — 리뷰어에게 허가할 계열.
59
62
  const READONLY_TOOL_KINDS = new Set(['read', 'search', 'fetch', 'think', 'switch_mode']);
60
63
  // 명시적 변경/실행 계열 — 리뷰(read-only)에선 절대 불허.
@@ -84,7 +87,7 @@ const TOOL_REVIEW_PREAMBLE = [
84
87
  * - model 지정 시 selectSessionModel 로 tier 고정(picked 관측).
85
88
  * - ⭐auto-allow permission approver — 리뷰어의 read-only 툴콜을 무조건 허가(대표 지시)해 Read 반복거부
86
89
  * 정체를 원천제거. 각 허가는 debug.log 로 각인(제1원칙 관측 관문 — 자동승인은 관측되는 결정).
87
- * - timeout: 초과 시 cancel→throw. 오류/타임아웃은 각인 후 rethrow → reviewPullRequest 가 fail-soft
90
+ * - timeout: 초과 시 실패를 확정하고 cancel·stop. 오류/타임아웃은 각인 후 rethrow → reviewPullRequest 가 fail-soft
88
91
  * (reviewed=false)로 흡수, CLI 가 reviewed=false 를 "리뷰 실패"로 표면화(부분결과 오판 pass 방지). */
89
92
  export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images?: readonly ReviewImage[]) => Promise<string> {
90
93
  return async (prompt: string, images?: readonly ReviewImage[]): Promise<string> => {
@@ -117,8 +120,13 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
117
120
  model: opts.model ?? '(default)',
118
121
  promptChars: prompt.length,
119
122
  });
123
+ const startedAt = Date.now();
124
+ let phase = 'spawn';
125
+ let phaseStartedAt = startedAt;
126
+ const enterPhase = (next: string): void => { phase = next; phaseStartedAt = Date.now(); };
120
127
  let allowed = 0;
121
128
  let denied = 0;
129
+ const observedToolCalls = new Set<string>();
122
130
  let capabilitiesObserved = false;
123
131
  const agentOpts: Omit<AcpAgentOpts, 'backendId'> = {
124
132
  cwd: opts.cwd,
@@ -149,10 +157,12 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
149
157
  };
150
158
  // A review owns its manager and subprocess: the global manager caches
151
159
  // chat agents, whose callbacks and lifecycle must not be mutated here.
152
- const reviewManager = injected || opts.backendSpec ? undefined : new AcpAgentManager();
160
+ // Grok's start can hang before the manager registers the subprocess;
161
+ // own it directly so the handshake timeout can stop that child.
162
+ const directAgent = injected || Boolean(opts.backendSpec) || backend === 'grok';
163
+ const reviewManager = directAgent ? undefined : new AcpAgentManager();
153
164
  let agent: AcpAgent | undefined;
154
165
  let text = '';
155
- let timedOut = false;
156
166
  let timer: ReturnType<typeof setTimeout> | undefined;
157
167
  const handshakeTimeoutMs = opts.handshakeTimeoutMs ?? Math.min(timeoutMs, 60_000);
158
168
  const handshakeDeadline = Date.now() + handshakeTimeoutMs;
@@ -165,9 +175,16 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
165
175
  })]).finally(() => { if (handshakeTimer) clearTimeout(handshakeTimer); });
166
176
  try {
167
177
  if (opts.createAgent) agent = opts.createAgent({ backendId: requestedBackend, ...agentOpts });
168
- else if (opts.backendSpec) agent = new AcpAgent({ backendId: requestedBackend, ...agentOpts });
169
- else agent = await withinHandshake(reviewManager!.getAgent(requestedBackend, agentOpts));
170
- if (injected || opts.backendSpec) await withinHandshake(agent.start());
178
+ else if (directAgent) agent = new AcpAgent({ backendId: requestedBackend, ...agentOpts });
179
+ else {
180
+ // getAgent owns both spawn and initialize; neither step is independently observable here.
181
+ enterPhase('spawn-initialize');
182
+ agent = await withinHandshake(reviewManager!.getAgent(requestedBackend, agentOpts));
183
+ }
184
+ if (directAgent) {
185
+ enterPhase(injected ? 'initialize' : 'spawn-initialize');
186
+ await withinHandshake(agent.start());
187
+ }
171
188
  if (!capabilitiesObserved) {
172
189
  try {
173
190
  debug.log('acp-review', 'capabilities', {
@@ -181,12 +198,14 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
181
198
  // Observability must not interrupt a review.
182
199
  }
183
200
  }
201
+ enterPhase('session-new');
184
202
  const sid = await withinHandshake(agent.newSession());
185
203
  if (opts.model) {
204
+ enterPhase('model-select');
186
205
  const picked = await withinHandshake(agent.selectSessionModel(sid, opts.model));
187
206
  debug.log('acp-review', 'model', { requested: opts.model, picked: picked?.name ?? null, backend });
188
207
  }
189
- timer = setTimeout(() => { timedOut = true; agent!.cancel(sid).catch(() => { /* noop */ }); }, timeoutMs);
208
+ enterPhase('prompt');
190
209
  // ⭐⭐ `P4b` 멀티미디어 — 이미지를 «별도 ContentBlock» 으로 싣는다.
191
210
  // ⛔ 광고를 «먼저 본다** — 백엔드가 image 를 안 받는다고 말하면 안 보낸다. 보내 봐야
192
211
  // 거절이 이 층보다 훨씬 읽기 어려운 자리에서 나고, 그 거절은 리뷰 실패로 보인다.
@@ -211,23 +230,44 @@ export function makeAcpReviewLLM(opts: AcpReviewerOpts): (prompt: string, images
211
230
  // Observation must not prevent the review from running.
212
231
  }
213
232
  }
214
- await agent.prompt(sid, [{ type: 'text', text: TOOL_REVIEW_PREAMBLE + prompt }, ...imageBlocks], (u) => {
233
+ const promptAttempt = agent.prompt(sid, [{ type: 'text', text: TOOL_REVIEW_PREAMBLE + prompt }, ...imageBlocks], (u) => {
234
+ if (u.sessionUpdate === 'tool_call' || u.sessionUpdate === 'tool_call_update') {
235
+ observedToolCalls.add(u.toolCallId);
236
+ }
215
237
  if (u.sessionUpdate === 'agent_message_chunk') {
216
238
  const c = u.content;
217
239
  if (c.type === 'text' && c.text) text += c.text;
218
240
  }
219
241
  });
220
- if (timedOut) throw new Error(`ACP 리뷰 타임아웃(${timeoutMs}ms·툴콜 ${allowed})`);
242
+ // Do not rely on cancel causing prompt() to settle: a stalled ACP child may never answer it.
243
+ await Promise.race([promptAttempt, new Promise<never>((_, reject) => {
244
+ timer = setTimeout(() => {
245
+ // Commit the timeout before cancel can settle prompt with a partial response.
246
+ reject(new Error(backend === 'grok'
247
+ ? `${GROK_ACP_REVIEW_TIMEOUT} ${timeoutMs}ms·툴콜 ${observedToolCalls.size}`
248
+ : `ACP 리뷰 타임아웃(${timeoutMs}ms·툴콜 ${allowed})`));
249
+ void agent!.cancel(sid).catch(() => { /* noop */ });
250
+ }, timeoutMs);
251
+ })]);
221
252
  } catch (e) {
222
- debug.log('acp-review', 'error', { backend, model: opts.model ?? '(default)', message: (e as Error).message }, { level: 'error' });
223
- throw e;
253
+ const message = (e as Error).message;
254
+ const handshakeTimeout = message.startsWith('ACP handshake timeout (');
255
+ const failure = backend === 'grok' && handshakeTimeout
256
+ ? new Error(`${GROK_ACP_REVIEW_TIMEOUT} ${message}`) : e;
257
+ const timeout = message.startsWith(GROK_ACP_REVIEW_TIMEOUT) || message.startsWith('ACP 리뷰 타임아웃(') || handshakeTimeout;
258
+ debug.log('acp-review', 'error', {
259
+ backend, provider: backend, model: opts.model ?? '(default)', message: (failure as Error).message,
260
+ phase, elapsedMs: Date.now() - startedAt, phaseElapsedMs: Date.now() - phaseStartedAt,
261
+ toolCalls: observedToolCalls.size, allowed, denied, ...(timeout ? { classification: phase === 'prompt' && observedToolCalls.size === 0 ? 'pre-tool-timeout' : 'acp-timeout' } : {}),
262
+ }, { level: 'error' });
263
+ throw failure;
224
264
  } finally {
225
265
  if (timer) clearTimeout(timer);
226
266
  // Both paths are review-owned: injected agents retain their direct
227
267
  // cleanup seam, while the per-review manager releases its agents and
228
268
  // process hooks. An injected agent is external to the manager.
229
269
  try {
230
- if (injected || opts.backendSpec) await agent?.stop();
270
+ if (directAgent) await agent?.stop();
231
271
  else await reviewManager!.dispose();
232
272
  } catch (e) {
233
273
  debug.log('acp-review', 'stop-fail', { backend, message: (e as Error).message }, { level: 'error' });
@@ -656,7 +656,7 @@ const BARE_SENTINEL = new RegExp(String.raw`^${NONE_WORD}\s*[.。]?$`, 'i');
656
656
  // 괄호 전체만 검사한다. 중간에 "no blockers" 가 있어도 뒤에 지적이 이어지면 버리지 않는다.
657
657
  const BRACKETED_PLACEHOLDER = /^[((]\s*([\s\S]*?)\s*[))]$/;
658
658
  const PLACEHOLDER_ONLY = /^(?:없음|해당\s*없음|none|n\/a|no\s+blockers?)$/i;
659
- const PLACEHOLDER_END = /(?:블로커|차단)\s*없음$|no\s+blockers?$/i;
659
+ const PLACEHOLDER_END = /(?:블로커|차단)(?:\s*(?:수준의?\s*)?(?:결함|문제|이슈|지적))?\s*없음$|no\s+blockers?$/i;
660
660
  function isBracketedPlaceholder(text: string): boolean {
661
661
  const bracketed = BRACKETED_PLACEHOLDER.exec(text);
662
662
  if (!bracketed) return false;
@@ -670,6 +670,8 @@ const BRACKETED_SENTINEL = new RegExp(String.raw`^[([(【]\s*${NONE_WORD}(?:\s
670
670
  // ⭐ 설명 «전체»가 「지적 없음」 한 문장일 때만 — 일부만 맞아도 접으면 `(none: no blockers are checked because …)` 같은 지적이 사라진다.
671
671
  const NO_FINDING_REMARK = new RegExp([
672
672
  String.raw`^(?:(?:블로커|차단)\s*)?(?:수준의?\s*)?(?:결함|문제|이슈|지적|블로커)(?:은|는|이|가)?\s*(?:발견되지\s*않(?:음|았(?:다|습니다)?)|없(?:음|다|습니다))[.。]?$`,
673
+ // REVIEW-MUSTFIX-NONE-PARSE — `(없음 — 이 조각 범위에서는 차단 결함 없음)` 꼬리.
674
+ String.raw`^(?:이\s*)?(?:조각\s*)?범위(?:에서는|에서|엔)?\s*(?:블로커|차단)(?:\s*(?:수준의?\s*)?(?:결함|문제|이슈|지적))?\s*없(?:음|다|습니다)[.。]?$`,
673
675
  String.raw`^(?:no|zero)\s+(?:blocking\s+)?(?:blockers?|issues?|problems?|findings?|must-?fix(?:es)?)(?:\s+found)?\.?$`,
674
676
  String.raw`^nothing\s+(?:blocking|to\s+fix)\.?$`,
675
677
  // REVIEW-MUSTFIX-NONE-SENTINEL — `(없음 — 수용기준 충족)` · `(none — acceptance criteria met)` (GLM 실측 6건). «미충족» 은 ^ 앵커로 안 맞는다.
@@ -1,8 +1,10 @@
1
1
  import { createHash } from 'node:crypto';
2
+ import { spawnSync } from 'node:child_process';
2
3
 
3
4
  export const REVIEW_FINDING_KEY_VERSION = 'reviewFindingKey-v1';
4
5
  export const MAX_CITED_REVIEW_SYMBOL_CHARS = 256;
5
6
  const CITED_REVIEW_SYMBOL_HASH_CHARS = 16;
7
+ const CITED_PATH_EXTENSION = /\.(?:ts|tsx|js|jsx|mjs|cjs|json|md|yaml|yml|sh|py|toml|css|go|sql|rs|rb|java|kt|swift|c|h|cpp|hpp|graphql|proto)$/;
6
8
 
7
9
  export interface CitedReviewSymbol {
8
10
  hash: string;
@@ -18,6 +20,57 @@ export interface ReviewFindingKeyOverlap {
18
20
  overlapRatio: number | undefined;
19
21
  }
20
22
 
23
+ export type CitedReviewPathStatus = 'present' | 'missing' | 'unreadable';
24
+
25
+ export interface ReviewFindingPathHeadCheck {
26
+ head: string;
27
+ status: 'verified' | 'path-missing' | 'unreadable' | 'no-cited-path';
28
+ paths: Array<{ path: string; status: CitedReviewPathStatus }>;
29
+ }
30
+
31
+ /** Only file-shaped citations are checked; symbols such as `terminal.id` are not paths. */
32
+ export function citedReviewPaths(finding: string): string[] {
33
+ return [...new Set(fullCitedReviewSymbols(finding)
34
+ .map((symbol) => symbol.replace(/^\.\//, '').replace(/:\d+(?::\d+)?$/, ''))
35
+ .filter((symbol) => !symbol.startsWith('/')
36
+ && !symbol.includes('\\')
37
+ && !symbol.includes('://')
38
+ && /^[A-Za-z0-9_.@+/-]+$/.test(symbol)
39
+ && !symbol.split('/').some((part) => part === '..' || part === '')
40
+ && (symbol.includes('/') || CITED_PATH_EXTENSION.test(symbol))))];
41
+ }
42
+
43
+ /** Check cited paths against the supplied exact commit, never the worktree's current HEAD. */
44
+ export function checkCitedReviewPathsAtHead(finding: string, repo: string, head: string): ReviewFindingPathHeadCheck {
45
+ const paths = citedReviewPaths(finding);
46
+ if (paths.length === 0) return { head, status: 'no-cited-path', paths: [] };
47
+ if (!/^[0-9a-f]{40}$/i.test(head)) {
48
+ return { head, status: 'unreadable', paths: paths.map((path) => ({ path, status: 'unreadable' })) };
49
+ }
50
+ const commitType = spawnSync('git', ['-C', repo, 'cat-file', '-t', head], { encoding: 'utf8' });
51
+ if (commitType.error || commitType.status !== 0 || commitType.stdout?.trim() !== 'commit') {
52
+ return { head, status: 'unreadable', paths: paths.map((path) => ({ path, status: 'unreadable' })) };
53
+ }
54
+ const checked = paths.map((path): { path: string; status: CitedReviewPathStatus } => {
55
+ const result = spawnSync('git', ['--literal-pathspecs', '-C', repo, 'ls-tree', '-r', '-z', '--full-tree', head, '--', path], {
56
+ encoding: 'utf8', maxBuffer: 1024 * 1024,
57
+ });
58
+ if (result.error || result.status !== 0) return { path, status: 'unreadable' };
59
+ const output = typeof result.stdout === 'string' ? result.stdout : '';
60
+ const present = output.split('\0').some((entry) => {
61
+ const separator = entry.indexOf('\t');
62
+ return separator >= 0 && entry.slice(separator + 1) === path;
63
+ });
64
+ return { path, status: present ? 'present' : 'missing' };
65
+ });
66
+ return {
67
+ head,
68
+ status: checked.some(({ status }) => status === 'unreadable') ? 'unreadable'
69
+ : checked.some(({ status }) => status === 'missing') ? 'path-missing' : 'verified',
70
+ paths: checked,
71
+ };
72
+ }
73
+
21
74
  interface ReviewFindingKey {
22
75
  key: string;
23
76
  source: 'symbol' | 'prose';