elanous 0.2.42 → 0.2.44

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 (764) 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/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_buildManifest.js +1 -1
  4. package/apps/pwa/out/_next/static/chunks/08334415.f0e80896acbef722.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/1032-78ba4f6391258cab.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/1082-53f86a26e03d309d.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/1109-7d0e264f6f2edbc7.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/1124-7c26330402481143.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/{2160.a097e7b138ae1c55.js → 118.2a89982fe4276880.js} +1 -1
  10. package/apps/pwa/out/_next/static/chunks/1244.6c435dbf1bf21d8a.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/1252.9e665904d3aa3b1a.js +32 -0
  12. package/apps/pwa/out/_next/static/chunks/1266.a46cc33cb6a72d75.js +104 -0
  13. package/apps/pwa/out/_next/static/chunks/1306.967240ede9a0f757.js +24 -0
  14. package/apps/pwa/out/_next/static/chunks/1344.3b95f3bd1b77a3fe.js +94 -0
  15. package/apps/pwa/out/_next/static/chunks/{4043.6b91203436c9c86b.js → 1401.22dfe92640a2b1ac.js} +4 -4
  16. package/apps/pwa/out/_next/static/chunks/1431-f7c78bd5be21e011.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/1451-cdd35a8a0b31834b.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/{6632.0eac1c554f8f2ef3.js → 1694.18debfd77562e56d.js} +2 -2
  19. package/apps/pwa/out/_next/static/chunks/1708-f03d587b7a7545c8.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/1775-fa7152bdeff6c95f.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/178-4da509cd7266672a.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/1850-522de4ee34957210.js +1 -0
  23. package/apps/pwa/out/_next/static/chunks/1876-c6f6e0ddcc76c6a1.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/1976.097066b072432242.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/{3507.97e1977bc4d5fb0a.js → 1978.eeb60a606dc5deac.js} +2 -2
  26. package/apps/pwa/out/_next/static/chunks/2043.e233e3b5a3e790f5.js +1 -0
  27. package/apps/pwa/out/_next/static/chunks/2150.71b94e3348107c83.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/2158.ebc6fc5a10280ab7.js +1 -0
  29. package/apps/pwa/out/_next/static/chunks/2216.802962c04f40a26e.js +64 -0
  30. package/apps/pwa/out/_next/static/chunks/2294.7890edcfa046c97d.js +1 -0
  31. package/apps/pwa/out/_next/static/chunks/235.c89aaae4bcd6233a.js +74 -0
  32. package/apps/pwa/out/_next/static/chunks/{5885.0a3e52c8faccec98.js → 239.de075467b5523469.js} +2 -2
  33. package/apps/pwa/out/_next/static/chunks/249.ba7051590d603c8f.js +226 -0
  34. package/apps/pwa/out/_next/static/chunks/2571.a6ac4e26c8618403.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/2610.e149cd564a08913e.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/2705.9816f3c244f8b85f.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/2801.afeb8a4dae22f85f.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/2954.bbefc95d6b20e0d8.js +1 -0
  39. package/apps/pwa/out/_next/static/chunks/2e0f720a.a0697c08e3806a60.js +1 -0
  40. package/apps/pwa/out/_next/static/chunks/3042.96ec235fe41c8d4e.js +1 -0
  41. package/apps/pwa/out/_next/static/chunks/3097-8e358f158acef46b.js +1 -0
  42. package/apps/pwa/out/_next/static/chunks/3205-93b1abe28b4fb16a.js +1 -0
  43. package/apps/pwa/out/_next/static/chunks/3273.b4434f0dcae7eb29.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/3311.9cbc43ea0c90d60c.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/{1487.2f67b79444062da6.js → 3349.b5f09ee474d9533e.js} +1 -1
  46. package/apps/pwa/out/_next/static/chunks/3503.a47a9755fb4d97b0.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/3506-5f429b3b7e1392b0.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/3843.bad404d008893291.js +77 -0
  49. package/apps/pwa/out/_next/static/chunks/3877-4b40e530b47e3bf9.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/435-ce2958253cf7de61.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/4393.28fa5228d0eec217.js +149 -0
  52. package/apps/pwa/out/_next/static/chunks/4404.7281c847c6e10dfc.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/{8673-bab689a55f7e13b9.js → 4415-b9d6a90960920a4a.js} +3 -3
  54. package/apps/pwa/out/_next/static/chunks/447-5b304de1fe098f43.js +1 -0
  55. package/apps/pwa/out/_next/static/chunks/4484-8ebea83d431e6fae.js +1 -0
  56. package/apps/pwa/out/_next/static/chunks/{8262.ddc03e06b733f184.js → 4502.bdcc877abd437a05.js} +1 -1
  57. package/apps/pwa/out/_next/static/chunks/4599-f95790fc5c65b8df.js +1 -0
  58. package/apps/pwa/out/_next/static/chunks/{1262.e804feb8fd1acb8c.js → 46.57c783fa4884714f.js} +2 -2
  59. package/apps/pwa/out/_next/static/chunks/463-b9114e411f33728e.js +1 -0
  60. package/apps/pwa/out/_next/static/chunks/4659.a57d1f0c5d754cd2.js +36 -0
  61. package/apps/pwa/out/_next/static/chunks/4722-a847e7a28115035f.js +1 -0
  62. package/apps/pwa/out/_next/static/chunks/{1063.2fb8a9dc55c731f2.js → 4757.67c6d7473a038e78.js} +1 -1
  63. package/apps/pwa/out/_next/static/chunks/4874-c86f878ec4502ad3.js +1 -0
  64. package/apps/pwa/out/_next/static/chunks/{6377.bc7df239edbff244.js → 4891.3f80ba517a3b2373.js} +1 -1
  65. package/apps/pwa/out/_next/static/chunks/4998.810ca8833084caa9.js +62 -0
  66. package/apps/pwa/out/_next/static/chunks/4f98febc.ea5841d4d616bfb2.js +1 -0
  67. package/apps/pwa/out/_next/static/chunks/{3482.a9ae9d2ad6a5bd97.js → 5052.7dbb12a55d4f18f5.js} +1 -1
  68. package/apps/pwa/out/_next/static/chunks/5166-ca73b3e361085a6d.js +1 -0
  69. package/apps/pwa/out/_next/static/chunks/5180-039f4a18b07ad387.js +1 -0
  70. package/apps/pwa/out/_next/static/chunks/5232.5a2ce4daf7a9e11d.js +115 -0
  71. package/apps/pwa/out/_next/static/chunks/5439.3fec6dbce29ecb36.js +1 -0
  72. package/apps/pwa/out/_next/static/chunks/5612-074d9a5e00dfac6a.js +1 -0
  73. package/apps/pwa/out/_next/static/chunks/5675-01989d524a84c505.js +1 -0
  74. package/apps/pwa/out/_next/static/chunks/5751.af641a1adf5ec697.js +1 -0
  75. package/apps/pwa/out/_next/static/chunks/5758-c6cb98714d18ab0c.js +1 -0
  76. package/apps/pwa/out/_next/static/chunks/578eded8.b582637306e16964.js +122 -0
  77. package/apps/pwa/out/_next/static/chunks/5790.5eb06a653ebd8571.js +34 -0
  78. package/apps/pwa/out/_next/static/chunks/5853-4033e5bd5afbe06b.js +1 -0
  79. package/apps/pwa/out/_next/static/chunks/5904.97d70bb7f46b2db7.js +1 -0
  80. package/apps/pwa/out/_next/static/chunks/{3347.f846266b5e5f3ede.js → 5989.7ecd362c5c44b747.js} +3 -3
  81. package/apps/pwa/out/_next/static/chunks/{73d2eb0e.4966ad55293c801a.js → 5a34fb2f.52f1b4e1baebb48a.js} +3 -3
  82. package/apps/pwa/out/_next/static/chunks/{7a98bc80.fa935989e829f9c2.js → 5a5078f8.2099200e5ea95e16.js} +1 -1
  83. package/apps/pwa/out/_next/static/chunks/6036-c302c34ff0b3d410.js +1 -0
  84. package/apps/pwa/out/_next/static/chunks/606.ef81c313381f4264.js +1 -0
  85. package/apps/pwa/out/_next/static/chunks/616.1af54a928b1ba704.js +1 -0
  86. package/apps/pwa/out/_next/static/chunks/6201.bc936f71f613a8e9.js +41 -0
  87. package/apps/pwa/out/_next/static/chunks/6204-fdc86e0e64c4f92d.js +1 -0
  88. package/apps/pwa/out/_next/static/chunks/{7411.9b4b8b747dc7b802.js → 6245.1182e007e9d230d9.js} +1 -1
  89. package/apps/pwa/out/_next/static/chunks/{b450776b.3db34d8d965f82d3.js → 63699a35.17262e162bc514b2.js} +1 -1
  90. package/apps/pwa/out/_next/static/chunks/6420.494801a80030160c.js +27 -0
  91. package/apps/pwa/out/_next/static/chunks/{e8543907.5b040a5f22a0b0e5.js → 6549dad0.2740b25e51bf8f05.js} +1 -1
  92. package/apps/pwa/out/_next/static/chunks/{9427.96aa912ddb5801e0.js → 6881.9e7955847640c7fe.js} +17 -17
  93. package/apps/pwa/out/_next/static/chunks/6931.fcdfb94141e67b3d.js +1 -0
  94. package/apps/pwa/out/_next/static/chunks/6991-8e081c6ce38c0ba1.js +1 -0
  95. package/apps/pwa/out/_next/static/chunks/7010.1bbd17a7f2b3e376.js +1 -0
  96. package/apps/pwa/out/_next/static/chunks/7029.d1466acf55fae2ed.js +1 -0
  97. package/apps/pwa/out/_next/static/chunks/7152-a123aa8e129c131f.js +1 -0
  98. package/apps/pwa/out/_next/static/chunks/7455.196168fffac3b9c4.js +24 -0
  99. package/apps/pwa/out/_next/static/chunks/7638.6ca4770dd1129138.js +1 -0
  100. package/apps/pwa/out/_next/static/chunks/7649-f37d76260e5e2a5a.js +1 -0
  101. package/apps/pwa/out/_next/static/chunks/7679.32c40cdd14f20b4a.js +1 -0
  102. package/apps/pwa/out/_next/static/chunks/7751.04bfbd16b4c6cd0a.js +1 -0
  103. package/apps/pwa/out/_next/static/chunks/7864.b1ff31d4030b8994.js +148 -0
  104. package/apps/pwa/out/_next/static/chunks/7869-c47bd2c075c1fefa.js +1 -0
  105. package/apps/pwa/out/_next/static/chunks/{8138.6c10b2a356d52fca.js → 8442.2f09ca969d631615.js} +1 -1
  106. package/apps/pwa/out/_next/static/chunks/8445.2738dbd59a78c78c.js +1 -0
  107. package/apps/pwa/out/_next/static/chunks/8447.5510c439f9938c6d.js +286 -0
  108. package/apps/pwa/out/_next/static/chunks/{9415.69e4a21c60c7d2db.js → 8551.f762945c2cda2e95.js} +1 -1
  109. package/apps/pwa/out/_next/static/chunks/8635-57a9d8d9db70f4f1.js +1 -0
  110. package/apps/pwa/out/_next/static/chunks/86961958-4b0689a5048f756b.js +1 -0
  111. package/apps/pwa/out/_next/static/chunks/8709.3c6019bb18f8554f.js +8 -0
  112. package/apps/pwa/out/_next/static/chunks/8759.c999528a0a907bf6.js +1 -0
  113. package/apps/pwa/out/_next/static/chunks/{9a852a62-6192a6ea9346ced3.js → 87f498e5-0881de09f2e44707.js} +1 -1
  114. package/apps/pwa/out/_next/static/chunks/8843.c3197f904c952b81.js +1 -0
  115. package/apps/pwa/out/_next/static/chunks/{3d0154af.5331fec737ffe8c3.js → 892fd990.456232f326cc39c2.js} +1 -1
  116. package/apps/pwa/out/_next/static/chunks/8965-135a2c9eaa2464cb.js +1 -0
  117. package/apps/pwa/out/_next/static/chunks/8971-8d3b9c96f8a6c958.js +1 -0
  118. package/apps/pwa/out/_next/static/chunks/9059.c8598d96f8e5e9cd.js +1 -0
  119. package/apps/pwa/out/_next/static/chunks/9115.90447ae198b84eae.js +1 -0
  120. package/apps/pwa/out/_next/static/chunks/9147.d9b0a02e0babc9b4.js +93 -0
  121. package/apps/pwa/out/_next/static/chunks/9204-83075f4b70c61cdc.js +1 -0
  122. package/apps/pwa/out/_next/static/chunks/9244-c32ef14b5dc72bdf.js +1 -0
  123. package/apps/pwa/out/_next/static/chunks/930.2a9a30f964350c66.js +90 -0
  124. package/apps/pwa/out/_next/static/chunks/9398.1f56e3f17795f43f.js +1 -0
  125. package/apps/pwa/out/_next/static/chunks/9527.3e5ad31c891c5fcb.js +79 -0
  126. package/apps/pwa/out/_next/static/chunks/9571-4ac933e774d1225c.js +1 -0
  127. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-9fc644de2d8edae3.js +1 -0
  128. package/apps/pwa/out/_next/static/chunks/app/approvals/page-0c9dace2db62bee8.js +1 -0
  129. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f5e65c3dc9d89f2a.js +1 -0
  130. package/apps/pwa/out/_next/static/chunks/app/board/page-2a9c19b9a140b7b1.js +1 -0
  131. package/apps/pwa/out/_next/static/chunks/app/botlab/page-61533ad92141adfb.js +1 -0
  132. package/apps/pwa/out/_next/static/chunks/app/bots/page-112004ced6fd0329.js +1 -0
  133. package/apps/pwa/out/_next/static/chunks/app/ceo/page-f733318c237a49d8.js +1 -0
  134. package/apps/pwa/out/_next/static/chunks/app/chat/page-51ea677d2d33bbc0.js +1 -0
  135. package/apps/pwa/out/_next/static/chunks/app/consult/page-428b41f2f9566e3c.js +1 -0
  136. package/apps/pwa/out/_next/static/chunks/app/control/page-1b29396ea90a61e5.js +1 -0
  137. package/apps/pwa/out/_next/static/chunks/app/decisions/page-cf83ec613ac904bf.js +1 -0
  138. package/apps/pwa/out/_next/static/chunks/app/design-check/page-3f4c0ecbc284bb5f.js +1 -0
  139. package/apps/pwa/out/_next/static/chunks/app/editor/page-b63c322f54f70cc6.js +1 -0
  140. package/apps/pwa/out/_next/static/chunks/app/exec/page-fe328c4ee9aac6b4.js +1 -0
  141. package/apps/pwa/out/_next/static/chunks/app/field/page-bfb855c584f0fb98.js +1 -0
  142. package/apps/pwa/out/_next/static/chunks/app/healthz/route-9fc644de2d8edae3.js +1 -0
  143. package/apps/pwa/out/_next/static/chunks/app/inside/page-47b1710c110eabd7.js +1 -0
  144. package/apps/pwa/out/_next/static/chunks/app/intake/page-42895214458bc6d2.js +1 -0
  145. package/apps/pwa/out/_next/static/chunks/app/layout-d03de0ebd8366e23.js +1 -0
  146. package/apps/pwa/out/_next/static/chunks/app/live/page-3ed6c47e4b1c61c2.js +1 -0
  147. package/apps/pwa/out/_next/static/chunks/app/live-run/page-ae653e9bf261c738.js +1 -0
  148. package/apps/pwa/out/_next/static/chunks/app/loops/page-23f3f0a0209c0ac4.js +1 -0
  149. package/apps/pwa/out/_next/static/chunks/app/market/page-88c691273aae66f9.js +1 -0
  150. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-e187ac52a95538b3.js +1 -0
  151. package/apps/pwa/out/_next/static/chunks/app/morning/page-6e45828daed1295e.js +1 -0
  152. package/apps/pwa/out/_next/static/chunks/app/not-found-edb5d7287bb46186.js +1 -0
  153. package/apps/pwa/out/_next/static/chunks/app/observatory/page-4a7eaacd93c3f6a5.js +1 -0
  154. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-3ca073d43d74cc84.js +1 -0
  155. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-1e9fee67b1199436.js +1 -0
  156. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-df1283ea963c6816.js +1 -0
  157. package/apps/pwa/out/_next/static/chunks/app/outputs/page-19fcf8d8301ccd18.js +1 -0
  158. package/apps/pwa/out/_next/static/chunks/app/page-5ab699e0303bbb40.js +1 -0
  159. package/apps/pwa/out/_next/static/chunks/app/reflection/page-7cde0d29756984c5.js +1 -0
  160. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-9d4c598e8ee22f7a.js +1 -0
  161. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cc1609a71f44ec62.js +1 -0
  162. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-7659a9a1345bfaa9.js +1 -0
  163. package/apps/pwa/out/_next/static/chunks/app/settings/page-0afef60ecc0c4af5.js +1 -0
  164. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a3553949f8f34f5f.js +1 -0
  165. package/apps/pwa/out/_next/static/chunks/app/setup/layout-9fc644de2d8edae3.js +1 -0
  166. package/apps/pwa/out/_next/static/chunks/app/setup/page-057a69702f3c67c7.js +1 -0
  167. package/apps/pwa/out/_next/static/chunks/app/share/page-c0f0e570f3f74c73.js +1 -0
  168. package/apps/pwa/out/_next/static/chunks/app/showroom/page-1825071ae34e3b89.js +1 -0
  169. package/apps/pwa/out/_next/static/chunks/app/tasks/page-6244e3e135d8ccfc.js +1 -0
  170. package/apps/pwa/out/_next/static/chunks/app/term/page-da787e8a10b8a82e.js +1 -0
  171. package/apps/pwa/out/_next/static/chunks/app/today/page-1316d32498e2be42.js +1 -0
  172. package/apps/pwa/out/_next/static/chunks/app/trace/page-4df94572e343de2e.js +1 -0
  173. package/apps/pwa/out/_next/static/chunks/app/vault/page-708969f7475e88c1.js +1 -0
  174. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c58add08c919a1dc.js +1 -0
  175. package/apps/pwa/out/_next/static/chunks/app/workflows/page-a24847f45e5d5bf9.js +1 -0
  176. package/apps/pwa/out/_next/static/chunks/app/workspace/page-acfec65a3a60e22e.js +1 -0
  177. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-3dfc598e6fbde245.js +1 -0
  178. package/apps/pwa/out/_next/static/chunks/framework-c658a626118411b7.js +1 -0
  179. package/apps/pwa/out/_next/static/chunks/main-4c73685fd891445b.js +1 -0
  180. package/apps/pwa/out/_next/static/chunks/main-app-6310f7e5de7dd01d.js +1 -0
  181. package/apps/pwa/out/_next/static/chunks/pages/_app-51c326bf48610be1.js +1 -0
  182. package/apps/pwa/out/_next/static/chunks/pages/_error-d0beadf754da59b0.js +1 -0
  183. package/apps/pwa/out/_next/static/chunks/webpack-acd243bfbf3f6732.js +1 -0
  184. package/apps/pwa/out/_next/static/css/d1f8bb401740a549.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 +23 -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/catalog/external-commands.yaml +5 -3
  279. package/catalog/meta/catalogVersion.yaml +2 -1
  280. package/catalog/signing/catalog-signing-public.pem +3 -0
  281. package/graphs/intake/intake-daily.yaml +16 -0
  282. package/graphs/intake/news-sources.yaml +1 -0
  283. package/graphs/intake/recipes.yaml +7 -0
  284. package/graphs/overlays/README.md +6 -0
  285. package/graphs/overlays/examples/research-runtime-empty-terminal.yaml +28 -0
  286. package/graphs/profiles/local.yaml +5 -0
  287. package/graphs/profiles/pod.yaml +4 -0
  288. package/graphs/release/release-loop.yaml +33 -17
  289. package/graphs/units/verbs/make-doc.yaml +1 -0
  290. package/package.json +6 -2
  291. package/plugins/demo-absorption-briefing/plugin.json +18 -0
  292. package/plugins/demo-absorption-briefing/skills/demo-absorption-briefing/SKILL.md +8 -0
  293. package/plugins/demo-browser-hand/plugin.json +13 -0
  294. package/plugins/demo-browser-hand/skills/demo-browser-hand/SKILL.md +8 -0
  295. package/plugins/demo-linear-secretary/plugin.json +15 -0
  296. package/plugins/demo-linear-secretary/skills/demo-linear-secretary/SKILL.md +8 -0
  297. package/plugins/demo-plugin-wizard/plugin.json +11 -0
  298. package/plugins/demo-plugin-wizard/skills/demo-plugin-wizard/SKILL.md +8 -0
  299. package/plugins/demo-research/plugin.json +16 -0
  300. package/plugins/demo-research/skills/demo-research/SKILL.md +8 -0
  301. package/plugins/demo-video-briefing/plugin.json +15 -0
  302. package/plugins/demo-video-briefing/skills/demo-video-briefing/SKILL.md +8 -0
  303. package/scripts/bench-metering-plan.ts +229 -0
  304. package/scripts/build-signed-catalog.ts +48 -0
  305. package/scripts/ci-typecheck-main-delta.sh +88 -0
  306. package/scripts/codex-fallback-live-probe.ts +1 -1
  307. package/scripts/demo/demo1104-parallel-host.ts +56 -0
  308. package/scripts/demo/demo1104-parallel-scenes.ts +301 -0
  309. package/scripts/demo/demo1104-parallel.ts +72 -0
  310. package/scripts/demo/demo1104-stage.config.ts +21 -0
  311. package/scripts/demo/demo1104-stage.ts +316 -0
  312. package/scripts/goal-method-audit.ts +17 -1
  313. package/scripts/graph-units/land-enqueue.ts +90 -0
  314. package/scripts/hooks/codex-notify.sh +32 -0
  315. package/scripts/install.sh +10 -38
  316. package/scripts/landing-heal/land-plan.ts +57 -0
  317. package/scripts/public-leak-baseline.txt +0 -1
  318. package/scripts/release-loop/auto-approve-node.ts +1 -1
  319. package/scripts/release-loop/docs-node.ts +4 -2
  320. package/scripts/release-loop/gate-autoheal-sim-evidence.ts +60 -0
  321. package/scripts/release-loop/gate-image-pin.ts +116 -2
  322. package/scripts/release-loop/gate-method.ts +139 -0
  323. package/scripts/release-loop/gate-node.ts +395 -43
  324. package/scripts/release-loop/gate-progress-sim.ts +73 -0
  325. package/scripts/release-loop/gate-traffic-mode.ts +151 -3
  326. package/scripts/release-loop/node-verdict.ts +38 -25
  327. package/scripts/release-loop/notes-repair.ts +18 -1
  328. package/scripts/release-loop/preflight.ts +544 -10
  329. package/scripts/release-loop/render-warm-control-manifest.ts +22 -0
  330. package/scripts/release-loop/resume-release.ts +9 -7
  331. package/scripts/release-loop/resume.ts +13 -4
  332. package/scripts/release-loop/unattended-release.ts +20 -9
  333. package/scripts/release-loop/warm-control-forward.ts +178 -0
  334. package/scripts/retro-cycle.ts +30 -8
  335. package/scripts/rhythm/daily.ts +39 -4
  336. package/scripts/rhythm/linear-progress-sync.ts +311 -0
  337. package/scripts/ux-sim.ts +7 -1
  338. package/scripts/video-pipeline.ts +9 -1
  339. package/scripts/warm-pool-provider-config.ts +35 -7
  340. package/src/acp/agent-manager.ts +1 -0
  341. package/src/acp/codex-app-server-agent.ts +33 -0
  342. package/src/acp/codex-app-server-client.ts +153 -16
  343. package/src/acp/core-turn-bridge.ts +17 -12
  344. package/src/acp/event-router.ts +20 -1
  345. package/src/acp/server.ts +6 -0
  346. package/src/agent-mission/browser-roundtrip-coordinator.ts +85 -0
  347. package/src/agent-mission/claude-headless.ts +4 -1
  348. package/src/agent-mission/codex-exec.ts +105 -0
  349. package/src/agent-mission/driver.ts +192 -11
  350. package/src/agent-mission/grok-auth-status.ts +107 -0
  351. package/src/agent-mission/hand-hooks.ts +101 -0
  352. package/src/agent-mission/mission-cli.ts +56 -21
  353. package/src/agent-mission/mission-hand-reply.ts +118 -0
  354. package/src/agent-mission/mission-line.ts +180 -0
  355. package/src/agent-mission/mission-out.ts +256 -18
  356. package/src/agent-mission/tool-install.ts +122 -11
  357. package/src/agent-substrate/pr-reviewer.ts +147 -11
  358. package/src/agent-substrate/self-review-cli.ts +10 -2
  359. package/src/agents/general-purpose.md +1 -1
  360. package/src/auto-research/research-fanout.ts +221 -0
  361. package/src/auto-research/research-turn.ts +362 -31
  362. package/src/autopilot/mission-codebase-gate.ts +7 -3
  363. package/src/autopilot/pr-manager.ts +31 -3
  364. package/src/boot/daemon-tools/self-implement.ts +3 -1
  365. package/src/boot/daemon-tools/web-search.ts +1 -2
  366. package/src/briefing/brief-items.ts +55 -11
  367. package/src/cli/agent-cli.ts +2 -1
  368. package/src/cli/catalog-cli.ts +31 -0
  369. package/src/cli/connector-cli.ts +16 -0
  370. package/src/cli/control-cli.ts +15 -6
  371. package/src/cli/doctor-fix.ts +2 -2
  372. package/src/cli/intake-source-cli.ts +44 -8
  373. package/src/cli/log-event-names.ts +8 -0
  374. package/src/cli/msg-cli.ts +32 -3
  375. package/src/cli/pr-cli.ts +21 -1
  376. package/src/cli/pr-land-heavy-remote.ts +44 -6
  377. package/src/cli/pr-land-overlap-evidence.ts +13 -1
  378. package/src/cli/pr-land-pod-shadow-job.ts +143 -5
  379. package/src/cli/pr-land-pod-shadow.ts +9 -2
  380. package/src/cli/release-checklist-read-cli.ts +44 -16
  381. package/src/cli/release-cli.ts +23 -3
  382. package/src/cli/research-cli.ts +9 -0
  383. package/src/cli/setup-cli.ts +166 -6
  384. package/src/cli/setup-keys.ts +199 -0
  385. package/src/cli/task-plugin-wizard-host.ts +114 -0
  386. package/src/cli/tasks-cli.ts +54 -9
  387. package/src/cli/tui-test-cli.ts +190 -0
  388. package/src/config.ts +4 -2
  389. package/src/connectors/linear-daily-progress.ts +228 -0
  390. package/src/connectors/linear-projector.ts +34 -12
  391. package/src/connectors/linear.ts +151 -7
  392. package/src/control-plane/ledger.ts +42 -4
  393. package/src/control-plane/member-tokens.ts +25 -2
  394. package/src/control-plane/ports.ts +8 -3
  395. package/src/control-plane/server.ts +26 -5
  396. package/src/core-turn/deep-turn-bloom.ts +67 -0
  397. package/src/core-turn/research-policy.ts +43 -0
  398. package/src/core-turn/run-core-turn.ts +488 -51
  399. package/src/core-turn/types.ts +4 -0
  400. package/src/dashboard/chat/acp-chat.ts +10 -0
  401. package/src/dashboard/classic-sidetab-mission-job.ts +192 -0
  402. package/src/dashboard/classic-sidetab-mission-pair.ts +82 -0
  403. package/src/dashboard/classic-sidetab-mission-trio.ts +242 -0
  404. package/src/dashboard/classic-sidetab-mission.ts +169 -5
  405. package/src/dashboard/index.ts +387 -14
  406. package/src/dashboard/input/chat-main-acp-dispatch.ts +23 -0
  407. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +8 -0
  408. package/src/dashboard/mission-cli-consumer.ts +20 -8
  409. package/src/dashboard/plugin-wizard-runtime.ts +50 -0
  410. package/src/dashboard/plugin-wizard-tool.ts +55 -0
  411. package/src/dashboard/sidetab-runtime.ts +3 -1
  412. package/src/dashboard/terminal-popup-runtime.ts +6 -3
  413. package/src/dashboard/visible-mission-diagnostics.ts +16 -0
  414. package/src/decisions/linear-progress-summary.ts +78 -0
  415. package/src/decisions/linear-progress-sync.ts +152 -0
  416. package/src/domains/outbound-alert.ts +49 -11
  417. package/src/domains/retro-cycle-observation.ts +43 -0
  418. package/src/domains/retro-cycle.ts +13 -2
  419. package/src/domains/retro-proposals.ts +92 -0
  420. package/src/domains/retro-report.ts +6 -1
  421. package/src/domains/telegram-kind-route.ts +16 -9
  422. package/src/graph-runner/arg-allowance.ts +13 -0
  423. package/src/graph-runner/graph-cli.ts +24 -1
  424. package/src/graph-runner/graph-grow-llm.ts +3 -1
  425. package/src/graph-runner/graph-run-api.ts +3 -1
  426. package/src/graph-runner/runner.ts +310 -46
  427. package/src/graph-wizard/mission-compose.ts +407 -12
  428. package/src/harness/dispatch-backpressure.ts +54 -1
  429. package/src/harness/dispatch-shadow-compare.ts +74 -0
  430. package/src/harness/harness-cli-command.ts +15 -3
  431. package/src/harness/harness-pod-dispatch.ts +3 -0
  432. package/src/harness/skill-exec.ts +21 -9
  433. package/src/harness/skill-select.ts +1 -1
  434. package/src/hooks/error-report-cloud.ts +101 -0
  435. package/src/hooks/receiver.ts +29 -2
  436. package/src/index.ts +129 -12
  437. package/src/intake-plane/actions.ts +354 -0
  438. package/src/intake-plane/adapters/telegram-ambient.ts +34 -18
  439. package/src/intake-plane/intake-sources.ts +78 -8
  440. package/src/intake-plane/items.ts +14 -4
  441. package/src/intake-plane/linear-mission-sync.ts +80 -0
  442. package/src/intake-plane/linear-secretary-runtime.ts +178 -0
  443. package/src/intake-plane/linear-wish.ts +227 -1
  444. package/src/life/life-cli.ts +168 -0
  445. package/src/life/life-kinds.ts +160 -0
  446. package/src/live-supply/budget-consumer.ts +78 -0
  447. package/src/live-supply/read.ts +3 -0
  448. package/src/live-supply/snapshot.ts +45 -0
  449. package/src/llm/child-first-llm-observation.ts +112 -0
  450. package/src/llm/provider-credentials.ts +68 -6
  451. package/src/llm/provider-failure-evidence.ts +44 -0
  452. package/src/llm.ts +172 -12
  453. package/src/maturity/feature-maturity.ts +3 -3
  454. package/src/mcp/client.ts +7 -0
  455. package/src/mcp/proxy-runtime.ts +6 -1
  456. package/src/mcp/server.ts +54 -0
  457. package/src/msg/msg-sse-server.ts +3 -3
  458. package/src/msg/msg-store.ts +177 -19
  459. package/src/native-tool-catalog.ts +36 -2
  460. package/src/nexus/api/consult-requests.ts +18 -6
  461. package/src/nexus/api/discord-trigger-bot.ts +6 -6
  462. package/src/nexus/api/graphs-api.ts +4 -2
  463. package/src/nexus/api/grokbot-trigger-bot.ts +206 -0
  464. package/src/nexus/api/http-server.ts +37 -1
  465. package/src/nexus/api/mcp-public-allowlist.ts +2 -0
  466. package/src/nexus/api/telegram-trigger-bot.ts +6 -6
  467. package/src/nexus/boot/register-mcp-clients.ts +114 -8
  468. package/src/nexus/index.ts +22 -2
  469. package/src/nexus/outbound/format.ts +9 -0
  470. package/src/nexus/outbound/grokbot-adapter.ts +71 -0
  471. package/src/nexus/outbound/router.ts +121 -16
  472. package/src/nexus/setup-status.ts +9 -0
  473. package/src/nexus/state/state.ts +3 -0
  474. package/src/oauth/codex-account-store.ts +20 -7
  475. package/src/oauth/codex-owner-mirror.ts +81 -0
  476. package/src/oauth/codex.ts +17 -2
  477. package/src/oauth/fallback-chain.ts +47 -17
  478. package/src/onboarding/first-run-doctor.ts +8 -1
  479. package/src/onboarding/first-run.ts +126 -29
  480. package/src/onboarding/key-setup.ts +103 -0
  481. package/src/onboarding/menu-answer.ts +13 -0
  482. package/src/onboarding/secret-prompt.ts +37 -0
  483. package/src/plugins/install/plugin-install.ts +59 -0
  484. package/src/pr-tool/census.ts +130 -0
  485. package/src/preview/terminal.ts +22 -7
  486. package/src/prompt-enhance/enhance.ts +10 -0
  487. package/src/pty-shell/pty-control-ipc.ts +4 -1
  488. package/src/pty-shell/pty-write-provenance.ts +21 -3
  489. package/src/pty-shell/registry.ts +9 -2
  490. package/src/registry/catalog-server.ts +232 -0
  491. package/src/registry/loader.ts +45 -1
  492. package/src/registry/types.ts +1 -2
  493. package/src/release-loop/proposal-auto-place.ts +83 -0
  494. package/src/research/axis-fanout.ts +79 -29
  495. package/src/research/lenses/second-order.ts +312 -0
  496. package/src/self-dev/ask-launch-flow.ts +72 -1
  497. package/src/self-dev/dev-cli.ts +7 -2
  498. package/src/self-dev/dev-pipeline.ts +5 -0
  499. package/src/self-dev/draft-residue.ts +64 -5
  500. package/src/self-dev/draft-sweep.ts +31 -10
  501. package/src/self-dev/draft-triage-rules.ts +60 -3
  502. package/src/self-dev/graph-front-nodes.ts +2 -1
  503. package/src/self-dev/graph-journey-route.ts +76 -21
  504. package/src/self-dev/launch-preflight.ts +58 -0
  505. package/src/self-dev/orchestrate.ts +1 -1
  506. package/src/self-dev/run-supervisor.ts +152 -2
  507. package/src/self-dev/shard-aggregate.ts +4 -0
  508. package/src/self-dev/shard-run.ts +36 -15
  509. package/src/self-implement/abandoned-classification.ts +12 -3
  510. package/src/self-implement/budget-gate.ts +7 -0
  511. package/src/self-implement/child-llm-preference.ts +10 -1
  512. package/src/self-implement/doctor-visit.ts +30 -8
  513. package/src/self-implement/elanous-tui-spawn.ts +3 -0
  514. package/src/self-implement/fixtures/tdd-green-missing-passing-child-transcript.txt +2 -0
  515. package/src/self-implement/gate-artifacts.ts +2 -1
  516. package/src/self-implement/goal-author-cli.ts +4 -2
  517. package/src/self-implement/goal-author.ts +549 -10
  518. package/src/self-implement/graph-overlay-yaml.ts +181 -4
  519. package/src/self-implement/graph-overlay.ts +3 -1
  520. package/src/self-implement/graph-profile-yaml.ts +107 -0
  521. package/src/self-implement/graph-yaml.ts +94 -5
  522. package/src/self-implement/off-diff-evidence.ts +249 -5
  523. package/src/self-implement/orchestrator.ts +298 -26
  524. package/src/self-implement/run-chart.ts +6 -3
  525. package/src/self-implement/run-ledger.ts +51 -1
  526. package/src/self-implement/runtime-overlay-run-steps.ts +95 -0
  527. package/src/self-implement/tdd-evidence-tags.ts +9 -0
  528. package/src/self-implement/test-scenario-request.ts +37 -6
  529. package/src/self-implement/train-gate-receipt.ts +166 -0
  530. package/src/self-implement/train-gate-remote.ts +62 -18
  531. package/src/session/chat.ts +6 -4
  532. package/src/session/session-fanout.ts +2 -0
  533. package/src/session/streaming/acp-stream-sink.ts +2 -1
  534. package/src/session/streaming/chunk-producer.ts +6 -0
  535. package/src/session/streaming/stream-compositor.ts +3 -2
  536. package/src/session-runtime/index.ts +74 -6
  537. package/src/session-runtime/retry-policy.ts +1 -1
  538. package/src/setup/llm-env-detect.ts +3 -0
  539. package/src/setup/service-key-catalog.ts +46 -0
  540. package/src/setup/service-keys.ts +241 -0
  541. package/src/sidetab-core/model.ts +205 -10
  542. package/src/sidetab-core/visible-agent-mission-pair.ts +51 -0
  543. package/src/sidetab-core/visible-agent-mission.ts +182 -48
  544. package/src/skills/tools/agent.ts +23 -4
  545. package/src/skills/tools/omni-search.ts +127 -27
  546. package/src/task-agent/parent-host.ts +29 -1
  547. package/src/task-agent/recall-inject.ts +98 -0
  548. package/src/task-agent/repair-outcomes.ts +65 -0
  549. package/src/task-agent/task-hand.ts +46 -14
  550. package/src/task-orchestrator/dispatcher.ts +14 -1
  551. package/src/task-orchestrator/linear-capture-events.ts +55 -0
  552. package/src/task-orchestrator/store.ts +16 -5
  553. package/src/task-orchestrator/surfaces/pod-artifact-return.ts +23 -1
  554. package/src/task-orchestrator/surfaces/pod-failure-reason.ts +107 -1
  555. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +113 -14
  556. package/src/task-orchestrator/surfaces/pod-si-warm-host.ts +21 -9
  557. package/src/task-orchestrator/surfaces/pod-source-receive.ts +23 -11
  558. package/src/task-orchestrator/surfaces/pod-warm-switch.ts +2 -0
  559. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +1 -1
  560. package/src/task-orchestrator/surfaces/pod-warm-worker-provider.ts +467 -77
  561. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +45 -3
  562. package/src/task-orchestrator/surfaces/self-implement-pod.ts +210 -14
  563. package/src/task-orchestrator/surfaces/self-implement.ts +27 -3
  564. package/src/task-orchestrator/surfaces/warm-reuse-evidence.ts +169 -0
  565. package/src/task-orchestrator/types.ts +14 -0
  566. package/src/telegram.ts +14 -16
  567. package/src/terminal/coding-agent.ts +14 -5
  568. package/src/terminal/session-registry.ts +1 -1
  569. package/src/tool-hints/gate.ts +46 -14
  570. package/src/tool-hints/signals.ts +1 -1
  571. package/src/tool-hints/types.ts +2 -0
  572. package/src/tool-runtime/agent-runtime.ts +1 -0
  573. package/src/tool-runtime/browser-hand-runtime.ts +391 -0
  574. package/src/tool-runtime/browser-runtime.ts +33 -19
  575. package/src/tool-runtime/elanous-linear-issue-runtime.ts +76 -0
  576. package/src/tool-runtime/elanous-linear-secretary-runtime.ts +173 -0
  577. package/src/tool-runtime/graph-mcp-runtimes.ts +240 -0
  578. package/src/tool-runtime/index.ts +6 -0
  579. package/src/tool-runtime/types.ts +5 -0
  580. package/src/tui/entry.ts +51 -8
  581. package/src/tui/sidetab/attach.ts +252 -11
  582. package/src/tui/sidetab/herdr-portal.ts +225 -0
  583. package/src/tui/sidetab/list.ts +3 -2
  584. package/src/tui-client/next-dashboard-runtime.ts +52 -0
  585. package/src/user-config.ts +34 -9
  586. package/src/user-intent/types.ts +4 -3
  587. package/src/ux-sim/browser-hand.ts +165 -0
  588. package/src/ux-sim/draft-inventory-builder.ts +199 -0
  589. package/src/ux-sim/fake-browser-page.ts +81 -0
  590. package/src/ux-sim/fake-linear-device.ts +31 -0
  591. package/src/ux-sim/graph-engine-sim.ts +47 -0
  592. package/src/ux-sim/linear-secretary.ts +208 -0
  593. package/src/ux-sim/mock-scenario-catalog.json +81 -26
  594. package/src/ux-sim/mock-scenario-catalog.ts +175 -5
  595. package/src/ux-sim/onboarding-first-run-device.ts +31 -21
  596. package/src/ux-sim/release-sim-rig.ts +62 -18
  597. package/src/ux-sim/scenario.ts +70 -26
  598. package/src/ux-sim/service-key-setup.ts +113 -0
  599. package/src/ux-sim/term-slash-device.ts +74 -0
  600. package/src/ux-sim/turn-throw-sim.ts +31 -0
  601. package/src/version/packed-revision.json +1 -1
  602. package/src/web-search/exa.ts +77 -0
  603. package/src/web-search/index.ts +30 -9
  604. package/src/web-search/provider.ts +4 -1
  605. package/src/web-search/x-intent.ts +5 -0
  606. package/apps/pwa/out/_next/static/chunks/0244e5b5.6fc7670f8223d82d.js +0 -1
  607. package/apps/pwa/out/_next/static/chunks/1121.13ba7a8aff19df81.js +0 -36
  608. package/apps/pwa/out/_next/static/chunks/1147-5196d19c222051b3.js +0 -1
  609. package/apps/pwa/out/_next/static/chunks/1319.b9b815ae0f181e06.js +0 -1
  610. package/apps/pwa/out/_next/static/chunks/1345-31427b833438f521.js +0 -1
  611. package/apps/pwa/out/_next/static/chunks/1455-530ca16c7e71baff.js +0 -1
  612. package/apps/pwa/out/_next/static/chunks/1574.878c18ecc97b1bd4.js +0 -1
  613. package/apps/pwa/out/_next/static/chunks/1586.fafc33a9a5835cb7.js +0 -32
  614. package/apps/pwa/out/_next/static/chunks/1744.855fd60ae4c4a8c8.js +0 -1
  615. package/apps/pwa/out/_next/static/chunks/193.21a47a3e07ef6860.js +0 -1
  616. package/apps/pwa/out/_next/static/chunks/1945.7b54990d578c119b.js +0 -1
  617. package/apps/pwa/out/_next/static/chunks/2004.e839fda7ea5a738a.js +0 -1
  618. package/apps/pwa/out/_next/static/chunks/2044-dd681a5c08779ff8.js +0 -1
  619. package/apps/pwa/out/_next/static/chunks/2101.2248decb38829b03.js +0 -286
  620. package/apps/pwa/out/_next/static/chunks/2300.41ea70ac1bef1446.js +0 -1
  621. package/apps/pwa/out/_next/static/chunks/2357-07b5eeb5fb12628d.js +0 -1
  622. package/apps/pwa/out/_next/static/chunks/2364.28652020695a6db3.js +0 -34
  623. package/apps/pwa/out/_next/static/chunks/2456.b6de0e1c05f28843.js +0 -1
  624. package/apps/pwa/out/_next/static/chunks/2526.c3e50ac1fec064bd.js +0 -1
  625. package/apps/pwa/out/_next/static/chunks/2549-cda50b716ff4250c.js +0 -1
  626. package/apps/pwa/out/_next/static/chunks/2550-5f1e88f615568045.js +0 -1
  627. package/apps/pwa/out/_next/static/chunks/261-319078c954e40d66.js +0 -1
  628. package/apps/pwa/out/_next/static/chunks/2690.0521c738b7749931.js +0 -115
  629. package/apps/pwa/out/_next/static/chunks/2974.595d1e29d040cb6a.js +0 -64
  630. package/apps/pwa/out/_next/static/chunks/3207.a756c95e9ec8c3c8.js +0 -1
  631. package/apps/pwa/out/_next/static/chunks/3285.89ee2f298682f5e5.js +0 -93
  632. package/apps/pwa/out/_next/static/chunks/3447.06edc7b092021417.js +0 -41
  633. package/apps/pwa/out/_next/static/chunks/3510-9ca392698bfe4391.js +0 -1
  634. package/apps/pwa/out/_next/static/chunks/3541.772e5ce425aaa611.js +0 -24
  635. package/apps/pwa/out/_next/static/chunks/3741.9cf76acaa2ee5298.js +0 -1
  636. package/apps/pwa/out/_next/static/chunks/3837.a210d7d0db8d8abd.js +0 -1
  637. package/apps/pwa/out/_next/static/chunks/3898-955c896f394217a6.js +0 -1
  638. package/apps/pwa/out/_next/static/chunks/3947-ef57acea76eaa8d2.js +0 -1
  639. package/apps/pwa/out/_next/static/chunks/4037-3b82ebc7d78afdc7.js +0 -1
  640. package/apps/pwa/out/_next/static/chunks/405.9022d4a478202b67.js +0 -77
  641. package/apps/pwa/out/_next/static/chunks/417-fb2cc9a9910e5968.js +0 -1
  642. package/apps/pwa/out/_next/static/chunks/4276.336d76d858fcdf1b.js +0 -1
  643. package/apps/pwa/out/_next/static/chunks/4302.6ced9aa4535de947.js +0 -1
  644. package/apps/pwa/out/_next/static/chunks/4320.583cbab64db6be02.js +0 -1
  645. package/apps/pwa/out/_next/static/chunks/4768-8eac183fd291ca53.js +0 -1
  646. package/apps/pwa/out/_next/static/chunks/4770.769c9cd9c7034eba.js +0 -148
  647. package/apps/pwa/out/_next/static/chunks/4895.65605ec3e6504e89.js +0 -74
  648. package/apps/pwa/out/_next/static/chunks/50061469.0326382241ef3b2d.js +0 -122
  649. package/apps/pwa/out/_next/static/chunks/5112.4b9f300124fab7b3.js +0 -149
  650. package/apps/pwa/out/_next/static/chunks/5335.375ee922bcd5bc83.js +0 -1
  651. package/apps/pwa/out/_next/static/chunks/5342.023a2e729689b320.js +0 -27
  652. package/apps/pwa/out/_next/static/chunks/53c73f84.373b6160adfa89a4.js +0 -1
  653. package/apps/pwa/out/_next/static/chunks/5431-72a1dbde59400691.js +0 -1
  654. package/apps/pwa/out/_next/static/chunks/5440-4236de26c5ea5856.js +0 -1
  655. package/apps/pwa/out/_next/static/chunks/5486-b318c165f645d8ba.js +0 -1
  656. package/apps/pwa/out/_next/static/chunks/5506-c7d2ec25c62a7c94.js +0 -1
  657. package/apps/pwa/out/_next/static/chunks/5570-c66ecbea26b4e3b1.js +0 -1
  658. package/apps/pwa/out/_next/static/chunks/5696.ffca5aa259d8451e.js +0 -1
  659. package/apps/pwa/out/_next/static/chunks/5793-8c584aea2aa87560.js +0 -1
  660. package/apps/pwa/out/_next/static/chunks/5848-6de6b8c173351a90.js +0 -1
  661. package/apps/pwa/out/_next/static/chunks/5999.94e3c83040200f31.js +0 -1
  662. package/apps/pwa/out/_next/static/chunks/5a7901d6-2d8d9b5587cf9042.js +0 -1
  663. package/apps/pwa/out/_next/static/chunks/6131.348b7d6bdcd267ce.js +0 -226
  664. package/apps/pwa/out/_next/static/chunks/6164.86133a0172611184.js +0 -90
  665. package/apps/pwa/out/_next/static/chunks/6515.e07e8b2b8a707a87.js +0 -1
  666. package/apps/pwa/out/_next/static/chunks/6522-c005514f87d18982.js +0 -1
  667. package/apps/pwa/out/_next/static/chunks/6642.648adb1767f39ecf.js +0 -1
  668. package/apps/pwa/out/_next/static/chunks/6848.138805a09d001d09.js +0 -1
  669. package/apps/pwa/out/_next/static/chunks/7049-c09e2b7a253a24f3.js +0 -1
  670. package/apps/pwa/out/_next/static/chunks/7072.1e00447d9fa39972.js +0 -104
  671. package/apps/pwa/out/_next/static/chunks/7106.64201c539c5e220c.js +0 -94
  672. package/apps/pwa/out/_next/static/chunks/7151-1f742b455986530e.js +0 -1
  673. package/apps/pwa/out/_next/static/chunks/7199.18d6b25e001154ce.js +0 -1
  674. package/apps/pwa/out/_next/static/chunks/7279-c199ea83f34338fa.js +0 -1
  675. package/apps/pwa/out/_next/static/chunks/728b938d.ffaa7ad583d60e58.js +0 -1
  676. package/apps/pwa/out/_next/static/chunks/7309.171c3de54e0322f1.js +0 -1
  677. package/apps/pwa/out/_next/static/chunks/733.7a1ab3342e03306f.js +0 -1
  678. package/apps/pwa/out/_next/static/chunks/7504.d5cf1e7cd89b1b08.js +0 -24
  679. package/apps/pwa/out/_next/static/chunks/7573-0fd4af62d65d4598.js +0 -1
  680. package/apps/pwa/out/_next/static/chunks/759.6f8267df4689c401.js +0 -1
  681. package/apps/pwa/out/_next/static/chunks/7825-668b046f72f14483.js +0 -1
  682. package/apps/pwa/out/_next/static/chunks/7852-1538768b6eb19388.js +0 -1
  683. package/apps/pwa/out/_next/static/chunks/7868.cff810430bb63c91.js +0 -1
  684. package/apps/pwa/out/_next/static/chunks/8084-dfcc796874ab4e07.js +0 -1
  685. package/apps/pwa/out/_next/static/chunks/8266.6bf9b131b2584678.js +0 -1
  686. package/apps/pwa/out/_next/static/chunks/8403.7b81d5e64074a725.js +0 -8
  687. package/apps/pwa/out/_next/static/chunks/8470.1998cbd0866a7eac.js +0 -1
  688. package/apps/pwa/out/_next/static/chunks/8505.fd803c6c33b54cc3.js +0 -79
  689. package/apps/pwa/out/_next/static/chunks/8546-6f03f8ea34dd61d9.js +0 -1
  690. package/apps/pwa/out/_next/static/chunks/8687-246fda8433d3477c.js +0 -1
  691. package/apps/pwa/out/_next/static/chunks/898-280022fb082936bc.js +0 -1
  692. package/apps/pwa/out/_next/static/chunks/9098-50eefc1844212e3d.js +0 -1
  693. package/apps/pwa/out/_next/static/chunks/9211-330b6736a63d4cb3.js +0 -1
  694. package/apps/pwa/out/_next/static/chunks/9249.976f1e69a9d80754.js +0 -1
  695. package/apps/pwa/out/_next/static/chunks/9255-cf88fceda5666645.js +0 -1
  696. package/apps/pwa/out/_next/static/chunks/9306-e523ba58bb8adc42.js +0 -1
  697. package/apps/pwa/out/_next/static/chunks/9324.a9866d717ba62cb6.js +0 -1
  698. package/apps/pwa/out/_next/static/chunks/9325.a8510e8aa87c8143.js +0 -1
  699. package/apps/pwa/out/_next/static/chunks/9353-12bfff0c130104cf.js +0 -1
  700. package/apps/pwa/out/_next/static/chunks/9479-154a697d4b6e4e98.js +0 -1
  701. package/apps/pwa/out/_next/static/chunks/9540-65aa6ccc31b3fd78.js +0 -1
  702. package/apps/pwa/out/_next/static/chunks/9633.ce5bddc56784da72.js +0 -1
  703. package/apps/pwa/out/_next/static/chunks/9656-374232558fd528d0.js +0 -1
  704. package/apps/pwa/out/_next/static/chunks/9832.f4a98c878ecf2c0a.js +0 -62
  705. package/apps/pwa/out/_next/static/chunks/9865.f094440645f02d98.js +0 -1
  706. package/apps/pwa/out/_next/static/chunks/app/_not-found/page-e772b4710df5d936.js +0 -1
  707. package/apps/pwa/out/_next/static/chunks/app/approvals/page-4361368e6a76b967.js +0 -1
  708. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-802f349fdd65248d.js +0 -1
  709. package/apps/pwa/out/_next/static/chunks/app/board/page-7f35513988a2a495.js +0 -1
  710. package/apps/pwa/out/_next/static/chunks/app/botlab/page-798121656540e33e.js +0 -1
  711. package/apps/pwa/out/_next/static/chunks/app/bots/page-20a089490affe98c.js +0 -1
  712. package/apps/pwa/out/_next/static/chunks/app/ceo/page-e5e4ec786d70e604.js +0 -1
  713. package/apps/pwa/out/_next/static/chunks/app/chat/page-d12fe5d0801430e4.js +0 -1
  714. package/apps/pwa/out/_next/static/chunks/app/consult/page-d8cf21022fecc026.js +0 -1
  715. package/apps/pwa/out/_next/static/chunks/app/control/page-21ce565c9c57ee97.js +0 -1
  716. package/apps/pwa/out/_next/static/chunks/app/decisions/page-b56563025f619c9b.js +0 -1
  717. package/apps/pwa/out/_next/static/chunks/app/design-check/page-52f14dd133da8348.js +0 -1
  718. package/apps/pwa/out/_next/static/chunks/app/editor/page-c0ed7fdcdba76633.js +0 -1
  719. package/apps/pwa/out/_next/static/chunks/app/exec/page-af8c3020cb520f15.js +0 -1
  720. package/apps/pwa/out/_next/static/chunks/app/field/page-72eda67af9f5e35c.js +0 -1
  721. package/apps/pwa/out/_next/static/chunks/app/healthz/route-e772b4710df5d936.js +0 -1
  722. package/apps/pwa/out/_next/static/chunks/app/inside/page-67a6620d31f0a46f.js +0 -1
  723. package/apps/pwa/out/_next/static/chunks/app/intake/page-f059363aa0880ec2.js +0 -1
  724. package/apps/pwa/out/_next/static/chunks/app/layout-f9f917d6a57f69fb.js +0 -1
  725. package/apps/pwa/out/_next/static/chunks/app/live/page-d3ae55eee2f0826c.js +0 -1
  726. package/apps/pwa/out/_next/static/chunks/app/live-run/page-0e3d7b9421b79dac.js +0 -1
  727. package/apps/pwa/out/_next/static/chunks/app/loops/page-ba738f7e233eb211.js +0 -1
  728. package/apps/pwa/out/_next/static/chunks/app/market/page-33438b98c74fd599.js +0 -1
  729. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-0b34d5fd990d793a.js +0 -1
  730. package/apps/pwa/out/_next/static/chunks/app/morning/page-0f291d3c8fd55a3a.js +0 -1
  731. package/apps/pwa/out/_next/static/chunks/app/not-found-3fced192be5279c1.js +0 -1
  732. package/apps/pwa/out/_next/static/chunks/app/observatory/page-04cb3cf182a7c1ea.js +0 -1
  733. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-6ccbd2ab23a21542.js +0 -1
  734. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-aa0518c48a5f4e56.js +0 -1
  735. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-4b32226d341ad7d7.js +0 -1
  736. package/apps/pwa/out/_next/static/chunks/app/outputs/page-3224fd8f6383b61f.js +0 -1
  737. package/apps/pwa/out/_next/static/chunks/app/page-efbc97459f2914e2.js +0 -1
  738. package/apps/pwa/out/_next/static/chunks/app/reflection/page-2fe487d88cd5d97c.js +0 -1
  739. package/apps/pwa/out/_next/static/chunks/app/scheduler/page-48861dd1a858bab7.js +0 -1
  740. package/apps/pwa/out/_next/static/chunks/app/sessions/page-197d5d4d21d228ea.js +0 -1
  741. package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a763ba89fbdd9c27.js +0 -1
  742. package/apps/pwa/out/_next/static/chunks/app/settings/page-7edb253510b1c136.js +0 -1
  743. package/apps/pwa/out/_next/static/chunks/app/setup/done/page-0c875702c61965ea.js +0 -1
  744. package/apps/pwa/out/_next/static/chunks/app/setup/layout-e772b4710df5d936.js +0 -1
  745. package/apps/pwa/out/_next/static/chunks/app/setup/page-e425c951151095f7.js +0 -1
  746. package/apps/pwa/out/_next/static/chunks/app/share/page-9c90e0aec4e27f77.js +0 -1
  747. package/apps/pwa/out/_next/static/chunks/app/showroom/page-733e09a02e727d42.js +0 -1
  748. package/apps/pwa/out/_next/static/chunks/app/tasks/page-4f899e14c34d77a1.js +0 -1
  749. package/apps/pwa/out/_next/static/chunks/app/term/page-bf067887b3307423.js +0 -1
  750. package/apps/pwa/out/_next/static/chunks/app/today/page-7af10868ff87d04e.js +0 -1
  751. package/apps/pwa/out/_next/static/chunks/app/trace/page-efe5304057aa11c7.js +0 -1
  752. package/apps/pwa/out/_next/static/chunks/app/vault/page-76bcd29aaa8a26c3.js +0 -1
  753. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-4cfd88e2273ce50f.js +0 -1
  754. package/apps/pwa/out/_next/static/chunks/app/workflows/page-0a1ddb47efba0a32.js +0 -1
  755. package/apps/pwa/out/_next/static/chunks/app/workspace/page-2a176c707152c892.js +0 -1
  756. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-efe03031b8797fbf.js +0 -1
  757. package/apps/pwa/out/_next/static/chunks/framework-d0d2d673bfd8a8a9.js +0 -1
  758. package/apps/pwa/out/_next/static/chunks/main-4c9fceb2baa09cb7.js +0 -1
  759. package/apps/pwa/out/_next/static/chunks/main-app-b0ab8d8fc9a97556.js +0 -1
  760. package/apps/pwa/out/_next/static/chunks/pages/_app-7e2cc62a2e5cec96.js +0 -1
  761. package/apps/pwa/out/_next/static/chunks/pages/_error-22324935f753ec5e.js +0 -1
  762. package/apps/pwa/out/_next/static/chunks/webpack-9dc1bfa25334998a.js +0 -1
  763. package/apps/pwa/out/_next/static/css/be9019f696217521.css +0 -1
  764. /package/apps/pwa/out/_next/static/{X1ucLw10Cds_h614NoEnh → HMXsxdy5MIIcHPMHv1wD4}/_ssgManifest.js +0 -0
