@qwen-code/qwen-code 0.20.1-preview.7215 → 0.20.1

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 (326) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +1 -1
  2. package/bundled/qc-helper/docs/features/auto-mode.md +19 -16
  3. package/bundled/qc-helper/docs/features/commands.md +54 -0
  4. package/bundled/qc-helper/docs/features/sub-agents.md +16 -7
  5. package/bundled/qc-helper/docs/integration-github-action.md +10 -10
  6. package/bundled/qc-helper/docs/qwen-serve.md +2 -1
  7. package/bundled/review/DESIGN.md +2 -2
  8. package/bundled/review/SKILL.md +4 -4
  9. package/chunks/{MaxSizedBox-EH6G5AEH.js → MaxSizedBox-4WZYPSRU.js} +40 -36
  10. package/chunks/{StandaloneSessionPicker-264A3TEA.js → StandaloneSessionPicker-PE4JAIFA.js} +58 -54
  11. package/chunks/{acpAgent-6RBIJFDI.js → acpAgent-BVIKGJ2C.js} +1503 -520
  12. package/chunks/{agent-QURXGAA3.js → agent-DHLFAOUV.js} +36 -32
  13. package/chunks/{agent-headless-CRGX4ICQ.js → agent-headless-ZP5WTNXZ.js} +36 -32
  14. package/chunks/{anthropicContentGenerator-BWBAZGTW.js → anthropicContentGenerator-NMSS7IMV.js} +11 -11
  15. package/chunks/{artifact-tool-IUJ7QWCX.js → artifact-tool-56T5IMBP.js} +3 -3
  16. package/chunks/{askUserQuestion-IUMUUTDQ.js → askUserQuestion-E25OBIC2.js} +3 -3
  17. package/chunks/{bridge-MNFVKPMI.js → bridge-XAK7JKMD.js} +41 -37
  18. package/chunks/{build-SSCNEHZZ.js → build-GHIZ4MSZ.js} +1 -1
  19. package/chunks/{ca-2SL2BXTK.js → ca-N6VVUFVB.js} +611 -201
  20. package/chunks/{channel-worker-group-53CMOPFT.js → channel-worker-group-LFBT7K64.js} +5 -5
  21. package/chunks/{channel-worker-manager-UTXILKC2.js → channel-worker-manager-3RUPERG2.js} +5 -5
  22. package/chunks/{channel-worker-supervisor-ZGO2W2MD.js → channel-worker-supervisor-A3KVATD3.js} +4 -4
  23. package/chunks/{chunk-IUSNI6IX.js → chunk-27CLX4FV.js} +1 -1
  24. package/chunks/{chunk-2HOVDT7W.js → chunk-2LI23QA6.js} +1 -1
  25. package/chunks/chunk-2RFKHEXL.js +74 -0
  26. package/chunks/{chunk-LZYWWWCZ.js → chunk-3KQSDUK3.js} +3 -3
  27. package/chunks/{chunk-NOWTNYC7.js → chunk-3LH5Q2AR.js} +8 -8
  28. package/chunks/{chunk-IB35C3IL.js → chunk-3SXF4GMQ.js} +1 -1
  29. package/chunks/chunk-43T5WDQ7.js +127 -0
  30. package/chunks/{chunk-KXEGCGUG.js → chunk-4BRH6FP5.js} +31 -6
  31. package/chunks/{chunk-TTSKHF43.js → chunk-4DSBFQMI.js} +2 -2
  32. package/chunks/{chunk-JD3MKVKL.js → chunk-4K56OJFJ.js} +1 -1
  33. package/chunks/{chunk-KTUQMDEP.js → chunk-4K7VDKAD.js} +1 -1
  34. package/chunks/{chunk-QKYTTBYW.js → chunk-4LVZNIDO.js} +1 -1
  35. package/chunks/{chunk-OF2BBLYQ.js → chunk-52T5UHAZ.js} +2 -2
  36. package/chunks/{chunk-ZEOZL37W.js → chunk-57FIIFJN.js} +1 -1
  37. package/chunks/{chunk-WAX3ITOA.js → chunk-5EA5NVXS.js} +1 -1
  38. package/chunks/chunk-5G2SK2OO.js +20600 -0
  39. package/chunks/{chunk-6EFTQYW7.js → chunk-5I5BM454.js} +1 -1
  40. package/chunks/{chunk-GMGDLUC7.js → chunk-6IL7KRLE.js} +1 -1
  41. package/chunks/{chunk-26LLB6FM.js → chunk-6NHK6HS7.js} +2 -2
  42. package/chunks/{chunk-FVS747N7.js → chunk-6PRNSLMB.js} +11 -6
  43. package/chunks/chunk-6PVPNMXU.js +29 -0
  44. package/chunks/{chunk-BDBMYST4.js → chunk-6X4GWOPW.js} +1 -1
  45. package/chunks/{chunk-4ODB7WIB.js → chunk-6ZBPS62S.js} +1 -1
  46. package/chunks/{chunk-E5GIFWE3.js → chunk-766HLFAG.js} +54 -33
  47. package/chunks/{chunk-SDXIH6OA.js → chunk-76OFFG6L.js} +137 -5
  48. package/chunks/{chunk-ANHT55MR.js → chunk-7LH6CHKG.js} +1 -1
  49. package/chunks/{chunk-Y4CRUWFZ.js → chunk-7NDXG4MB.js} +60 -35
  50. package/chunks/{chunk-KPZNOZPC.js → chunk-7SWFAKVH.js} +22 -22
  51. package/chunks/{chunk-AYCDXHZB.js → chunk-7Z6JQEL6.js} +1 -1
  52. package/chunks/{chunk-5NWV4NFB.js → chunk-AZD6KAV7.js} +3 -3
  53. package/chunks/{chunk-7YBZGNEC.js → chunk-BKZEHVPV.js} +176 -168
  54. package/chunks/{chunk-WXAXH7IJ.js → chunk-BWQRDISK.js} +1 -1
  55. package/chunks/{chunk-X4CGDBKA.js → chunk-BZAEENUV.js} +3 -3
  56. package/chunks/{chunk-BF32GYSY.js → chunk-CHXKGIMK.js} +1 -1
  57. package/chunks/{chunk-4SLLEAQP.js → chunk-D53NR4GO.js} +562 -301
  58. package/chunks/{chunk-FLTN6NRU.js → chunk-D6ZOVZLF.js} +5 -1
  59. package/chunks/{chunk-NBMIC7DR.js → chunk-D7WXIW7H.js} +4 -4
  60. package/chunks/{chunk-MKLKHZAK.js → chunk-DPRMI6NU.js} +1 -1
  61. package/chunks/{chunk-AR27OPIU.js → chunk-DRIXALGM.js} +2 -2
  62. package/chunks/{chunk-5SCI6E3E.js → chunk-E4IMU4Y5.js} +1 -1
  63. package/chunks/{chunk-Z5Q65RVH.js → chunk-EC2ET5ZZ.js} +1 -1
  64. package/chunks/{chunk-B453NMZJ.js → chunk-EFIOE2EH.js} +3 -3
  65. package/chunks/{chunk-OKWRU4NO.js → chunk-EWXXMRMP.js} +3 -3
  66. package/chunks/{chunk-NEEB7UEN.js → chunk-FFFM6NJV.js} +1 -2
  67. package/chunks/{chunk-JVTCARQ6.js → chunk-G6LRTI62.js} +4 -4
  68. package/chunks/{chunk-6OH6A5EX.js → chunk-GEB2CGUV.js} +20262 -17752
  69. package/chunks/{chunk-OONJNQ42.js → chunk-GPSKDNEE.js} +3 -3
  70. package/chunks/{chunk-FNGK2Z5B.js → chunk-H4AR2JQF.js} +3 -3
  71. package/chunks/chunk-HTR4WV6U.js +327 -0
  72. package/chunks/chunk-IS2SBY6T.js +2256 -0
  73. package/chunks/{chunk-G45X5TRN.js → chunk-JCW2R7WC.js} +1 -72
  74. package/chunks/{chunk-6GUTHAN7.js → chunk-JHFVJQRO.js} +1 -1
  75. package/chunks/{chunk-IE4JSQ5L.js → chunk-JIBBZH37.js} +27 -23
  76. package/chunks/{chunk-UJEZQ562.js → chunk-JJEFX6U5.js} +3 -3
  77. package/chunks/{chunk-QOK6RMIP.js → chunk-JKFHJK5U.js} +4 -4
  78. package/chunks/{chunk-GA7VRJVN.js → chunk-JO7FGOSY.js} +5 -5
  79. package/chunks/{chunk-WOT64EP2.js → chunk-JTUAAVUT.js} +2 -2
  80. package/chunks/{chunk-MAQQGNQ5.js → chunk-JYS55H6Z.js} +66 -7
  81. package/chunks/{chunk-DA7OOKVN.js → chunk-KDPIV6WC.js} +29 -2
  82. package/chunks/{chunk-EIAK6Q2B.js → chunk-KHOVYUHX.js} +2 -2
  83. package/chunks/{chunk-OLMETXLX.js → chunk-KQQ757OQ.js} +2 -2
  84. package/chunks/{chunk-Z6UEAQTP.js → chunk-KSZZBDVD.js} +165 -48
  85. package/chunks/chunk-KWK7UE6L.js +6194 -0
  86. package/chunks/{chunk-OOCI5VVU.js → chunk-LIZRAKPB.js} +1 -1
  87. package/chunks/{chunk-VFAE4AGH.js → chunk-LPMBFOWH.js} +73 -68
  88. package/chunks/{chunk-IKP5DXZY.js → chunk-LYEKAAEH.js} +5 -5
  89. package/chunks/chunk-M7WBGLYP.js +151 -0
  90. package/chunks/{chunk-P2YAOGJD.js → chunk-MTSYH4MB.js} +3 -3
  91. package/chunks/{chunk-WKRXIHD6.js → chunk-N5ARKAVE.js} +8 -8
  92. package/chunks/chunk-NABLFI57.js +82 -0
  93. package/chunks/{chunk-CVDW42JT.js → chunk-NNFK277W.js} +1 -1
  94. package/chunks/{chunk-467G3SV5.js → chunk-NPQDJGKU.js} +1 -1
  95. package/chunks/chunk-OQ5SYCPE.js +10017 -0
  96. package/chunks/{chunk-C27BYUX6.js → chunk-OQB4EXO4.js} +14 -11
  97. package/chunks/{chunk-RELYEO3R.js → chunk-OUDZVU7H.js} +242 -1607
  98. package/chunks/{chunk-3EUZWNWA.js → chunk-PBED7USE.js} +1 -1
  99. package/chunks/{chunk-WBTZGWQ6.js → chunk-PIHKWN7M.js} +1 -1
  100. package/chunks/{chunk-XNP57UDV.js → chunk-PPIHLGNE.js} +2 -2
  101. package/chunks/{chunk-Q4RBU7WX.js → chunk-PSVSP2OS.js} +6 -6
  102. package/chunks/{chunk-BRXIO5WY.js → chunk-Q2V2ADXF.js} +7 -7
  103. package/chunks/{chunk-JDI67JFB.js → chunk-Q2YKNMLS.js} +3 -3
  104. package/chunks/{chunk-BAIEQKR5.js → chunk-Q3GGJDYN.js} +5 -5
  105. package/chunks/{chunk-PBATSWUQ.js → chunk-QBUDF33N.js} +1 -1
  106. package/chunks/{chunk-OMH3276Y.js → chunk-QD6BRERJ.js} +7 -7
  107. package/chunks/{chunk-Y2ENGUD6.js → chunk-QKTHJXCS.js} +1 -1
  108. package/chunks/{chunk-BVLROR2T.js → chunk-QLJUC7TG.js} +1 -1
  109. package/chunks/{chunk-UEY4AYUL.js → chunk-QNLNLENL.js} +2 -2
  110. package/chunks/{chunk-7KDI2IB2.js → chunk-QSJ6JIF5.js} +4 -4
  111. package/chunks/{chunk-Q3ZBFXK4.js → chunk-QUHJRRUA.js} +126 -30
  112. package/chunks/{chunk-N6YTEVLV.js → chunk-R3BCL5XW.js} +10 -4
  113. package/chunks/{chunk-EVSTCA7S.js → chunk-R7MPKABX.js} +307 -86
  114. package/chunks/{chunk-RFIAR4YL.js → chunk-RV4C2ZFG.js} +1 -1
  115. package/chunks/{chunk-NIJEXGV6.js → chunk-RVLZCXEE.js} +79 -10
  116. package/chunks/{chunk-T7DDD7CZ.js → chunk-RYSMKY43.js} +4 -4
  117. package/chunks/{chunk-MC2DOZS7.js → chunk-S3YQCNJE.js} +3 -3
  118. package/chunks/{chunk-4WUAQ2DO.js → chunk-SP32MK6J.js} +2 -2
  119. package/chunks/{chunk-JNWZQ27S.js → chunk-SP5WRGVG.js} +3 -3
  120. package/chunks/{chunk-FSL5W5TI.js → chunk-T2L47JJK.js} +3 -3
  121. package/chunks/{chunk-TB6UDU4T.js → chunk-THJNPLI4.js} +16 -16
  122. package/chunks/{chunk-TCKTNY66.js → chunk-TPR35HHZ.js} +6 -6
  123. package/chunks/{chunk-UQES76OO.js → chunk-TXRKCFWS.js} +6 -6
  124. package/chunks/chunk-U7ZFW55U.js +2098 -0
  125. package/chunks/{chunk-W7H223ZZ.js → chunk-UGYMA4EI.js} +1 -1
  126. package/chunks/{chunk-X6YQWCIJ.js → chunk-UH3WSE5L.js} +13 -1
  127. package/chunks/{chunk-R3VWUU2E.js → chunk-VYPFXUCB.js} +1 -1
  128. package/chunks/{chunk-2DXOIVUI.js → chunk-WCFTQD7H.js} +11 -11
  129. package/chunks/chunk-WHGVTP7Q.js +1049 -0
  130. package/chunks/{chunk-PWVTCGBP.js → chunk-WML6JOGQ.js} +31 -19
  131. package/chunks/{chunk-D2VIDMVM.js → chunk-X6N25LXS.js} +2 -2
  132. package/chunks/{chunk-Z5R4JMOL.js → chunk-X7XWGRDT.js} +4 -4
  133. package/chunks/chunk-XHATNRQA.js +1500 -0
  134. package/chunks/{chunk-V25Z5UUB.js → chunk-Y2DAH52F.js} +7 -6
  135. package/chunks/{chunk-S35ZDXOS.js → chunk-YM3SZTH4.js} +2 -1
  136. package/chunks/{chunk-GKY2OJ7R.js → chunk-ZHERRXZJ.js} +1 -1
  137. package/chunks/{computer-use-R7KA6UJ6.js → computer-use-MV4K6WJM.js} +41 -37
  138. package/chunks/{config-utils-6FXFJUYB.js → config-utils-WYUQ7II4.js} +3 -3
  139. package/chunks/{contextCommand-KAQQPHZ4.js → contextCommand-TQD36VNX.js} +38 -34
  140. package/chunks/{create-sub-session-X5RVIHCK.js → create-sub-session-AZ77LBL3.js} +3 -3
  141. package/chunks/{create-sub-session-TDPDBU4K.js → create-sub-session-JOW4BKMC.js} +36 -32
  142. package/chunks/{cron-create-AC5FFLN7.js → cron-create-KTWJM7QT.js} +5 -5
  143. package/chunks/{cron-delete-JEB3FAHA.js → cron-delete-2P3I5ULL.js} +5 -5
  144. package/chunks/{cron-list-NBYPCNIB.js → cron-list-PXDPGEDQ.js} +5 -5
  145. package/chunks/{daemon-RG2MAI6T.js → daemon-KLPTQIE4.js} +138 -81
  146. package/chunks/daemon-status-provider-TII4SMCZ.js +81 -0
  147. package/chunks/{de-I7ZIYXZC.js → de-4IBXM7CN.js} +5 -1
  148. package/chunks/{dist-2BHAYBKP.js → dist-HMU6CYS4.js} +2 -2
  149. package/chunks/{dist-AU7NQQRP.js → dist-OAV7LJGJ.js} +1 -1
  150. package/chunks/{dist-FUTEXY6A.js → dist-OMW6WDEO.js} +1 -1
  151. package/chunks/{dist-2MIU4UUH.js → dist-PJLG2XYX.js} +1 -1
  152. package/chunks/{dist-53PZYC5B.js → dist-UIFWIFRO.js} +2 -2
  153. package/chunks/{dist-WGTQO7F2.js → dist-XRYV6TJP.js} +65 -25
  154. package/chunks/{earlyInputCapture-WC7RI5HV.js → earlyInputCapture-2V57RG6H.js} +37 -33
  155. package/chunks/{edit-6MHKCJCM.js → edit-TTUH7PWR.js} +43 -41
  156. package/chunks/{en-XE34GKAA.js → en-USMCCJAJ.js} +5 -1
  157. package/chunks/{enter-worktree-O7VJ2E7A.js → enter-worktree-D4IVCXYB.js} +41 -37
  158. package/chunks/{enterPlanMode-5XYAALIO.js → enterPlanMode-WRUJTVYN.js} +47 -38
  159. package/chunks/{environment-LSKFNLBU.js → environment-SEPKXB2C.js} +38 -34
  160. package/chunks/{errors-ZFVCY6HG.js → errors-YSVGBLBU.js} +38 -34
  161. package/chunks/{exit-worktree-MYIK66T7.js → exit-worktree-MZ4JSSP6.js} +41 -37
  162. package/chunks/{exitPlanMode-7MBNU76O.js → exitPlanMode-HAZLSSOJ.js} +41 -37
  163. package/chunks/{fast-path-RNLIB64C.js → fast-path-EVBVIE2U.js} +4 -3
  164. package/chunks/{fast-path-settings-DAOVFADC.js → fast-path-settings-XB3CPUJT.js} +2 -2
  165. package/chunks/{fr-X7KDVZIY.js → fr-WVHEBDDB.js} +5 -1
  166. package/chunks/{gemini-WK5ISEAQ.js → gemini-APQ76464.js} +100 -95
  167. package/chunks/{geminiContentGenerator-NUJQBZBW.js → geminiContentGenerator-LB4MA2LI.js} +5 -5
  168. package/chunks/{getMachineId-bsd-EXV7SWPA.js → getMachineId-bsd-QFVLPUPT.js} +1 -1
  169. package/chunks/{getMachineId-darwin-IUOMFXU3.js → getMachineId-darwin-DGMQQE2E.js} +1 -1
  170. package/chunks/{getMachineId-linux-K7XJYFHL.js → getMachineId-linux-R4Z6CSWC.js} +1 -1
  171. package/chunks/{getMachineId-unsupported-EA5FDRJ6.js → getMachineId-unsupported-Z3SBVBUV.js} +1 -1
  172. package/chunks/{getMachineId-win-KBA6RAI5.js → getMachineId-win-SCK5UFDT.js} +1 -1
  173. package/chunks/{glob-7P6RYY4L.js → glob-LABYMYKG.js} +43 -39
  174. package/chunks/{grep-V3QHNP2J.js → grep-HKIKJCAS.js} +43 -39
  175. package/chunks/{handleAutoUpdate-AAQ6PL3E.js → handleAutoUpdate-RWAAL2UM.js} +40 -36
  176. package/chunks/{i18n-B7IO7WQT.js → i18n-ZUVDAJIJ.js} +37 -33
  177. package/chunks/{initializer-E5TIC3CW.js → initializer-7YUHIC36.js} +43 -39
  178. package/chunks/{installationInfo-XLPNAISK.js → installationInfo-DVEOMWDE.js} +39 -33
  179. package/chunks/{ja-2ICT3KXF.js → ja-KY4ROZTE.js} +5 -1
  180. package/chunks/{keychain-token-storage-DWRJMNH3.js → keychain-token-storage-6ACJDYIB.js} +3 -3
  181. package/chunks/list-WHCZSIR2.js +82 -0
  182. package/chunks/{loadedSettingsAdapter-X5BSC6CE.js → loadedSettingsAdapter-YCWN6AK3.js} +42 -38
  183. package/chunks/{loop-wakeup-HMHCT5GU.js → loop-wakeup-RNMRVA66.js} +6 -6
  184. package/chunks/{ls-IW5HYDG4.js → ls-J2ZI5XYK.js} +5 -5
  185. package/chunks/{lsp-4RL52YIZ.js → lsp-UMS3NUB5.js} +3 -3
  186. package/chunks/managed-npm-update-PG3463CJ.js +333 -0
  187. package/chunks/{mcp-4C4HWXAR.js → mcp-VLHDCKAN.js} +42 -38
  188. package/chunks/{monitor-3CJDNZB2.js → monitor-GG4F4YM6.js} +41 -37
  189. package/chunks/nonInteractiveCli-UYXYV4YX.js +133 -0
  190. package/chunks/{notebook-edit-MX366HCT.js → notebook-edit-US4VLN6Q.js} +44 -42
  191. package/chunks/{openaiContentGenerator-KRPNNJGZ.js → openaiContentGenerator-CVEDTMDB.js} +20 -18
  192. package/chunks/{pidfile-K7T2JLUJ.js → pidfile-QQ45OIOY.js} +37 -33
  193. package/chunks/{processUtils-YXL3VIBR.js → processUtils-3WMHLQE5.js} +2 -2
  194. package/chunks/{pt-JJ4XPIBP.js → pt-OK455PLH.js} +5 -1
  195. package/chunks/{qwenContentGenerator-GJVXFZ3U.js → qwenContentGenerator-Y2GRNYZQ.js} +42 -38
  196. package/chunks/{qwenOAuth2-UZTIBQLY.js → qwenOAuth2-J2X6E5VO.js} +18 -16
  197. package/chunks/{read-file-S5XQSYOW.js → read-file-C7Z266CU.js} +13 -11
  198. package/chunks/{read-mcp-resource-OIBCNIX7.js → read-mcp-resource-F6HYMDUY.js} +3 -3
  199. package/chunks/{record-artifact-HDMK4LHG.js → record-artifact-7GCFLDD7.js} +3 -3
  200. package/chunks/{resumeHistoryUtils-IKR6XD2S.js → resumeHistoryUtils-KBQWX77U.js} +43 -39
  201. package/chunks/{ripGrep-H65GRSQX.js → ripGrep-RW26MTQ3.js} +36 -32
  202. package/chunks/{ru-STR4KTW7.js → ru-7SPDGMGD.js} +5 -1
  203. package/chunks/{run-qwen-serve-7SKAQOAA.js → run-qwen-serve-MXFMOMEL.js} +104 -82
  204. package/chunks/{runtime-I2STBGPR.js → runtime-APNO3V6D.js} +48 -42
  205. package/chunks/{scheduler-6F7HETNO.js → scheduler-L6FYCGVO.js} +36 -32
  206. package/chunks/sdk-exporters-grpc-ETLH47EP.js +23214 -0
  207. package/chunks/sdk-exporters-http-IDGLRBGP.js +563 -0
  208. package/chunks/sdk-impl-5ESZBGJQ.js +9186 -0
  209. package/chunks/{send-message-WXVVK4DB.js → send-message-PYIJ2PZL.js} +6 -4
  210. package/chunks/{serve-4ATEWSEA.js → serve-6QBXDVWT.js} +42 -38
  211. package/chunks/{server-YPUPFV2O.js → server-5TJJEMVQ.js} +1006 -305
  212. package/chunks/{session-AZFIERIY.js → session-BWEUHKQB.js} +92 -176
  213. package/chunks/{settings-EFQHLTM3.js → settings-O7IUQNRR.js} +45 -41
  214. package/chunks/{shell-FWXWBJ4Q.js → shell-R5L4NQYY.js} +36 -32
  215. package/chunks/{skill-A634MNCD.js → skill-ITEOSNW6.js} +24 -20
  216. package/chunks/{spawnChannel-KKBGGR47.js → spawnChannel-E7NTWSGW.js} +38 -34
  217. package/chunks/{src-BVROLD6N.js → src-FFXGUTNL.js} +303 -237
  218. package/chunks/{standalone-update-ERLA3BDC.js → standalone-update-JCJOXW4P.js} +38 -34
  219. package/chunks/{startInteractiveUI-3VZ23WAY.js → startInteractiveUI-IJSBLZFO.js} +1057 -864
  220. package/chunks/{syntheticOutput-HCUFXSIA.js → syntheticOutput-H7RTI5KL.js} +4 -4
  221. package/chunks/{task-create-RIY5JTFC.js → task-create-7474AJJD.js} +10 -8
  222. package/chunks/{task-list-XBUCV3CO.js → task-list-633HGOIB.js} +6 -6
  223. package/chunks/{task-stop-QDFCCYR5.js → task-stop-MNUGHPIA.js} +3 -3
  224. package/chunks/{task-update-7PXKJQOI.js → task-update-66GQB5LI.js} +10 -8
  225. package/chunks/{team-create-ZZO7QFQ7.js → team-create-OVSZTJZO.js} +44 -40
  226. package/chunks/{team-delete-TNSSE2S5.js → team-delete-BB3CG3QF.js} +6 -6
  227. package/chunks/{team-plan-approval-3BZBJ46K.js → team-plan-approval-SLEVDLT5.js} +41 -37
  228. package/chunks/{theme-manager-FSFWNXFJ.js → theme-manager-V6ZQISHM.js} +37 -33
  229. package/chunks/{todoWrite-OMAIGB6V.js → todoWrite-KRAUN54W.js} +5 -5
  230. package/chunks/{tool-search-VYXAAIDW.js → tool-search-KYIF6C6E.js} +21 -17
  231. package/chunks/{total-session-admission-PSMLQICS.js → total-session-admission-EU77XTL7.js} +42 -38
  232. package/chunks/{trustedFolders-QA3RK2NV.js → trustedFolders-DDEF3ADH.js} +37 -33
  233. package/chunks/{update-relaunch-LNLZFX3J.js → update-relaunch-XEZTDP6K.js} +17 -17
  234. package/chunks/updateCheck-KZ5LZ545.js +89 -0
  235. package/chunks/{useAutoAcceptIndicator-DIWN27LT.js → useAutoAcceptIndicator-47EZERGQ.js} +47 -43
  236. package/chunks/{validateNonInterActiveAuth-LOEOFCAF.js → validateNonInterActiveAuth-J2DM4LWZ.js} +79 -75
  237. package/chunks/{version-HBF2VBLE.js → version-PN7WYXHP.js} +1 -1
  238. package/chunks/{web-fetch-BWGSD2BD.js → web-fetch-WRI5QRFR.js} +100 -42
  239. package/chunks/{web-search-OOHTCVR3.js → web-search-2HCXNAVX.js} +111 -60
  240. package/chunks/{workflow-LJAJBOR4.js → workflow-U5XBPGQZ.js} +48 -43
  241. package/chunks/workspace-providers-status-2T54GIJZ.js +79 -0
  242. package/chunks/{workspace-registration-store-4EHGQW4Y.js → workspace-registration-store-F3V4KBIW.js} +8 -2
  243. package/chunks/{workspace-registry-BKD7VC4Y.js → workspace-registry-U6QVZ5BU.js} +42 -38
  244. package/chunks/{workspace-service-75RHX6KR.js → workspace-service-734D36QD.js} +49 -45
  245. package/chunks/{workspace-skills-status-WBZBZI6A.js → workspace-skills-status-5ABUKOAQ.js} +43 -39
  246. package/chunks/write-file-CIH4I4CS.js +66 -0
  247. package/chunks/{zh-TW-4RR3YHNN.js → zh-TW-BM47YBFH.js} +5 -1
  248. package/chunks/{zh-6ANG2HTL.js → zh-WY5DWYZD.js} +5 -1
  249. package/cli-entry.js +164 -12
  250. package/cli.js +18 -11
  251. package/locales/ca.js +772 -203
  252. package/locales/de.js +8 -2
  253. package/locales/en.js +8 -2
  254. package/locales/fr.js +8 -2
  255. package/locales/ja.js +8 -2
  256. package/locales/pt.js +8 -2
  257. package/locales/ru.js +8 -2
  258. package/locales/zh-TW.js +8 -2
  259. package/locales/zh.js +8 -2
  260. package/package.json +3 -3
  261. package/web-shell/assets/{arc-Buk1besA.js → arc-ByltRugA.js} +1 -1
  262. package/web-shell/assets/{architectureDiagram-3BPJPVTR-B1aUKYDC.js → architectureDiagram-3BPJPVTR-CCRTto5d.js} +1 -1
  263. package/web-shell/assets/{blockDiagram-GPEHLZMM-CRTdg3Zx.js → blockDiagram-GPEHLZMM-Jfy36u1L.js} +1 -1
  264. package/web-shell/assets/{c4Diagram-AAUBKEIU-DFdRMp5g.js → c4Diagram-AAUBKEIU-4d5FfEZ0.js} +1 -1
  265. package/web-shell/assets/channel-4N2UIFcG.js +1 -0
  266. package/web-shell/assets/{chunk-2J33WTMH-4rYQdkEI.js → chunk-2J33WTMH-BPwxCEro.js} +1 -1
  267. package/web-shell/assets/{chunk-4BX2VUAB-Coi-pQJy.js → chunk-4BX2VUAB-jY7ZmJWY.js} +1 -1
  268. package/web-shell/assets/{chunk-55IACEB6-BtBjz02t.js → chunk-55IACEB6-C98HgCsS.js} +1 -1
  269. package/web-shell/assets/{chunk-727SXJPM-CGYOWorl.js → chunk-727SXJPM-cDu-ge-q.js} +1 -1
  270. package/web-shell/assets/{chunk-AQP2D5EJ-CH5AKhqx.js → chunk-AQP2D5EJ-BKdJwxXK.js} +1 -1
  271. package/web-shell/assets/{chunk-FMBD7UC4-Cd50-w85.js → chunk-FMBD7UC4-DnuxqwMu.js} +1 -1
  272. package/web-shell/assets/{chunk-ND2GUHAM-C2wF3KCK.js → chunk-ND2GUHAM-C4fZNPv0.js} +1 -1
  273. package/web-shell/assets/{chunk-QZHKN3VN-pCeRTaWi.js → chunk-QZHKN3VN-Cf4XWOmz.js} +1 -1
  274. package/web-shell/assets/classDiagram-4FO5ZUOK-Q4dYOtsh.js +1 -0
  275. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Q4dYOtsh.js +1 -0
  276. package/web-shell/assets/{cose-bilkent-S5V4N54A-B-_fAB6D.js → cose-bilkent-S5V4N54A-C82mFiqj.js} +1 -1
  277. package/web-shell/assets/{dagre-BM42HDAG-ChSPNHpL.js → dagre-BM42HDAG-Df8KACER.js} +1 -1
  278. package/web-shell/assets/{diagram-2AECGRRQ-BX7cFOF3.js → diagram-2AECGRRQ-EzNs7s_2.js} +1 -1
  279. package/web-shell/assets/{diagram-5GNKFQAL-BQUTW92n.js → diagram-5GNKFQAL-BRLNvreg.js} +1 -1
  280. package/web-shell/assets/{diagram-KO2AKTUF-BkYPh3e4.js → diagram-KO2AKTUF-2HLYHRjC.js} +1 -1
  281. package/web-shell/assets/{diagram-LMA3HP47-Cl6jsNyx.js → diagram-LMA3HP47-DeH0NzSp.js} +1 -1
  282. package/web-shell/assets/{diagram-OG6HWLK6-DRWoHz8n.js → diagram-OG6HWLK6-k5Gn47-G.js} +1 -1
  283. package/web-shell/assets/{erDiagram-TEJ5UH35-CGvFcZco.js → erDiagram-TEJ5UH35-gPHFo79f.js} +1 -1
  284. package/web-shell/assets/{flowDiagram-I6XJVG4X-vms6oVdv.js → flowDiagram-I6XJVG4X-DYBOiTRW.js} +1 -1
  285. package/web-shell/assets/{ganttDiagram-6RSMTGT7-ukT_sfmi.js → ganttDiagram-6RSMTGT7-cxjAuic9.js} +1 -1
  286. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Bn2ZE2Ut.js → gitGraphDiagram-PVQCEYII-3nPqpmCP.js} +1 -1
  287. package/web-shell/assets/index-B7jzUZ_s.css +5 -0
  288. package/web-shell/assets/{index-wFXp7W68.js → index-Cl8d-1bK.js} +1 -1
  289. package/web-shell/assets/index-gE8OWwj_.js +1197 -0
  290. package/web-shell/assets/{infoDiagram-5YYISTIA-DHJdSi7x.js → infoDiagram-5YYISTIA-Dph21pR5.js} +1 -1
  291. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-DOvd2Wph.js → ishikawaDiagram-YF4QCWOH-Cjg1hSaG.js} +1 -1
  292. package/web-shell/assets/{journeyDiagram-JHISSGLW-CH_urMCT.js → journeyDiagram-JHISSGLW-CR-IzvnU.js} +1 -1
  293. package/web-shell/assets/{kanban-definition-UN3LZRKU-FKiBdgbH.js → kanban-definition-UN3LZRKU-BYmuybuC.js} +1 -1
  294. package/web-shell/assets/{linear-0ZVQFVKf.js → linear-CngEEoy8.js} +1 -1
  295. package/web-shell/assets/{mermaid.core-DJ05ZZIK.js → mermaid.core-G6fbZRPf.js} +5 -5
  296. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BPuUhkUm.js → mindmap-definition-RKZ34NQL-BtnqnUwJ.js} +1 -1
  297. package/web-shell/assets/{pieDiagram-4H26LBE5-yLFKcXyG.js → pieDiagram-4H26LBE5-XTq6UHIA.js} +1 -1
  298. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-irWqc1pE.js → quadrantDiagram-W4KKPZXB-D1J5PrsS.js} +1 -1
  299. package/web-shell/assets/{requirementDiagram-4Y6WPE33-B_4uMoIV.js → requirementDiagram-4Y6WPE33-CLcBUy3t.js} +1 -1
  300. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-ciA4GPwk.js → sankeyDiagram-5OEKKPKP-iwKV02_6.js} +1 -1
  301. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CRdZvy0U.js → sequenceDiagram-3UESZ5HK-7NFYQcEX.js} +1 -1
  302. package/web-shell/assets/{stateDiagram-AJRCARHV-DaYIkCCn.js → stateDiagram-AJRCARHV-Bvm4Wih6.js} +1 -1
  303. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-xXU_zO2Z.js +1 -0
  304. package/web-shell/assets/{timeline-definition-PNZ67QCA-oBUKv6iH.js → timeline-definition-PNZ67QCA-B4FZFE9O.js} +1 -1
  305. package/web-shell/assets/{vennDiagram-CIIHVFJN-CGW9Sdmb.js → vennDiagram-CIIHVFJN-CvMBpmtL.js} +1 -1
  306. package/web-shell/assets/{wardley-L42UT6IY-CvwKJOCm.js → wardley-L42UT6IY-E3ag2327.js} +1 -1
  307. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-Ipc260sN.js → wardleyDiagram-YWT4CUSO-BEXWlgxC.js} +1 -1
  308. package/web-shell/assets/{xychartDiagram-2RQKCTM6-D6-CM7pK.js → xychartDiagram-2RQKCTM6-CICK05gI.js} +1 -1
  309. package/web-shell/index.html +2 -2
  310. package/chunks/chunk-ETD6K42I.js +0 -358
  311. package/chunks/chunk-I5NLVPZJ.js +0 -45
  312. package/chunks/chunk-ONWW74X6.js +0 -74639
  313. package/chunks/chunk-W7FJ3N32.js +0 -49
  314. package/chunks/daemon-status-provider-LVTVJGAD.js +0 -77
  315. package/chunks/list-3CZR5I42.js +0 -78
  316. package/chunks/nonInteractiveCli-QTEHDDFH.js +0 -129
  317. package/chunks/updateCheck-JJEUQ54U.js +0 -73
  318. package/chunks/workspace-providers-status-FYV7TTHA.js +0 -75
  319. package/chunks/write-file-M2DTFILF.js +0 -599
  320. package/web-shell/assets/channel-04R0vLbG.js +0 -1
  321. package/web-shell/assets/classDiagram-4FO5ZUOK-Bw9SOwAV.js +0 -1
  322. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-Bw9SOwAV.js +0 -1
  323. package/web-shell/assets/index-DgkKrjw3.js +0 -1187
  324. package/web-shell/assets/index-Rv6mOAN9.css +0 -5
  325. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DWBoO4UY.js +0 -1
  326. package/chunks/{chunk-PEJWA3QQ.js → chunk-QZJY47IE.js} +5 -5
@@ -1,5 +1,8 @@
1
1
  // Force strict mode and setup for ESM
2
2
  "use strict";
3
+ import {
4
+ recomputeMcpGating
5
+ } from "./chunk-JO7FGOSY.js";
3
6
  import {
4
7
  classifyApiError
5
8
  } from "./chunk-V7RNNPGC.js";
@@ -12,42 +15,49 @@ import {
12
15
  matchMcpServerByRef,
13
16
  parseExtensionRef,
14
17
  parseMcpServerRef
15
- } from "./chunk-Z5R4JMOL.js";
18
+ } from "./chunk-X7XWGRDT.js";
16
19
  import {
17
20
  getAvailableCommands,
18
21
  handleSlashCommand,
19
22
  insertAfterFunctionResponses,
20
23
  isSlashCommand,
21
24
  normalizePartList
22
- } from "./chunk-VFAE4AGH.js";
23
- import {
24
- recomputeMcpGating
25
- } from "./chunk-GA7VRJVN.js";
25
+ } from "./chunk-LPMBFOWH.js";
26
26
  import {
27
27
  appEvents,
28
28
  buildDisabledSkillNamesProvider,
29
29
  loadCliConfig,
30
30
  normalizeDisabledToolList
31
- } from "./chunk-4SLLEAQP.js";
32
- import {
33
- getCommandSubcommandNames
34
- } from "./chunk-3EUZWNWA.js";
35
- import {
36
- getEffectiveSupportedModes
37
- } from "./chunk-WOT64EP2.js";
31
+ } from "./chunk-D53NR4GO.js";
38
32
  import "./chunk-5DTTYNB7.js";
39
- import "./chunk-QKYTTBYW.js";
40
33
  import {
41
34
  collectContextData,
42
35
  formatContextUsageText
43
- } from "./chunk-NOWTNYC7.js";
36
+ } from "./chunk-3LH5Q2AR.js";
37
+ import {
38
+ getCommandSubcommandNames
39
+ } from "./chunk-PBED7USE.js";
40
+ import {
41
+ getEffectiveSupportedModes
42
+ } from "./chunk-JTUAAVUT.js";
43
+ import "./chunk-4LVZNIDO.js";
44
44
  import "./chunk-4WGODMVR.js";
45
- import "./chunk-AYCDXHZB.js";
46
- import "./chunk-QOK6RMIP.js";
47
- import "./chunk-P2YAOGJD.js";
48
- import "./chunk-DA7OOKVN.js";
49
- import "./chunk-LZYWWWCZ.js";
45
+ import "./chunk-3KQSDUK3.js";
50
46
  import "./chunk-YAF2MQZ6.js";
47
+ import "./chunk-7Z6JQEL6.js";
48
+ import {
49
+ computeCpuPercent
50
+ } from "./chunk-HGT6JR3U.js";
51
+ import "./chunk-R3BCL5XW.js";
52
+ import "./chunk-6H67XLET.js";
53
+ import {
54
+ beginAcpBootstrapConfigProfiling,
55
+ buildAndFreezeAcpStartupProfile,
56
+ endAcpBootstrapConfigProfiling,
57
+ markAcpStartup
58
+ } from "./chunk-TDKQP3M6.js";
59
+ import "./chunk-JKFHJK5U.js";
60
+ import "./chunk-MTSYH4MB.js";
51
61
  import {
52
62
  GENERATION_MAX_PROMPT_BYTES,
53
63
  GENERATION_TIMEOUT_MS,
@@ -66,7 +76,7 @@ import {
66
76
  shouldSuppressRememberErrorDetails,
67
77
  workspaceMemoryFailureCode,
68
78
  workspaceMemoryFailureDiagnostics
69
- } from "./chunk-TTSKHF43.js";
79
+ } from "./chunk-4DSBFQMI.js";
70
80
  import {
71
81
  HistoryReplayer,
72
82
  MessageEmitter,
@@ -76,54 +86,20 @@ import {
76
86
  goalTerminalEventToHistoryItem,
77
87
  recordGoalStatusItem,
78
88
  restoreGoalFromHistory
79
- } from "./chunk-FVS747N7.js";
80
- import "./chunk-KTUQMDEP.js";
89
+ } from "./chunk-6PRNSLMB.js";
90
+ import "./chunk-4K7VDKAD.js";
81
91
  import "./chunk-RS7MT2QG.js";
82
- import "./chunk-CVDW42JT.js";
92
+ import "./chunk-NNFK277W.js";
83
93
  import "./chunk-H2XVO6NE.js";
94
+ import "./chunk-QHTIBUWB.js";
84
95
  import {
85
96
  isTerminalGoalStatusKind
86
97
  } from "./chunk-QTERJVPZ.js";
87
- import "./chunk-QHTIBUWB.js";
88
98
  import "./chunk-L573Z2QZ.js";
89
- import {
90
- computeCpuPercent
91
- } from "./chunk-HGT6JR3U.js";
92
99
  import "./chunk-RXFQM6FQ.js";
93
- import "./chunk-N6YTEVLV.js";
94
- import "./chunk-6H67XLET.js";
95
- import {
96
- beginAcpBootstrapConfigProfiling,
97
- buildAndFreezeAcpStartupProfile,
98
- endAcpBootstrapConfigProfiling,
99
- markAcpStartup
100
- } from "./chunk-TDKQP3M6.js";
101
- import {
102
- createLoadedSettingsAdapter
103
- } from "./chunk-Z5Q65RVH.js";
104
100
  import "./chunk-LXXMOYPL.js";
105
- import "./chunk-7KDI2IB2.js";
101
+ import "./chunk-QSJ6JIF5.js";
106
102
  import "./chunk-E5Z2AVNV.js";
107
- import {
108
- parseSessionSource
109
- } from "./chunk-EVSTCA7S.js";
110
- import "./chunk-6RLROE6G.js";
111
- import "./chunk-COH43MRJ.js";
112
- import {
113
- CHANNEL_STARTUP_PROFILE_META_KEY,
114
- CHANNEL_STARTUP_PROFILE_VERSION,
115
- CLIENT_MCP_OVER_WS_CONFIG_FLAG,
116
- LOAD_REPLAY_BULK_MODE,
117
- LOAD_REPLAY_META_KEY,
118
- LOAD_REPLAY_MODE_META_KEY,
119
- LOAD_REPLAY_PAGE_SIZE_META_KEY,
120
- LOAD_REPLAY_VERSION,
121
- MID_TURN_QUEUE_DRAIN_METHOD,
122
- TODO_STOP_GUARD_QUEUE_RELEASE_METHOD
123
- } from "./chunk-QR6U5QPP.js";
124
- import {
125
- ndJsonStream
126
- } from "./chunk-6GUTHAN7.js";
127
103
  import {
128
104
  ACP_ROUTE_ID_PREFIX,
129
105
  buildAcpModelOptions,
@@ -132,7 +108,7 @@ import {
132
108
  parseAcpModelOption,
133
109
  resolveAcpModelOption,
134
110
  sanitizeProviderBaseUrl
135
- } from "./chunk-TCKTNY66.js";
111
+ } from "./chunk-TPR35HHZ.js";
136
112
  import {
137
113
  mapSkillConfigToStatus
138
114
  } from "./chunk-2W3OOD4W.js";
@@ -142,19 +118,48 @@ import {
142
118
  buildPermissionSettings,
143
119
  normalizePermissionRules,
144
120
  readPermissionRuleSet
145
- } from "./chunk-WAX3ITOA.js";
121
+ } from "./chunk-5EA5NVXS.js";
146
122
  import {
147
123
  MAX_AUDIO_BYTES,
148
124
  sanitizeVoiceErrorMessage,
149
125
  transcribeVoiceAudio
150
- } from "./chunk-B453NMZJ.js";
126
+ } from "./chunk-EFIOE2EH.js";
151
127
  import {
152
128
  readVoiceModel
153
- } from "./chunk-IB35C3IL.js";
154
- import "./chunk-BVLROR2T.js";
129
+ } from "./chunk-3SXF4GMQ.js";
130
+ import "./chunk-QLJUC7TG.js";
131
+ import "./chunk-4BRH6FP5.js";
132
+ import "./chunk-G6LRTI62.js";
133
+ import "./chunk-57OAHC2Y.js";
134
+ import "./chunk-QD6BRERJ.js";
135
+ import "./chunk-6ZBPS62S.js";
136
+ import "./chunk-V6WHFGST.js";
137
+ import {
138
+ createLoadedSettingsAdapter
139
+ } from "./chunk-EC2ET5ZZ.js";
140
+ import {
141
+ parseSessionSource
142
+ } from "./chunk-R7MPKABX.js";
143
+ import "./chunk-6RLROE6G.js";
144
+ import "./chunk-COH43MRJ.js";
145
+ import {
146
+ CHANNEL_STARTUP_PROFILE_META_KEY,
147
+ CHANNEL_STARTUP_PROFILE_VERSION,
148
+ CLIENT_MCP_OVER_WS_CONFIG_FLAG,
149
+ LOAD_REPLAY_BULK_MODE,
150
+ LOAD_REPLAY_META_KEY,
151
+ LOAD_REPLAY_MODE_META_KEY,
152
+ LOAD_REPLAY_PAGE_SIZE_META_KEY,
153
+ LOAD_REPLAY_VERSION,
154
+ MID_TURN_QUEUE_DRAIN_METHOD,
155
+ TODO_STOP_GUARD_QUEUE_RELEASE_METHOD
156
+ } from "./chunk-QR6U5QPP.js";
155
157
  import {
156
158
  NOT_CURRENTLY_GENERATING_CANCEL_MESSAGE
157
- } from "./chunk-X6YQWCIJ.js";
159
+ } from "./chunk-UH3WSE5L.js";
160
+ import {
161
+ ndJsonStream
162
+ } from "./chunk-JHFVJQRO.js";
158
163
  import {
159
164
  ACP_PREFLIGHT_KINDS,
160
165
  IDLE_HOOK_EVENTS,
@@ -162,29 +167,22 @@ import {
162
167
  SERVE_STATUS_EXT_METHODS,
163
168
  STATUS_SCHEMA_VERSION,
164
169
  mapDomainErrorToErrorKind
165
- } from "./chunk-WXAXH7IJ.js";
166
- import "./chunk-KXEGCGUG.js";
167
- import "./chunk-JVTCARQ6.js";
168
- import "./chunk-57OAHC2Y.js";
169
- import "./chunk-OMH3276Y.js";
170
- import "./chunk-4ODB7WIB.js";
171
- import "./chunk-V6WHFGST.js";
172
- import {
173
- assembleMcpServers,
174
- loadMcpApprovals
175
- } from "./chunk-V25Z5UUB.js";
176
- import "./chunk-W7FJ3N32.js";
177
- import "./chunk-Y2ENGUD6.js";
170
+ } from "./chunk-BWQRDISK.js";
171
+ import "./chunk-QKTHJXCS.js";
178
172
  import "./chunk-TJTKSVIV.js";