@@ -27,6 +27,19 @@ import { debug, redactSecretText, withAmbientSessionScope } from '../debug/log.j
27
27
  import { applyDeferredTools } from '../session-runtime/tier-flip.js';
28
28
  import { isResearchAgentIntent } from '../tool-hints/signals.js';
29
29
  import { buildResearchDateSystemMessage, resolveSessionSurfaceProfile } from '../session-runtime/index.js';
30
+ import {
31
+ isResearchToolAllowed,
32
+ RESEARCH_DOCUMENT_WRITE_TOOLS,
33
+ requestsResearchDocumentWrite,
34
+ RESEARCH_TOOL_ALLOWLIST,
35
+ RESEARCH_TURN_DEEP_BUDGET_MS,
36
+ RESEARCH_TURN_DEADLINE_STOP_ERROR,
37
+ RESEARCH_TURN_FIRST_REPLY_BUDGET_MS,
38
+ RESEARCH_TURN_FINAL_ANSWER_DEADLINE_MS,
39
+ RESEARCH_TURN_MAX_TOOL_TURNS,
40
+ RESEARCH_TURN_SHALLOW_FINAL_ANSWER_DEADLINE_MS,
41
+ RESEARCH_TURN_SHALLOW_BUDGET_MS,
42
+ } from './research-policy.js';
30
43
  import type {
31
44
  CoreTurnContext,
32
45
  CoreTurnResult,
@@ -35,6 +48,14 @@ import type {
35
48
 
36
49
  const CORE_TURN_TOOL_RESULT_INLINE_LIMIT_BYTES = 50 * 1024;
37
50
 
51
+ // A deep, non-research prompt gets the same-call Bloom frame, but should not
52
+ // silently grow into multi-source research just because the model can reach
53
+ // generic skill/search tools. Explicit research turns and explicit named-skill
54
+ // requests keep the normal tool surface.
55
+ const DEEP_NON_RESEARCH_SEARCH_TOOLS = new Set([
56
+ 'skill_exec', 'elanous_skills_list', 'websearch', 'web_search', 'omnisearch', 'omni_search', 'webfetch', 'web_fetch',
57
+ ]);
58
+
38
59
  /** Classify an error thrown out of `streamLLMWithTools` into the
39
60
  * Core-turn stop-reason set. Abort wins over everything else;
40
61
  * credential rejection (`isAuthRejectionError`) is distinct from a
@@ -82,8 +103,31 @@ function selectSurfaceUserText(ctx: CoreTurnContext): string | undefined {
82
103
  * the research turn's text-only provisional answer. That provisional pass
83
104
  * has no tools by design and otherwise tells the user the requested skill
84
105
  * cannot be invoked, even when the skill router already resolved it. */
85
- function requestsNamedSkill(text: string | undefined): boolean {
106
+ function requestedInstalledSkillName(text: string | undefined, installedSkillNames: readonly string[]): string | undefined {
107
+ if (!text) return undefined;
108
+ return installedSkillNames
109
+ .filter((name) => name.includes('-'))
110
+ .sort((a, b) => b.length - a.length)
111
+ .find((name) => {
112
+ const parts = name.trim().split(/[-\s]+/).filter(Boolean);
113
+ if (parts.length < 2 || !parts.every((part) => /^[a-z0-9]+$/i.test(part))) return false;
114
+ const slug = parts.join('[\\s-]*');
115
+ return new RegExp('(?:^|[^\\p{L}\\p{N}])' + slug + '(?=$|[^a-z0-9])\\s*(?:으로|로)(?=[^\\n!?]{0,120}(?:찾아|조사|정리))', 'iu').test(text);
116
+ });
117
+ }
118
+
119
+ export function requestsNamedSkill(text: string | undefined, installedSkillNames: readonly string[] = []): boolean {
86
120
  if (!text) return false;
121
+ const requestedInstalledSkill = installedSkillNames
122
+ .filter((name) => name.includes('-'))
123
+ .sort((a, b) => b.length - a.length)
124
+ .some((name) => {
125
+ const parts = name.trim().split(/[-\s]+/).filter(Boolean);
126
+ if (parts.length < 2 || !parts.every((part) => /^[a-z0-9]+$/i.test(part))) return false;
127
+ const slug = parts.join('[\\s-]*');
128
+ return new RegExp('(?:^|[^\\p{L}\\p{N}])' + slug + '(?=$|[^a-z0-9])\\s*(?:으로|로)(?=[^\\n!?]{0,120}(?:찾아|조사|정리))', 'iu').test(text);
129
+ });
130
+ if (requestedInstalledSkill) return true;
87
131
  const action = '(?:use|invoke|run|call|execute|launch|trigger|apply|start)';
88
132
  return new RegExp(`\\b${action}\\s+(?:(?:the|a|an)\\s+)?skill\\s+(?:named|called)\\s+['"“‘]([a-z0-9][a-z0-9 _-]{1,60}?)['"”’](?=$|[\\s.,;!?])`, 'i').test(text)
89
133
  || new RegExp(`\\b${action}\\s+(?:the\\s+)?['"“‘]([a-z0-9][a-z0-9 _-]{1,60}?)['"”’](?=$|[\\s.,;!?])`, 'i').test(text)
@@ -119,23 +163,36 @@ function requestsNamedSkill(text: string | undefined): boolean {
119
163
  */
120
164
  export interface RunCoreTurnOptions {
121
165
  now?: () => number;
122
- runResearch?: (request: string, signal: AbortSignal) => Promise<{ ok: boolean; output: string; error?: string }>;
166
+ timers?: { setTimeout(callback: () => void, delayMs: number): ReturnType<typeof setTimeout>; clearTimeout(handle: ReturnType<typeof setTimeout>): void };
167
+ firstReplyBudgetMs?: number;
168
+ researchWallClockBudgetMs?: number;
169
+ runResearch?: (
170
+ request: string,
171
+ signal: AbortSignal,
172
+ admitToolCall?: (name: string) => boolean,
173
+ providerRouting?: Pick<CoreTurnContext, 'initialProvider' | 'skipProviders' | 'runId'>,
174
+ ) => Promise<{ ok: boolean; output: string; error?: string; axisCount?: number }>;
123
175
  }
124
176
 
177
+ type ResearchTimer = ReturnType<typeof setTimeout>;
178
+
125
179
  type AbortRace<T> = { aborted: true } | { aborted: false; value: T };
126
180
 
127
181
  function settleBeforeAbort<T>(work: Promise<T>, signal: AbortSignal): Promise<AbortRace<T>> {
128
- if (signal.aborted) return Promise.resolve({ aborted: true });
129
182
  return new Promise((resolve, reject) => {
183
+ let abortGraceTimer: ReturnType<typeof setTimeout> | undefined;
130
184
  const onAbort = () => {
131
185
  signal.removeEventListener('abort', onAbort);
132
- resolve({ aborted: true });
186
+ // Let work handlers that synchronously settle in response to abort
187
+ // expose their final partial result before taking the deadline path.
188
+ abortGraceTimer = setTimeout(() => resolve({ aborted: true }), 50);
133
189
  };
134
- signal.addEventListener('abort', onAbort, { once: true });
135
190
  work.then(
136
- value => { signal.removeEventListener('abort', onAbort); resolve({ aborted: false, value }); },
137
- error => { signal.removeEventListener('abort', onAbort); reject(error); },
191
+ value => { signal.removeEventListener('abort', onAbort); if (abortGraceTimer) clearTimeout(abortGraceTimer); resolve({ aborted: false, value }); },
192
+ error => { signal.removeEventListener('abort', onAbort); if (abortGraceTimer) clearTimeout(abortGraceTimer); reject(error); },
138
193
  );
194
+ if (signal.aborted) onAbort();
195
+ else signal.addEventListener('abort', onAbort, { once: true });
139
196
  });
140
197
  }
141
198
 
@@ -174,6 +231,41 @@ function commitProvisionalTurn(
174
231
  commitCompletion(messages, handlers, setFinalPhaseAnswer);
175
232
  }
176
233
 
234
+ function completionWithFinalText(messages: TurnCompletion | undefined, text: string): TurnCompletion {
235
+ const completed = [...(messages ?? [])];
236
+ let lastAssistant = -1;
237
+ for (let index = completed.length - 1; index >= 0; index -= 1) {
238
+ if (completed[index]?.role === 'assistant') { lastAssistant = index; break; }
239
+ }
240
+ if (lastAssistant < 0) {
241
+ completed.push({ role: 'assistant', content: text, phase: 'final_answer' });
242
+ } else {
243
+ const previous = completed[lastAssistant]!;
244
+ let content: typeof previous.content;
245
+ if (typeof previous.content === 'string') {
246
+ content = text;
247
+ } else {
248
+ let lastText = -1;
249
+ for (let index = previous.content.length - 1; index >= 0; index -= 1) {
250
+ if (previous.content[index]?.type === 'text') { lastText = index; break; }
251
+ }
252
+ if (lastText < 0) {
253
+ // A tool-only assistant message must stay paired with its tool result;
254
+ // the synthesized prose is a separate final answer message.
255
+ completed.push({ role: 'assistant', content: text, phase: 'final_answer' });
256
+ return completed;
257
+ }
258
+ content = previous.content.map((block, index) => index === lastText && block.type === 'text'
259
+ ? { ...block, text }
260
+ : block);
261
+ }
262
+ completed[lastAssistant] = {
263
+ ...previous, content, phase: 'final_answer',
264
+ };
265
+ }
266
+ return completed;
267
+ }
268
+
177
269
  function commitStagedTurn(
178
270
  messages: TurnCompletion | undefined,
179
271
  handlers: StreamWithToolsHandlers,
@@ -182,8 +274,25 @@ function commitStagedTurn(
182
274
  setFinalPhaseAnswer: (value: boolean) => void,
183
275
  onReplaceText?: (fullText: string) => void,
184
276
  ): void {
185
- commitCompletion(messages, handlers, setFinalPhaseAnswer);
277
+ // Replacement must reach the stream bridge before completion: ACP tracks the
278
+ // visible tail in `onReplaceText` so its completion callback will not emit the
279
+ // same synthesized answer a second time.
186
280
  if (replaceVisibleText && text) onReplaceText?.(text);
281
+ commitCompletion(messages, handlers, setFinalPhaseAnswer);
282
+ }
283
+
284
+ function commitSynthesizedTurn(
285
+ staged: ReturnType<typeof createStagedHandlers>,
286
+ fallbackMessages: TurnCompletion | undefined,
287
+ handlers: StreamWithToolsHandlers,
288
+ finalText: string,
289
+ provisionalText: string,
290
+ setFinalPhaseAnswer: (value: boolean) => void,
291
+ onReplaceText?: (fullText: string) => void,
292
+ ): void {
293
+ const completion = staged.completion() ?? completionWithFinalText(fallbackMessages, finalText);
294
+ commitStagedTurn(completion, handlers, finalText, finalText !== provisionalText,
295
+ setFinalPhaseAnswer, onReplaceText);
187
296
  }
188
297
 
189
298
  export async function runCoreTurn(
@@ -191,6 +300,10 @@ export async function runCoreTurn(
191
300
  options: RunCoreTurnOptions = {},
192
301
  ): Promise<CoreTurnResult> {
193
302
  const now = options.now ?? Date.now;
303
+ const timers = options.timers ?? {
304
+ setTimeout: (callback: () => void, delayMs: number) => setTimeout(callback, delayMs),
305
+ clearTimeout: (handle: ReturnType<typeof setTimeout>) => clearTimeout(handle),
306
+ };
194
307
  let turnStartedAt: number | undefined;
195
308
  let researchStartedAt: number | undefined;
196
309
  let researchFirstTokenRecorded = false;
@@ -214,6 +327,62 @@ export async function runCoreTurn(
214
327
  let accumulatedText = '';
215
328
  let dispatchCount = 0;
216
329
  let finalPhaseAnswer = false;
330
+ let enforceResearchToolAllowlist = false;
331
+ let enforceResearchDocumentWrite = false;
332
+ const isAllowedResearchTool = (name: string): boolean => isResearchToolAllowed(name)
333
+ || (enforceResearchDocumentWrite && (RESEARCH_DOCUMENT_WRITE_TOOLS as readonly string[]).includes(name));
334
+ let enforceResearchToolBudget = false;
335
+ let researchToolCallCount = 0;
336
+ let researchAxisCount = 0;
337
+ let researchStopReason: string | undefined;
338
+ const loggedResearchStops = new Set<string>();
339
+ const logResearchStop = (reason: string, extra: Record<string, unknown> = {}): void => {
340
+ if (loggedResearchStops.has(reason)) return;
341
+ loggedResearchStops.add(reason);
342
+ debug.log('research.stop', 'stopped', { sessionId: ctx.sessionId, reason, ...extra });
343
+ };
344
+ const admitResearchToolCall = (name: string): boolean => {
345
+ if (!enforceResearchToolBudget) return true;
346
+ if (name === 'Agent' && researchAxisCount < 3) {
347
+ debug.log('research.turn', 'subagent-skipped', {
348
+ sessionId: ctx.sessionId, reason: 'insufficient-judgment-axes', axisCount: researchAxisCount, minimum: 3,
349
+ });
350
+ return false;
351
+ }
352
+ if (researchToolCallCount >= RESEARCH_TURN_MAX_TOOL_TURNS) {
353
+ // A prior denied tool is observable, but it must not mask the hard
354
+ // budget stop that requires tool-free synthesis. A wall-clock stop is
355
+ // already terminal and keeps its more specific reason.
356
+ if (researchStopReason !== 'wall-clock-budget') researchStopReason = 'tool-budget';
357
+ logResearchStop('tool-budget', { stage: 'tool-dispatch', tool: name, count: researchToolCallCount, limit: RESEARCH_TURN_MAX_TOOL_TURNS });
358
+ return false;
359
+ }
360
+ researchToolCallCount += 1;
361
+ return true;
362
+ };
363
+ const constrainResearchToolArgs = (name: string, args: Record<string, unknown>): Record<string, unknown> => {
364
+ if (!enforceResearchToolAllowlist || name !== 'Agent' || !args || typeof args !== 'object' || Array.isArray(args)) return args;
365
+ const raw = args;
366
+ const rawFilter = raw.tool_filter && typeof raw.tool_filter === 'object' && !Array.isArray(raw.tool_filter)
367
+ ? raw.tool_filter as { deny?: unknown }
368
+ : {};
369
+ const deny = Array.isArray(rawFilter.deny) ? rawFilter.deny.filter((tool): tool is string => typeof tool === 'string') : [];
370
+ return {
371
+ ...raw,
372
+ subagent_type: typeof raw.subagent_type === 'string' && raw.subagent_type.trim()
373
+ ? raw.subagent_type
374
+ : 'general-purpose',
375
+ run_in_background: false,
376
+ wait_for_slot: false,
377
+ max_turns: typeof raw.max_turns === 'number' && Number.isFinite(raw.max_turns)
378
+ ? Math.max(1, Math.min(RESEARCH_TURN_MAX_TOOL_TURNS, Math.floor(raw.max_turns)))
379
+ : RESEARCH_TURN_MAX_TOOL_TURNS,
380
+ tool_filter: {
381
+ allow: ['Read', 'WebFetch'],
382
+ deny: [...new Set([...deny, 'Bash', 'Edit', 'Grep'])],
383
+ },
384
+ };
385
+ };
217
386
 
218
387
  const handlers: StreamWithToolsHandlers = {
219
388
  onText: (delta, full) => {
@@ -254,9 +423,28 @@ export async function runCoreTurn(
254
423
 
255
424
  let success = false;
256
425
  try {
257
- const result = await ctx.dispatchTool(
258
- name,
259
- args,
426
+ let result: unknown;
427
+ if (enforceResearchToolAllowlist && !isAllowedResearchTool(name)) {
428
+ researchStopReason ??= 'tool-not-allowed';
429
+ logResearchStop('tool-not-allowed', { stage: 'tool-dispatch', tool: name, allowedTools: [...RESEARCH_TOOL_ALLOWLIST, ...(enforceResearchDocumentWrite ? ['Edit', 'Write'] : [])] });
430
+ debug.log('core.turn', 'research-tool-denied', {
431
+ sessionId: ctx.sessionId,
432
+ tool: name,
433
+ dispatchCount: currentDispatchCount,
434
+ }, { level: 'warn' });
435
+ result = { error: enforceResearchDocumentWrite
436
+ ? 'This research turn may use research tools and Edit/Write only for the explicitly requested document.'
437
+ : 'This research turn may only use the research tool allowlist.' };
438
+ } else if (enforceResearchToolAllowlist && !admitResearchToolCall(name)) {
439
+ debug.log('core.turn', 'research-tool-budget-reached', {
440
+ sessionId: ctx.sessionId, tool: name, count: researchToolCallCount,
441
+ maxToolTurns: RESEARCH_TURN_MAX_TOOL_TURNS,
442
+ }, { level: 'warn' });
443
+ result = { error: 'Research tool budget reached. Answer with the evidence collected so far.' };
444
+ } else {
445
+ result = await ctx.dispatchTool(
446
+ name,
447
+ constrainResearchToolArgs(name, args),
260
448
  // Image-pipeline followup #1 (2026-05-05) — forward sessionId so
261
449
  // the dispatcher can auto-inject into session-keyed tool calls
262
450
  // (WebTerminal* etc.) when the LLM didn't supply one. `c` may
@@ -269,10 +457,20 @@ export async function runCoreTurn(
269
457
  c
270
458
  ? { ...c, sessionId: ctx.sessionId, signal: ctx.signal, ...(ctx.userText ? { userText: ctx.userText } : {}) }
271
459
  : { callId: '', sessionId: ctx.sessionId, signal: ctx.signal, ...(ctx.userText ? { userText: ctx.userText } : {}) },
272
- );
460
+ );
461
+ }
273
462
  success = true;
274
463
  return result;
275
464
  } finally {
465
+ if (name === 'Agent' && enforceResearchToolAllowlist) {
466
+ debug.log('research.turn', 'subagent-completed', {
467
+ sessionId: ctx.sessionId,
468
+ dispatchCount: currentDispatchCount,
469
+ durationMs: now() - startedAt,
470
+ completionMode: 'awaited-tool-result',
471
+ success,
472
+ });
473
+ }
276
474
  try {
277
475
  debug.log('core.turn', 'dispatch-done', {
278
476
  sessionId: ctx.sessionId,
@@ -344,20 +542,140 @@ export async function runCoreTurn(
344
542
  // Use the shared #31663 research-intent verdict. Surface labels are a
345
543
  // presentation/routing result and may remain `chat` for a research turn.
346
544
  const researchTurn = isResearchAgentIntent(surfaceUserText);
347
- const { messages, tools, stats } = applyDeferredTools(
545
+ const { selectDeepBloom } = await import('./deep-turn-bloom.js');
546
+ const deepBloomDecision = selectDeepBloom(surfaceUserText, {
547
+ researchIntent: researchTurn,
548
+ reasoningEffort: ctx.reasoningEffort,
549
+ });
550
+ const { messages, tools: tieredTools, stats } = applyDeferredTools(
348
551
  ctx.messages,
349
552
  ctx.tools,
350
553
  { enabled: deferredEnabled, ...(recentUserText ? { userText: recentUserText } : {}) },
351
554
  );
555
+ // Preserve the pre-routing contract: a named skill only skips the research
556
+ // prepass when skill_exec is actually active after the normal tier split.
557
+ // Resolve the installed skill name even if skill_exec is deferred/missing:
558
+ // a named request with no executor falls back to the unfiltered normal pool.
559
+ let installedSkillNames: string[] = [];
560
+ if (researchTurn && surfaceUserText?.trim()) {
561
+ const { getSkillIndex } = await import('../skills/index.js');
562
+ installedSkillNames = getSkillIndex().map(({ name }) => name);
563
+ }
564
+ const namedSkillRequest = requestsNamedSkill(surfaceUserText, installedSkillNames);
565
+ // A named skill only skips the research prepass when its executor is active.
566
+ const explicitSkillToolRequest = namedSkillRequest
567
+ && tieredTools.some((tool) => tool.name === 'skill_exec');
568
+ const constrainDeepNonResearchTools = deepBloomDecision.apply && !researchTurn;
569
+ // ToolSearch routes against the surface's full live pool, so hiding a tool
570
+ // from the model alone is insufficient. Remove the summoner from the
571
+ // model-visible tiered set while retaining original split stats/messages.
572
+ const bloomFilteredTools = constrainDeepNonResearchTools
573
+ ? tieredTools.filter((tool) => {
574
+ const name = tool.name.toLowerCase();
575
+ return name === 'skill_exec' && explicitSkillToolRequest
576
+ ? true
577
+ : name !== 'toolsearch' && !DEEP_NON_RESEARCH_SEARCH_TOOLS.has(name);
578
+ })
579
+ : tieredTools;
580
+ if (constrainDeepNonResearchTools) {
581
+ const suppressed = tieredTools.filter((tool) => !bloomFilteredTools.includes(tool)).map((tool) => tool.name);
582
+ debug.log('research.turn', 'deep-bloom-search-tools-suppressed', {
583
+ sessionId: ctx.sessionId, reason: deepBloomDecision.reason, suppressed,
584
+ explicitSkillToolRequest,
585
+ });
586
+ }
587
+ enforceResearchToolBudget = researchTurn;
588
+ enforceResearchToolAllowlist = researchTurn && !namedSkillRequest;
589
+ enforceResearchDocumentWrite = enforceResearchToolAllowlist && requestsResearchDocumentWrite(surfaceUserText);
590
+ // Codex Responses only supports tool_choice="required" (not a named
591
+ // function choice). Make the first request deterministic by exposing only
592
+ // skill_exec there; streamLLMWithTools restores the full pool on later turns.
593
+ const routedSkillTools = explicitSkillToolRequest
594
+ ? bloomFilteredTools.filter((tool) => tool.name === 'skill_exec')
595
+ : [];
596
+ const tools = enforceResearchToolAllowlist
597
+ ? bloomFilteredTools.filter((tool) => isAllowedResearchTool(tool.name))
598
+ : bloomFilteredTools;
599
+ // Preserve the ordinary pool if a later filter removes the executor.
600
+ const firstTurnTools = routedSkillTools.length > 0 ? routedSkillTools : undefined;
601
+ const maxToolTurns = researchTurn
602
+ ? Math.min(ctx.maxToolTurns ?? RESEARCH_TURN_MAX_TOOL_TURNS, RESEARCH_TURN_MAX_TOOL_TURNS)
603
+ : ctx.maxToolTurns;
352
604
  if (researchTurn && !messages.some((message) =>
353
605
  message.role === 'system' && typeof message.content === 'string'
354
606
  && message.content.startsWith('Current local date:'))
355
607
  ) {
356
608
  messages.unshift(buildResearchDateSystemMessage());
609
+ }
610
+ if (researchTurn) {
611
+ messages.unshift({
612
+ role: 'system',
613
+ content: [
614
+ '<research-answer-guidance>',
615
+ '작은 후속 작업은 추가 질문 없이 현재 턴에서 먼저 처리한다.',
616
+ '답은 결론(무엇을 찾았고 무엇을 해 두었는지)을 먼저 말하고, 근거를 짧게 덧붙인다.',
617
+ '비용·외부 노출·되돌리기 어려움이 큰 다음 단계만 그 하나를 확인한다. 그 밖에는 묻지 않는다.',
618
+ '다음 할 일 목록을 형식으로 요구하지 않는다.',
619
+ '본문은 질문이 요구한 범위만 답하고, 가정 나열과 반복 설명을 줄인다.',
620
+ '근거는 출처 링크로 짧게 붙인다.',
621
+ '질문에 필요한 만큼 읽기 좋게 설명하며, 고정 줄 수나 글자 수로 자르지 않는다.',
622
+ '</research-answer-guidance>',
623
+ ].join('\n'),
624
+ });
625
+ }
626
+ if (deepBloomDecision.apply) {
627
+ const { buildDeepBloomInstruction } = await import('./deep-turn-bloom.js');
628
+ const instruction = await buildDeepBloomInstruction(surfaceUserText ?? '', deepBloomDecision.reason);
629
+ messages.unshift({ role: 'system', content: instruction.prompt! });
630
+ debug.log('research.turn', 'deep-bloom-applied', {
631
+ sessionId: ctx.sessionId, levels: instruction.levels, trigger: instruction.reason,
632
+ questionCount: instruction.questionCount, stage: researchTurn ? 'first-answer' : 'answer',
633
+ exemplarDomain: instruction.exemplarDomain,
634
+ exemplarLevels: instruction.exemplarLevels,
635
+ });
636
+ } else if (!deepBloomDecision.apply) {
637
+ debug.log('research.turn', 'deep-bloom-skipped', {
638
+ sessionId: ctx.sessionId, reason: deepBloomDecision.reason,
639
+ });
357
640
  }
358
641
  let researchResultPromise: Promise<{ ok: boolean; output: string; error?: string } | null> | undefined;
359
- const explicitSkillToolRequest = requestsNamedSkill(surfaceUserText)
360
- && tools.some((tool) => tool.name === 'skill_exec');
642
+ let researchDeadlineSignal: AbortSignal | undefined;
643
+ let requestedSkillName: string | undefined;
644
+ if (researchTurn && surfaceUserText?.trim() && explicitSkillToolRequest) {
645
+ // Resolve a display name only for the research opening plan; ordinary
646
+ // turns and unrequested research keep the core startup lean.
647
+ requestedSkillName = requestedInstalledSkillName(surfaceUserText, installedSkillNames);
648
+ const selectedTool = firstTurnTools?.find((tool) => tool.name === 'skill_exec');
649
+ if (requestedSkillName && selectedTool) {
650
+ debug.log('research.turn', 'named-skill-route-first', {
651
+ sessionId: ctx.sessionId,
652
+ requestedSkillName,
653
+ selectedTool: selectedTool.name,
654
+ availableToolNames: firstTurnTools?.map((tool) => tool.name) ?? [],
655
+ });
656
+ }
657
+ }
658
+ if (researchTurn && surfaceUserText?.trim()) {
659
+ // `tools` is the active post-tier-flip pool; use the shared research
660
+ // allowlist order so the plan names only currently callable tools.
661
+ const availableResearchTools = RESEARCH_TOOL_ALLOWLIST
662
+ .filter((name) => tools.some((tool) => tool.name === name));
663
+ const planTools = requestedSkillName && firstTurnTools?.some((tool) => tool.name === 'skill_exec')
664
+ ? [`${requestedSkillName} (skill_exec)`]
665
+ : availableResearchTools;
666
+ const plan = planTools.length > 0
667
+ ? [
668
+ `${planTools.join(' → ')}로 질문에 나온 주제와 요구 조건의 근거를 찾습니다.`,
669
+ '출처의 주장과 제약을 비교해 확인된 사실을 가립니다.',
670
+ '확인한 결론과 짧은 근거로 답합니다.',
671
+ ].join('\n')
672
+ : [
673
+ '현재 사용할 수 있는 조사 도구가 없습니다.',
674
+ '근거를 확인할 수 없어 결론을 단정하지 않습니다.',
675
+ '도구가 활성화되면 출처를 확인해 답합니다.',
676
+ ].join('\n');
677
+ try { ctx.callbacks?.onStatus?.(plan); } catch { /* UI feedback is fail-soft. */ }
678
+ }
361
679
  if (researchTurn && surfaceUserText?.trim() && !explicitSkillToolRequest) {
362
680
  turnStartedAt = now();
363
681
  researchStartedAt = turnStartedAt;
@@ -365,17 +683,61 @@ export async function runCoreTurn(
365
683
  sessionId: ctx.sessionId,
366
684
  sinceTurnStartMs: researchStartedAt - turnStartedAt,
367
685
  });
368
- // Start evidence collection beside the first answer. The user gets an
369
- // immediate, visible status and an initial answer while research runs;
370
- // a second text-only synthesis then reconciles that answer with evidence.
371
- try { ctx.callbacks?.onStatus?.('먼저 답변을 시작하고 근거를 확인합니다.'); } catch { /* UI feedback is fail-soft. */ }
686
+ // The opening plan was already emitted above. Do not add a generic
687
+ // answer-first status that contradicts that plan; stream the provisional
688
+ // answer while evidence collection runs, then reconcile in the second pass.
689
+ const researchController = new AbortController();
690
+ researchDeadlineSignal = researchController.signal;
691
+ const abortResearchFromParent = (): void => {
692
+ if (researchStopReason !== 'wall-clock-budget') researchStopReason = 'parent-abort';
693
+ researchController.abort(ctx.signal.reason);
694
+ };
695
+ if (ctx.signal.aborted) abortResearchFromParent();
696
+ else ctx.signal.addEventListener('abort', abortResearchFromParent, { once: true });
697
+ const defaultResearchWallClockBudgetMs = deepBloomDecision.apply
698
+ ? RESEARCH_TURN_DEEP_BUDGET_MS
699
+ : RESEARCH_TURN_SHALLOW_BUDGET_MS;
700
+ const researchWallClockBudgetMs = options.researchWallClockBudgetMs ?? defaultResearchWallClockBudgetMs;
701
+ let researchDeadlineTimer: ResearchTimer | undefined;
702
+ if (!researchController.signal.aborted) {
703
+ researchDeadlineTimer = timers.setTimeout(() => {
704
+ if (researchController.signal.aborted) return;
705
+ researchStopReason = 'wall-clock-budget';
706
+ logResearchStop('wall-clock-budget', {
707
+ stage: 'research-prepass',
708
+ elapsedMs: researchStartedAt === undefined ? undefined : now() - researchStartedAt,
709
+ limitMs: researchWallClockBudgetMs,
710
+ });
711
+ researchController.abort(new Error('Research wall-clock budget reached'));
712
+ }, researchWallClockBudgetMs);
713
+ }
372
714
  researchResultPromise = (async () => {
373
715
  try {
374
- const result = await (options.runResearch ?? (async (request, signal) => {
716
+ const work = (options.runResearch ?? (async (request, signal, admitToolCall, providerRouting) => {
375
717
  // Keep the Bloom/skill pipeline out of ordinary and packaged TUI startup graphs.
376
718
  const { researchTurnForGrounding, runResearchQuestionLadder } = await import('../auto-research/research-turn.js');
377
- return researchTurnForGrounding(await runResearchQuestionLadder(request, { signal }));
378
- }))(surfaceUserText, ctx.signal);
719
+ return researchTurnForGrounding(await runResearchQuestionLadder(request, {
720
+ ...providerRouting,
721
+ signal, admitToolCall, allowPartialOnAbort: true, allowOutputSkill: false,
722
+ deadlineMs: deepBloomDecision.apply
723
+ ? RESEARCH_TURN_FINAL_ANSWER_DEADLINE_MS
724
+ : Math.min(RESEARCH_TURN_SHALLOW_FINAL_ANSWER_DEADLINE_MS, Math.max(1, researchWallClockBudgetMs - 1)),
725
+ }));
726
+ }))(surfaceUserText, researchController.signal, admitResearchToolCall, {
727
+ ...(ctx.initialProvider ? { initialProvider: ctx.initialProvider } : {}),
728
+ ...(ctx.skipProviders ? { skipProviders: ctx.skipProviders } : {}),
729
+ ...(ctx.runId ? { runId: ctx.runId } : {}),
730
+ });
731
+ const result = await work;
732
+ researchAxisCount = result?.axisCount ?? 0;
733
+ if (researchController.signal.aborted && !researchStopReason) researchStopReason = ctx.signal.aborted ? 'parent-abort' : 'research-aborted';
734
+ if (researchStopReason) logResearchStop(researchStopReason, {
735
+ stage: 'research-prepass',
736
+ elapsedMs: researchStartedAt === undefined ? undefined : now() - researchStartedAt,
737
+ });
738
+ logResearchStop(result.ok ? 'evidence-complete' : 'evidence-incomplete', {
739
+ stage: 'research-prepass', outputChars: result.output.length,
740
+ });
379
741
  debug.log('research.turn', 'tui-research-completed', {
380
742
  sessionId: ctx.sessionId,
381
743
  ok: result.ok,
@@ -385,23 +747,30 @@ export async function runCoreTurn(
385
747
  });
386
748
  return result;
387
749
  } catch (error) {
750
+ logResearchStop('research-error', { stage: 'research-prepass', error: error instanceof Error ? error.message : String(error) });
388
751
  debug.log('research.turn', 'tui-research-fallback', {
389
752
  sessionId: ctx.sessionId,
390
753
  reason: error instanceof Error ? error.message : String(error),
391
754
  elapsedMs: researchStartedAt === undefined ? undefined : now() - researchStartedAt,
392
755
  }, { level: 'warn' });
393
756
  return null;
757
+ } finally {
758
+ if (researchDeadlineTimer !== undefined) timers.clearTimeout(researchDeadlineTimer);
759
+ ctx.signal.removeEventListener('abort', abortResearchFromParent);
394
760
  }
395
761
  })();
396
762
  }
397
- const streamOptions = (turnTools: typeof tools) => ({
763
+ const streamOptions = (turnTools: typeof tools, signal: AbortSignal = ctx.signal) => ({
398
764
  tools: turnTools,
765
+ ...(firstTurnTools ? { firstTurnTools } : {}),
399
766
  researchTurn,
400
- signal: ctx.signal,
767
+ ...(firstTurnTools ? { toolChoice: { name: 'skill_exec' } } : {}),
768
+ signal,
401
769
  ...(ctx.requestSizeGuard ? { requestSizeGuard: ctx.requestSizeGuard } : {}),
770
+ ...(ctx.reasoningEffort !== undefined ? { reasoningEffort: ctx.reasoningEffort } : {}),
402
771
  toolResultInlineLimitBytes: CORE_TURN_TOOL_RESULT_INLINE_LIMIT_BYTES,
403
772
  ...(ctx.sessionId !== undefined ? { sessionId: ctx.sessionId } : {}),
404
- ...(ctx.maxToolTurns !== undefined ? { maxTurns: ctx.maxToolTurns } : {}),
773
+ ...(maxToolTurns !== undefined ? { maxTurns: maxToolTurns } : {}),
405
774
  ...(ctx.initialProvider !== undefined
406
775
  ? { initialProvider: ctx.initialProvider, ...(ctx.skipProviders ? { skipProviders: ctx.skipProviders } : {}) }
407
776
  : ctx.modelOverride !== undefined ? { model: ctx.modelOverride } : {}),
@@ -431,12 +800,34 @@ export async function runCoreTurn(
431
800
  surfaceSelectionReason: surface.selectionReason,
432
801
  activeCount: stats.activeCount,
433
802
  deferredCount: stats.deferredCount,
434
- immediateCount: stats.activeCount,
803
+ immediateCount: tools.length,
435
804
  immediate: tools.map((tool) => tool.name),
436
805
  warmPreloaded: stats.warmPreloaded,
437
806
  deferred: stats.deferredNames,
438
807
  unhydratable: stats.unhydratableNames,
439
808
  }, { compact: { arrayMax: Number.MAX_SAFE_INTEGER } });
809
+ const activeToolNames = new Set(tools.map((tool) => tool.name));
810
+ const immediateToolNames = new Set(tieredTools.map((tool) => tool.name));
811
+ const bloomToolNames = new Set(bloomFilteredTools.map((tool) => tool.name));
812
+ const excludedTools = ctx.tools
813
+ .filter((tool) => !activeToolNames.has(tool.name))
814
+ .map((tool) => ({
815
+ name: tool.name,
816
+ reason: !immediateToolNames.has(tool.name)
817
+ ? stats.deferredNames.includes(tool.name) ? 'deferred-tool-tier' : 'not-in-immediate-tier'
818
+ : !bloomToolNames.has(tool.name) ? 'deep-bloom-non-research-suppression'
819
+ : enforceResearchToolAllowlist && !isAllowedResearchTool(tool.name) ? 'research-tool-allowlist'
820
+ : 'not-active-after-turn-filtering',
821
+ }));
822
+ debug.log('capability.resolve', 'tier-split', {
823
+ sessionId: ctx.sessionId,
824
+ surfaceId: surface.id,
825
+ researchTurn,
826
+ activeTools: [...activeToolNames],
827
+ excludedTools,
828
+ deferredTools: stats.deferredNames,
829
+ unhydratableTools: stats.unhydratableNames,
830
+ }, { compact: { arrayMax: Number.MAX_SAFE_INTEGER } });
440
831
  if (stats.unhydratableCount > 0) {
441
832
  debug.log('capability.resolve', 'unhydratable-capabilities', {
442
833
  sessionId: ctx.sessionId,
@@ -447,8 +838,13 @@ export async function runCoreTurn(
447
838
 
448
839
  try {
449
840
  let provisionalTurnMessages: Parameters<NonNullable<StreamWithToolsHandlers['onTurnComplete']>>[0] | undefined;
450
- const firstPassHandlers: StreamWithToolsHandlers = researchResultPromise && handlers.onTurnComplete
451
- ? { ...handlers, onTurnComplete: (newMessages) => { provisionalTurnMessages = newMessages; } }
841
+ let firstPassTimedOut = false;
842
+ const firstPassHandlers: StreamWithToolsHandlers = researchResultPromise
843
+ ? {
844
+ ...handlers,
845
+ onText: (delta, full) => { if (!firstPassTimedOut) handlers.onText?.(delta, full); },
846
+ onTurnComplete: (newMessages) => { if (!firstPassTimedOut) provisionalTurnMessages = newMessages; },
847
+ }
452
848
  : handlers;
453
849
  const firstPassMessages = researchResultPromise
454
850
  ? [...messages, {
@@ -457,7 +853,38 @@ export async function runCoreTurn(
457
853
  }]
458
854
  : messages;
459
855
  const firstPassStartedAt = researchResultPromise ? now() : undefined;
460
- finalText = await streamLLMWithTools(firstPassMessages, firstPassHandlers, streamOptions(researchResultPromise ? [] : tools));
856
+ if (researchResultPromise && firstPassStartedAt !== undefined) {
857
+ const firstPassController = new AbortController();
858
+ const abortFirstPassFromParent = (): void => firstPassController.abort(ctx.signal.reason);
859
+ if (ctx.signal.aborted) abortFirstPassFromParent();
860
+ else ctx.signal.addEventListener('abort', abortFirstPassFromParent, { once: true });
861
+ const firstReplyBudgetMs = options.firstReplyBudgetMs ?? RESEARCH_TURN_FIRST_REPLY_BUDGET_MS;
862
+ let firstReplyTimer: ResearchTimer | undefined;
863
+ const deadline = new Promise<{ timedOut: true }>(resolve => {
864
+ firstReplyTimer = timers.setTimeout(() => resolve({ timedOut: true }), firstReplyBudgetMs);
865
+ });
866
+ try {
867
+ const firstPass = streamLLMWithTools(firstPassMessages, firstPassHandlers, streamOptions(tools, firstPassController.signal))
868
+ .then(text => ({ timedOut: false as const, text }));
869
+ const outcome = await Promise.race([firstPass, deadline]);
870
+ if (outcome.timedOut) {
871
+ firstPassTimedOut = true;
872
+ firstPassController.abort(new Error('First answer budget reached'));
873
+ logResearchStop('first-reply-budget', { stage: 'first-response', limitMs: firstReplyBudgetMs, elapsedMs: now() - firstPassStartedAt });
874
+ const partial = accumulatedText.trim();
875
+ finalText = partial || '질문을 확인하고 있습니다. 근거를 조사한 뒤 제한 시간 안에 답을 정리하겠습니다.';
876
+ if (!partial) handlers.onText?.(finalText, finalText);
877
+ provisionalTurnMessages = [{ role: 'assistant', content: finalText, phase: 'final_answer' }];
878
+ } else {
879
+ finalText = outcome.text;
880
+ }
881
+ } finally {
882
+ if (firstReplyTimer !== undefined) timers.clearTimeout(firstReplyTimer);
883
+ ctx.signal.removeEventListener('abort', abortFirstPassFromParent);
884
+ }
885
+ } else {
886
+ finalText = await streamLLMWithTools(firstPassMessages, firstPassHandlers, streamOptions(tools));
887
+ }
461
888
  if (researchResultPromise && firstPassStartedAt !== undefined) {
462
889
  debug.log('research.turn', 'first-pass-answer-ready', {
463
890
  sessionId: ctx.sessionId,
@@ -468,17 +895,29 @@ export async function runCoreTurn(
468
895
  });
469
896
  }
470
897
  if (researchResultPromise) {
471
- const racedResearch = await settleBeforeAbort(researchResultPromise, ctx.signal);
472
- if (racedResearch.aborted) {
898
+ const racedResearch = await settleBeforeAbort(researchResultPromise, researchDeadlineSignal ?? ctx.signal);
899
+ if (racedResearch.aborted && ctx.signal.aborted) {
473
900
  commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
474
901
  return { stopReason: 'aborted', finalText };
475
902
  }
476
- const result = racedResearch.value;
903
+ // A native research tool can ignore cancellation and leave its promise
904
+ // pending. The deadline must still end the prepass and enter the
905
+ // no-tools synthesis path with the provisional answer.
906
+ const result = racedResearch.aborted
907
+ ? { ok: false, output: '', error: RESEARCH_TURN_DEADLINE_STOP_ERROR }
908
+ : racedResearch.value;
477
909
  if (ctx.signal.aborted) {
478
910
  commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
479
911
  return { stopReason: 'aborted', finalText };
480
912
  }
481
- if (result?.ok && result.output.trim() && !ctx.signal.aborted) {
913
+ const forcedSynthesis = researchStopReason === 'wall-clock-budget' || researchStopReason === 'tool-budget';
914
+ const hasUsableResearch = Boolean(result?.output.trim())
915
+ && (result?.ok === true || result?.error === RESEARCH_TURN_DEADLINE_STOP_ERROR);
916
+ if (forcedSynthesis) {
917
+ logResearchStop('forced-synthesis', { stage: 'synthesis', trigger: researchStopReason, toolCalls: researchToolCallCount });
918
+ try { ctx.callbacks?.onStatus?.('조사 한도에 도달해 확인된 근거만으로 답을 정리합니다.'); } catch { /* UI feedback is fail-soft. */ }
919
+ }
920
+ if (hasUsableResearch && result && !ctx.signal.aborted) {
482
921
  try { ctx.callbacks?.onStatus?.('근거를 반영해 답변을 보강합니다.'); } catch { /* UI feedback is fail-soft. */ }
483
922
  const synthesisStartedAt = now();
484
923
  debug.log('research.turn', 'synthesis-started', {
@@ -492,9 +931,11 @@ export async function runCoreTurn(
492
931
  messages.push(
493
932
  { role: 'assistant', content: provisionalText.trim() },
494
933
  { role: 'system', content: `<bloom-research>\n${result.output.trim()}\n</bloom-research>` },
495
- { role: 'system', content: 'Revise the answer above using this research evidence. Correct any unsupported or contradicted claims, preserve uncertainty, and answer in natural prose. Do not output JSON or a tool transcript. If the evidence does not materially change the answer, state the answer directly.' },
934
+ { role: 'system', content: forcedSynthesis
935
+ ? 'The research budget has ended. Synthesize now using only the partial evidence above. State uncertainty and gaps clearly. Do not call tools or continue research.'
936
+ : 'Revise the answer above using this research evidence. Correct any unsupported or contradicted claims, preserve uncertainty, and answer in natural prose. Do not output JSON or a tool transcript. If the evidence does not materially change the answer, state the answer directly.' },
496
937
  );
497
- const synthesisTools = tools.filter(tool => !['WebSearch', 'OmniSearch'].includes(tool.name));
938
+ const synthesisTools = forcedSynthesis ? [] : tools.filter(tool => !['WebSearch', 'OmniSearch'].includes(tool.name));
498
939
  try {
499
940
  const synthesizedText = await streamLLMWithTools(messages, staged.handlers, streamOptions(synthesisTools));
500
941
  if (ctx.signal.aborted) {
@@ -509,12 +950,9 @@ export async function runCoreTurn(
509
950
  sinceTurnStartMs: turnStartedAt === undefined ? undefined : now() - turnStartedAt,
510
951
  outputChars: finalText.length,
511
952
  });
512
- if (staged.completion()) {
513
- commitStagedTurn(staged.completion(), handlers, finalText, finalText !== provisionalText,
514
- value => { finalPhaseAnswer = value; }, ctx.callbacks?.onReplaceText);
515
- } else {
516
- commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
517
- }
953
+ logResearchStop('synthesis-complete', { stage: 'synthesis', outputChars: finalText.length });
954
+ commitSynthesizedTurn(staged, provisionalTurnMessages, handlers, finalText, provisionalText,
955
+ value => { finalPhaseAnswer = value; }, ctx.callbacks?.onReplaceText);
518
956
  } catch (error) {
519
957
  commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
520
958
  const stopReason = classifyStopReason(error, ctx.signal);
@@ -529,15 +967,18 @@ export async function runCoreTurn(
529
967
  try { ctx.callbacks?.onStatus?.('근거 반영에 실패해 첫 답변을 유지합니다.'); } catch { /* UI feedback is fail-soft. */ }
530
968
  return { stopReason: 'end_turn', finalText: provisionalText, ...(handlers.onTurnComplete ? { finalPhaseAnswer } : {}) };
531
969
  }
532
- } else if (tools.some(tool => !['WebSearch', 'OmniSearch'].includes(tool.name))) {
533
- try { ctx.callbacks?.onStatus?.('근거 검색은 실패해 사용할 수 있는 도구로 답변을 마무리합니다.'); } catch { /* UI feedback is fail-soft. */ }
970
+ } else if (forcedSynthesis || tools.some(tool => !['WebSearch', 'OmniSearch'].includes(tool.name))) {
971
+ try { ctx.callbacks?.onStatus?.(forcedSynthesis ? '조사 한도에 도달해 첫 답변을 근거 없이 확장하지 않고 마무리합니다.' : '근거 검색은 실패해 사용할 수 있는 도구로 답변을 마무리합니다.'); } catch { /* UI feedback is fail-soft. */ }
534
972
  const provisionalText = finalText;
535
973
  const staged = createStagedHandlers(handlers);
536
974
  messages.push(
537
975
  { role: 'assistant', content: provisionalText.trim() },
538
- { role: 'system', content: 'Research evidence was unavailable. Continue answering the user using available non-search tools as needed. Do not invoke web search.' },
976
+ ...(result?.output.trim() ? [{ role: 'system' as const, content: `<partial-research>\n${result.output.trim()}\n</partial-research>` }] : []),
977
+ { role: 'system', content: forcedSynthesis
978
+ ? 'The research budget has ended. Synthesize now without tools. Use any partial evidence above and clearly state uncertainty; do not continue research.'
979
+ : 'Research evidence was unavailable. Continue answering the user using available non-search tools as needed. Do not invoke web search.' },
539
980
  );
540
- const fallbackTools = tools.filter(tool => !['WebSearch', 'OmniSearch'].includes(tool.name));
981
+ const fallbackTools = forcedSynthesis ? [] : tools.filter(tool => !['WebSearch', 'OmniSearch'].includes(tool.name));
541
982
  try {
542
983
  const fallbackText = await streamLLMWithTools(messages, staged.handlers, streamOptions(fallbackTools));
543
984
  if (ctx.signal.aborted) {
@@ -546,12 +987,8 @@ export async function runCoreTurn(
546
987
  }
547
988
  finalText = fallbackText || staged.text() || provisionalText;
548
989
  accumulatedText = finalText;
549
- if (staged.completion()) {
550
- commitStagedTurn(staged.completion(), handlers, finalText, finalText !== provisionalText,
551
- value => { finalPhaseAnswer = value; }, ctx.callbacks?.onReplaceText);
552
- } else {
553
- commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
554
- }
990
+ commitSynthesizedTurn(staged, provisionalTurnMessages, handlers, finalText, provisionalText,
991
+ value => { finalPhaseAnswer = value; }, ctx.callbacks?.onReplaceText);
555
992
  } catch (error) {
556
993
  commitProvisionalTurn(provisionalTurnMessages, handlers, value => { finalPhaseAnswer = value; });
557
994
  const stopReason = classifyStopReason(error, ctx.signal);