179
173
  import "./chunk-M5GB774H.js";
180
- import "./chunk-RFIAR4YL.js";
181
- import "./chunk-2HOVDT7W.js";
182
- import "./chunk-NIJEXGV6.js";
174
+ import "./chunk-RV4C2ZFG.js";
175
+ import "./chunk-2LI23QA6.js";
176
+ import "./chunk-RVLZCXEE.js";
183
177
  import {
184
178
  AgentSideConnection,
185
179
  PROTOCOL_VERSION,
186
180
  RequestError
187
181
  } from "./chunk-UDXSXLER.js";
182
+ import {
183
+ assembleMcpServers,
184
+ loadMcpApprovals
185
+ } from "./chunk-Y2DAH52F.js";
188
186
  import {
189
187
  getOutputLanguageFilePath,
190
188
  getPersistScopeForModelSelection,
@@ -193,38 +191,40 @@ import {
193
191
  resolveOutputLanguageOrPreserveAuto,
194
192
  updateOutputLanguageFile,
195
193
  writeOutputLanguageAndRegisterPath
196
- } from "./chunk-KPZNOZPC.js";
194
+ } from "./chunk-7SWFAKVH.js";
197
195
  import "./chunk-RKUWKYED.js";
198
- import "./chunk-GOXKNSDZ.js";
199
- import {
200
- getSystemDefaultsPath,
201
- getSystemSettingsPath
202
- } from "./chunk-IDS7MSUP.js";
203
196
  import {
204
197
  SUPPORTED_LANGUAGES,
205
198
  getCurrentLanguage,
206
199
  setLanguageAsync
207
- } from "./chunk-2DXOIVUI.js";
200
+ } from "./chunk-WCFTQD7H.js";
208
201
  import {
209
202
  findEnvFiles,
210
203
  preResolveHomeEnvOverrides,
211
204
  reloadEnvironment
212
- } from "./chunk-OF2BBLYQ.js";
205
+ } from "./chunk-52T5UHAZ.js";
206
+ import "./chunk-KDPIV6WC.js";
207
+ import "./chunk-GOXKNSDZ.js";
213
208
  import "./chunk-QRUIS3DN.js";
214
- import "./chunk-IUSNI6IX.js";
209
+ import "./chunk-2RFKHEXL.js";
210
+ import {
211
+ getSystemDefaultsPath,
212
+ getSystemSettingsPath
213
+ } from "./chunk-IDS7MSUP.js";
214
+ import "./chunk-XFSFZCM5.js";
215
+ import "./chunk-27CLX4FV.js";
215
216
  import "./chunk-VJNBRRZG.js";
216
217
  import {
217
218
  isFolderTrustEnabled,
218
219
  isWorkspaceTrusted,
219
220
  loadTrustedFolders
220
- } from "./chunk-MC2DOZS7.js";
221
+ } from "./chunk-S3YQCNJE.js";
221
222
  import "./chunk-ALGGS7UH.js";
222
223
  import "./chunk-MR3PXB6E.js";
223
224
  import {
224
225
  writeStderrLine,
225
226
  writeStderrLineSafe
226
227
  } from "./chunk-OWAK7LMW.js";
227
- import "./chunk-XFSFZCM5.js";
228
228
  import {
229
229
  ALL_PROVIDERS,
230
230
  APPROVAL_MODE_INFO,
@@ -243,16 +243,20 @@ import {
243
243
  McpServerSpawnFailedError,
244
244
  McpTransportPool,
245
245
  MessageDisplayDispatcher,
246
+ PLAN_MODE_ENTRY_SIBLING_SKIP_MESSAGE,
246
247
  POOLED_TRANSPORTS_DEFAULT,
247
248
  SESSION_ARTIFACT_PERSISTENCE_VERSION,
248
249
  SESSION_TITLE_MAX_LENGTH,
249
250
  SESSION_TRANSCRIPT_MAX_LIMIT,
250
251
  SESSION_TRANSCRIPT_MAX_PAGE_BYTES,
252
+ SESSION_WRITER_RPC_CODES,
251
253
  SessionService,
252
254
  SessionTranscriptPageTooLargeError,
253
255
  SessionTranscriptReader,
254
256
  SessionTranscriptSnapshotUnavailableError,
255
257
  SessionTranscriptTooLargeError,
258
+ SessionWriterError,
259
+ SessionWriterUnavailableError,
256
260
  TURN_INTERRUPTION_HISTORY_TAIL_COUNT,
257
261
  WorkspaceMcpBudget,
258
262
  abortGoalForStopHookCap,
@@ -272,13 +276,18 @@ import {
272
276
  convertToFunctionErrorResponse,
273
277
  convertToFunctionResponse,
274
278
  createDuplicateProviderToolCallResponse,
279
+ decorateClassifierUnavailableConfirmation,
280
+ decoratePlanModeShellConfirmation,
275
281
  dedupeToolCallsById,
276
282
  detectAutonomousSentinel,
277
283
  detectLoopSentinel,
278
284
  encodeSessionTranscriptCursor,
279
285
  evaluateAutoMode,
280
286
  evaluatePermissionFlow,
287
+ evaluatePlanModeShellPolicy,
288
+ finalizeToolResponses,
281
289
  findExistingProviderModels,
290
+ findPlanModeEntryBatchBoundaryIndex,
282
291
  findProviderById,
283
292
  findRepeatedDuplicateProviderToolCall,
284
293
  fireNotificationHook,
@@ -301,21 +310,19 @@ import {
301
310
  getPlanModeSystemReminder,
302
311
  getProviderToolCallId,
303
312
  getScopedEnvContents,
304
- getStartupContextLength,
313
+ getStopHookContinuationReason,
305
314
  ideContextStore,
306
315
  injectPermissionRulesIfMissing,
307
316
  isApproveOutcome,
308
317
  isDenialFallbackReason,
309
318
  isGatedMcpScope,
310
319
  isPlanModeBlocked,
311
- isSystemReminderContent,
312
320
  markDuplicateProviderToolCallResponseSent,
313
321
  matchesAnyServerPattern,
314
322
  mcpServerRequiresOAuth,
315
323
  needsConfirmation,
316
324
  normalizeEventPayload,
317
325
  normalizeSnapshotPayload,
318
- parsePositiveIntegerEnv,
319
326
  persistPermissionOutcome,
320
327
  readManyFiles,
321
328
  recordAllow,
@@ -337,45 +344,58 @@ import {
337
344
  shouldRunAutoModeForCall,
338
345
  subagentGenerator,
339
346
  unregisterGoalHook,
340
- updateSetting
341
- } from "./chunk-6OH6A5EX.js";
342
- import "./chunk-5M6IDOMF.js";
347
+ updateSetting,
348
+ validatePlanModeShellApproval,
349
+ validatePlanModeShellContext
350
+ } from "./chunk-GEB2CGUV.js";
343
351
  import "./chunk-T4TZQJ7W.js";
344
352
  import {
345
353
  external_exports
346
354
  } from "./chunk-H6XPXXMH.js";
347
- import "./chunk-OONJNQ42.js";
348
- import "./chunk-JDI67JFB.js";
355
+ import "./chunk-5M6IDOMF.js";
356
+ import "./chunk-T2L47JJK.js";
357
+ import "./chunk-GPSKDNEE.js";
358
+ import "./chunk-X6N25LXS.js";
359
+ import "./chunk-E2UVIFI2.js";
360
+ import "./chunk-Q2YKNMLS.js";
349
361
  import "./chunk-XU457J4V.js";
350
362
  import "./chunk-VDDGDZMA.js";
351
- import "./chunk-EIAK6Q2B.js";
352
- import "./chunk-FSL5W5TI.js";
353
- import "./chunk-D2VIDMVM.js";
354
- import "./chunk-E2UVIFI2.js";
355
- import "./chunk-WBTZGWQ6.js";
363
+ import "./chunk-KHOVYUHX.js";
356
364
  import "./chunk-SZRN75WQ.js";
357
- import "./chunk-HTO4JFDZ.js";
365
+ import {
366
+ parsePositiveIntegerEnv
367
+ } from "./chunk-6PVPNMXU.js";
368
+ import "./chunk-PIHKWN7M.js";
358
369
  import "./chunk-CPBF7KYF.js";
370
+ import "./chunk-NABLFI57.js";
371
+ import {
372
+ HookEventName,
373
+ createHookOutput
374
+ } from "./chunk-QBUDF33N.js";
375
+ import "./chunk-LIZRAKPB.js";
359
376
  import {
360
377
  APPROVAL_MODES,
361
378
  FORK_SUBAGENT_TYPE,
379
+ getStartupContextLength,
380
+ isSystemReminderContent,
362
381
  runWithRuntimeContentGenerator
363
- } from "./chunk-ETD6K42I.js";
382
+ } from "./chunk-WHGVTP7Q.js";
364
383
  import "./chunk-6AM5D4ME.js";
365
- import "./chunk-G45X5TRN.js";
366
- import {
367
- HookEventName,
368
- createHookOutput
369
- } from "./chunk-PBATSWUQ.js";
370
- import "./chunk-ZEOZL37W.js";
371
- import "./chunk-OOCI5VVU.js";
384
+ import "./chunk-JCW2R7WC.js";
385
+ import "./chunk-57FIIFJN.js";
386
+ import "./chunk-HTO4JFDZ.js";
387
+ import "./chunk-XVNQMZ2I.js";
388
+ import "./chunk-FODK6UMO.js";
389
+ import "./chunk-GLNBDYUX.js";
372
390
  import {
373
391
  clearCachedCredentialFile,
374
392
  qwenOAuth2Events
375
- } from "./chunk-UQES76OO.js";
376
- import "./chunk-OKWRU4NO.js";
377
- import "./chunk-XNP57UDV.js";
393
+ } from "./chunk-TXRKCFWS.js";
378
394
  import "./chunk-JESCGQM3.js";
395
+ import "./chunk-EWXXMRMP.js";
396
+ import "./chunk-PPIHLGNE.js";
397
+ import "./chunk-DJ2GSRLV.js";
398
+ import "./chunk-5I5BM454.js";
379
399
  import {
380
400
  AuthType,
381
401
  ConversationFinishedEvent,
@@ -383,8 +403,6 @@ import {
383
403
  LoopDetectedEvent,
384
404
  PromptSuggestionEvent,
385
405
  UserPromptEvent,
386
- endToolExecutionSpan,
387
- endToolSpan,
388
406
  extractDaemonTraceContext,
389
407
  formatFullTurnVisionNotice,
390
408
  formatVisionBridgeNotice,
@@ -400,63 +418,63 @@ import {
400
418
  logUserPrompt,
401
419
  normalizeParts,
402
420
  registerAcpEventLoopLagGauge,
403
- runInToolSpanContext,
404
421
  runSideQuery,
405
422
  runVisionBridge,
406
423
  shouldRunVisionBridge,
407
424
  splitImageParts,
408
425
  startEventLoopLagMonitor,
409
- startToolExecutionSpan,
410
- startToolSpan,
411
426
  uiTelemetryService,
412
- withDaemonSpan,
413
- withInteractionSpan
414
- } from "./chunk-ONWW74X6.js";
415
- import "./chunk-4WKAA4KS.js";
416
- import "./chunk-CR3C7WXL.js";
427
+ withDaemonSpan
428
+ } from "./chunk-5G2SK2OO.js";
417
429
  import "./chunk-VGC4I5JJ.js";
418
430
  import {
419
431
  getAutoMemoryRoot,
420
432
  getUserAutoMemoryRoot
421
- } from "./chunk-JD3MKVKL.js";
422
- import "./chunk-UEY4AYUL.js";
423
- import "./chunk-BDBMYST4.js";
424
- import "./chunk-467G3SV5.js";
425
- import {
426
- ToolConfirmationOutcome,
427
- ToolNames,
428
- isShellProgressData
429
- } from "./chunk-S35ZDXOS.js";
430
- import "./chunk-XVNQMZ2I.js";
431
- import "./chunk-FODK6UMO.js";
432
- import "./chunk-GLNBDYUX.js";
433
- import "./chunk-DJ2GSRLV.js";
434
- import "./chunk-6EFTQYW7.js";
433
+ } from "./chunk-4K56OJFJ.js";
435
434
  import {
436
435
  DEFAULT_TOKEN_LIMIT,
437
436
  getToolCallPreparations,
438
437
  tokenLimit
439
- } from "./chunk-MAQQGNQ5.js";
438
+ } from "./chunk-JYS55H6Z.js";
440
439
  import "./chunk-A4UCTEB5.js";
441
440
  import "./chunk-XWRJCPHC.js";
441
+ import "./chunk-QNLNLENL.js";
442
+ import "./chunk-6X4GWOPW.js";
442
443
  import "./chunk-TYQMGACW.js";
443
444
  import "./chunk-TYAMGABM.js";
444
445
  import "./chunk-FCMNKVXT.js";
446
+ import {
447
+ endToolExecutionSpan,
448
+ endToolSpan,
449
+ runInToolSpanContext,
450
+ startToolExecutionSpan,
451
+ startToolSpan,
452
+ withInteractionSpan
453
+ } from "./chunk-IS2SBY6T.js";
454
+ import "./chunk-HTR4WV6U.js";
455
+ import "./chunk-M7WBGLYP.js";
456
+ import "./chunk-U7ZFW55U.js";
457
+ import "./chunk-NPQDJGKU.js";
458
+ import {
459
+ ToolConfirmationOutcome,
460
+ ToolNames,
461
+ isShellProgressData
462
+ } from "./chunk-YM3SZTH4.js";
445
463
  import {
446
464
  Storage,
447
465
  createDebugLogger,
448
466
  getErrorMessage,
449
467
  getErrorStatus,
450
468
  isSubpath
451
- } from "./chunk-C27BYUX6.js";
452
- import "./chunk-MKLKHZAK.js";
469
+ } from "./chunk-OQB4EXO4.js";
470
+ import "./chunk-DPRMI6NU.js";
453
471
  import {
454
472
  runExitCleanup
455
- } from "./chunk-FLTN6NRU.js";
473
+ } from "./chunk-D6ZOVZLF.js";
456
474
  import "./chunk-75DOP5OR.js";
457
475
  import "./chunk-DMTGGOSA.js";
458
476
  import "./chunk-YQ3U5MUC.js";
459
- import "./chunk-TB6UDU4T.js";
477
+ import "./chunk-THJNPLI4.js";
460
478
  import {
461
479
  init_esbuild_shims
462
480
  } from "./chunk-5O2XNYP6.js";
@@ -466,7 +484,7 @@ import {
466
484
 
467
485
  // packages/cli/src/acp-integration/acpAgent.ts
468
486
  init_esbuild_shims();
469
- import { randomUUID } from "node:crypto";
487
+ import { randomUUID as randomUUID2 } from "node:crypto";
470
488
  import { performance } from "node:perf_hooks";
471
489
 
472
490
  // packages/cli/src/acp-integration/authMethods.ts
@@ -844,6 +862,7 @@ __name(isInactiveExtensionSkill, "isInactiveExtensionSkill");
844
862
  // packages/cli/src/acp-integration/session/Session.ts
845
863
  init_esbuild_shims();
846
864
  import { Buffer as Buffer2 } from "node:buffer";
865
+ import { randomUUID } from "node:crypto";
847
866
  import { existsSync as existsSync2, statSync as statSync2 } from "node:fs";
848
867
  import * as os2 from "node:os";
849
868
  import * as path3 from "node:path";
@@ -968,8 +987,23 @@ function supportsHideAlwaysAllow(confirmation) {
968
987
  }
969
988
  __name(supportsHideAlwaysAllow, "supportsHideAlwaysAllow");
970
989
  function filterAlwaysAllowOptions(confirmation, options, forceHideAlwaysAllow = false) {
971
- const hideAlwaysAllow = forceHideAlwaysAllow || supportsHideAlwaysAllow(confirmation) && confirmation.hideAlwaysAllow === true;
972
- return hideAlwaysAllow ? options.filter((option) => option.kind !== "allow_always") : options;
990
+ const hideAlwaysAllow = forceHideAlwaysAllow || confirmation.autoModeFallback !== void 0 || supportsHideAlwaysAllow(confirmation) && confirmation.hideAlwaysAllow === true;
991
+ const visibleOptions = hideAlwaysAllow ? options.filter((option) => option.kind !== "allow_always") : options;
992
+ if (!confirmation.autoModeFallback) return visibleOptions;
993
+ const switchOption = {
994
+ optionId: "proceed_once_and_switch_to_default" /* ProceedOnceAndSwitchToDefault */,
995
+ name: "Switch to Default Mode and allow once (recommended)",
996
+ kind: "allow_once"
997
+ };
998
+ const rejectIndex = visibleOptions.findIndex(
999
+ (option) => option.kind === "reject_once"
1000
+ );
1001
+ if (rejectIndex === -1) return [...visibleOptions, switchOption];
1002
+ return [
1003
+ ...visibleOptions.slice(0, rejectIndex),
1004
+ switchOption,
1005
+ ...visibleOptions.slice(rejectIndex)
1006
+ ];
973
1007
  }
974
1008
  __name(filterAlwaysAllowOptions, "filterAlwaysAllowOptions");
975
1009
  function formatExecPermissionScopeLabel(confirmation) {
@@ -997,6 +1031,22 @@ function interactionMetaFields(confirmation) {
997
1031
  __name(interactionMetaFields, "interactionMetaFields");
998
1032
  function buildPermissionRequestContent(confirmation) {
999
1033
  const content = [];
1034
+ if (confirmation.autoModeFallback) {
1035
+ content.push({
1036
+ type: "content",
1037
+ content: {
1038
+ type: "text",
1039
+ text: confirmation.autoModeFallback.message
1040
+ }
1041
+ });
1042
+ }
1043
+ const warnings = confirmation.type === "exec" || confirmation.type === "edit" ? confirmation.warnings ?? [] : [];
1044
+ for (const warning of warnings) {
1045
+ content.push({
1046
+ type: "content",
1047
+ content: { type: "text", text: warning }
1048
+ });
1049
+ }
1000
1050
  if (confirmation.type === "edit") {
1001
1051
  content.push({
1002
1052
  type: "diff",
@@ -1017,6 +1067,56 @@ function buildPermissionRequestContent(confirmation) {
1017
1067
  return content;
1018
1068
  }
1019
1069
  __name(buildPermissionRequestContent, "buildPermissionRequestContent");
1070
+ function permissionAbortError(signal) {
1071
+ return signal.reason instanceof Error ? signal.reason : new Error("Permission request was aborted.");
1072
+ }
1073
+ __name(permissionAbortError, "permissionAbortError");
1074
+ function requestPermissionWithAbort(client, params, signal) {
1075
+ if (signal.aborted) {
1076
+ return Promise.reject(permissionAbortError(signal));
1077
+ }
1078
+ return new Promise((resolve5, reject) => {
1079
+ let settled = false;
1080
+ const finish = /* @__PURE__ */ __name((callback) => {
1081
+ if (settled) return;
1082
+ settled = true;
1083
+ signal.removeEventListener("abort", onAbort);
1084
+ callback();
1085
+ }, "finish");
1086
+ const onAbort = /* @__PURE__ */ __name(() => finish(() => reject(permissionAbortError(signal))), "onAbort");
1087
+ signal.addEventListener("abort", onAbort, { once: true });
1088
+ let request;
1089
+ try {
1090
+ request = client.requestPermission(params);
1091
+ } catch (error) {
1092
+ finish(() => reject(error));
1093
+ return;
1094
+ }
1095
+ request.then(
1096
+ (response) => finish(() => resolve5(response)),
1097
+ (error) => finish(() => reject(error))
1098
+ );
1099
+ });
1100
+ }
1101
+ __name(requestPermissionWithAbort, "requestPermissionWithAbort");
1102
+ function resolvePermissionOutcome(response, offeredOptions) {
1103
+ if (response.outcome.outcome === "cancelled") {
1104
+ return "cancel" /* Cancel */;
1105
+ }
1106
+ const optionId = response.outcome.optionId;
1107
+ if (!offeredOptions.some((option) => option.optionId === optionId)) {
1108
+ throw new Error(
1109
+ `Permission response selected unoffered option: ${optionId}`
1110
+ );
1111
+ }
1112
+ if (!Object.values(ToolConfirmationOutcome).includes(
1113
+ optionId
1114
+ )) {
1115
+ throw new Error(`Permission response selected invalid option: ${optionId}`);
1116
+ }
1117
+ return optionId;
1118
+ }
1119
+ __name(resolvePermissionOutcome, "resolvePermissionOutcome");
1020
1120
  function toPermissionOptions(confirmation, forceHideAlwaysAllow = false) {
1021
1121
  switch (confirmation.type) {
1022
1122
  case "edit":
@@ -1243,9 +1343,13 @@ var SubAgentTracker = class {
1243
1343
  }, "onConfirm")
1244
1344
  };
1245
1345
  const { title, locations, kind } = this.toolCallEmitter.resolveToolMetadata(event.name, state?.args);
1346
+ const permissionOptions = toPermissionOptions(fullConfirmationDetails);
1347
+ const offeredPermissionOptions = permissionOptions.map((option) => ({
1348
+ ...option
1349
+ }));
1246
1350
  const params = {
1247
1351
  sessionId: this.ctx.sessionId,
1248
- options: toPermissionOptions(fullConfirmationDetails),
1352
+ options: permissionOptions,
1249
1353
  toolCall: {
1250
1354
  toolCallId: event.callId,
1251
1355
  status: "pending",
@@ -1266,8 +1370,15 @@ var SubAgentTracker = class {
1266
1370
  }
1267
1371
  };
1268
1372
  try {
1269
- const output = await this.client.requestPermission(params);
1270
- const outcome = output.outcome.outcome === "cancelled" ? "cancel" /* Cancel */ : external_exports.nativeEnum(ToolConfirmationOutcome).parse(output.outcome.optionId);
1373
+ const output = await requestPermissionWithAbort(
1374
+ this.client,
1375
+ params,
1376
+ abortSignal
1377
+ );
1378
+ const outcome = resolvePermissionOutcome(
1379
+ output,
1380
+ offeredPermissionOptions
1381
+ );
1271
1382
  await event.respond(outcome, {
1272
1383
  answers: "answers" in output ? output.answers : void 0
1273
1384
  });
@@ -1859,6 +1970,10 @@ function maskApiKeyForDisplay(apiKey) {
1859
1970
  return `${trimmed.slice(0, 3)}...${trimmed.slice(-4)}`;
1860
1971
  }
1861
1972
  __name(maskApiKeyForDisplay, "maskApiKeyForDisplay");
1973
+ function getAbortAwareEndTurnStopReason(signal) {
1974
+ return signal.aborted ? "cancelled" : "end_turn";
1975
+ }
1976
+ __name(getAbortAwareEndTurnStopReason, "getAbortAwareEndTurnStopReason");
1862
1977
  var DAEMON_INVALID_TOOL_PARAMS_THRESHOLD = 3;
1863
1978
  var PERMISSION_CANCEL_SKIP_MESSAGE = "Skipped because a permission request was cancelled before the user answered; user input is required before continuing.";
1864
1979
  var LOOP_DETECTED_SKIP_MESSAGE = "Skipped because loop detection stopped the current turn before this tool call could run.";
@@ -2310,7 +2425,7 @@ var Session = class {
2310
2425
  this.client = client;
2311
2426
  this.settings = settings;
2312
2427
  this.sessionId = id;
2313
- this.runtimeBaseDir = Storage.getRuntimeBaseDir();
2428
+ this.runtimeBaseDir = config.storage.getRuntimeBaseDir();
2314
2429
  const todoStopGuardEnabled = this.settings.merged.experimental?.todoStopGuard === true && !this.config.getBareMode() && !this.config.isSafeMode();
2315
2430
  this.todoStopGuard = new DaemonTodoStopGuard(todoStopGuardEnabled);
2316
2431
  this.todoStopGuardBackgroundBaseline = todoStopGuardEnabled ? this.#captureTodoStopGuardBackgroundBaseline() : {
@@ -2341,6 +2456,7 @@ var Session = class {
2341
2456
  * process termination is slow.
2342
2457
  */
2343
2458
  pendingPromptCompletion = null;
2459
+ automaticDrainRetry = null;
2344
2460
  /**
2345
2461
  * Per-turn AbortController for the fire-and-forget follow-up suggestion
2346
2462
  * generation. Aborted on the top of the next `prompt()` and on
@@ -2403,6 +2519,9 @@ var Session = class {
2403
2519
  // or session reload), which would otherwise execute orphaned cron prompts
2404
2520
  // on a session whose registries are already unregistered.
2405
2521
  disposed = false;
2522
+ closing = false;
2523
+ closeGateCompletion = null;
2524
+ resolveCloseGate = null;
2406
2525
  unsubscribeChatRecordingFailure;
2407
2526
  // Modular components
2408
2527
  historyReplayer;
@@ -2637,7 +2756,7 @@ var Session = class {
2637
2756
  * mount.
2638
2757
  */
2639
2758
  startCronScheduler() {
2640
- this.#startCronSchedulerIfNeeded().catch((error) => {
2759
+ this.#startCronSchedulerInRuntime().catch((error) => {
2641
2760
  debugLogger6.warn(
2642
2761
  `Cron scheduler startup failed [session ${this.sessionId}]: ${error}`
2643
2762
  );
@@ -2646,8 +2765,95 @@ var Session = class {
2646
2765
  getConfig() {
2647
2766
  return this.config;
2648
2767
  }
2768
+ async assertCanStartTurn() {
2769
+ if (this.closing) {
2770
+ throw RequestError.invalidParams(void 0, "Session is closing");
2771
+ }
2772
+ try {
2773
+ await this.config.assertCanStartTurn();
2774
+ } catch (error) {
2775
+ if (error instanceof SessionWriterError) {
2776
+ throw new RequestError(error.rpcCode, error.message, {
2777
+ errorKind: error.errorKind
2778
+ });
2779
+ }
2780
+ throw error;
2781
+ }
2782
+ if (this.closing) {
2783
+ throw RequestError.invalidParams(void 0, "Session is closing");
2784
+ }
2785
+ }
2649
2786
  isIdle() {
2650
- return !this.pendingPrompt && !this.pendingPromptCompletion && !this.cronProcessing && !this.cronAbortController && !this.notificationProcessing && !this.notificationAbortController;
2787
+ return !this.closing && !this.#hasActiveTurn();
2788
+ }
2789
+ #hasActiveTurn() {
2790
+ return Boolean(
2791
+ this.pendingPrompt || this.pendingPromptCompletion || this.cronProcessing || this.cronAbortController || this.cronCompletion || this.notificationProcessing || this.notificationAbortController || this.notificationCompletion
2792
+ );
2793
+ }
2794
+ beginClose() {
2795
+ if (this.closing) {
2796
+ throw RequestError.invalidParams(
2797
+ void 0,
2798
+ "Session close is already in progress"
2799
+ );
2800
+ }
2801
+ this.closing = true;
2802
+ let resolveGate;
2803
+ const completion = new Promise((resolve5) => {
2804
+ resolveGate = resolve5;
2805
+ });
2806
+ this.closeGateCompletion = completion;
2807
+ this.resolveCloseGate = resolveGate;
2808
+ let released = false;
2809
+ return () => {
2810
+ if (released) return;
2811
+ released = true;
2812
+ if (this.closeGateCompletion === completion) {
2813
+ this.closeGateCompletion = null;
2814
+ this.resolveCloseGate = null;
2815
+ }
2816
+ resolveGate();
2817
+ if (this.disposed) return;
2818
+ this.closing = false;
2819
+ void this.#drainCronQueue();
2820
+ void this.#drainNotificationQueue();
2821
+ };
2822
+ }
2823
+ beginCloseIfAvailable() {
2824
+ if (this.disposed) {
2825
+ throw RequestError.invalidParams(void 0, "Session has been disposed");
2826
+ }
2827
+ return this.closing ? null : this.beginClose();
2828
+ }
2829
+ waitForCloseGateToRelease() {
2830
+ return this.closeGateCompletion ?? Promise.resolve();
2831
+ }
2832
+ async waitForActiveTurnsToSettle() {
2833
+ const pending = [
2834
+ this.pendingPromptCompletion,
2835
+ this.cronCompletion,
2836
+ this.notificationCompletion
2837
+ ].filter((completion) => completion !== null);
2838
+ await Promise.allSettled(pending);
2839
+ }
2840
+ #deferAutomaticQueueDrainUntilTurnsSettle() {
2841
+ const completions = [
2842
+ this.pendingPromptCompletion,
2843
+ this.cronCompletion,
2844
+ this.notificationCompletion
2845
+ ].filter((completion) => completion !== null);
2846
+ if (completions.length === 0) return false;
2847
+ if (this.automaticDrainRetry) return true;
2848
+ const retry = Promise.allSettled(completions).then(() => {
2849
+ if (this.automaticDrainRetry !== retry) return;
2850
+ this.automaticDrainRetry = null;
2851
+ if (this.disposed) return;
2852
+ void this.#drainCronQueue();
2853
+ void this.#drainNotificationQueue();
2854
+ });
2855
+ this.automaticDrainRetry = retry;
2856
+ return true;
2651
2857
  }
2652
2858
  getTurnCount() {
2653
2859
  return this.turn;
@@ -2657,6 +2863,10 @@ var Session = class {
2657
2863
  }
2658
2864
  dispose() {
2659
2865
  this.disposed = true;
2866
+ this.closing = true;
2867
+ this.resolveCloseGate?.();
2868
+ this.resolveCloseGate = null;
2869
+ this.closeGateCompletion = null;
2660
2870
  this.todoStopGuardQueuedPromptPriority = false;
2661
2871
  this.todoStopGuardDrainAutomaticQueuesWhenIdle = false;
2662
2872
  this.todoStopGuard.clearTrust();
@@ -2673,7 +2883,7 @@ var Session = class {
2673
2883
  this.cronProcessing = false;
2674
2884
  this.cronCompletion = null;
2675
2885
  if (this.config.isCronEnabled()) {
2676
- this.config.getCronScheduler().stop();
2886
+ this.#stopCronSchedulerInRuntime();
2677
2887
  }
2678
2888
  this.config.getBackgroundTaskRegistry().setNotificationCallback(void 0);
2679
2889
  this.config.getMonitorRegistry().setNotificationCallback(void 0);
@@ -2757,7 +2967,7 @@ var Session = class {
2757
2967
  "targetTurnIndex must be a non-negative integer"
2758
2968
  );
2759
2969
  }
2760
- if (this.pendingPrompt || this.cronProcessing || this.cronAbortController || this.notificationProcessing || this.notificationAbortController) {
2970
+ if (this.closing || this.#hasActiveTurn()) {
2761
2971
  throw RequestError.invalidParams(
2762
2972
  void 0,
2763
2973
  "Cannot rewind while a prompt is running"
@@ -2814,7 +3024,7 @@ var Session = class {
2814
3024
  return count;
2815
3025
  }
2816
3026
  restoreHistory(history) {
2817
- if (this.pendingPrompt || this.cronProcessing || this.cronAbortController || this.notificationProcessing || this.notificationAbortController) {
3027
+ if (this.closing || this.#hasActiveTurn()) {
2818
3028
  throw RequestError.invalidParams(
2819
3029
  void 0,
2820
3030
  "Cannot restore history while a prompt is running"
@@ -2888,13 +3098,17 @@ var Session = class {
2888
3098
  const scheduler = this.config.isCronEnabled() ? this.config.getCronScheduler() : null;
2889
3099
  if (scheduler) {
2890
3100
  const summary = scheduler.getExitSummary();
2891
- scheduler.stop();
3101
+ this.#stopCronSchedulerInRuntime();
2892
3102
  if (summary) {
2893
3103
  await this.messageEmitter.emitAgentMessage(summary);
2894
3104
  }
2895
3105
  }
2896
3106
  }
2897
3107
  async prompt(params) {
3108
+ if (this.closing) {
3109
+ throw RequestError.invalidParams(void 0, "Session is closing");
3110
+ }
3111
+ await this.assertCanStartTurn();
2898
3112
  const todoStopGuardPreparation = this.#prepareTodoStopGuardForPrompt(params);
2899
3113
  this.pendingPrompt?.abort();
2900
3114
  const pendingSend = new AbortController();
@@ -2954,6 +3168,13 @@ var Session = class {
2954
3168
  void this.#drainNotificationQueue();
2955
3169
  this.#maybeEmitFollowupSuggestion(result);
2956
3170
  return result;
3171
+ } catch (error) {
3172
+ if (error instanceof SessionWriterError) {
3173
+ throw new RequestError(error.rpcCode, error.message, {
3174
+ errorKind: error.errorKind
3175
+ });
3176
+ }
3177
+ throw error;
2957
3178
  } finally {
2958
3179
  this.pendingPrompt = null;
2959
3180
  const shouldDrainAutomaticQueues = todoStopGuardPreparation.drainSupersededAutomaticQueues || this.todoStopGuardDrainAutomaticQueuesWhenIdle || this.todoStopGuard.blocksUnrelatedAutomaticTurns || this.todoStopGuard.hasCommittedContinuation || this.todoStopGuardQueuedPromptPriority;
@@ -2962,7 +3183,7 @@ var Session = class {
2962
3183
  void this.#drainCronQueue();
2963
3184
  void this.#drainNotificationQueue();
2964
3185
  }
2965
- void this.#startCronSchedulerIfNeeded();
3186
+ void this.#startCronSchedulerInRuntime();
2966
3187
  resolveCompletion();
2967
3188
  this.pendingPromptCompletion = null;
2968
3189
  }
@@ -3096,6 +3317,10 @@ var Session = class {
3096
3317
  this.runtimeBaseDir,
3097
3318
  this.config.getWorkingDir(),
3098
3319
  async () => {
3320
+ await this.assertCanStartTurn();
3321
+ if (pendingSend.signal.aborted) {
3322
+ return { stopReason: "cancelled" };
3323
+ }
3099
3324
  this.turn += 1;
3100
3325
  const promptId = this.config.getSessionId() + "########" + this.turn;
3101
3326
  const parentContext = extractDaemonTraceContext(params);
@@ -3406,7 +3631,11 @@ ${this.pendingWorktreeNotice}
3406
3631
  toolRun,
3407
3632
  pendingSend.signal
3408
3633
  );
3409
- return { stopReason: "end_turn" };
3634
+ return {
3635
+ stopReason: getAbortAwareEndTurnStopReason(
3636
+ pendingSend.signal
3637
+ )
3638
+ };
3410
3639
  }
3411
3640
  const nextAfterTools = await this.#buildNextMessageAfterToolRun(
3412
3641
  toolRun,
@@ -3420,7 +3649,11 @@ ${this.pendingWorktreeNotice}
3420
3649
  toolRun,
3421
3650
  pendingSend.signal
3422
3651
  );
3423
- return { stopReason: "end_turn" };
3652
+ return {
3653
+ stopReason: getAbortAwareEndTurnStopReason(
3654
+ pendingSend.signal
3655
+ )
3656
+ };
3424
3657
  }
3425
3658
  }
3426
3659
  }
@@ -3465,7 +3698,7 @@ ${this.pendingWorktreeNotice}
3465
3698
  while (true) {
3466
3699
  if (pendingSend.signal.aborted) {
3467
3700
  this.todoStopGuard.suspend();
3468
- return { stopReason: "end_turn" };
3701
+ return { stopReason: "cancelled" };
3469
3702
  }
3470
3703
  if (this.config.getApprovalMode() === "plan" /* PLAN */) {
3471
3704
  this.#clearTodoStopGuardTrustAndDrainAutomaticQueues();
@@ -3568,7 +3801,7 @@ ${this.pendingWorktreeNotice}
3568
3801
  await this.messageEmitter.emitAgentMessage(stopOutput.systemMessage);
3569
3802
  }
3570
3803
  if (stopOutput?.isBlockingDecision() || stopOutput?.shouldStopExecution()) {
3571
- externalReason = stopOutput.getEffectiveReason();
3804
+ externalReason = getStopHookContinuationReason(stopOutput);
3572
3805
  stopHookIterationCount++;
3573
3806
  stopHookReasons = [...stopHookReasons, externalReason];
3574
3807
  stopHookCount = response.stopHookCount ?? 1;
@@ -3915,7 +4148,7 @@ ${this.pendingWorktreeNotice}
3915
4148
  await this.#preserveStoppedToolRun(toolRun, pendingSend.signal);
3916
4149
  return {
3917
4150
  kind: "terminal",
3918
- stopReason: "end_turn",
4151
+ stopReason: getAbortAwareEndTurnStopReason(pendingSend.signal),
3919
4152
  ...supersededAutomaticContinuation ? { supersededAutomaticContinuation: true } : {}
3920
4153
  };
3921
4154
  }
@@ -4164,13 +4397,18 @@ ${this.pendingWorktreeNotice}
4164
4397
  }
4165
4398
  }
4166
4399
  async #preserveStoppedToolRun(toolRun, abortSignal) {
4400
+ const midTurnParts = abortSignal.aborted ? await this.#buildMidTurnParts(
4401
+ this.#takeRecoveredMidTurnMessages(),
4402
+ abortSignal,
4403
+ { preserveFallbackOnAbort: true }
4404
+ ) : await this.#drainMidTurnUserMessages(abortSignal);
4167
4405
  this.#preserveUnsentMessageHistory(
4168
4406
  {
4169
4407
  role: "user",
4170
4408
  parts: [
4171
4409
  ...toolRun.parts,
4172
4410
  ...toolRun.loopDetected ? [{ text: LOOP_DETECTED_CONTEXT_MESSAGE }] : [],
4173
- ...await this.#drainMidTurnUserMessages(abortSignal)
4411
+ ...midTurnParts
4174
4412
  ]
4175
4413
  },
4176
4414
  true
@@ -4285,11 +4523,7 @@ ${this.pendingWorktreeNotice}
4285
4523
  const recovered = this.#takeRecoveredMidTurnMessages();
4286
4524
  if (this.midTurnDrainUnavailable) {
4287
4525
  return {
4288
- parts: await this.#buildMidTurnParts(
4289
- recovered,
4290
- abortSignal,
4291
- options.onFullTurnModel
4292
- ),
4526
+ parts: await this.#buildMidTurnParts(recovered, abortSignal, options),
4293
4527
  hasQueuedPrompt: false
4294
4528
  };
4295
4529
  }
@@ -4317,7 +4551,7 @@ ${this.pendingWorktreeNotice}
4317
4551
  parts: await this.#buildMidTurnParts(
4318
4552
  [...recovered, ...parseMidTurnDrainResponse(response)],
4319
4553
  abortSignal,
4320
- options.onFullTurnModel
4554
+ options
4321
4555
  ),
4322
4556
  hasQueuedPrompt: isRecord2(response) && response["hasQueuedPrompt"] === true
4323
4557
  };
@@ -4337,11 +4571,7 @@ ${this.pendingWorktreeNotice}
4337
4571
  `Mid-turn queue drain ${isPermanentError ? "permanently " : ""}unavailable [session ${this.sessionId}]: ${errorMessage}`
4338
4572
  );
4339
4573
  return {
4340
- parts: await this.#buildMidTurnParts(
4341
- recovered,
4342
- abortSignal,
4343
- options.onFullTurnModel
4344
- ),
4574
+ parts: await this.#buildMidTurnParts(recovered, abortSignal, options),
4345
4575
  hasQueuedPrompt: false
4346
4576
  };
4347
4577
  }
@@ -4401,7 +4631,7 @@ ${this.pendingWorktreeNotice}
4401
4631
  * happens on injection (here), so a message recovered from an earlier
4402
4632
  * timed-out drain is still recorded exactly once.
4403
4633
  */
4404
- async #buildMidTurnParts(messages, abortSignal, onFullTurnModel) {
4634
+ async #buildMidTurnParts(messages, abortSignal, options = {}) {
4405
4635
  const parts = [];
4406
4636
  for (const message of messages) {
4407
4637
  const displayText = message.kind === "text" ? message.message : message.displayText;
@@ -4411,13 +4641,19 @@ ${this.pendingWorktreeNotice}
4411
4641
  abortSignal,
4412
4642
  MID_TURN_QUEUE_RESOLVE_TIMEOUT_MS,
4413
4643
  (signal) => this.#resolvePrompt(message.content, signal, {
4414
- onFullTurnModel
4644
+ onFullTurnModel: options.onFullTurnModel
4415
4645
  })
4416
4646
  );
4417
4647
  } catch (messageError) {
4418
- if (abortSignal.aborted) return parts;
4419
- const errorMessage = this.#formatError(messageError);
4420
- debugLogger6.warn(`Failed to resolve mid-turn message: ${errorMessage}`);
4648
+ if (abortSignal.aborted && !options.preserveFallbackOnAbort) {
4649
+ return parts;
4650
+ }
4651
+ if (!abortSignal.aborted) {
4652
+ const errorMessage = this.#formatError(messageError);
4653
+ debugLogger6.warn(
4654
+ `Failed to resolve mid-turn message: ${errorMessage}`
4655
+ );
4656
+ }
4421
4657
  rawParts = [{ text: displayText }];
4422
4658
  if (message.kind === "structured" && hasInlineMediaContentBlock(message.content)) {
4423
4659
  rawParts.push({ text: MID_TURN_ATTACHMENT_PROCESSING_FAILURE_TEXT });
@@ -4459,6 +4695,20 @@ ${this.pendingWorktreeNotice}
4459
4695
  void this.#drainCronQueue();
4460
4696
  });
4461
4697
  }
4698
+ #startCronSchedulerInRuntime() {
4699
+ return Storage.runWithRuntimeBaseDir(
4700
+ this.runtimeBaseDir,
4701
+ this.config.getWorkingDir(),
4702
+ () => this.#startCronSchedulerIfNeeded()
4703
+ );
4704
+ }
4705
+ #stopCronSchedulerInRuntime() {
4706
+ Storage.runWithRuntimeBaseDir(
4707
+ this.runtimeBaseDir,
4708
+ this.config.getWorkingDir(),
4709
+ () => this.config.getCronScheduler().stop()
4710
+ );
4711
+ }
4462
4712
  #enqueueCronPrompt(item) {
4463
4713
  if ((this.todoStopGuard.blocksUnrelatedAutomaticTurns || this.todoStopGuardQueuedPromptPriority) && !this.#cronContinuesTodoStopGuardWorkChain(item)) {
4464
4714
  if (item.taskId) {
@@ -4489,10 +4739,24 @@ ${this.pendingWorktreeNotice}
4489
4739
  */
4490
4740
  async #drainCronQueue() {
4491
4741
  if (this.disposed) return;
4742
+ if (this.closing) return;
4492
4743
  if (this.cronProcessing) return;
4493
4744
  if (this.pendingPrompt) return;
4494
4745
  if (this.notificationProcessing) return;
4746
+ if (this.#deferAutomaticQueueDrainUntilTurnsSettle()) return;
4495
4747
  if (this.#nextCronQueueIndex() < 0) return;
4748
+ try {
4749
+ await this.assertCanStartTurn();
4750
+ } catch (error) {
4751
+ debugLogger6.warn(
4752
+ `Cron turn rejected [session ${this.sessionId}]: ${error instanceof Error ? error.message : String(error)}`
4753
+ );
4754
+ return;
4755
+ }
4756
+ if (this.disposed || this.closing || this.cronProcessing || this.pendingPrompt || this.notificationProcessing || this.#nextCronQueueIndex() < 0) {
4757
+ return;
4758
+ }
4759
+ if (this.#deferAutomaticQueueDrainUntilTurnsSettle()) return;
4496
4760
  this.cronProcessing = true;
4497
4761
  let resolveCompletion;
4498
4762
  this.cronCompletion = new Promise((resolve5) => {
@@ -4514,7 +4778,7 @@ ${this.pendingWorktreeNotice}
4514
4778
  if (this.config.isCronEnabled()) {
4515
4779
  const scheduler = this.config.getCronScheduler();
4516
4780
  if (!scheduler.hasPendingWork) {
4517
- scheduler.stop();
4781
+ this.#stopCronSchedulerInRuntime();
4518
4782
  }
4519
4783
  }
4520
4784
  }
@@ -4581,6 +4845,8 @@ ${this.pendingWorktreeNotice}
4581
4845
  async () => {
4582
4846
  let turnCount = 0;
4583
4847
  try {
4848
+ await this.assertCanStartTurn();
4849
+ if (ac.signal.aborted) return;
4584
4850
  const loopMode = detectLoopSentinel(prompt);
4585
4851
  const autonomousMode = loopMode ? null : detectAutonomousSentinel(prompt);
4586
4852
  let loopTick = null;
@@ -4910,12 +5176,26 @@ ${this.pendingWorktreeNotice}
4910
5176
  }
4911
5177
  async #drainNotificationQueue() {
4912
5178
  if (this.disposed) return;
5179
+ if (this.closing) return;
4913
5180
  if (this.notificationProcessing) return;
4914
5181
  if (this.pendingPrompt || this.cronProcessing || this.cronAbortController) {
4915
5182
  return;
4916
5183
  }
5184
+ if (this.#deferAutomaticQueueDrainUntilTurnsSettle()) return;
4917
5185
  if (this.notificationQueue.length === 0) return;
4918
5186
  if (this.#nextNotificationQueueIndex() < 0) return;
5187
+ try {
5188
+ await this.assertCanStartTurn();
5189
+ } catch (error) {
5190
+ debugLogger6.warn(
5191
+ `Notification turn rejected [session ${this.sessionId}]: ${error instanceof Error ? error.message : String(error)}`
5192
+ );
5193
+ return;
5194
+ }
5195
+ if (this.disposed || this.closing || this.notificationProcessing || this.pendingPrompt || this.cronProcessing || this.cronAbortController || this.#nextNotificationQueueIndex() < 0) {
5196
+ return;
5197
+ }
5198
+ if (this.#deferAutomaticQueueDrainUntilTurnsSettle()) return;
4919
5199
  this.notificationProcessing = true;
4920
5200
  let resolveCompletion;
4921
5201
  this.notificationCompletion = new Promise((resolve5) => {
@@ -4965,6 +5245,8 @@ ${this.pendingWorktreeNotice}
4965
5245
  );
4966
5246
  const promptId = this.config.getSessionId() + "########notification" + Date.now();
4967
5247
  try {
5248
+ await this.assertCanStartTurn();
5249
+ if (ac.signal.aborted) return;
4968
5250
  await this.#emitBackgroundNotificationDisplay(item);
4969
5251
  const notificationParts = [{ text: item.modelText }];
4970
5252
  this.config.getChatRecordingService()?.recordNotification(notificationParts, item.displayText);
@@ -5094,7 +5376,9 @@ ${this.pendingWorktreeNotice}
5094
5376
  if (toolRun.stopAfterPermissionCancel) {
5095
5377
  this.todoStopGuard.suspend();
5096
5378
  await this.#preserveStoppedToolRun(toolRun, ac.signal);
5097
- await this.#emitBackgroundNotificationEndTurn("end_turn");
5379
+ await this.#emitBackgroundNotificationEndTurn(
5380
+ getAbortAwareEndTurnStopReason(ac.signal)
5381
+ );
5098
5382
  return;
5099
5383
  }
5100
5384
  const nextAfterTools = await this.#buildNextMessageAfterToolRun(
@@ -5105,7 +5389,9 @@ ${this.pendingWorktreeNotice}
5105
5389
  if (toolRun.loopDetected) {
5106
5390
  this.todoStopGuard.suspend();
5107
5391
  await this.#preserveStoppedToolRun(toolRun, ac.signal);
5108
- await this.#emitBackgroundNotificationEndTurn("end_turn");
5392
+ await this.#emitBackgroundNotificationEndTurn(
5393
+ getAbortAwareEndTurnStopReason(ac.signal)
5394
+ );
5109
5395
  return;
5110
5396
  }
5111
5397
  }
@@ -5123,7 +5409,9 @@ ${this.pendingWorktreeNotice}
5123
5409
  false
5124
5410
  )).stopReason;
5125
5411
  }
5126
- await this.#emitBackgroundNotificationEndTurn(stopReason);
5412
+ await this.#emitBackgroundNotificationEndTurn(
5413
+ ac.signal.aborted ? "cancelled" : stopReason
5414
+ );
5127
5415
  } catch (error) {
5128
5416
  if (ac.signal.aborted) {
5129
5417
  this.todoStopGuard.suspend();
@@ -5416,8 +5704,46 @@ ${this.pendingWorktreeNotice}
5416
5704
  */
5417
5705
  async runToolCalls(abortSignal, promptId, functionCalls, toolLoopState) {
5418
5706
  const dedupedFunctionCalls = dedupeToolCallsById(functionCalls);
5707
+ const generatedCallIdBase = randomUUID();
5708
+ const executionCallIds = new Map(
5709
+ dedupedFunctionCalls.map((functionCall, index) => [
5710
+ functionCall,
5711
+ functionCall.id ?? `${functionCall.name ?? "tool"}-${generatedCallIdBase}-${index}`
5712
+ ])
5713
+ );
5714
+ const pendingToolResultRecords = [];
5715
+ let toolResultRecordSequence = 0;
5716
+ const queueToolResultRecord = /* @__PURE__ */ __name((fc, record) => {
5717
+ pendingToolResultRecords.push({
5718
+ ...record,
5719
+ ordinal: dedupedFunctionCalls.indexOf(fc),
5720
+ sequence: toolResultRecordSequence++
5721
+ });
5722
+ }, "queueToolResultRecord");
5723
+ const finalizeRunToolResult = /* @__PURE__ */ __name(async (result) => {
5724
+ if (pendingToolResultRecords.length === 0) return result;
5725
+ const orderedRecords = [...pendingToolResultRecords].sort(
5726
+ (left, right) => left.ordinal - right.ordinal || left.sequence - right.sequence
5727
+ );
5728
+ const finalized = await finalizeToolResponses(
5729
+ this.config,
5730
+ orderedRecords.map((record) => ({
5731
+ callId: record.callId,
5732
+ toolName: record.toolName,
5733
+ responseParts: record.responseParts,
5734
+ persistedOutputFiles: record.persistedOutputFiles
5735
+ }))
5736
+ );
5737
+ orderedRecords.forEach((record, index) => {
5738
+ this.config.getChatRecordingService()?.recordToolResult(finalized[index].responseParts, record.metadata);
5739
+ });
5740
+ return {
5741
+ ...result,
5742
+ parts: finalized.flatMap((entry) => entry.responseParts)
5743
+ };
5744
+ }, "finalizeRunToolResult");
5419
5745
  let skippedToolCallCounter = 0;
5420
- const recordSkippedToolCall = /* @__PURE__ */ __name(async (fc, message = PERMISSION_CANCEL_SKIP_MESSAGE, emitStart = true) => {
5746
+ const recordSkippedToolCall = /* @__PURE__ */ __name(async (fc, message = PERMISSION_CANCEL_SKIP_MESSAGE, emitStart = true, errorType) => {
5421
5747
  const toolName = fc.name ?? "unknown_tool";
5422
5748
  const callId = fc.id ?? `${toolName}-skip-${++skippedToolCallCounter}`;
5423
5749
  const part = {
@@ -5429,12 +5755,17 @@ ${this.pendingWorktreeNotice}
5429
5755
  };
5430
5756
  const error = new Error(message);
5431
5757
  try {
5432
- this.config.getChatRecordingService()?.recordToolResult([part], {
5758
+ queueToolResultRecord(fc, {
5433
5759
  callId,
5434
- status: "error",
5435
- resultDisplay: void 0,
5436
- error,
5437
- errorType: void 0
5760
+ toolName,
5761
+ responseParts: [part],
5762
+ metadata: {
5763
+ callId,
5764
+ status: "error",
5765
+ resultDisplay: void 0,
5766
+ error,
5767
+ errorType
5768
+ }
5438
5769
  });
5439
5770
  if (emitStart) {
5440
5771
  await this.toolCallEmitter.emitStart({
@@ -5456,7 +5787,7 @@ ${this.pendingWorktreeNotice}
5456
5787
  toolLoopState,
5457
5788
  dedupedFunctionCalls.length
5458
5789
  )) {
5459
- return {
5790
+ return await finalizeRunToolResult({
5460
5791
  parts: await Promise.all(
5461
5792
  dedupedFunctionCalls.map(
5462
5793
  (fc) => recordSkippedToolCall(fc, LOOP_DETECTED_SKIP_MESSAGE, false)
@@ -5464,7 +5795,7 @@ ${this.pendingWorktreeNotice}
5464
5795
  ),
5465
5796
  stopAfterPermissionCancel: false,
5466
5797
  loopDetected: true
5467
- };
5798
+ });
5468
5799
  }
5469
5800
  const batches = [];
5470
5801
  const handledProviderToolCallIds = new Set(
@@ -5481,13 +5812,13 @@ ${this.pendingWorktreeNotice}
5481
5812
  debugLogger6.debug(
5482
5813
  `[Session.runToolCalls] Dropping batch after repeated duplicate provider tool-call id: ${providerCallId} (tool: ${repeatedDuplicateCall.name ?? "unknown_tool"})`
5483
5814
  );
5484
- return {
5815
+ return await finalizeRunToolResult({
5485
5816
  parts: [],
5486
5817
  stopAfterPermissionCancel: false,
5487
5818
  repeatedDuplicateProviderToolCall: true
5488
- };
5819
+ });
5489
5820
  }
5490
- const pushDuplicateBatch = /* @__PURE__ */ __name((request) => {
5821
+ const pushDuplicateBatch = /* @__PURE__ */ __name((fc, request) => {
5491
5822
  const providerCallId = request.providerCallId ?? request.callId;
5492
5823
  markDuplicateProviderToolCallResponseSent(
5493
5824
  providerCallId,
@@ -5497,7 +5828,7 @@ ${this.pendingWorktreeNotice}
5497
5828
  debugLogger6.debug(
5498
5829
  `[Session.runToolCalls] Suppressing duplicate provider tool-call id: ${providerCallId} (tool: ${request.name})`
5499
5830
  );
5500
- batches.push({ kind: "duplicate", request, response });
5831
+ batches.push({ kind: "duplicate", fc, request, response });
5501
5832
  }, "pushDuplicateBatch");
5502
5833
  const emitDuplicateBatch = /* @__PURE__ */ __name(async (batch) => {
5503
5834
  const { request, response } = batch;
@@ -5534,20 +5865,26 @@ ${this.pendingWorktreeNotice}
5534
5865
  success: false
5535
5866
  });
5536
5867
  }
5537
- this.config.getChatRecordingService()?.recordToolResult(response.responseParts, {
5868
+ queueToolResultRecord(batch.fc, {
5538
5869
  callId: response.callId,
5539
- status: "error",
5540
- resultDisplay: response.resultDisplay,
5541
- error: response.error,
5542
- errorType: response.errorType
5870
+ toolName: request.name,
5871
+ responseParts: response.responseParts,
5872
+ persistedOutputFiles: response.persistedOutputFiles,
5873
+ metadata: {
5874
+ callId: response.callId,
5875
+ status: "error",
5876
+ resultDisplay: response.resultDisplay,
5877
+ error: response.error,
5878
+ errorType: response.errorType
5879
+ }
5543
5880
  });
5544
5881
  }, "emitDuplicateBatch");
5545
5882
  for (const fc of dedupedFunctionCalls) {
5546
5883
  const providerCallId = getProviderToolCallId(fc) ?? fc.id;
5547
5884
  if (providerCallId) {
5548
5885
  if (handledProviderToolCallIds.has(providerCallId)) {
5549
- const callId = fc.id ?? `${fc.name}-${Date.now()}`;
5550
- pushDuplicateBatch({
5886
+ const callId = executionCallIds.get(fc);
5887
+ pushDuplicateBatch(fc, {
5551
5888
  callId,
5552
5889
  providerCallId,
5553
5890
  name: fc.name ?? "unknown_tool",
@@ -5567,6 +5904,13 @@ ${this.pendingWorktreeNotice}
5567
5904
  batches.push({ kind: "execute", concurrent: isAgent, calls: [fc] });
5568
5905
  }
5569
5906
  }
5907
+ const executableCalls = batches.flatMap(
5908
+ (batch) => batch.kind === "execute" ? batch.calls : []
5909
+ );
5910
+ const planModeEntryBoundaryIndex = findPlanModeEntryBatchBoundaryIndex(
5911
+ executableCalls.map((call) => call.name)
5912
+ );
5913
+ const planModeEntryBoundary = planModeEntryBoundaryIndex === void 0 ? void 0 : executableCalls[planModeEntryBoundaryIndex];
5570
5914
  const appendSkippedAfter = /* @__PURE__ */ __name(async (parts2, fc, message = PERMISSION_CANCEL_SKIP_MESSAGE) => {
5571
5915
  const startIndex = dedupedFunctionCalls.indexOf(fc) + 1;
5572
5916
  for (const remainingCall of dedupedFunctionCalls.slice(startIndex)) {
@@ -5633,7 +5977,9 @@ ${this.pendingWorktreeNotice}
5633
5977
  calls[i],
5634
5978
  onStopAfterPermissionCancel,
5635
5979
  toolLoopState,
5636
- recordSkippedToolCall
5980
+ recordSkippedToolCall,
5981
+ queueToolResultRecord,
5982
+ executionCallIds.get(calls[i])
5637
5983
  );
5638
5984
  results[i] = r;
5639
5985
  if (r.loopDetected) {
@@ -5665,7 +6011,9 @@ ${this.pendingWorktreeNotice}
5665
6011
  calls[idx],
5666
6012
  onStopAfterPermissionCancel,
5667
6013
  toolLoopState,
5668
- recordSkippedToolCall
6014
+ recordSkippedToolCall,
6015
+ queueToolResultRecord,
6016
+ executionCallIds.get(calls[idx])
5669
6017
  ).then((r) => {
5670
6018
  results[idx] = r;
5671
6019
  }).finally(() => {
@@ -5704,6 +6052,19 @@ ${this.pendingWorktreeNotice}
5704
6052
  parts.push(...batch.response.responseParts);
5705
6053
  continue;
5706
6054
  }
6055
+ if (planModeEntryBoundary && !batch.calls.includes(planModeEntryBoundary)) {
6056
+ for (const fc of batch.calls) {
6057
+ parts.push(
6058
+ await recordSkippedToolCall(
6059
+ fc,
6060
+ PLAN_MODE_ENTRY_SIBLING_SKIP_MESSAGE,
6061
+ true,
6062
+ "execution_denied" /* EXECUTION_DENIED */
6063
+ )
6064
+ );
6065
+ }
6066
+ continue;
6067
+ }
5707
6068
  if (batch.concurrent && batch.calls.length > 1) {
5708
6069
  const batchAbortController = new AbortController();
5709
6070
  let batchStopAfterPermissionCancel = false;
@@ -5747,24 +6108,24 @@ ${this.pendingWorktreeNotice}
5747
6108
  batch.calls[batch.calls.length - 1],
5748
6109
  LOOP_DETECTED_SKIP_MESSAGE
5749
6110
  );
5750
- return {
6111
+ return await finalizeRunToolResult({
5751
6112
  parts,
5752
6113
  stopAfterPermissionCancel: false,
5753
6114
  loopDetected: true,
5754
6115
  memoryWriteCandidates
5755
- };
6116
+ });
5756
6117
  }
5757
6118
  if (shouldStop) {
5758
6119
  await appendSkippedAfter(
5759
6120
  parts,
5760
6121
  batch.calls[batch.calls.length - 1]
5761
6122
  );
5762
- return {
6123
+ return await finalizeRunToolResult({
5763
6124
  parts,
5764
6125
  stopAfterPermissionCancel: true,
5765
6126
  repeatedDuplicateProviderToolCall: false,
5766
6127
  memoryWriteCandidates
5767
- };
6128
+ });
5768
6129
  }
5769
6130
  } else {
5770
6131
  for (const fc of batch.calls) {
@@ -5774,37 +6135,39 @@ ${this.pendingWorktreeNotice}
5774
6135
  fc,
5775
6136
  void 0,
5776
6137
  toolLoopState,
5777
- recordSkippedToolCall
6138
+ recordSkippedToolCall,
6139
+ queueToolResultRecord,
6140
+ executionCallIds.get(fc)
5778
6141
  );
5779
6142
  parts.push(...r.parts);
5780
6143
  collectMemoryWriteCandidates(r);
5781
6144
  if (r.loopDetected) {
5782
6145
  await appendSkippedAfter(parts, fc, LOOP_DETECTED_SKIP_MESSAGE);
5783
- return {
6146
+ return await finalizeRunToolResult({
5784
6147
  parts,
5785
6148
  stopAfterPermissionCancel: false,
5786
6149
  loopDetected: true,
5787
6150
  memoryWriteCandidates
5788
- };
6151
+ });
5789
6152
  }
5790
6153
  if (r.stopAfterPermissionCancel) {
5791
6154
  await appendSkippedAfter(parts, fc);
5792
- return {
6155
+ return await finalizeRunToolResult({
5793
6156
  parts,
5794
6157
  stopAfterPermissionCancel: true,
5795
6158
  repeatedDuplicateProviderToolCall: false,
5796
6159
  memoryWriteCandidates
5797
- };
6160
+ });
5798
6161
  }
5799
6162
  }
5800
6163
  }
5801
6164
  }
5802
- return {
6165
+ return await finalizeRunToolResult({
5803
6166
  parts,
5804
6167
  stopAfterPermissionCancel: false,
5805
6168
  repeatedDuplicateProviderToolCall: false,
5806
6169
  memoryWriteCandidates
5807
- };
6170
+ });
5808
6171
  } finally {
5809
6172
  await refreshMemoryIfNeeded();
5810
6173
  }
@@ -5839,8 +6202,8 @@ ${this.pendingWorktreeNotice}
5839
6202
  }
5840
6203
  return reminders;
5841
6204
  }
5842
- async runTool(abortSignal, promptId, fc, onStopAfterPermissionCancel, toolLoopState, recordSkippedToolCall) {
5843
- const callId = fc.id ?? `${fc.name}-${Date.now()}`;
6205
+ async runTool(abortSignal, promptId, fc, onStopAfterPermissionCancel, toolLoopState, recordSkippedToolCall, queueToolResultRecord, generatedCallId) {
6206
+ const callId = fc.id ?? generatedCallId ?? `${fc.name}-${Date.now()}`;
5844
6207
  let args = fc.args ?? {};
5845
6208
  if (toolLoopState?.loopDetected) {
5846
6209
  return {
@@ -5902,12 +6265,17 @@ ${this.pendingWorktreeNotice}
5902
6265
  await this.toolCallEmitter.emitError(callId, toolName2, error);
5903
6266
  }
5904
6267
  const errorParts = errorResponse(error);
5905
- this.config.getChatRecordingService()?.recordToolResult(errorParts, {
6268
+ queueToolResultRecord?.(fc, {
5906
6269
  callId,
5907
- status: "error",
5908
- resultDisplay: void 0,
5909
- error,
5910
- errorType: void 0
6270
+ toolName: toolName2,
6271
+ responseParts: errorParts,
6272
+ metadata: {
6273
+ callId,
6274
+ status: "error",
6275
+ resultDisplay: void 0,
6276
+ error,
6277
+ errorType: void 0
6278
+ }
5911
6279
  });
5912
6280
  const loopDetected = opts?.recordInvalidToolParams === true && !activeToolAbortSignal.aborted && !opts?.stopAfterPermissionCancel && recordDaemonInvalidToolParams(
5913
6281
  this.config,
@@ -5937,19 +6305,21 @@ ${this.pendingWorktreeNotice}
5937
6305
  { recordInvalidToolParams: true }
5938
6306
  );
5939
6307
  }
5940
- const toolSpan = startToolSpan(toolName, {
6308
+ const policyToolName = tool.name;
6309
+ const originalPolicyRequestArgs = policyToolName === ToolNames.SHELL || policyToolName === ToolNames.MONITOR ? structuredClone(args) : args;
6310
+ const toolSpan = startToolSpan(policyToolName, {
5941
6311
  "tool.call_id": callId,
5942
6312
  // Dual-emit the legacy call_id/tool_name aliases like CoreToolScheduler
5943
6313
  // (coreToolScheduler.ts) so pre-Phase-2 dashboards keyed off call_id keep
5944
6314
  // matching daemon/ACP tool spans during the migration window.
5945
6315
  call_id: callId,
5946
- tool_name: toolName
6316
+ tool_name: policyToolName
5947
6317
  });
5948
6318
  let spanSuccess = false;
5949
6319
  try {
5950
6320
  return await runInToolSpanContext(toolSpan, async () => {
5951
6321
  const pm = this.config.getPermissionManager?.();
5952
- if (pm && !await pm.isToolEnabled(toolName)) {
6322
+ if (pm && !await pm.isToolEnabled(policyToolName)) {
5953
6323
  return earlyErrorResponse(
5954
6324
  new Error(`Tool "${toolName}" is disabled.`),
5955
6325
  toolName
@@ -5978,7 +6348,7 @@ ${this.pendingWorktreeNotice}
5978
6348
  }
5979
6349
  }
5980
6350
  const toolUseId = generateToolUseId();
5981
- const approvalMode = this.config.getApprovalMode();
6351
+ let approvalMode = this.config.getApprovalMode();
5982
6352
  let toolBuildSucceeded = false;
5983
6353
  try {
5984
6354
  const invocation = tool.build(args);
@@ -6003,12 +6373,12 @@ ${this.pendingWorktreeNotice}
6003
6373
  activeToolAbortSignal
6004
6374
  );
6005
6375
  }
6006
- const isAskUserQuestionTool = toolName === ToolNames.ASK_USER_QUESTION;
6007
- const toolParams = invocation.params;
6376
+ const isAskUserQuestionTool = policyToolName === ToolNames.ASK_USER_QUESTION;
6377
+ let toolParams = invocation.params;
6008
6378
  const flowResult = await evaluatePermissionFlow(
6009
6379
  this.config,
6010
6380
  invocation,
6011
- toolName,
6381
+ policyToolName,
6012
6382
  toolParams
6013
6383
  );
6014
6384
  const {
@@ -6018,31 +6388,75 @@ ${this.pendingWorktreeNotice}
6018
6388
  denyMessage,
6019
6389
  requiresUserInteraction
6020
6390
  } = flowResult;
6391
+ approvalMode = this.config.getApprovalMode();
6021
6392
  const isPlanMode = approvalMode === "plan" /* PLAN */;
6393
+ const isPlanShellCall = isPlanMode && (policyToolName === ToolNames.SHELL || policyToolName === ToolNames.MONITOR);
6022
6394
  if (finalPermission === "deny") {
6023
6395
  return earlyErrorResponse(
6024
6396
  new Error(denyMessage ?? `Tool "${toolName}" is denied.`),
6025
6397
  toolName
6026
6398
  );
6027
6399
  }
6028
- const forceAutoReviewForAllow = approvalMode === "auto" /* AUTO */ && (shouldForceAutoModeReviewForAllow(pmCtx, this.config.getCwd()) || shouldClassifyAllShellForAutoMode(toolName, this.config));
6400
+ let planShellAmbientWorkingDirectory;
6401
+ if (isPlanShellCall) {
6402
+ const directory = toolParams["directory"];
6403
+ planShellAmbientWorkingDirectory = typeof directory === "string" && directory.length > 0 ? void 0 : this.config.getTargetDir();
6404
+ invocation.params = {
6405
+ ...structuredClone(invocation.params),
6406
+ directory: typeof directory === "string" && directory.length > 0 ? directory : planShellAmbientWorkingDirectory
6407
+ };
6408
+ toolParams = invocation.params;
6409
+ }
6410
+ const planShellDecision = isPlanShellCall ? await evaluatePlanModeShellPolicy({
6411
+ config: this.config,
6412
+ toolName: policyToolName,
6413
+ requestArgs: originalPolicyRequestArgs,
6414
+ invocationParams: toolParams,
6415
+ permissionContext: pmCtx,
6416
+ ambientWorkingDirectory: planShellAmbientWorkingDirectory,
6417
+ signal: activeToolAbortSignal
6418
+ }) : { classification: "not-applicable" };
6419
+ if (planShellDecision.classification !== "not-applicable") {
6420
+ const initialPlanShellError = await validatePlanModeShellContext({
6421
+ config: this.config,
6422
+ decision: planShellDecision,
6423
+ requestArgs: args,
6424
+ invocationParams: invocation.params,
6425
+ signal: activeToolAbortSignal
6426
+ });
6427
+ if (initialPlanShellError) {
6428
+ return earlyErrorResponse(
6429
+ new Error(initialPlanShellError),
6430
+ toolName
6431
+ );
6432
+ }
6433
+ }
6434
+ if (planShellDecision.classification === "write") {
6435
+ return earlyErrorResponse(
6436
+ new Error(planShellDecision.writeBlockMessage),
6437
+ toolName
6438
+ );
6439
+ }
6440
+ const planShellRequiresConfirmation = planShellDecision.classification === "unknown";
6441
+ const forceAutoReviewForAllow = approvalMode === "auto" /* AUTO */ && (shouldForceAutoModeReviewForAllow(pmCtx, this.config.getCwd()) || shouldClassifyAllShellForAutoMode(policyToolName, this.config));
6029
6442
  const confirmationPermission = getEffectivePermissionForConfirmation(
6030
6443
  finalPermission,
6031
6444
  forceAutoReviewForAllow
6032
6445
  );
6033
6446
  if (finalPermission === "allow" && forceAutoReviewForAllow) {
6034
6447
  debugLogger6.info(
6035
- `Auto mode: L4 allow overridden by protected-write guard for ${toolName}`
6448
+ `Auto mode: L4 allow overridden by protected-write guard for ${policyToolName}`
6036
6449
  );
6037
6450
  }
6038
- let autoModeAllowed = finalPermission === "allow" && !forceAutoReviewForAllow;
6451
+ let autoModeAllowed = finalPermission === "allow" && !forceAutoReviewForAllow && !planShellRequiresConfirmation;
6039
6452
  if (autoModeAllowed && approvalMode === "auto" /* AUTO */) {
6040
6453
  this.config.setAutoModeDenialState(
6041
6454
  recordAllow(this.config.getAutoModeDenialState())
6042
6455
  );
6043
6456
  }
6044
- let wasAutoModeDenialFallback = false;
6045
- if (!autoModeAllowed && !requiresUserInteraction && shouldRunAutoModeForCall(approvalMode, toolName)) {
6457
+ let wasAutoModeManualFallback = false;
6458
+ let autoModeFallbackMessage;
6459
+ if (!autoModeAllowed && !requiresUserInteraction && shouldRunAutoModeForCall(approvalMode, policyToolName)) {
6046
6460
  const denialState = this.config.getAutoModeDenialState();
6047
6461
  const fallback = shouldFallback(denialState);
6048
6462
  const messages = this.config.getGeminiClient?.()?.getHistoryTail(MAX_TRANSCRIPT_MESSAGES, false) ?? [];
@@ -6064,7 +6478,7 @@ ${this.pendingWorktreeNotice}
6064
6478
  this.config,
6065
6479
  decision,
6066
6480
  outcome,
6067
- toolName,
6481
+ policyToolName,
6068
6482
  toolParams,
6069
6483
  callId,
6070
6484
  abortSignal
@@ -6075,17 +6489,16 @@ ${this.pendingWorktreeNotice}
6075
6489
  break;
6076
6490
  case "blocked":
6077
6491
  debugLogger6.warn(
6078
- `Auto mode blocked (${outcome.reason}): tool=${toolName}, ` + formatDenialStateLog(denialState)
6492
+ `Auto mode blocked (${outcome.reason}): tool=${policyToolName}, ` + formatDenialStateLog(denialState)
6079
6493
  );
6080
6494
  return earlyErrorResponse(
6081
6495
  new Error(outcome.errorMessage),
6082
6496
  toolName
6083
6497
  );
6084
6498
  case "fallback":
6085
- wasAutoModeDenialFallback = isDenialFallbackReason(
6086
- outcome.reason
6087
- );
6088
- if (wasAutoModeDenialFallback) {
6499
+ wasAutoModeManualFallback = isDenialFallbackReason(outcome.reason) || outcome.reason === "classifier_unavailable";
6500
+ autoModeFallbackMessage = outcome.message;
6501
+ if (wasAutoModeManualFallback) {
6089
6502
  debugLogger6.warn(
6090
6503
  `Auto mode fallback to manual approval (${outcome.reason}): ` + formatDenialStateLog(denialState)
6091
6504
  );
@@ -6100,7 +6513,7 @@ ${this.pendingWorktreeNotice}
6100
6513
  let didRequestPermission = false;
6101
6514
  let confirmationDetails;
6102
6515
  const recordAutoModeFallbackResolution = /* @__PURE__ */ __name((outcome) => {
6103
- if (approvalMode === "auto" /* AUTO */ && wasAutoModeDenialFallback && isApproveOutcome(outcome)) {
6516
+ if (approvalMode === "auto" /* AUTO */ && wasAutoModeManualFallback && isApproveOutcome(outcome)) {
6104
6517
  const before = this.config.getAutoModeDenialState();
6105
6518
  const after = recordFallbackApprove(before);
6106
6519
  if (after === before) {
@@ -6116,14 +6529,51 @@ ${this.pendingWorktreeNotice}
6116
6529
  }
6117
6530
  }, "recordAutoModeFallbackResolution");
6118
6531
  if (!autoModeAllowed && needsConfirmation(
6119
- confirmationPermission,
6532
+ planShellRequiresConfirmation ? "ask" : confirmationPermission,
6120
6533
  approvalMode,
6121
- toolName,
6534
+ policyToolName,
6122
6535
  requiresUserInteraction
6123
6536
  )) {
6124
- confirmationDetails = await invocation.getConfirmationDetails(abortSignal);
6537
+ confirmationDetails = await invocation.getConfirmationDetails(
6538
+ activeToolAbortSignal
6539
+ );
6540
+ if (autoModeFallbackMessage) {
6541
+ confirmationDetails = decorateClassifierUnavailableConfirmation(
6542
+ confirmationDetails,
6543
+ autoModeFallbackMessage
6544
+ );
6545
+ }
6546
+ if (planShellDecision.classification !== "not-applicable") {
6547
+ const preDisplayPlanShellError = await validatePlanModeShellContext({
6548
+ config: this.config,
6549
+ decision: planShellDecision,
6550
+ requestArgs: args,
6551
+ invocationParams: invocation.params,
6552
+ signal: activeToolAbortSignal
6553
+ });
6554
+ if (preDisplayPlanShellError) {
6555
+ return earlyErrorResponse(
6556
+ new Error(preDisplayPlanShellError),
6557
+ toolName
6558
+ );
6559
+ }
6560
+ }
6561
+ try {
6562
+ confirmationDetails = decoratePlanModeShellConfirmation(
6563
+ planShellDecision,
6564
+ confirmationDetails
6565
+ );
6566
+ } catch {
6567
+ if (planShellDecision.classification === "unknown") {
6568
+ return earlyErrorResponse(
6569
+ new Error(planShellDecision.noApprovalMessage),
6570
+ toolName
6571
+ );
6572
+ }
6573
+ throw new Error("Unable to prepare shell confirmation.");
6574
+ }
6125
6575
  injectPermissionRulesIfMissing(confirmationDetails, pmCtx);
6126
- if (isPlanModeBlocked(
6576
+ if (planShellDecision.classification === "not-applicable" && isPlanModeBlocked(
6127
6577
  isPlanMode,
6128
6578
  isExitPlanModeTool,
6129
6579
  isAskUserQuestionTool,
@@ -6143,23 +6593,50 @@ ${this.pendingWorktreeNotice}
6143
6593
  if (hooksEnabled && messageBus) {
6144
6594
  const hookResult = await firePermissionRequestHook(
6145
6595
  messageBus,
6146
- toolName,
6596
+ policyToolName,
6147
6597
  args,
6148
- String(approvalMode)
6598
+ String(approvalMode),
6599
+ void 0,
6600
+ activeToolAbortSignal
6149
6601
  );
6150
6602
  if (hookResult.hasDecision && (!hookResult.shouldAllow || !requiresUserInteraction)) {
6151
6603
  hookHandled = true;
6152
6604
  if (hookResult.shouldAllow) {
6153
- if (hookResult.updatedInput) {
6154
- args = hookResult.updatedInput;
6155
- invocation.params = hookResult.updatedInput;
6605
+ if (planShellDecision.classification !== "not-applicable") {
6606
+ const approval = await validatePlanModeShellApproval({
6607
+ config: this.config,
6608
+ decision: planShellDecision,
6609
+ requestArgs: args,
6610
+ invocationParams: invocation.params,
6611
+ signal: activeToolAbortSignal,
6612
+ outcome: "proceed_once" /* ProceedOnce */,
6613
+ payload: hookResult.updatedInput ? { updatedInput: hookResult.updatedInput } : void 0
6614
+ });
6615
+ await confirmationDetails.onConfirm(
6616
+ approval.outcome,
6617
+ approval.payload
6618
+ );
6619
+ if (approval.outcome === "cancel" /* Cancel */) {
6620
+ return earlyErrorResponse(
6621
+ new Error(
6622
+ approval.payload?.cancelMessage ?? planShellDecision.noApprovalMessage
6623
+ ),
6624
+ toolName
6625
+ );
6626
+ }
6627
+ recordAutoModeFallbackResolution(approval.outcome);
6628
+ } else {
6629
+ if (hookResult.updatedInput) {
6630
+ args = hookResult.updatedInput;
6631
+ invocation.params = hookResult.updatedInput;
6632
+ }
6633
+ await confirmationDetails.onConfirm(
6634
+ "proceed_once" /* ProceedOnce */
6635
+ );
6636
+ recordAutoModeFallbackResolution(
6637
+ "proceed_once" /* ProceedOnce */
6638
+ );
6156
6639
  }
6157
- await confirmationDetails.onConfirm(
6158
- "proceed_once" /* ProceedOnce */
6159
- );
6160
- recordAutoModeFallbackResolution(
6161
- "proceed_once" /* ProceedOnce */
6162
- );
6163
6640
  } else {
6164
6641
  return earlyErrorResponse(
6165
6642
  new Error(
@@ -6172,11 +6649,26 @@ ${this.pendingWorktreeNotice}
6172
6649
  }
6173
6650
  if (!requiresUserInteraction && approvalMode === "auto-edit" /* AUTO_EDIT */ && (confirmationDetails.type === "edit" || confirmationDetails.type === "info")) {
6174
6651
  } else if (!hookHandled) {
6652
+ if (planShellDecision.classification !== "not-applicable") {
6653
+ const finalPreDisplayPlanShellError = await validatePlanModeShellContext({
6654
+ config: this.config,
6655
+ decision: planShellDecision,
6656
+ requestArgs: args,
6657
+ invocationParams: invocation.params,
6658
+ signal: activeToolAbortSignal
6659
+ });
6660
+ if (finalPreDisplayPlanShellError) {
6661
+ return earlyErrorResponse(
6662
+ new Error(finalPreDisplayPlanShellError),
6663
+ toolName
6664
+ );
6665
+ }
6666
+ }
6175
6667
  didRequestPermission = true;
6176
6668
  const content = buildPermissionRequestContent(confirmationDetails);
6177
6669
  const mappedKind = this.toolCallEmitter.mapToolKind(
6178
6670
  tool.kind,
6179
- toolName
6671
+ policyToolName
6180
6672
  );
6181
6673
  if (hooksEnabled && messageBus) {
6182
6674
  this.fireNotificationHookWithTerminalSequence(
@@ -6186,9 +6678,16 @@ ${this.pendingWorktreeNotice}
6186
6678
  "Permission needed"
6187
6679
  );
6188
6680
  }
6681
+ const permissionOptions = toPermissionOptions(
6682
+ confirmationDetails,
6683
+ pmForcedAsk
6684
+ );
6685
+ const offeredPermissionOptions = permissionOptions.map(
6686
+ (option) => ({ ...option })
6687
+ );
6189
6688
  const params = {
6190
6689
  sessionId: this.sessionId,
6191
- options: toPermissionOptions(confirmationDetails, pmForcedAsk),
6690
+ options: permissionOptions,
6192
6691
  toolCall: {
6193
6692
  toolCallId: callId,
6194
6693
  status: "pending",
@@ -6207,10 +6706,12 @@ ${this.pendingWorktreeNotice}
6207
6706
  }
6208
6707
  }
6209
6708
  };
6210
- const stopAfterPermissionCancel = /* @__PURE__ */ __name(() => {
6709
+ const stopAfterPermissionCancel = /* @__PURE__ */ __name((message) => {
6211
6710
  onStopAfterPermissionCancel?.();
6212
6711
  return earlyErrorResponse(
6213
- new Error(`Tool "${toolName}" was canceled by the user.`),
6712
+ new Error(
6713
+ message ?? `Tool "${toolName}" was canceled by the user.`
6714
+ ),
6214
6715
  toolName,
6215
6716
  { stopAfterPermissionCancel: true }
6216
6717
  );
@@ -6218,10 +6719,15 @@ ${this.pendingWorktreeNotice}
6218
6719
  let output;
6219
6720
  let outcome;
6220
6721
  try {
6221
- output = await this.client.requestPermission(
6222
- params
6722
+ output = await requestPermissionWithAbort(
6723
+ this.client,
6724
+ params,
6725
+ activeToolAbortSignal
6726
+ );
6727
+ outcome = resolvePermissionOutcome(
6728
+ output,
6729
+ offeredPermissionOptions
6223
6730
  );
6224
- outcome = output.outcome.outcome === "cancelled" ? "cancel" /* Cancel */ : external_exports.nativeEnum(ToolConfirmationOutcome).parse(output.outcome.optionId);
6225
6731
  } catch (error) {
6226
6732
  debugLogger6.error(
6227
6733
  `Permission request failed for tool ${toolName}:`,
@@ -6238,7 +6744,9 @@ ${this.pendingWorktreeNotice}
6238
6744
  );
6239
6745
  }
6240
6746
  onStopAfterPermissionCancel?.();
6241
- const permissionFailureMessage = isExitPlanModeTool ? "The host could not present plan-exit approval. Plan mode remains active; use the host mode selector or /plan exit to leave plan mode." : `Permission request failed for "${toolName}": ${this.#formatError(
6747
+ const permissionFailureMessage = isExitPlanModeTool ? "The host could not present plan-exit approval. Plan mode remains active; use the host mode selector or /plan exit to leave plan mode." : planShellDecision.classification === "unknown" ? `Plan mode could not complete approval for this shell command: ${this.#formatError(
6748
+ error
6749
+ )}. The command was not run; Plan mode remains active.` : `Permission request failed for "${toolName}": ${this.#formatError(
6242
6750
  error
6243
6751
  )}`;
6244
6752
  return earlyErrorResponse(
@@ -6247,11 +6755,32 @@ ${this.pendingWorktreeNotice}
6247
6755
  { stopAfterPermissionCancel: true }
6248
6756
  );
6249
6757
  }
6758
+ let confirmationPayload = {
6759
+ answers: output.answers
6760
+ };
6761
+ if (planShellDecision.classification !== "not-applicable") {
6762
+ const approval = await validatePlanModeShellApproval({
6763
+ config: this.config,
6764
+ decision: planShellDecision,
6765
+ requestArgs: args,
6766
+ invocationParams: invocation.params,
6767
+ signal: activeToolAbortSignal,
6768
+ outcome,
6769
+ payload: confirmationPayload
6770
+ });
6771
+ outcome = approval.outcome;
6772
+ confirmationPayload = approval.payload;
6773
+ }
6774
+ const shouldSwitchToDefault = outcome === "proceed_once_and_switch_to_default" /* ProceedOnceAndSwitchToDefault */;
6775
+ if (shouldSwitchToDefault) {
6776
+ outcome = "proceed_once" /* ProceedOnce */;
6777
+ }
6250
6778
  recordAutoModeFallbackResolution(outcome);
6251
6779
  try {
6252
- await confirmationDetails.onConfirm(outcome, {
6253
- answers: output.answers
6254
- });
6780
+ await confirmationDetails.onConfirm(
6781
+ outcome,
6782
+ confirmationPayload
6783
+ );
6255
6784
  } catch (error) {
6256
6785
  if (outcome !== "cancel" /* Cancel */) {
6257
6786
  throw error;
@@ -6262,21 +6791,31 @@ ${this.pendingWorktreeNotice}
6262
6791
  );
6263
6792
  return stopAfterPermissionCancel();
6264
6793
  }
6794
+ if (shouldSwitchToDefault) {
6795
+ this.config.setApprovalMode("default" /* DEFAULT */);
6796
+ await this.sendCurrentModeUpdateNotification();
6797
+ }
6265
6798
  if (outcome === "proceed_always" /* ProceedAlways */ || outcome === "proceed_always_project" /* ProceedAlwaysProject */ || outcome === "proceed_always_user" /* ProceedAlwaysUser */) {
6266
6799
  await persistPermissionOutcome(
6267
6800
  outcome,
6268
6801
  confirmationDetails,
6269
6802
  this.config.getOnPersistPermissionRule?.(),
6270
6803
  this.config.getPermissionManager?.(),
6271
- { answers: output.answers }
6804
+ confirmationPayload
6272
6805
  );
6273
6806
  }
6274
6807
  if (confirmationDetails.type === "edit" && outcome === "proceed_always" /* ProceedAlways */) {
6275
6808
  await this.sendCurrentModeUpdateNotification();
6276
6809
  }
6277
6810
  switch (outcome) {
6811
+ case "proceed_once_and_switch_to_default" /* ProceedOnceAndSwitchToDefault */:
6812
+ throw new Error(
6813
+ "Switch-to-Default outcome must be normalized before execution."
6814
+ );
6278
6815
  case "cancel" /* Cancel */:
6279
- return stopAfterPermissionCancel();
6816
+ return stopAfterPermissionCancel(
6817
+ confirmationPayload?.cancelMessage
6818
+ );
6280
6819
  case "proceed_once" /* ProceedOnce */:
6281
6820
  case "proceed_always" /* ProceedAlways */:
6282
6821
  case "proceed_always_project" /* ProceedAlwaysProject */:
@@ -6308,7 +6847,7 @@ ${this.pendingWorktreeNotice}
6308
6847
  if (hooksEnabledForTool && messageBusForTool) {
6309
6848
  const preHookResult = await firePreToolUseHook(
6310
6849
  messageBusForTool,
6311
- toolName,
6850
+ policyToolName,
6312
6851
  args,
6313
6852
  toolUseId,
6314
6853
  permissionMode,
@@ -6425,7 +6964,7 @@ ${this.pendingWorktreeNotice}
6425
6964
  };
6426
6965
  const postHookResult = await firePostToolUseHook(
6427
6966
  messageBusForTool,
6428
- toolName,
6967
+ policyToolName,
6429
6968
  args,
6430
6969
  toolResponse,
6431
6970
  toolUseId,
@@ -6456,7 +6995,7 @@ ${this.pendingWorktreeNotice}
6456
6995
  const failureHookResult = await firePostToolUseFailureHook(
6457
6996
  messageBusForTool,
6458
6997
  toolUseId,
6459
- toolName,
6998
+ policyToolName,
6460
6999
  args,
6461
7000
  toolResult.error?.message ?? "Tool execution was cancelled",
6462
7001
  isInterrupt,
@@ -6510,12 +7049,18 @@ ${this.pendingWorktreeNotice}
6510
7049
  prompt_id: promptId,
6511
7050
  tool_type: typeof tool !== "undefined" && tool instanceof DiscoveredMCPTool ? "mcp" : "native"
6512
7051
  });
6513
- this.config.getChatRecordingService()?.recordToolResult(responseParts, {
7052
+ queueToolResultRecord?.(fc, {
6514
7053
  callId,
6515
- status,
6516
- resultDisplay: toolResult.returnDisplay,
6517
- error: toolResult.error ? new Error(toolResult.error.message) : void 0,
6518
- errorType: toolResult.error?.type
7054
+ toolName,
7055
+ responseParts,
7056
+ persistedOutputFiles: toolResult.persistedOutputFiles,
7057
+ metadata: {
7058
+ callId,
7059
+ status,
7060
+ resultDisplay: toolResult.returnDisplay,
7061
+ error: toolResult.error ? new Error(toolResult.error.message) : void 0,
7062
+ errorType: toolResult.error?.type
7063
+ }
6519
7064
  });
6520
7065
  spanSuccess = succeeded;
6521
7066
  if (toolResult.error) {
@@ -6545,7 +7090,7 @@ ${this.pendingWorktreeNotice}
6545
7090
  const failureHookResult = await firePostToolUseFailureHook(
6546
7091
  messageBusForError,
6547
7092
  toolUseId,
6548
- toolName,
7093
+ policyToolName,
6549
7094
  args,
6550
7095
  error.message,
6551
7096
  isInterrupt,
@@ -6566,24 +7111,6 @@ ${this.pendingWorktreeNotice}
6566
7111
  });
6567
7112
  }
6568
7113
  await this.toolCallEmitter.emitError(callId, toolName, error);
6569
- const errorParts = [
6570
- {
6571
- functionResponse: {
6572
- id: callId,
6573
- name: toolName,
6574
- response: { error: error.message }
6575
- }
6576
- }
6577
- ];
6578
- this.config.getChatRecordingService()?.recordToolResult(errorParts, {
6579
- callId,
6580
- // A throw caused by abort (e.g. AbortError) is a cancellation, not
6581
- // a genuine tool error — keep it consistent with the success path.
6582
- status: activeToolAbortSignal.aborted ? "cancelled" : "error",
6583
- resultDisplay: void 0,
6584
- error,
6585
- errorType: void 0
6586
- });
6587
7114
  const loopDetected = !activeToolAbortSignal.aborted && !toolBuildSucceeded && recordDaemonInvalidToolParams(
6588
7115
  this.config,
6589
7116
  promptId,
@@ -6592,6 +7119,18 @@ ${this.pendingWorktreeNotice}
6592
7119
  error
6593
7120
  );
6594
7121
  const responseParts = errorResponse(error);
7122
+ queueToolResultRecord?.(fc, {
7123
+ callId,
7124
+ toolName,
7125
+ responseParts,
7126
+ metadata: {
7127
+ callId,
7128
+ status: activeToolAbortSignal.aborted ? "cancelled" : "error",
7129
+ resultDisplay: void 0,
7130
+ error,
7131
+ errorType: void 0
7132
+ }
7133
+ });
6595
7134
  return {
6596
7135
  parts: responseParts,
6597
7136
  stopAfterPermissionCancel: nestedPermissionCancelled,
@@ -7228,6 +7767,7 @@ var QWEN_ACP_LOCAL_READ_ROOTS_ENV = "QWEN_ACP_LOCAL_READ_ROOTS";
7228
7767
  var POSIX_TMP_LOCAL_READ_ROOT = "/tmp";
7229
7768
  var BTW_CHILD_TIMEOUT_MS = 55e3;
7230
7769
  var MCP_OAUTH_START_TIMEOUT_MS = 3e4;
7770
+ var SESSION_DRAIN_TIMEOUT_MS = 3e4;
7231
7771
  var WORKSPACE_MEMORY_REMEMBER_CHILD_TIMEOUT_MS = 295e3;
7232
7772
  function createAcpSessionStartProfiler(span) {
7233
7773
  let failedStage;
@@ -7286,6 +7826,77 @@ function workspaceMemoryErrorData(code, diagnostics) {
7286
7826
  };
7287
7827
  }
7288
7828
  __name(workspaceMemoryErrorData, "workspaceMemoryErrorData");
7829
+ var SESSION_WRITER_MESSAGES = {
7830
+ session_writer_conflict: "This session is already open in another Qwen process.",
7831
+ session_writer_lost: "Write ownership for this session was lost.",
7832
+ session_transcript_changed: "The session transcript changed outside its active writer.",
7833
+ session_writer_unavailable: "Session write ownership could not be verified."
7834
+ };
7835
+ function getSessionWriterError(error) {
7836
+ if (!error || typeof error !== "object") return void 0;
7837
+ const candidate = error;
7838
+ const errorKind = candidate["errorKind"];
7839
+ if (typeof errorKind !== "string" || !(errorKind in SESSION_WRITER_RPC_CODES)) {
7840
+ return void 0;
7841
+ }
7842
+ const typedKind = errorKind;
7843
+ if (candidate["rpcCode"] !== SESSION_WRITER_RPC_CODES[typedKind]) {
7844
+ return void 0;
7845
+ }
7846
+ return {
7847
+ rpcCode: SESSION_WRITER_RPC_CODES[typedKind],
7848
+ errorKind: typedKind,
7849
+ message: SESSION_WRITER_MESSAGES[typedKind]
7850
+ };
7851
+ }
7852
+ __name(getSessionWriterError, "getSessionWriterError");
7853
+ function mapSessionWriterRequestError(error) {
7854
+ const writerError = getSessionWriterError(error);
7855
+ return writerError ? new RequestError(writerError.rpcCode, writerError.message, {
7856
+ errorKind: writerError.errorKind
7857
+ }) : error;
7858
+ }
7859
+ __name(mapSessionWriterRequestError, "mapSessionWriterRequestError");
7860
+ async function shutdownSessionConfig(config) {
7861
+ await config.shutdown({ shutdownTelemetry: false });
7862
+ if (config.hasSessionWriteOwnership()) {
7863
+ throw new SessionWriterUnavailableError();
7864
+ }
7865
+ }
7866
+ __name(shutdownSessionConfig, "shutdownSessionConfig");
7867
+ async function waitForSessionDrain(operation, timeoutMs, kind) {
7868
+ let timer;
7869
+ const timeout = new Promise((_, reject) => {
7870
+ timer = setTimeout(
7871
+ () => reject(new Error(`Session ${kind} timed out after ${timeoutMs}ms`)),
7872
+ timeoutMs
7873
+ );
7874
+ timer.unref();
7875
+ });
7876
+ try {
7877
+ await Promise.race([operation, timeout]);
7878
+ } finally {
7879
+ if (timer) clearTimeout(timer);
7880
+ }
7881
+ }
7882
+ __name(waitForSessionDrain, "waitForSessionDrain");
7883
+ async function beginSessionCloseAfterCurrentGate(session, timeoutMs) {
7884
+ const deadline = Date.now() + timeoutMs;
7885
+ while (true) {
7886
+ const releaseGate = session.beginCloseIfAvailable();
7887
+ if (releaseGate) return releaseGate;
7888
+ const remainingMs = deadline - Date.now();
7889
+ if (remainingMs <= 0) {
7890
+ throw new Error(`Session close timed out after ${timeoutMs}ms`);
7891
+ }
7892
+ await waitForSessionDrain(
7893
+ session.waitForCloseGateToRelease(),
7894
+ remainingMs,
7895
+ "close"
7896
+ );
7897
+ }
7898
+ }
7899
+ __name(beginSessionCloseAfterCurrentGate, "beginSessionCloseAfterCurrentGate");
7289
7900
  var logWorkspaceMemoryExtractionError = createWorkspaceMemoryExtractionErrorLogger(debugLogger7);
7290
7901
  function parseAcpLocalReadRootsEnv(raw = process.env[QWEN_ACP_LOCAL_READ_ROOTS_ENV]) {
7291
7902
  if (!raw) return [];
@@ -7303,7 +7914,7 @@ function buildAcpLocalReadRoots(config) {
7303
7914
  // local read fallback, not read_file's default permission.
7304
7915
  config.storage.getProjectTempDir(),
7305
7916
  path4.join(config.storage.getProjectDir(), "subagents"),
7306
- Storage.getGlobalTempDir(),
7917
+ path4.join(config.getSessionRuntimeBaseDir(), "tmp"),
7307
7918
  getAutoMemoryRoot(config.getTargetDir()),
7308
7919
  getUserAutoMemoryRoot(),
7309
7920
  ...config.storage.getUserSkillsDirs(),
@@ -8881,7 +9492,7 @@ async function runAcpAgent(config, settings, argv) {
8881
9492
  debugLogger7.debug("[ACP] Shutdown signal received, closing streams");
8882
9493
  try {
8883
9494
  await fireSessionEndOnce("other" /* Other */);
8884
- agentInstance?.disposeSessions();
9495
+ await agentInstance?.disposeSessions();
8885
9496
  try {
8886
9497
  process.stdin.destroy();
8887
9498
  } catch {
@@ -8908,7 +9519,7 @@ async function runAcpAgent(config, settings, argv) {
8908
9519
  await connection.closed;
8909
9520
  await fireSessionEndOnce("prompt_input_exit" /* PromptInputExit */);
8910
9521
  await drainPoolBeforeExit("ide_close");
8911
- agentInstance?.disposeSessions();
9522
+ await agentInstance?.disposeSessions();
8912
9523
  } finally {
8913
9524
  process.off("SIGTERM", shutdownHandler);
8914
9525
  process.off("SIGINT", shutdownHandler);
@@ -9067,6 +9678,7 @@ var QwenAgent = class {
9067
9678
  mcpAuthenticationResults = /* @__PURE__ */ new Map();
9068
9679
  generationControllers = /* @__PURE__ */ new Map();
9069
9680
  transcriptReplayConfigCache = /* @__PURE__ */ new Map();
9681
+ pendingConfigCleanup = /* @__PURE__ */ new Map();
9070
9682
  clientCapabilities;
9071
9683
  // CPU-usage delta baseline for the daemon's `workspaceResource` extMethod
9072
9684
  // (Daemon Status child-resource chart). The daemon polls this at a fixed
@@ -9169,21 +9781,26 @@ var QwenAgent = class {
9169
9781
  async createWorkspaceMcpDiscoveryConfig(settings) {
9170
9782
  if (this.workspaceMcpDiscoveryConfig) return;
9171
9783
  const cwd = this.config.getTargetDir();
9172
- const config = await loadCliConfig(
9173
- settings.merged,
9174
- {
9175
- ...this.argv,
9176
- sessionId: "workspace-mcp-discovery",
9177
- resume: void 0,
9178
- continue: false
9179
- },
9784
+ const config = await this.runWithPinnedRuntimeBaseDir(
9785
+ settings,
9180
9786
  cwd,
9181
- void 0,
9182
- {
9183
- userHooks: settings.getUserHooks(),
9184
- projectHooks: settings.getProjectHooks()
9185
- },
9186
- buildDisabledSkillNamesProvider(settings)
9787
+ () => loadCliConfig(
9788
+ settings.merged,
9789
+ {
9790
+ ...this.argv,
9791
+ sessionId: "workspace-mcp-discovery",
9792
+ resume: void 0,
9793
+ continue: false,
9794
+ chatRecording: false
9795
+ },
9796
+ cwd,
9797
+ void 0,
9798
+ {
9799
+ userHooks: settings.getUserHooks(),
9800
+ projectHooks: settings.getProjectHooks()
9801
+ },
9802
+ buildDisabledSkillNamesProvider(settings)
9803
+ )
9187
9804
  );
9188
9805
  config.setMcpTransportPool(this.mcpPool);
9189
9806
  try {
@@ -9291,100 +9908,225 @@ var QwenAgent = class {
9291
9908
  );
9292
9909
  }
9293
9910
  }
9294
- async closeStoredSession(sessionId, opts) {
9295
- for (const [requestId, generation] of this.generationControllers) {
9296
- if (generation.sessionId !== sessionId) continue;
9297
- generation.controller.abort();
9298
- this.generationControllers.delete(requestId);
9299
- }
9300
- const session = this.sessions.get(sessionId);
9301
- if (!session) {
9302
- this.mcpPool?.releaseSession(sessionId);
9303
- return;
9911
+ async removeStoredSessionEntry(sessionId, session, cleanupErrors = [], options = {}) {
9912
+ if (this.sessions.get(sessionId) !== session) return;
9913
+ try {
9914
+ session.dispose();
9915
+ } catch (error) {
9916
+ cleanupErrors.push(error);
9304
9917
  }
9305
- const requireFlush = opts?.requireFlush === true;
9306
- const flushRecording = /* @__PURE__ */ __name(async () => {
9918
+ if (options.shutdownConfig !== false) {
9307
9919
  try {
9308
- await session.getConfig().getChatRecordingService()?.flush();
9309
- return void 0;
9310
- } catch (err) {
9311
- debugLogger7.debug(
9312
- `Session ${sessionId} chat recording flush during close failed: ${err instanceof Error ? err.message : String(err)}`
9313
- );
9314
- return err;
9315
- }
9316
- }, "flushRecording");
9317
- if (requireFlush) {
9318
- const preCancelFlushError = await flushRecording();
9319
- if (preCancelFlushError !== void 0) {
9320
- throw preCancelFlushError;
9920
+ await session.getConfig().shutdown({ shutdownTelemetry: false });
9921
+ } catch (error) {
9922
+ cleanupErrors.push(error);
9321
9923
  }
9322
9924
  }
9323
9925
  try {
9324
- await session.cancelPendingPrompt();
9325
- } catch (err) {
9326
- debugLogger7.debug(
9327
- `Session ${sessionId} cancel during close failed: ${err instanceof Error ? err.message : String(err)}`
9328
- );
9926
+ unregisterGoalHook(session.getConfig(), sessionId);
9927
+ } catch (error) {
9928
+ cleanupErrors.push(error);
9329
9929
  }
9330
- const flushError = await flushRecording();
9331
- if (flushError !== void 0 && requireFlush) {
9332
- throw flushError;
9930
+ try {
9931
+ this.mcpPool?.releaseSession(sessionId);
9932
+ } catch (error) {
9933
+ cleanupErrors.push(error);
9333
9934
  }
9334
9935
  try {
9335
- await session.getConfig().getToolRegistry()?.stop();
9336
- } catch (err) {
9337
- debugLogger7.debug(
9338
- `Session ${sessionId} tool registry stop during close failed: ${err instanceof Error ? err.message : String(err)}`
9339
- );
9936
+ uiTelemetryService.removeSession(sessionId);
9937
+ } catch (error) {
9938
+ cleanupErrors.push(error);
9340
9939
  }
9341
- unregisterGoalHook(session.getConfig(), sessionId);
9342
- this.mcpPool?.releaseSession(sessionId);
9343
- uiTelemetryService.removeSession(sessionId);
9344
9940
  this.sessions.delete(sessionId);
9345
- }
9346
- discardStoredSessionIfCurrent(sessionId, session) {
9347
- if (this.sessions.get(sessionId) !== session) {
9348
- return;
9349
- }
9350
- const logCleanupFailure = /* @__PURE__ */ __name((action, err) => {
9351
- debugLogger7.debug(
9352
- `Session ${sessionId} ${action} during failed restore cleanup failed: ${err instanceof Error ? err.message : String(err)}`
9941
+ if (cleanupErrors.length > 0) {
9942
+ debugLogger7.warn(
9943
+ `Session ${sessionId} closed after ${cleanupErrors.length} cleanup failure(s): ${cleanupErrors.map(
9944
+ (error) => error instanceof Error ? error.message : String(error)
9945
+ ).join("; ")}`
9353
9946
  );
9354
- }, "logCleanupFailure");
9947
+ }
9948
+ }
9949
+ async withLiveSessionRestore(sessionId, session, operation) {
9950
+ await session.assertCanStartTurn();
9951
+ const config = session.getConfig();
9952
+ const releaseGate = session.beginClose();
9355
9953
  try {
9356
- session.dispose();
9357
- } catch (err) {
9358
- logCleanupFailure("dispose", err);
9954
+ await waitForSessionDrain(
9955
+ session.waitForActiveTurnsToSettle(),
9956
+ SESSION_DRAIN_TIMEOUT_MS,
9957
+ "restore"
9958
+ );
9959
+ const recorder = config.getChatRecordingService();
9960
+ const loadAuthoritative = /* @__PURE__ */ __name(() => config.getSessionService().loadSession(sessionId), "loadAuthoritative");
9961
+ const data = recorder ? await recorder.runWithWriteBarrier(loadAuthoritative) : await loadAuthoritative();
9962
+ if (!data) throw new SessionWriterUnavailableError();
9963
+ return await operation(config, data);
9964
+ } catch (error) {
9965
+ throw mapSessionWriterRequestError(error);
9966
+ } finally {
9967
+ releaseGate();
9359
9968
  }
9969
+ }
9970
+ async cleanupUnstoredConfig(config) {
9971
+ const sessionId = config.getSessionId();
9972
+ const cleanupKey = this.pendingConfigCleanupKey(
9973
+ config.getSessionRuntimeBaseDir(),
9974
+ sessionId
9975
+ );
9360
9976
  try {
9361
- unregisterGoalHook(session.getConfig(), sessionId);
9362
- } catch (err) {
9363
- logCleanupFailure("goal hook unregister", err);
9977
+ await shutdownSessionConfig(config);
9978
+ } catch (error) {
9979
+ const pending2 = this.pendingConfigCleanup.get(cleanupKey) ?? /* @__PURE__ */ new Set();
9980
+ pending2.add(config);
9981
+ this.pendingConfigCleanup.set(cleanupKey, pending2);
9982
+ throw mapSessionWriterRequestError(error);
9983
+ }
9984
+ const pending = this.pendingConfigCleanup.get(cleanupKey);
9985
+ pending?.delete(config);
9986
+ if (pending?.size === 0) {
9987
+ this.pendingConfigCleanup.delete(cleanupKey);
9364
9988
  }
9989
+ }
9990
+ async cleanupAfterRequestFailure(error, cleanup) {
9365
9991
  try {
9992
+ await cleanup();
9993
+ } catch (cleanupError) {
9994
+ debugLogger7.warn(
9995
+ `Session cleanup failed while preserving the original request error: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`
9996
+ );
9997
+ }
9998
+ throw error;
9999
+ }
10000
+ pendingConfigCleanupKey(runtimeBaseDir, sessionId) {
10001
+ return `${path4.resolve(runtimeBaseDir)}\0${sessionId}`;
10002
+ }
10003
+ async retryPendingConfigCleanup(runtimeBaseDir, requiredSessionId) {
10004
+ const resolvedRuntimeBaseDir = path4.resolve(runtimeBaseDir);
10005
+ const configs = /* @__PURE__ */ new Set();
10006
+ for (const pending of this.pendingConfigCleanup.values()) {
10007
+ for (const config of pending) {
10008
+ if (path4.resolve(config.getSessionRuntimeBaseDir()) === resolvedRuntimeBaseDir) {
10009
+ configs.add(config);
10010
+ }
10011
+ }
10012
+ }
10013
+ for (const config of configs) {
10014
+ try {
10015
+ await this.cleanupUnstoredConfig(config);
10016
+ } catch (error) {
10017
+ if (config.getSessionId() === requiredSessionId) throw error;
10018
+ debugLogger7.warn(
10019
+ `Deferred Config cleanup retry failed for session ${config.getSessionId()}: ${error instanceof Error ? error.message : String(error)}`
10020
+ );
10021
+ }
10022
+ }
10023
+ }
10024
+ async closeStoredSession(sessionId, opts) {
10025
+ const session = this.sessions.get(sessionId);
10026
+ if (!session) {
9366
10027
  this.mcpPool?.releaseSession(sessionId);
9367
- } catch (err) {
9368
- logCleanupFailure("MCP pool release", err);
10028
+ return;
10029
+ }
10030
+ const recorder = session.getConfig().getChatRecordingService();
10031
+ const requireFlush = opts?.requireFlush === true;
10032
+ if (requireFlush) {
10033
+ await recorder?.flush();
10034
+ }
10035
+ const drainTimeoutMs = opts?.drainTimeoutMs ?? SESSION_DRAIN_TIMEOUT_MS;
10036
+ const cancelClose = opts?.waitForCloseGate ? await beginSessionCloseAfterCurrentGate(session, drainTimeoutMs) : session.beginClose();
10037
+ for (const [requestId, generation] of this.generationControllers) {
10038
+ if (generation.sessionId !== sessionId) continue;
10039
+ generation.controller.abort();
10040
+ this.generationControllers.delete(requestId);
9369
10041
  }
10042
+ let removedFromStore = false;
9370
10043
  try {
9371
- uiTelemetryService.removeSession(sessionId);
9372
- } catch (err) {
9373
- logCleanupFailure("telemetry removal", err);
10044
+ await waitForSessionDrain(
10045
+ (async () => {
10046
+ try {
10047
+ await session.cancelPendingPrompt();
10048
+ } catch (err) {
10049
+ debugLogger7.debug(
10050
+ `Session ${sessionId} cancel during close failed: ${err instanceof Error ? err.message : String(err)}`
10051
+ );
10052
+ }
10053
+ await session.waitForActiveTurnsToSettle();
10054
+ })(),
10055
+ drainTimeoutMs,
10056
+ "close"
10057
+ );
10058
+ recorder?.finalize();
10059
+ let flushError;
10060
+ try {
10061
+ await recorder?.flush();
10062
+ } catch (error) {
10063
+ flushError = error;
10064
+ }
10065
+ if (flushError !== void 0 && requireFlush) {
10066
+ throw flushError;
10067
+ }
10068
+ let closeError;
10069
+ try {
10070
+ await recorder?.close();
10071
+ } catch (error) {
10072
+ closeError = error;
10073
+ }
10074
+ if (recorder?.hasWriteOwnership()) {
10075
+ throw closeError ?? new SessionWriterUnavailableError();
10076
+ }
10077
+ const cleanupErrors = [];
10078
+ if (flushError !== void 0) cleanupErrors.push(flushError);
10079
+ if (closeError !== void 0) cleanupErrors.push(closeError);
10080
+ await this.removeStoredSessionEntry(sessionId, session, cleanupErrors, {
10081
+ shutdownConfig: opts?.shutdownConfig
10082
+ });
10083
+ removedFromStore = true;
10084
+ } finally {
10085
+ if (!removedFromStore) cancelClose();
9374
10086
  }
9375
- this.sessions.delete(sessionId);
9376
10087
  }
9377
- disposeSessions() {
10088
+ async discardStoredSessionIfCurrent(sessionId, session, opts) {
10089
+ if (this.sessions.get(sessionId) !== session) {
10090
+ return;
10091
+ }
10092
+ await this.closeStoredSession(sessionId, opts);
10093
+ }
10094
+ async disposeSessions() {
9378
10095
  for (const generation of this.generationControllers.values()) {
9379
10096
  generation.controller.abort();
9380
10097
  }
9381
10098
  this.generationControllers.clear();
9382
- for (const session of this.sessions.values()) {
9383
- session.dispose();
9384
- }
9385
- this.sessions.clear();
10099
+ await Promise.allSettled(
10100
+ [...this.sessions.entries()].map(
10101
+ ([sessionId, session]) => this.discardStoredSessionIfCurrent(sessionId, session, {
10102
+ waitForCloseGate: true
10103
+ })
10104
+ )
10105
+ );
10106
+ await Promise.allSettled(
10107
+ [...this.pendingConfigCleanup.values()].flatMap((configs) => [...configs]).map((config) => this.cleanupUnstoredConfig(config))
10108
+ );
9386
10109
  this.disposeTranscriptReplayConfigs();
9387
10110
  }
10111
+ runWithPinnedRuntimeBaseDir(settings, cwd, operation) {
10112
+ return runWithAcpRuntimeOutputDir(settings, cwd, operation);
10113
+ }
10114
+ async assertLiveSessionScope(config, settings, cwd) {
10115
+ if (path4.resolve(config.storage.getProjectRoot()) !== path4.resolve(cwd)) {
10116
+ throw RequestError.invalidParams(
10117
+ void 0,
10118
+ "The live session belongs to another workspace."
10119
+ );
10120
+ }
10121
+ const requestedRuntimeBaseDir = await this.runWithPinnedRuntimeBaseDir(
10122
+ settings,
10123
+ cwd,
10124
+ () => Storage.getRuntimeBaseDir()
10125
+ );
10126
+ if (path4.resolve(config.getSessionRuntimeBaseDir()) !== path4.resolve(requestedRuntimeBaseDir)) {
10127
+ throw mapSessionWriterRequestError(new SessionWriterUnavailableError());
10128
+ }
10129
+ }
9388
10130
  /** Expose the pool's workspace-scoped budget controller for snapshot builders. */
9389
10131
  getWorkspaceMcpBudget() {
9390
10132
  return this.workspaceMcpBudget;
@@ -9414,7 +10156,7 @@ var QwenAgent = class {
9414
10156
  markAcpStartup("initializeHandlerStart");
9415
10157
  this.clientCapabilities = args.clientCapabilities;
9416
10158
  const authMethods = buildAuthMethods();
9417
- const version = "0.20.1-preview.7215";
10159
+ const version = "0.20.1";
9418
10160
  const response = {
9419
10161
  protocolVersion: PROTOCOL_VERSION,
9420
10162
  agentInfo: {
@@ -9503,15 +10245,24 @@ var QwenAgent = class {
9503
10245
  "config_setup",
9504
10246
  () => this.newSessionConfig(cwd, mcpServers, settings)
9505
10247
  );
9506
- await profiler.time("auth", () => this.ensureAuthenticated(config));
9507
- profiler.timeSync(
9508
- "file_system_setup",
9509
- () => this.setupFileSystem(config)
9510
- );
9511
- const session = await profiler.time(
9512
- "session_register",
9513
- () => this.createAndStoreSession(config, settings)
9514
- );
10248
+ let session;
10249
+ try {
10250
+ await profiler.time("auth", () => this.ensureAuthenticated(config));
10251
+ profiler.timeSync(
10252
+ "file_system_setup",
10253
+ () => this.setupFileSystem(config)
10254
+ );
10255
+ session = await profiler.time(
10256
+ "session_register",
10257
+ () => this.createAndStoreSession(config, settings)
10258
+ );
10259
+ } catch (error) {
10260
+ return this.cleanupAfterRequestFailure(error, async () => {
10261
+ if (this.sessions.get(config.getSessionId())?.getConfig() !== config) {
10262
+ await this.cleanupUnstoredConfig(config);
10263
+ }
10264
+ });
10265
+ }
9515
10266
  profiler.setSessionId(session.getId());
9516
10267
  return profiler.timeSync("response_build", () => ({
9517
10268
  sessionId: session.getId(),
@@ -9525,7 +10276,56 @@ var QwenAgent = class {
9525
10276
  }
9526
10277
  async loadSession(params) {
9527
10278
  const settings = loadSettingsCached(params.cwd);
9528
- const exists = await runWithAcpRuntimeOutputDir(
10279
+ const liveSession = this.sessions.get(params.sessionId);
10280
+ if (liveSession) {
10281
+ const liveConfig = liveSession.getConfig();
10282
+ await this.assertLiveSessionScope(liveConfig, settings, params.cwd);
10283
+ return this.withLiveSessionRestore(
10284
+ params.sessionId,
10285
+ liveSession,
10286
+ async (config2, sessionData2) => {
10287
+ const response2 = {
10288
+ modes: this.buildModesData(config2),
10289
+ models: this.buildAvailableModels(config2),
10290
+ configOptions: this.buildConfigOptions(config2),
10291
+ ...sessionData2.artifactSnapshot ? { artifactSnapshot: sessionData2.artifactSnapshot } : {}
10292
+ };
10293
+ const records = sessionData2.conversation.messages;
10294
+ if (records.length === 0) return response2;
10295
+ const bulkReplay2 = isBulkLoadReplayRequest(params);
10296
+ const replayPage = bulkReplay2 ? selectRecentHistoryRecords(records, getLoadReplayPageSize(params)) : { records, hasMore: false };
10297
+ const replay = await collectHistoryReplayUpdates({
10298
+ sessionId: params.sessionId,
10299
+ config: config2,
10300
+ records: replayPage.records,
10301
+ gaps: sessionData2.historyGaps,
10302
+ cumulativeUsage: createReplayCumulativeUsage(),
10303
+ logger: debugLogger7
10304
+ });
10305
+ if (!bulkReplay2) {
10306
+ for (const update of replay.updates) {
10307
+ await liveSession.sendUpdate(update);
10308
+ }
10309
+ if (replay.replayError !== void 0) {
10310
+ throw RequestError.internalError(void 0, replay.replayError);
10311
+ }
10312
+ return response2;
10313
+ }
10314
+ return {
10315
+ ...response2,
10316
+ _meta: {
10317
+ [LOAD_REPLAY_META_KEY]: {
10318
+ v: LOAD_REPLAY_VERSION,
10319
+ updates: replay.updates,
10320
+ ...replay.replayError !== void 0 ? { partial: true, replayError: replay.replayError } : {},
10321
+ ...replayPage.hasMore ? { hasMore: true } : {}
10322
+ }
10323
+ }
10324
+ };
10325
+ }
10326
+ );
10327
+ }
10328
+ const exists = await this.runWithPinnedRuntimeBaseDir(
9529
10329
  settings,
9530
10330
  params.cwd,
9531
10331
  async () => {
@@ -9548,17 +10348,26 @@ var QwenAgent = class {
9548
10348
  params.sessionId,
9549
10349
  true
9550
10350
  );
9551
- await this.ensureAuthenticated(config);
9552
- this.setupFileSystem(config);
9553
10351
  const sessionData = config.getResumedSessionData();
9554
10352
  const bulkReplay = isBulkLoadReplayRequest(params);
9555
10353
  const replayPageSize = bulkReplay ? getLoadReplayPageSize(params) : void 0;
9556
- const session = await this.createAndStoreSession(
9557
- config,
9558
- settings,
9559
- sessionData,
9560
- bulkReplay ? { replayHistory: false, startPostReplayServices: false } : {}
9561
- );
10354
+ let session;
10355
+ try {
10356
+ await this.ensureAuthenticated(config);
10357
+ this.setupFileSystem(config);
10358
+ session = await this.createAndStoreSession(
10359
+ config,
10360
+ settings,
10361
+ sessionData,
10362
+ bulkReplay ? { replayHistory: false, startPostReplayServices: false } : {}
10363
+ );
10364
+ } catch (error) {
10365
+ return this.cleanupAfterRequestFailure(error, async () => {
10366
+ if (this.sessions.get(config.getSessionId())?.getConfig() !== config) {
10367
+ await this.cleanupUnstoredConfig(config);
10368
+ }
10369
+ });
10370
+ }
9562
10371
  let replayEnvelope;
9563
10372
  if (bulkReplay) {
9564
10373
  try {
@@ -9605,8 +10414,21 @@ var QwenAgent = class {
9605
10414
  session.installRewriter();
9606
10415
  session.startCronScheduler();
9607
10416
  } catch (err) {
9608
- this.discardStoredSessionIfCurrent(params.sessionId, session);
9609
- throw err;
10417
+ return this.cleanupAfterRequestFailure(err, async () => {
10418
+ try {
10419
+ await this.discardStoredSessionIfCurrent(params.sessionId, session);
10420
+ } catch (cleanupError) {
10421
+ await this.removeStoredSessionEntry(
10422
+ params.sessionId,
10423
+ session,
10424
+ [cleanupError],
10425
+ {
10426
+ shutdownConfig: false
10427
+ }
10428
+ );
10429
+ await this.cleanupUnstoredConfig(config);
10430
+ }
10431
+ });
9610
10432
  }
9611
10433
  }
9612
10434
  await this.#restoreWorktreeOnResume(config, session);
@@ -9632,7 +10454,22 @@ var QwenAgent = class {
9632
10454
  }
9633
10455
  async unstable_resumeSession(params) {
9634
10456
  const settings = loadSettingsCached(params.cwd);
9635
- const exists = await runWithAcpRuntimeOutputDir(
10457
+ const liveSession = this.sessions.get(params.sessionId);
10458
+ if (liveSession) {
10459
+ const liveConfig = liveSession.getConfig();
10460
+ await this.assertLiveSessionScope(liveConfig, settings, params.cwd);
10461
+ return this.withLiveSessionRestore(
10462
+ params.sessionId,
10463
+ liveSession,
10464
+ async (config2, sessionData2) => ({
10465
+ modes: this.buildModesData(config2),
10466
+ models: this.buildAvailableModels(config2),
10467
+ configOptions: this.buildConfigOptions(config2),
10468
+ ...sessionData2.artifactSnapshot ? { artifactSnapshot: sessionData2.artifactSnapshot } : {}
10469
+ })
10470
+ );
10471
+ }
10472
+ const exists = await this.runWithPinnedRuntimeBaseDir(
9636
10473
  settings,
9637
10474
  params.cwd,
9638
10475
  async () => {
@@ -9651,14 +10488,23 @@ var QwenAgent = class {
9651
10488
  params.sessionId,
9652
10489
  true
9653
10490
  );
9654
- await this.ensureAuthenticated(config);
9655
- this.setupFileSystem(config);
9656
- const session = await this.createAndStoreSession(
9657
- config,
9658
- settings,
9659
- config.getResumedSessionData(),
9660
- { replayHistory: false }
9661
- );
10491
+ let session;
10492
+ try {
10493
+ await this.ensureAuthenticated(config);
10494
+ this.setupFileSystem(config);
10495
+ session = await this.createAndStoreSession(
10496
+ config,
10497
+ settings,
10498
+ config.getResumedSessionData(),
10499
+ { replayHistory: false }
10500
+ );
10501
+ } catch (error) {
10502
+ return this.cleanupAfterRequestFailure(error, async () => {
10503
+ if (this.sessions.get(config.getSessionId())?.getConfig() !== config) {
10504
+ await this.cleanupUnstoredConfig(config);
10505
+ }
10506
+ });
10507
+ }
9662
10508
  await this.#restoreWorktreeOnResume(config, session);
9663
10509
  this.#restoreGoalOnResume(config, session);
9664
10510
  const modesData = this.buildModesData(config);
@@ -11572,6 +12418,19 @@ var QwenAgent = class {
11572
12418
  };
11573
12419
  }
11574
12420
  async extMethod(method, params) {
12421
+ try {
12422
+ return await this.extMethodInternal(method, params);
12423
+ } catch (error) {
12424
+ const writerError = getSessionWriterError(error);
12425
+ if (writerError) {
12426
+ throw new RequestError(writerError.rpcCode, writerError.message, {
12427
+ errorKind: writerError.errorKind
12428
+ });
12429
+ }
12430
+ throw error;
12431
+ }
12432
+ }
12433
+ async extMethodInternal(method, params) {
11575
12434
  const requestedCwd = typeof params["cwd"] === "string" ? params["cwd"] : void 0;
11576
12435
  const cwd = requestedCwd || process.cwd();
11577
12436
  const SESSION_ID_RE = /^[0-9a-fA-F-]{32,36}$/;
@@ -12712,6 +13571,34 @@ var QwenAgent = class {
12712
13571
  }
12713
13572
  return { sessionId, persisted: true, kind };
12714
13573
  }
13574
+ case "qwen/session/recordTextElements": {
13575
+ const sessionId = params["sessionId"];
13576
+ const content = params["content"];
13577
+ const textElements = params["textElements"];
13578
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
13579
+ throw RequestError.invalidParams(
13580
+ void 0,
13581
+ "Invalid or missing sessionId"
13582
+ );
13583
+ }
13584
+ if (typeof content !== "string" || !Array.isArray(textElements)) {
13585
+ throw RequestError.invalidParams(
13586
+ void 0,
13587
+ "Invalid user text elements payload"
13588
+ );
13589
+ }
13590
+ const session = this.sessionOrThrow(sessionId);
13591
+ await session.assertCanStartTurn();
13592
+ const recording = session.getConfig().getChatRecordingService();
13593
+ if (!recording) {
13594
+ throw RequestError.internalError(
13595
+ void 0,
13596
+ "Chat recording service unavailable"
13597
+ );
13598
+ }
13599
+ await recording.recordUserTextElements({ content, textElements });
13600
+ return { sessionId, persisted: true };
13601
+ }
12715
13602
  case SERVE_CONTROL_EXT_METHODS.sessionTitle: {
12716
13603
  const sessionId = params["sessionId"];
12717
13604
  const displayName = params["displayName"];
@@ -12807,8 +13694,16 @@ var QwenAgent = class {
12807
13694
  "Invalid or missing sessionId"
12808
13695
  );
12809
13696
  }
13697
+ const rawDrainTimeoutMs = params["drainTimeoutMs"];
13698
+ if (rawDrainTimeoutMs !== void 0 && (typeof rawDrainTimeoutMs !== "number" || !Number.isSafeInteger(rawDrainTimeoutMs) || rawDrainTimeoutMs < 1 || rawDrainTimeoutMs > 2147483647)) {
13699
+ throw RequestError.invalidParams(
13700
+ void 0,
13701
+ "Invalid session close drain timeout"
13702
+ );
13703
+ }
12810
13704
  await this.closeStoredSession(sessionId, {
12811
- requireFlush: params["requireFlush"] === true
13705
+ requireFlush: params["requireFlush"] === true,
13706
+ ...typeof rawDrainTimeoutMs === "number" ? { drainTimeoutMs: rawDrainTimeoutMs } : {}
12812
13707
  });
12813
13708
  return { sessionId, closed: true };
12814
13709
  }
@@ -12850,6 +13745,21 @@ var QwenAgent = class {
12850
13745
  });
12851
13746
  }
12852
13747
  const canonicalPath = await fs2.realpath(targetPath);
13748
+ const allowedRoots = params["allowedRoots"];
13749
+ if (Array.isArray(allowedRoots) && allowedRoots.length > 0) {
13750
+ const contained = allowedRoots.some((root) => {
13751
+ if (typeof root !== "string") return false;
13752
+ const rel = path4.relative(root, canonicalPath);
13753
+ return !rel.startsWith("..") && !path4.isAbsolute(rel);
13754
+ });
13755
+ if (!contained) {
13756
+ throw new RequestError(
13757
+ -32004,
13758
+ `Path outside allowed roots: ${canonicalPath}`,
13759
+ { errorKind: "containment_violation", path: canonicalPath }
13760
+ );
13761
+ }
13762
+ }
12853
13763
  const previousCwd = config.getTargetDir();
12854
13764
  if (canonicalPath === previousCwd) {
12855
13765
  return { previousCwd, newCwd: canonicalPath, warnings: [] };
@@ -13731,16 +14641,11 @@ ${outputText}
13731
14641
  let artifactSnapshot;
13732
14642
  let artifactSnapshotUnavailable;
13733
14643
  try {
13734
- await session.getConfig().getChatRecordingService()?.flush();
13735
- const cwd2 = session.getConfig().getProjectRoot();
13736
- const sessionData = await runWithAcpRuntimeOutputDir(
13737
- this.settings,
13738
- cwd2,
13739
- async () => {
13740
- const sessionService = new SessionService(cwd2);
13741
- return sessionService.loadSession(sessionId);
13742
- }
13743
- );
14644
+ const config = session.getConfig();
14645
+ const recording = config.getChatRecordingService();
14646
+ await recording?.flush();
14647
+ const loadAuthoritative = /* @__PURE__ */ __name(() => config.getSessionService().loadSession(sessionId), "loadAuthoritative");
14648
+ const sessionData = recording ? await recording.runWithWriteBarrier(loadAuthoritative) : await loadAuthoritative();
13744
14649
  if (sessionData === void 0) {
13745
14650
  artifactSnapshotUnavailable = "session data unavailable after rewind";
13746
14651
  } else if (sessionData.artifactSnapshot) {
@@ -13781,20 +14686,37 @@ ${outputText}
13781
14686
  "Invalid or missing sessionId"
13782
14687
  );
13783
14688
  }
13784
- const sessionData = await runWithAcpRuntimeOutputDir(
13785
- this.settings,
13786
- cwd,
13787
- async () => {
13788
- const sessionService = new SessionService(cwd);
13789
- return sessionService.loadSession(sessionId);
13790
- }
13791
- );
14689
+ const liveSession = this.sessions.get(sessionId);
14690
+ let replayConfig = this.config;
14691
+ let sessionData;
14692
+ if (liveSession) {
14693
+ const config = liveSession.getConfig();
14694
+ await this.assertLiveSessionScope(
14695
+ config,
14696
+ loadSettingsCached(cwd),
14697
+ cwd
14698
+ );
14699
+ const recording = config.getChatRecordingService();
14700
+ const loadAuthoritative = /* @__PURE__ */ __name(() => config.getSessionService().loadSession(sessionId), "loadAuthoritative");
14701
+ sessionData = recording ? await recording.runWithWriteBarrier(loadAuthoritative) : await loadAuthoritative();
14702
+ replayConfig = config;
14703
+ } else {
14704
+ const settings = loadSettingsCached(cwd);
14705
+ sessionData = await this.runWithPinnedRuntimeBaseDir(
14706
+ settings,
14707
+ cwd,
14708
+ async () => {
14709
+ const sessionService = new SessionService(cwd);
14710
+ return sessionService.loadSession(sessionId);
14711
+ }
14712
+ );
14713
+ }
13792
14714
  if (!sessionData?.conversation) {
13793
14715
  return { updates: [] };
13794
14716
  }
13795
14717
  const replay = await collectHistoryReplayUpdates({
13796
14718
  sessionId,
13797
- config: this.config,
14719
+ config: replayConfig,
13798
14720
  records: sessionData.conversation.messages,
13799
14721
  gaps: sessionData.historyGaps,
13800
14722
  cumulativeUsage: createReplayCumulativeUsage(),
@@ -13862,56 +14784,51 @@ ${outputText}
13862
14784
  sessionId
13863
14785
  });
13864
14786
  }
13865
- const recording = sourceSession.getConfig().getChatRecordingService();
14787
+ const sourceConfig = sourceSession.getConfig();
14788
+ const recording = sourceConfig.getChatRecordingService();
13866
14789
  if (recording) {
13867
14790
  await recording.flush();
13868
14791
  }
13869
- const newSessionId = randomUUID();
13870
- return await runWithAcpRuntimeOutputDir(
13871
- this.settings,
13872
- cwd,
13873
- async () => {
13874
- const sessionService = new SessionService(cwd);
13875
- await sessionService.forkSession(sessionId, newSessionId);
13876
- let title;
13877
- try {
13878
- let baseName;
13879
- if (typeof name === "string" && name.trim().length > 0) {
13880
- baseName = name.trim();
13881
- } else {
13882
- const existingTitle = recording?.getCurrentCustomTitle();
13883
- const stripped = existingTitle?.replace(/\s*\(Branch(?:\s+\d+)?\)\s*$/, "").trim();
13884
- if (stripped && stripped.length > 0) {
13885
- baseName = stripped;
13886
- } else {
13887
- baseName = sessionId.slice(0, 8);
13888
- }
13889
- }
13890
- title = await computeUniqueBranchTitle(baseName, sessionService);
13891
- const renamed = await sessionService.renameSession(
13892
- newSessionId,
13893
- title,
13894
- "manual"
13895
- );
13896
- if (!renamed) {
13897
- throw new RequestError(
13898
- -32603,
13899
- `Failed to set title on forked session ${newSessionId}`,
13900
- { errorKind: "internal", sessionId: newSessionId }
13901
- );
13902
- }
13903
- } catch (err) {
13904
- sessionService.removeSession(newSessionId).catch((rmErr) => {
13905
- process.stderr.write(
13906
- `qwen serve: failed to clean up orphan session ${newSessionId}: ${rmErr instanceof Error ? rmErr.message : rmErr}
13907
- `
13908
- );
13909
- });
13910
- throw err;
14792
+ const newSessionId = randomUUID2();
14793
+ const sessionService = sourceConfig.getSessionService();
14794
+ await sessionService.forkSession(sessionId, newSessionId);
14795
+ let title;
14796
+ try {
14797
+ let baseName;
14798
+ if (typeof name === "string" && name.trim().length > 0) {
14799
+ baseName = name.trim();
14800
+ } else {
14801
+ const existingTitle = recording?.getCurrentCustomTitle();
14802
+ const stripped = existingTitle?.replace(/\s*\(Branch(?:\s+\d+)?\)\s*$/, "").trim();
14803
+ if (stripped && stripped.length > 0) {
14804
+ baseName = stripped;
14805
+ } else {
14806
+ baseName = sessionId.slice(0, 8);
13911
14807
  }
13912
- return { newSessionId, title, displayName: title };
13913
14808
  }
13914
- );
14809
+ title = await computeUniqueBranchTitle(baseName, sessionService);
14810
+ const renamed = await sessionService.renameSession(
14811
+ newSessionId,
14812
+ title,
14813
+ "manual"
14814
+ );
14815
+ if (!renamed) {
14816
+ throw new RequestError(
14817
+ -32603,
14818
+ `Failed to set title on forked session ${newSessionId}`,
14819
+ { errorKind: "internal", sessionId: newSessionId }
14820
+ );
14821
+ }
14822
+ } catch (err) {
14823
+ sessionService.removeSession(newSessionId).catch((rmErr) => {
14824
+ process.stderr.write(
14825
+ `qwen serve: failed to clean up orphan session ${newSessionId}: ${rmErr instanceof Error ? rmErr.message : rmErr}
14826
+ `
14827
+ );
14828
+ });
14829
+ throw err;
14830
+ }
14831
+ return { newSessionId, title, displayName: title };
13915
14832
  }
13916
14833
  case "qwen/settings/getCore": {
13917
14834
  const settings = loadSettings(cwd);
@@ -14300,17 +15217,25 @@ ${outputText}
14300
15217
  this.disposeTranscriptReplayConfig(cached.config);
14301
15218
  }
14302
15219
  const entry = { settings };
14303
- const pending = this.newSessionConfig(cwd, [], settings, void 0, false, {
14304
- skipMcpDiscovery: true,
14305
- skipHooks: true,
14306
- skipSkillManager: true,
14307
- skipFileCheckpointing: true,
14308
- // Read-only replay: tolerate tools that cannot construct without the
14309
- // subsystems skipped above (e.g. SkillTool needs the SkillManager). The
14310
- // registry is only consulted for optional tool_call metadata during
14311
- // replay, and ToolCallEmitter falls back to the recorded tool name.
14312
- lenientToolWarmup: true
14313
- });
15220
+ const pending = this.newSessionConfig(
15221
+ cwd,
15222
+ [],
15223
+ settings,
15224
+ void 0,
15225
+ false,
15226
+ {
15227
+ skipMcpDiscovery: true,
15228
+ skipHooks: true,
15229
+ skipSkillManager: true,
15230
+ skipFileCheckpointing: true,
15231
+ // Read-only replay: tolerate tools that cannot construct without the
15232
+ // subsystems skipped above (e.g. SkillTool needs the SkillManager). The
15233
+ // registry is only consulted for optional tool_call metadata during
15234
+ // replay, and ToolCallEmitter falls back to the recorded tool name.
15235
+ lenientToolWarmup: true
15236
+ },
15237
+ false
15238
+ );
14314
15239
  entry.pending = pending;
14315
15240
  this.transcriptReplayConfigCache.set(key, entry);
14316
15241
  try {
@@ -14338,7 +15263,34 @@ ${outputText}
14338
15263
  throw error;
14339
15264
  }
14340
15265
  }
14341
- async newSessionConfig(cwd, mcpServers, settings, sessionId, resume, initializeOptions = {}) {
15266
+ async newSessionConfig(cwd, mcpServers, settings, sessionId, resume, initializeOptions = {}, chatRecording) {
15267
+ try {
15268
+ return await this.runWithPinnedRuntimeBaseDir(settings, cwd, async () => {
15269
+ await this.retryPendingConfigCleanup(
15270
+ Storage.getRuntimeBaseDir(),
15271
+ sessionId
15272
+ );
15273
+ return this.newSessionConfigInRuntimeContext(
15274
+ cwd,
15275
+ mcpServers,
15276
+ settings,
15277
+ sessionId,
15278
+ resume,
15279
+ initializeOptions,
15280
+ chatRecording
15281
+ );
15282
+ });
15283
+ } catch (error) {
15284
+ const writerError = getSessionWriterError(error);
15285
+ if (writerError) {
15286
+ throw new RequestError(writerError.rpcCode, writerError.message, {
15287
+ errorKind: writerError.errorKind
15288
+ });
15289
+ }
15290
+ throw error;
15291
+ }
15292
+ }
15293
+ async newSessionConfigInRuntimeContext(cwd, mcpServers, settings, sessionId, resume, initializeOptions = {}, chatRecording) {
14342
15294
  const sessionMcpServers = {};
14343
15295
  for (const server of mcpServers) {
14344
15296
  const stdioServer = toStdioServer(server);
@@ -14394,8 +15346,14 @@ ${outputText}
14394
15346
  const sessionArg = resume === true ? { resume: sessionId, sessionId: void 0 } : { sessionId, resume: void 0 };
14395
15347
  const argvForSession = {
14396
15348
  ...this.argv,
15349
+ // Docker sandbox relaunch injects a fixed --sandbox-session-id into
15350
+ // the ACP process argv. Without clearing it, every newSession()
15351
+ // inherits the same ID and the second session collides with the
15352
+ // first's writer lease (#7435).
15353
+ sandboxSessionId: void 0,
14397
15354
  ...sessionArg,
14398
- continue: false
15355
+ continue: false,
15356
+ ...chatRecording !== void 0 ? { chatRecording } : {}
14399
15357
  };
14400
15358
  const config = await loadCliConfig(
14401
15359
  mergedSettings,
@@ -14449,15 +15407,22 @@ ${outputText}
14449
15407
  });
14450
15408
  });
14451
15409
  }
14452
- await config.initialize({
14453
- ...initializeOptions,
14454
- // Reverse tool channel (issue #5626, Phase 2): bind the session
14455
- // manager's SDK MCP callback to the `client_mcp/message` ext-method so a
14456
- // client-hosted (extension) MCP server added at runtime reaches the
14457
- // daemon WS. Servers that aren't client-hosted never use this callback
14458
- // (the daemon only adds SDK-type runtime servers for client MCP).
14459
- sendSdkMcpMessage: this.buildClientMcpSender(wiredSessionId)
14460
- });
15410
+ try {
15411
+ await config.initialize({
15412
+ ...initializeOptions,
15413
+ // Reverse tool channel (issue #5626, Phase 2): bind the session
15414
+ // manager's SDK MCP callback to the `client_mcp/message` ext-method so a
15415
+ // client-hosted (extension) MCP server added at runtime reaches the
15416
+ // daemon WS. Servers that aren't client-hosted never use this callback
15417
+ // (the daemon only adds SDK-type runtime servers for client MCP).
15418
+ sendSdkMcpMessage: this.buildClientMcpSender(wiredSessionId)
15419
+ });
15420
+ } catch (error) {
15421
+ return this.cleanupAfterRequestFailure(
15422
+ error,
15423
+ () => this.cleanupUnstoredConfig(config)
15424
+ );
15425
+ }
14461
15426
  void this.surfaceMcpFailuresWhenReady(config);
14462
15427
  return config;
14463
15428
  }
@@ -14518,29 +15483,47 @@ ${outputText}
14518
15483
  if (needsInitialize) {
14519
15484
  await geminiClient.initialize();
14520
15485
  }
14521
- this.sessions.get(sessionId)?.dispose();
15486
+ if (this.sessions.has(sessionId)) {
15487
+ throw new Error(`Session ${sessionId} is already active.`);
15488
+ }
14522
15489
  const session = new Session(sessionId, config, this.connection, settings);
14523
15490
  this.sessions.set(sessionId, session);
14524
- setTimeout(async () => {
14525
- await session.sendAvailableCommandsUpdate();
14526
- }, 0);
14527
- if (sessionData?.fileHistorySnapshots?.length) {
14528
- config.getFileHistoryService().restoreFromSnapshots(sessionData.fileHistorySnapshots);
14529
- }
14530
- if (sessionData?.conversation.messages) {
14531
- config.getChatRecordingService()?.rebuildTurnBoundaries(sessionData.conversation.messages);
14532
- }
14533
- if (options.replayHistory !== false && sessionData?.conversation.messages) {
14534
- await session.replayHistory(
14535
- sessionData.conversation.messages,
14536
- sessionData.historyGaps
14537
- );
14538
- }
14539
- if (options.startPostReplayServices !== false) {
14540
- session.installRewriter();
14541
- session.startCronScheduler();
15491
+ try {
15492
+ if (sessionData?.fileHistorySnapshots?.length) {
15493
+ config.getFileHistoryService().restoreFromSnapshots(sessionData.fileHistorySnapshots);
15494
+ }
15495
+ if (sessionData?.conversation.messages) {
15496
+ config.getChatRecordingService()?.rebuildTurnBoundaries(sessionData.conversation.messages);
15497
+ }
15498
+ if (options.replayHistory !== false && sessionData?.conversation.messages) {
15499
+ await session.replayHistory(
15500
+ sessionData.conversation.messages,
15501
+ sessionData.historyGaps
15502
+ );
15503
+ }
15504
+ if (options.startPostReplayServices !== false) {
15505
+ session.installRewriter();
15506
+ session.startCronScheduler();
15507
+ }
15508
+ setTimeout(() => {
15509
+ void session.sendAvailableCommandsUpdate();
15510
+ }, 0);
15511
+ return session;
15512
+ } catch (error) {
15513
+ try {
15514
+ await this.discardStoredSessionIfCurrent(sessionId, session, {
15515
+ shutdownConfig: false
15516
+ });
15517
+ } catch (cleanupError) {
15518
+ await this.removeStoredSessionEntry(
15519
+ sessionId,
15520
+ session,
15521
+ [cleanupError],
15522
+ { shutdownConfig: false }
15523
+ );
15524
+ }
15525
+ throw error;
14542
15526
  }
14543
- return session;
14544
15527
  }
14545
15528
  buildAvailableModels(config) {
14546
15529
  const rawCurrentModelId = (config.getModel() || this.config.getModel() || "").trim();