@qwen-code/qwen-code 0.19.2 → 0.19.3-nightly.20260630.e00fe6a27

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 (286) hide show
  1. package/bundled/extension-creator/SKILL.md +357 -0
  2. package/bundled/loop/SKILL.md +21 -7
  3. package/bundled/loop/SKILL.test.ts +41 -0
  4. package/bundled/loop/loop-task-file.test.ts +1064 -0
  5. package/bundled/loop/loop-task-file.ts +404 -0
  6. package/bundled/loop/loop-tick-resolver.test.ts +665 -0
  7. package/bundled/loop/loop-tick-resolver.ts +347 -0
  8. package/bundled/qc-helper/SKILL.md +26 -19
  9. package/bundled/qc-helper/docs/configuration/auth.md +11 -11
  10. package/bundled/qc-helper/docs/configuration/model-providers.md +13 -13
  11. package/bundled/qc-helper/docs/configuration/settings.md +76 -75
  12. package/bundled/qc-helper/docs/features/channels/plugins.md +1 -1
  13. package/bundled/qc-helper/docs/features/commands.md +108 -77
  14. package/bundled/qc-helper/docs/features/hooks.md +6 -1
  15. package/bundled/qc-helper/docs/features/memory.md +52 -0
  16. package/bundled/qc-helper/docs/qwen-serve.md +24 -2
  17. package/bundled/qc-helper/docs/support/tos-privacy.md +16 -3
  18. package/bundled/qc-helper/docs/support/troubleshooting.md +6 -0
  19. package/chunks/{MaxSizedBox-7RERNLFK.js → MaxSizedBox-T5X5MN5Q.js} +29 -27
  20. package/chunks/{StandaloneSessionPicker-S22XBSN6.js → StandaloneSessionPicker-P3E3WTOQ.js} +42 -37
  21. package/chunks/{acpAgent-4MCETHF2.js → acpAgent-QEP6DXFW.js} +864 -175
  22. package/chunks/{agent-K3ENVYSB.js → agent-UDANDUF7.js} +24 -23
  23. package/chunks/{agent-headless-HO3V3A3A.js → agent-headless-KYVSZHSO.js} +24 -23
  24. package/chunks/{anthropicContentGenerator-E3TQ5XJJ.js → anthropicContentGenerator-KWSJAQ7B.js} +33 -12
  25. package/chunks/{artifact-tool-QA4KRO3B.js → artifact-tool-D2X7G3C3.js} +2 -2
  26. package/chunks/{askUserQuestion-HMWXW6VN.js → askUserQuestion-UGETICJQ.js} +2 -2
  27. package/chunks/{bridge-4LV2HBH2.js → bridge-X42LXPTA.js} +31 -30
  28. package/chunks/{ca-7WC7ELX6.js → ca-IUFWESZL.js} +1 -0
  29. package/chunks/{chunk-JXQ23SNT.js → chunk-2JKEQWDZ.js} +623 -78
  30. package/chunks/{chunk-2TJ3YN6Q.js → chunk-2RJA6J57.js} +416 -401
  31. package/chunks/{chunk-3UALQ56H.js → chunk-3227DZO4.js} +1 -1
  32. package/chunks/{chunk-BGUDAULQ.js → chunk-3CPCDXFR.js} +5 -5
  33. package/chunks/{chunk-5RVSM6NW.js → chunk-3HUHAQF3.js} +1 -1
  34. package/chunks/{chunk-D5E5TMYH.js → chunk-3M4W4U5G.js} +16 -2
  35. package/chunks/{chunk-DBZUXSSV.js → chunk-4X7NIEQJ.js} +3 -3
  36. package/chunks/chunk-5GOVVXEV.js +73 -0
  37. package/chunks/{chunk-2BAQ3ACS.js → chunk-5SM4VT6V.js} +405 -5
  38. package/chunks/{chunk-NYOHZYHM.js → chunk-5XQ4A26L.js} +45 -3
  39. package/chunks/{chunk-CI5O6SQL.js → chunk-6FKEVYCD.js} +4 -4
  40. package/chunks/{chunk-ZD3NW5KL.js → chunk-7LM4XHPE.js} +63 -9
  41. package/chunks/chunk-7UNP2XM7.js +840 -0
  42. package/chunks/{chunk-OQHQHJRK.js → chunk-ARYCHZ4B.js} +151 -4775
  43. package/chunks/chunk-BC3C4F3Q.js +40 -0
  44. package/chunks/{chunk-CGEGHF2C.js → chunk-BKXBARJZ.js} +1 -1
  45. package/chunks/chunk-BMFMJINR.js +45 -0
  46. package/chunks/chunk-BOJWHRMX.js +11273 -0
  47. package/chunks/{chunk-CGOMICBE.js → chunk-BSZEQNUA.js} +34 -1
  48. package/chunks/{chunk-OIC6S73E.js → chunk-BUUQ5HPX.js} +1 -1
  49. package/chunks/{chunk-2BIF2NVV.js → chunk-BVSVIN45.js} +2 -2
  50. package/chunks/{chunk-TOEGRAVX.js → chunk-BX5YO7UW.js} +17 -5
  51. package/chunks/{chunk-4W4T77MO.js → chunk-BXVWV4GI.js} +109 -6
  52. package/chunks/{chunk-VQRYPFCV.js → chunk-CYHVPQYT.js} +10 -460
  53. package/chunks/{chunk-PRYMDRBV.js → chunk-DDMOU62Q.js} +1 -1
  54. package/chunks/{chunk-S566HKUS.js → chunk-DHXWNSJA.js} +15 -1
  55. package/chunks/{chunk-F6XNTYNE.js → chunk-E6XQPQXW.js} +30 -307
  56. package/chunks/{chunk-QBZ22PQX.js → chunk-EWALXUAD.js} +3 -1
  57. package/chunks/{chunk-EL5IHQON.js → chunk-EWYQFWYF.js} +6 -27
  58. package/chunks/{chunk-HG6YKEBI.js → chunk-F2DOT6UZ.js} +161 -30
  59. package/chunks/{chunk-JTYRZODB.js → chunk-FOOIZCWL.js} +16 -7
  60. package/chunks/{chunk-EX4W6ZYG.js → chunk-G5G4TFZ7.js} +1 -1
  61. package/chunks/{chunk-EW6C27XX.js → chunk-GEHVIWAT.js} +9 -3
  62. package/chunks/chunk-HEVBZSXG.js +4923 -0
  63. package/chunks/chunk-HFQ2XSE7.js +690 -0
  64. package/chunks/{chunk-PF523XJX.js → chunk-HPGTGMP3.js} +1 -1
  65. package/chunks/{chunk-OTBK43JR.js → chunk-HYCC3XM3.js} +1 -1
  66. package/chunks/{chunk-TMBPDHXD.js → chunk-I4H7PRWQ.js} +1 -1
  67. package/chunks/{chunk-EEEZIVFJ.js → chunk-JOLIREYR.js} +1 -1
  68. package/chunks/{chunk-TZM5JIAX.js → chunk-JYPQTRA3.js} +10 -7
  69. package/chunks/chunk-K5XU6E4T.js +167 -0
  70. package/chunks/{chunk-BS64PXY3.js → chunk-KFVU7ODN.js} +1 -1
  71. package/chunks/{chunk-3RJ3ZPPR.js → chunk-KKQWC6WS.js} +7 -7
  72. package/chunks/{chunk-3QFE4OTE.js → chunk-LBW7NW7X.js} +4 -4
  73. package/chunks/{chunk-Z7XXFPGP.js → chunk-LDWTYE33.js} +1 -1
  74. package/chunks/{chunk-EXMX5YHG.js → chunk-LP5E4YIH.js} +1 -1
  75. package/chunks/{chunk-ZUAXI2OA.js → chunk-M2U5NM24.js} +188 -11366
  76. package/chunks/{chunk-I5T6PIBQ.js → chunk-MBV2CTRL.js} +1010 -925
  77. package/chunks/{chunk-5JZLXFPD.js → chunk-MTHMXSNT.js} +11 -11
  78. package/chunks/{chunk-FPACXT7T.js → chunk-MTJVHQDP.js} +534 -164
  79. package/chunks/chunk-NDOC6M5S.js +481 -0
  80. package/chunks/{chunk-HGNSRCRB.js → chunk-NL4C3H6C.js} +1 -1
  81. package/chunks/{chunk-GZCJS5WH.js → chunk-O2VBQ3Y2.js} +2 -2
  82. package/chunks/{chunk-UN3C6GOR.js → chunk-PPFWEV7G.js} +10 -108
  83. package/chunks/{chunk-RS4HRC75.js → chunk-QI2CFVRF.js} +85 -8
  84. package/chunks/{chunk-XU5P23GN.js → chunk-QLDPRILK.js} +3 -3
  85. package/chunks/chunk-QYUE6W3T.js +123 -0
  86. package/chunks/{chunk-USGMPVOY.js → chunk-R3LHDWF2.js} +21 -12
  87. package/chunks/{chunk-BNXANYLH.js → chunk-RD6YJJJ6.js} +81 -1
  88. package/chunks/{chunk-PXFFKNCO.js → chunk-RIP623NO.js} +4877 -2469
  89. package/chunks/{chunk-XKBP7M7A.js → chunk-RYBSUGOR.js} +142 -30
  90. package/chunks/{chunk-BG4BIP7F.js → chunk-SBBN4BWR.js} +4 -2
  91. package/chunks/{chunk-T2VDEFUU.js → chunk-SKQZZVAV.js} +2 -2
  92. package/chunks/{chunk-5R4SBCX6.js → chunk-SL5MOGQH.js} +3 -3
  93. package/chunks/chunk-SMXULRAN.js +37 -0
  94. package/chunks/{chunk-WA5OJGFL.js → chunk-SS6WJMQK.js} +363 -76
  95. package/chunks/{chunk-UAARVVBI.js → chunk-TNWFHGN6.js} +1 -1
  96. package/chunks/{chunk-I2RFAW6Q.js → chunk-TT6Q3EN4.js} +7 -5
  97. package/chunks/chunk-UAKXW3DN.js +30 -0
  98. package/chunks/{chunk-C4K3FEQ2.js → chunk-UX4SGCGN.js} +32 -3
  99. package/chunks/{chunk-J6AW7O5D.js → chunk-WHDQZHRU.js} +2 -2
  100. package/chunks/{chunk-WGAEWQTF.js → chunk-WN6K47NR.js} +1 -2
  101. package/chunks/{chunk-UAARJR2G.js → chunk-WQT5SOI6.js} +2 -2
  102. package/chunks/{chunk-VYFMN7C6.js → chunk-WUMVIRTN.js} +225 -37
  103. package/chunks/{chunk-R36VMVEP.js → chunk-XJMKOTVV.js} +5 -5
  104. package/chunks/{chunk-TXVGVZYR.js → chunk-XJYUPHRC.js} +3 -3
  105. package/chunks/{chunk-2JD55C6G.js → chunk-Y6YMRS3U.js} +2 -2
  106. package/chunks/{chunk-LLFFKXZZ.js → chunk-YALKC62D.js} +56 -29
  107. package/chunks/{chunk-GYZQA2FO.js → chunk-YLZJCUH6.js} +1 -1
  108. package/chunks/chunk-YTFBURQD.js +313 -0
  109. package/chunks/{chunk-KBXLIVWQ.js → chunk-ZFPRYHWR.js} +2 -2
  110. package/chunks/{chunk-X6EDWN44.js → chunk-ZP6UKOPB.js} +1 -1
  111. package/chunks/{computer-use-6BBRNT6S.js → computer-use-LF2S6LUZ.js} +103 -49
  112. package/chunks/{contextCommand-UJAJ6N57.js → contextCommand-VPX5UG55.js} +26 -25
  113. package/chunks/{cron-create-4KQE6YLH.js → cron-create-SKEY55RG.js} +4 -4
  114. package/chunks/{cron-delete-THME66UP.js → cron-delete-I3NAT32Z.js} +6 -6
  115. package/chunks/{cron-list-7A54SJ5N.js → cron-list-6XRRL6TH.js} +5 -5
  116. package/chunks/{daemon-status-provider-CSL3BUOY.js → daemon-status-provider-5JAWZS4V.js} +34 -34
  117. package/chunks/{de-ACHALDED.js → de-EOW5PVHF.js} +1 -0
  118. package/chunks/{dist-BD27IA3L.js → dist-4FCNM6KJ.js} +2 -2
  119. package/chunks/{dist-OD2FY543.js → dist-O3H4PABL.js} +2 -2
  120. package/chunks/{dist-BOOH5JWN.js → dist-SCAAUWPS.js} +18 -4
  121. package/chunks/{dist-QHJRBCMP.js → dist-UKPWQJCL.js} +44 -2
  122. package/chunks/{dist-QFFZWACU.js → dist-VD7HXTML.js} +20 -9
  123. package/chunks/{earlyInputCapture-X6KMCSHD.js → earlyInputCapture-7FRQMU4P.js} +25 -24
  124. package/chunks/{edit-7J6WXARF.js → edit-REKJDIRL.js} +68 -27
  125. package/chunks/{en-NCUBOJOY.js → en-HPWEJBTR.js} +8 -0
  126. package/chunks/{enter-worktree-KULCKJPJ.js → enter-worktree-GBKUDCD3.js} +24 -23
  127. package/chunks/{enterPlanMode-H2CIOLMH.js → enterPlanMode-WB3Y4FGT.js} +24 -23
  128. package/chunks/{errors-6G2JYR54.js → errors-2XJDYO3M.js} +26 -25
  129. package/chunks/{exit-worktree-ECBWBVC5.js → exit-worktree-KKC7O2ZV.js} +24 -23
  130. package/chunks/{exitPlanMode-DQV56GTW.js → exitPlanMode-7HMS3TF7.js} +24 -23
  131. package/chunks/{fast-path-35JJFS3C.js → fast-path-XVNIYWGG.js} +4 -4
  132. package/chunks/{fast-path-settings-TSVI53EB.js → fast-path-settings-UQLRFDQP.js} +3 -2
  133. package/chunks/{fr-GVKZ27MF.js → fr-BN5NKSAC.js} +1 -0
  134. package/chunks/{gemini-NDTG7WAX.js → gemini-U5TPU3IQ.js} +210 -104
  135. package/chunks/{geminiContentGenerator-XTG6SFLA.js → geminiContentGenerator-ZVWRHXOO.js} +4 -4
  136. package/chunks/{glob-SJ2JBZK4.js → glob-FEJWIH2W.js} +24 -23
  137. package/chunks/{grep-BRMWFEWR.js → grep-KMP25IIA.js} +24 -23
  138. package/chunks/{headlessSafetyWarnings-LJ6FJX77.js → headlessSafetyWarnings-5DEDET4M.js} +24 -23
  139. package/chunks/{initializer-P5AXF7PV.js → initializer-FJTACLOH.js} +31 -28
  140. package/chunks/{ja-FKZ2WZ4D.js → ja-7DEUB2TS.js} +1 -0
  141. package/chunks/{keychain-token-storage-CSYMNRPP.js → keychain-token-storage-YLMDLKXT.js} +2 -2
  142. package/chunks/{list-6COK34BP.js → list-SCQXYJUW.js} +32 -29
  143. package/chunks/{loadedSettingsAdapter-XIUTN245.js → loadedSettingsAdapter-P6KPNAG7.js} +30 -27
  144. package/chunks/{loop-wakeup-33GPXJLA.js → loop-wakeup-FYEQEJUA.js} +7 -7
  145. package/chunks/{ls-BYQY7RVV.js → ls-R5WP4BGZ.js} +4 -4
  146. package/chunks/{lsp-X54RO4IV.js → lsp-GSICJMMW.js} +2 -2
  147. package/chunks/{monitor-DH7KFSJV.js → monitor-JU3HHHVY.js} +24 -23
  148. package/chunks/nonInteractiveCli-IZEKUHU3.js +100 -0
  149. package/chunks/{notebook-edit-D4R4ZLMA.js → notebook-edit-YHY3Z2QQ.js} +52 -23
  150. package/chunks/{openaiContentGenerator-F74IPQ6E.js → openaiContentGenerator-4WUVA3Q2.js} +13 -12
  151. package/chunks/{pt-SY5NCFGR.js → pt-TNZRNLQB.js} +1 -0
  152. package/chunks/{qwenContentGenerator-ATTK5P4D.js → qwenContentGenerator-MVYYR44B.js} +26 -25
  153. package/chunks/{qwenOAuth2-K4AASPCV.js → qwenOAuth2-6HNGHALT.js} +5 -4
  154. package/chunks/{read-file-767G23OY.js → read-file-NABEO2X4.js} +8 -8
  155. package/chunks/{read-mcp-resource-I5HCZJ6X.js → read-mcp-resource-DQQW7H7T.js} +2 -2
  156. package/chunks/{ripGrep-4OMMGSWX.js → ripGrep-YXLK6UTX.js} +24 -23
  157. package/chunks/{ru-FWNXJG4F.js → ru-NIAUBKCN.js} +1 -0
  158. package/chunks/{run-qwen-serve-REKSTYRA.js → run-qwen-serve-4B5QBMLQ.js} +144 -41
  159. package/chunks/{scheduler-UNTFDQLG.js → scheduler-XAKIYBDL.js} +24 -23
  160. package/chunks/{send-message-2DAFXEYP.js → send-message-EE4TWKVU.js} +2 -2
  161. package/chunks/{serve-KZ56QB5S.js → serve-4RXVLUKD.js} +30 -28
  162. package/chunks/{server-BV5TZUMU.js → server-7PA5QGIA.js} +11037 -8747
  163. package/chunks/{session-OIBXFSGD.js → session-WNVWRYAH.js} +194 -57
  164. package/chunks/{settings-WJTCBIRA.js → settings-YJH32TFF.js} +30 -27
  165. package/chunks/{shell-WC52IBHW.js → shell-YFLABOS5.js} +24 -23
  166. package/chunks/{skill-U7F7JR4M.js → skill-N3J7FUAY.js} +38 -11
  167. package/chunks/{spawnChannel-EI2E5BCW.js → spawnChannel-D6WVMFZJ.js} +26 -25
  168. package/chunks/{src-4F6FBZFI.js → src-IU5GDBEH.js} +88 -28
  169. package/chunks/{startInteractiveUI-SFRVB3CE.js → startInteractiveUI-QIPQTRT4.js} +2784 -2474
  170. package/chunks/{syntheticOutput-PPS3HDVA.js → syntheticOutput-T5YHQ6S2.js} +3 -3
  171. package/chunks/{task-create-OUYCA553.js → task-create-BLY7RHXX.js} +6 -6
  172. package/chunks/{task-list-WAX7I2IA.js → task-list-3QUYNVYR.js} +5 -5
  173. package/chunks/{task-stop-CAIL6FNH.js → task-stop-U4RATK2V.js} +2 -2
  174. package/chunks/{task-update-AHEO5OUT.js → task-update-U54O7KJX.js} +6 -6
  175. package/chunks/{team-create-3WC7CIIW.js → team-create-TP4CLLM3.js} +24 -23
  176. package/chunks/{team-delete-HGHFG23B.js → team-delete-LKBYPASD.js} +5 -5
  177. package/chunks/{theme-manager-DICFCT3P.js → theme-manager-N2TBIBZT.js} +25 -24
  178. package/chunks/{todoWrite-IFBMN3FH.js → todoWrite-OYXKTVYN.js} +4 -4
  179. package/chunks/{tool-search-L5K7HLER.js → tool-search-GBBSICYB.js} +101 -16
  180. package/chunks/trustedFolders-F7TBU5CD.js +76 -0
  181. package/chunks/types-QX5C3CHJ.js +12 -0
  182. package/chunks/{validateNonInterActiveAuth-GCH4Z6KI.js → validateNonInterActiveAuth-EQDQPSMI.js} +55 -50
  183. package/chunks/{web-fetch-B5IIQ5TT.js → web-fetch-PCVCML2X.js} +29 -15
  184. package/chunks/{workflow-OB3AND7I.js → workflow-ANJ4FYBK.js} +32 -30
  185. package/chunks/{workspace-providers-status-ZIR5EPOO.js → workspace-providers-status-462QQKQM.js} +32 -29
  186. package/chunks/workspace-service-VTG4G6CW.js +75 -0
  187. package/chunks/{write-file-SEXBNDZM.js → write-file-3P3WMQQW.js} +63 -27
  188. package/chunks/{zh-RBEGQVQT.js → zh-5EUYXASN.js} +8 -0
  189. package/chunks/{zh-TW-QGAVRXT3.js → zh-TW-TR3XYGE5.js} +8 -0
  190. package/cli-entry.js +20 -9
  191. package/cli.js +6 -6
  192. package/locales/ca.js +2 -0
  193. package/locales/de.js +2 -0
  194. package/locales/en.js +14 -0
  195. package/locales/fr.js +2 -0
  196. package/locales/ja.js +1 -0
  197. package/locales/pt.js +2 -0
  198. package/locales/ru.js +2 -0
  199. package/locales/zh-TW.js +12 -0
  200. package/locales/zh.js +12 -0
  201. package/node_modules/@qwen-code/audio-capture/dist/index.d.ts +35 -0
  202. package/node_modules/@qwen-code/audio-capture/dist/index.js +48 -0
  203. package/node_modules/@qwen-code/audio-capture/dist/index.js.map +1 -0
  204. package/node_modules/@qwen-code/audio-capture/dist/platform.d.ts +7 -0
  205. package/node_modules/@qwen-code/audio-capture/dist/platform.js +18 -0
  206. package/node_modules/@qwen-code/audio-capture/dist/platform.js.map +1 -0
  207. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/LICENSE +21 -0
  208. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/README.md +58 -0
  209. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/SECURITY.md +5 -0
  210. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/bin.js +84 -0
  211. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/build-test.js +19 -0
  212. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/index.js +6 -0
  213. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/node-gyp-build.js +207 -0
  214. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/optional.js +7 -0
  215. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/package.json +43 -0
  216. package/node_modules/@qwen-code/audio-capture/package.json +30 -0
  217. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  218. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  219. package/node_modules/@qwen-code/audio-capture/prebuilds/linux-arm64/@qwen-code+audio-capture.node +0 -0
  220. package/node_modules/@qwen-code/audio-capture/prebuilds/linux-x64/@qwen-code+audio-capture.node +0 -0
  221. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  222. package/package.json +18 -6
  223. package/patches/chrome-devtools-mcp+1.4.0.patch +31 -0
  224. package/postinstall.js +50 -0
  225. package/web-shell/assets/{arc-D_ae_Y9k.js → arc-DIemsO_F.js} +1 -1
  226. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BMLRjppa.js → architectureDiagram-3BPJPVTR-CTlUvIQv.js} +1 -1
  227. package/web-shell/assets/{blockDiagram-GPEHLZMM-qVDQC8KL.js → blockDiagram-GPEHLZMM-DG0jmIZK.js} +1 -1
  228. package/web-shell/assets/{c4Diagram-AAUBKEIU-CxWS6MBd.js → c4Diagram-AAUBKEIU-WljDBi55.js} +1 -1
  229. package/web-shell/assets/channel-CbzRbdpA.js +1 -0
  230. package/web-shell/assets/{chunk-2J33WTMH-BtNuY5Yp.js → chunk-2J33WTMH-8nc6onr2.js} +1 -1
  231. package/web-shell/assets/{chunk-4BX2VUAB-BU-x368d.js → chunk-4BX2VUAB-EopXix8Z.js} +1 -1
  232. package/web-shell/assets/{chunk-55IACEB6-DRgTLvBu.js → chunk-55IACEB6-BE4Jz3N3.js} +1 -1
  233. package/web-shell/assets/{chunk-727SXJPM-D2aElv7q.js → chunk-727SXJPM-C_eErgDN.js} +1 -1
  234. package/web-shell/assets/{chunk-AQP2D5EJ-BwHCMRQ0.js → chunk-AQP2D5EJ-DFtVW-Is.js} +1 -1
  235. package/web-shell/assets/{chunk-FMBD7UC4-BMyPH-ku.js → chunk-FMBD7UC4-CJPyxIg9.js} +1 -1
  236. package/web-shell/assets/{chunk-ND2GUHAM-BNKTstUf.js → chunk-ND2GUHAM-Bk-xgj6M.js} +1 -1
  237. package/web-shell/assets/{chunk-QZHKN3VN-gD3vsFId.js → chunk-QZHKN3VN-p3Y4yaFB.js} +1 -1
  238. package/web-shell/assets/classDiagram-4FO5ZUOK-BFdyQ52h.js +1 -0
  239. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BFdyQ52h.js +1 -0
  240. package/web-shell/assets/{cose-bilkent-S5V4N54A-BG9FAsXE.js → cose-bilkent-S5V4N54A-BCMO6Js3.js} +1 -1
  241. package/web-shell/assets/{dagre-BM42HDAG-Cy1sR7om.js → dagre-BM42HDAG-DUMrwASf.js} +1 -1
  242. package/web-shell/assets/default-aEtf0G7-.svg +1 -0
  243. package/web-shell/assets/{diagram-2AECGRRQ-Bxi1I_Vu.js → diagram-2AECGRRQ-C5d7qJbL.js} +1 -1
  244. package/web-shell/assets/{diagram-5GNKFQAL-BGCJjO6y.js → diagram-5GNKFQAL-CjLzMhbT.js} +1 -1
  245. package/web-shell/assets/{diagram-KO2AKTUF-CMTeLXp7.js → diagram-KO2AKTUF-RCoNWeAm.js} +1 -1
  246. package/web-shell/assets/{diagram-LMA3HP47-BN1wyAGh.js → diagram-LMA3HP47-KThXjaNV.js} +1 -1
  247. package/web-shell/assets/{diagram-OG6HWLK6-UYSG_zcp.js → diagram-OG6HWLK6-DKsC2BWz.js} +1 -1
  248. package/web-shell/assets/{erDiagram-TEJ5UH35-DqXL08lw.js → erDiagram-TEJ5UH35-DJ2ukmq0.js} +1 -1
  249. package/web-shell/assets/{flowDiagram-I6XJVG4X-BPJ9SFji.js → flowDiagram-I6XJVG4X-zzqaARRX.js} +1 -1
  250. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BEd9Pnms.js → ganttDiagram-6RSMTGT7-kFUg-gqT.js} +1 -1
  251. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-DrNRH3oi.js → gitGraphDiagram-PVQCEYII-C6JnMVzD.js} +1 -1
  252. package/web-shell/assets/index-B3XUm7dw.js +713 -0
  253. package/web-shell/assets/index-CHmzAWys.css +5 -0
  254. package/web-shell/assets/{infoDiagram-5YYISTIA-CFYBrkVI.js → infoDiagram-5YYISTIA-XqPVhp89.js} +1 -1
  255. package/web-shell/assets/insert-DmRbh9Rv.svg +1 -0
  256. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-Dxsddth7.js → ishikawaDiagram-YF4QCWOH-D2k8sGpf.js} +1 -1
  257. package/web-shell/assets/{journeyDiagram-JHISSGLW-DxaDK80t.js → journeyDiagram-JHISSGLW-CQEST1GE.js} +1 -1
  258. package/web-shell/assets/{kanban-definition-UN3LZRKU-Q0jQCOct.js → kanban-definition-UN3LZRKU-DZ7kqVBC.js} +1 -1
  259. package/web-shell/assets/{linear-DGGM2kcP.js → linear-B6C_6q_E.js} +1 -1
  260. package/web-shell/assets/{mermaid.core-ByoxnWut.js → mermaid.core-CsyNP1qt.js} +5 -5
  261. package/web-shell/assets/{mindmap-definition-RKZ34NQL-C0ZseHsi.js → mindmap-definition-RKZ34NQL-B1VDIzJq.js} +1 -1
  262. package/web-shell/assets/{pieDiagram-4H26LBE5-MQXNhl5A.js → pieDiagram-4H26LBE5-DN0E7Jwu.js} +1 -1
  263. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DIR4ee2A.js → quadrantDiagram-W4KKPZXB-UKTQdHKm.js} +1 -1
  264. package/web-shell/assets/queue-DWpnpFgW.svg +1 -0
  265. package/web-shell/assets/{requirementDiagram-4Y6WPE33-BTR0UdYQ.js → requirementDiagram-4Y6WPE33-BRGceQvN.js} +1 -1
  266. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-sfnhMELN.js → sankeyDiagram-5OEKKPKP-2DDyu41v.js} +1 -1
  267. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DXczHOHH.js → sequenceDiagram-3UESZ5HK-CT5iE8ZU.js} +1 -1
  268. package/web-shell/assets/{stateDiagram-AJRCARHV-DdE_KQFH.js → stateDiagram-AJRCARHV-CqMQ_s4G.js} +1 -1
  269. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CamhV5pM.js +1 -0
  270. package/web-shell/assets/{timeline-definition-PNZ67QCA-DIc61uE8.js → timeline-definition-PNZ67QCA-Di37QSZU.js} +1 -1
  271. package/web-shell/assets/{vennDiagram-CIIHVFJN-BF7ODmxB.js → vennDiagram-CIIHVFJN-DCXvpz5S.js} +1 -1
  272. package/web-shell/assets/{wardley-L42UT6IY-3pc1MEaw.js → wardley-L42UT6IY-CpUCk6OX.js} +1 -1
  273. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-9jnPcZuP.js → wardleyDiagram-YWT4CUSO-D01pVEBg.js} +1 -1
  274. package/web-shell/assets/{xychartDiagram-2RQKCTM6-DcthaZK6.js → xychartDiagram-2RQKCTM6-DOu5JDoz.js} +1 -1
  275. package/web-shell/index.html +2 -2
  276. package/chunks/chunk-B6HQGTYR.js +0 -410
  277. package/chunks/chunk-R2BXK7SX.js +0 -13
  278. package/chunks/chunk-RKIZXJMB.js +0 -13
  279. package/chunks/nonInteractiveCli-7575LBXP.js +0 -91
  280. package/chunks/workspace-service-OM5D4OI2.js +0 -60
  281. package/web-shell/assets/channel-DYPNiTww.js +0 -1
  282. package/web-shell/assets/classDiagram-4FO5ZUOK-p_g25Tni.js +0 -1
  283. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-p_g25Tni.js +0 -1
  284. package/web-shell/assets/index-CpOXWDPh.js +0 -714
  285. package/web-shell/assets/index-oVK7qhre.css +0 -5
  286. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BHUSEndU.js +0 -1
@@ -3,8 +3,13 @@
3
3
  import {
4
4
  classifyApiError,
5
5
  prefixMidTurnUserMessageParts
6
- } from "./chunk-LLFFKXZZ.js";
7
- import "./chunk-B6HQGTYR.js";
6
+ } from "./chunk-YALKC62D.js";
7
+ import {
8
+ EXTENSION_CONTEXT_BUDGET,
9
+ buildExtensionMentionContext,
10
+ matchExtensionByRef,
11
+ parseExtensionRef
12
+ } from "./chunk-7UNP2XM7.js";
8
13
  import {
9
14
  HistoryReplayer,
10
15
  MessageEmitter,
@@ -12,105 +17,118 @@ import {
12
17
  ToolCallEmitter,
13
18
  getAvailableCommands,
14
19
  handleSlashCommand,
20
+ insertAfterFunctionResponses,
15
21
  isSlashCommand,
16
22
  normalizePartList
17
- } from "./chunk-2TJ3YN6Q.js";
23
+ } from "./chunk-2RJA6J57.js";
18
24
  import {
19
25
  appEvents,
20
26
  buildDisabledSkillNamesProvider,
21
27
  loadCliConfig,
22
28
  normalizeDisabledToolList
23
- } from "./chunk-ZUAXI2OA.js";
29
+ } from "./chunk-BOJWHRMX.js";
30
+ import {
31
+ collectContextData,
32
+ formatContextUsageText
33
+ } from "./chunk-JYPQTRA3.js";
24
34
  import {
25
35
  getCommandSubcommandNames
26
- } from "./chunk-4W4T77MO.js";
36
+ } from "./chunk-BXVWV4GI.js";
37
+ import "./chunk-5GOVVXEV.js";
27
38
  import {
28
39
  getEffectiveSupportedModes
29
- } from "./chunk-JTYRZODB.js";
30
- import "./chunk-MRO43B25.js";
31
- import "./chunk-UAARJR2G.js";
32
- import "./chunk-JZSY4WP3.js";
33
- import {
34
- collectContextData,
35
- formatContextUsageText
36
- } from "./chunk-TZM5JIAX.js";
40
+ } from "./chunk-FOOIZCWL.js";
37
41
  import {
38
42
  isTerminalGoalStatusKind
39
43
  } from "./chunk-KSPVDFE4.js";
44
+ import "./chunk-MRO43B25.js";
45
+ import "./chunk-SMXULRAN.js";
46
+ import "./chunk-WQT5SOI6.js";
40
47
  import "./chunk-KYMBIKIW.js";
41
- import "./chunk-I2RFAW6Q.js";
48
+ import "./chunk-I4H7PRWQ.js";
49
+ import "./chunk-JZSY4WP3.js";
50
+ import "./chunk-4X7NIEQJ.js";
51
+ import "./chunk-TT6Q3EN4.js";
42
52
  import "./chunk-3GONHQOA.js";
43
- import "./chunk-5R4SBCX6.js";
44
- import "./chunk-Z7XXFPGP.js";
45
- import "./chunk-JXQ23SNT.js";
46
- import "./chunk-TMBPDHXD.js";
53
+ import "./chunk-SL5MOGQH.js";
54
+ import "./chunk-LDWTYE33.js";
55
+ import "./chunk-2JKEQWDZ.js";
47
56
  import {
48
- PERMISSION_RULE_TYPES,
49
- PermissionRulesValidationError,
50
- buildPermissionSettings,
51
- normalizePermissionRules,
52
- readPermissionRuleSet
53
- } from "./chunk-WGAEWQTF.js";
54
- import "./chunk-NYOHZYHM.js";
55
- import "./chunk-CGOMICBE.js";
56
- import "./chunk-RKIZXJMB.js";
57
- import "./chunk-CI5O6SQL.js";
57
+ isValidServerName
58
+ } from "./chunk-UAKXW3DN.js";
59
+ import "./chunk-NDOC6M5S.js";
60
+ import "./chunk-M2U5NM24.js";
61
+ import "./chunk-BSZEQNUA.js";
62
+ import "./chunk-6FKEVYCD.js";
58
63
  import "./chunk-KHDZHZMH.js";
64
+ import "./chunk-ALX6BUYW.js";
59
65
  import {
60
- MID_TURN_QUEUE_DRAIN_METHOD
61
- } from "./chunk-QBZ22PQX.js";
66
+ AgentSideConnection,
67
+ PROTOCOL_VERSION,
68
+ RequestError,
69
+ ndJsonStream
70
+ } from "./chunk-UFC57OYT.js";
62
71
  import {
63
72
  formatAcpModelId,
64
73
  parseAcpBaseModelId,
65
74
  parseAcpModelOption,
66
75
  sanitizeProviderBaseUrl
67
- } from "./chunk-RS4HRC75.js";
76
+ } from "./chunk-QI2CFVRF.js";
77
+ import {
78
+ PERMISSION_RULE_TYPES,
79
+ PermissionRulesValidationError,
80
+ buildPermissionSettings,
81
+ normalizePermissionRules,
82
+ readPermissionRuleSet
83
+ } from "./chunk-WN6K47NR.js";
84
+ import "./chunk-5XQ4A26L.js";
85
+ import "./chunk-BC3C4F3Q.js";
68
86
  import {
69
87
  NOT_CURRENTLY_GENERATING_CANCEL_MESSAGE
70
- } from "./chunk-S566HKUS.js";
71
- import "./chunk-BS64PXY3.js";
88
+ } from "./chunk-DHXWNSJA.js";
89
+ import {
90
+ ACP_PREFLIGHT_KINDS,
91
+ IDLE_HOOK_EVENTS,
92
+ SERVE_CONTROL_EXT_METHODS,
93
+ SERVE_STATUS_EXT_METHODS,
94
+ STATUS_SCHEMA_VERSION,
95
+ mapDomainErrorToErrorKind
96
+ } from "./chunk-3M4W4U5G.js";
97
+ import "./chunk-KFVU7ODN.js";
98
+ import {
99
+ CLIENT_MCP_OVER_WS_CONFIG_FLAG,
100
+ MID_TURN_QUEUE_DRAIN_METHOD
101
+ } from "./chunk-EWALXUAD.js";
72
102
  import "./chunk-SEZC2725.js";
73
- import "./chunk-DBZUXSSV.js";
74
- import "./chunk-R2BXK7SX.js";
75
- import "./chunk-ALX6BUYW.js";
76
103
  import "./chunk-5DWXLGOM.js";
77
104
  import {
78
105
  createLoadedSettingsAdapter
79
- } from "./chunk-5RVSM6NW.js";
106
+ } from "./chunk-3HUHAQF3.js";
80
107
  import {
81
108
  OUTPUT_LANGUAGE_AUTO,
82
109
  getOutputLanguageFilePath,
83
110
  getPersistScopeForModelSelection,
84
111
  isAutoLanguage,
85
- isWorkspaceTrusted,
86
112
  loadSettings,
87
113
  reloadEnvironment,
88
114
  resolveOutputLanguage,
89
115
  updateOutputLanguageFile,
90
116
  writeOutputLanguageAndRegisterPath
91
- } from "./chunk-OQHQHJRK.js";
117
+ } from "./chunk-HEVBZSXG.js";
92
118
  import {
93
119
  SUPPORTED_LANGUAGES,
94
120
  getCurrentLanguage,
95
121
  setLanguageAsync
96
- } from "./chunk-5JZLXFPD.js";
122
+ } from "./chunk-MTHMXSNT.js";
97
123
  import "./chunk-TLRYABYP.js";
98
- import "./chunk-Y6Z2O3WR.js";
99
- import {
100
- AgentSideConnection,
101
- PROTOCOL_VERSION,
102
- RequestError,
103
- ndJsonStream
104
- } from "./chunk-UFC57OYT.js";
124
+ import "./chunk-PPFWEV7G.js";
105
125
  import {
106
- ACP_PREFLIGHT_KINDS,
107
- IDLE_HOOK_EVENTS,
108
- SERVE_CONTROL_EXT_METHODS,
109
- SERVE_STATUS_EXT_METHODS,
110
- STATUS_SCHEMA_VERSION,
111
- mapDomainErrorToErrorKind
112
- } from "./chunk-D5E5TMYH.js";
113
- import "./chunk-UN3C6GOR.js";
126
+ isFolderTrustEnabled,
127
+ isWorkspaceTrusted,
128
+ loadTrustedFolders
129
+ } from "./chunk-ARYCHZ4B.js";
130
+ import "./chunk-Y6Z2O3WR.js";
131
+ import "./chunk-QYUE6W3T.js";
114
132
  import {
115
133
  ALL_PROVIDERS,
116
134
  APPROVAL_MODES,
@@ -119,6 +137,7 @@ import {
119
137
  ExtensionManager,
120
138
  FORK_SUBAGENT_TYPE,
121
139
  InvalidMcpConfigError,
140
+ LoopTickResolver,
122
141
  MAX_TRANSCRIPT_MESSAGES,
123
142
  MCPOAuthProvider,
124
143
  MCPOAuthTokenStorage,
@@ -127,9 +146,11 @@ import {
127
146
  McpBudgetWouldExceedError,
128
147
  McpServerSpawnFailedError,
129
148
  McpTransportPool,
149
+ ORPHAN_TOOL_USE_REPAIR_REASON,
130
150
  POOLED_TRANSPORTS_DEFAULT,
131
151
  SESSION_TITLE_MAX_LENGTH,
132
152
  SessionService,
153
+ TURN_INTERRUPTION_HISTORY_TAIL_COUNT,
133
154
  WorkspaceMcpBudget,
134
155
  abortGoalForStopHookCap,
135
156
  acquireSleepInhibitor,
@@ -138,17 +159,22 @@ import {
138
159
  buildBackgroundEntryLabel,
139
160
  buildBtwCacheSafeParams,
140
161
  buildBtwPrompt,
162
+ buildContextUsage,
141
163
  buildInstallPlan,
164
+ buildSyntheticToolResponseParts,
142
165
  clampInlineMediaPart,
143
166
  clearGoalTerminalObserver,
144
167
  computeUniqueBranchTitle,
145
168
  convertToFunctionResponse,
146
169
  createDuplicateProviderToolCallResponse,
147
170
  dedupeToolCallsById,
171
+ detectLoopSentinel,
172
+ detectTurnInterruption,
148
173
  evaluateAutoMode,
149
174
  evaluatePermissionFlow,
150
175
  findExistingProviderModels,
151
176
  findProviderById,
177
+ findRepeatedDuplicateProviderToolCall,
152
178
  fireNotificationHook,
153
179
  firePermissionRequestHook,
154
180
  firePostToolUseFailureHook,
@@ -174,6 +200,7 @@ import {
174
200
  isDenialFallbackReason,
175
201
  isPlanModeBlocked,
176
202
  isSystemReminderContent,
203
+ markDuplicateProviderToolCallResponseSent,
177
204
  needsConfirmation,
178
205
  parsePositiveIntegerEnv,
179
206
  persistPermissionOutcome,
@@ -193,32 +220,32 @@ import {
193
220
  subagentGenerator,
194
221
  unregisterGoalHook,
195
222
  updateSetting
196
- } from "./chunk-PXFFKNCO.js";
223
+ } from "./chunk-RIP623NO.js";
197
224
  import {
198
225
  external_exports
199
226
  } from "./chunk-K5PGHDBN.js";
200
227
  import "./chunk-5P5XGNYH.js";
201
228
  import "./chunk-SKAZWEV5.js";
202
- import "./chunk-TXVGVZYR.js";
203
- import "./chunk-XU5P23GN.js";
204
- import "./chunk-2BIF2NVV.js";
229
+ import "./chunk-XJYUPHRC.js";
230
+ import "./chunk-QLDPRILK.js";
231
+ import "./chunk-BVSVIN45.js";
205
232
  import {
206
233
  runSideQuery
207
- } from "./chunk-BG4BIP7F.js";
208
- import "./chunk-ZD3NW5KL.js";
234
+ } from "./chunk-SBBN4BWR.js";
235
+ import "./chunk-7LM4XHPE.js";
209
236
  import "./chunk-2MPVVENX.js";
210
237
  import "./chunk-ZTQ26VBE.js";
211
- import "./chunk-GZCJS5WH.js";
238
+ import "./chunk-O2VBQ3Y2.js";
212
239
  import "./chunk-MLZQVCF3.js";
213
240
  import "./chunk-LQ7TMOCE.js";
214
241
  import "./chunk-LD2XBG6Z.js";
215
- import "./chunk-OTBK43JR.js";
242
+ import "./chunk-HYCC3XM3.js";
216
243
  import {
217
244
  HookEventName,
218
245
  createHookOutput
219
- } from "./chunk-HGNSRCRB.js";
220
- import "./chunk-EEEZIVFJ.js";
221
- import "./chunk-PRYMDRBV.js";
246
+ } from "./chunk-NL4C3H6C.js";
247
+ import "./chunk-JOLIREYR.js";
248
+ import "./chunk-DDMOU62Q.js";
222
249
  import {
223
250
  AuthType,
224
251
  ConversationFinishedEvent,
@@ -239,46 +266,48 @@ import {
239
266
  startToolSpan,
240
267
  uiTelemetryService,
241
268
  withInteractionSpan
242
- } from "./chunk-WA5OJGFL.js";
269
+ } from "./chunk-SS6WJMQK.js";
243
270
  import "./chunk-3PJXIDKI.js";
244
271
  import "./chunk-UWCTAVOD.js";
245
272
  import "./chunk-OFEVLU4C.js";
246
273
  import "./chunk-OMX7CUOE.js";
247
274
  import {
248
275
  getAutoMemoryRoot
249
- } from "./chunk-BNXANYLH.js";
250
- import "./chunk-T2VDEFUU.js";
251
- import "./chunk-OIC6S73E.js";
276
+ } from "./chunk-RD6YJJJ6.js";
277
+ import "./chunk-SKQZZVAV.js";
278
+ import "./chunk-BUUQ5HPX.js";
252
279
  import {
253
280
  ToolConfirmationOutcome,
254
281
  ToolNames
255
- } from "./chunk-TOEGRAVX.js";
282
+ } from "./chunk-BX5YO7UW.js";
256
283
  import {
257
284
  clearCachedCredentialFile,
258
285
  qwenOAuth2Events
259
- } from "./chunk-BGUDAULQ.js";
260
- import "./chunk-EW6C27XX.js";
286
+ } from "./chunk-3CPCDXFR.js";
287
+ import "./chunk-GEHVIWAT.js";
261
288
  import "./chunk-22IFUCVR.js";
262
- import "./chunk-64WXLC72.js";
263
- import "./chunk-3UALQ56H.js";
289
+ import "./chunk-3227DZO4.js";
264
290
  import {
291
+ DEFAULT_TOKEN_LIMIT,
265
292
  tokenLimit
266
- } from "./chunk-F6XNTYNE.js";
267
- import "./chunk-CGEGHF2C.js";
293
+ } from "./chunk-YTFBURQD.js";
294
+ import "./chunk-BKXBARJZ.js";
268
295
  import "./chunk-IRJWHZWU.js";
269
296
  import "./chunk-SYCJMSIJ.js";
270
297
  import "./chunk-55ZMG67I.js";
271
298
  import "./chunk-H6BD2ELD.js";
272
299
  import "./chunk-5IFG2VC4.js";
300
+ import "./chunk-64WXLC72.js";
301
+ import "./chunk-E6XQPQXW.js";
273
302
  import {
274
303
  Storage,
275
304
  createDebugLogger,
276
305
  getErrorStatus
277
- } from "./chunk-C4K3FEQ2.js";
278
- import "./chunk-PF523XJX.js";
306
+ } from "./chunk-UX4SGCGN.js";
307
+ import "./chunk-HPGTGMP3.js";
279
308
  import {
280
309
  runExitCleanup
281
- } from "./chunk-GYZQA2FO.js";
310
+ } from "./chunk-YLZJCUH6.js";
282
311
  import "./chunk-ZERZSAZL.js";
283
312
  import "./chunk-QN5NZ3UQ.js";
284
313
  import "./chunk-BR4QREVK.js";
@@ -391,11 +420,14 @@ var AcpFileSystemService = class {
391
420
  import { Readable, Writable } from "node:stream";
392
421
  import { pipeline } from "node:stream/promises";
393
422
  import * as fs from "node:fs/promises";
394
- import * as path from "node:path";
423
+ import { createRequire } from "node:module";
424
+ import * as path2 from "node:path";
395
425
  import { createGunzip } from "node:zlib";
396
426
 
397
427
  // packages/cli/src/acp-integration/session/Session.ts
398
428
  init_esbuild_shims();
429
+ import * as os from "node:os";
430
+ import * as path from "node:path";
399
431
 
400
432
  // packages/cli/src/acp-integration/session/SubAgentTracker.ts
401
433
  init_esbuild_shims();
@@ -1087,6 +1119,7 @@ __name(loadRewriteConfig, "loadRewriteConfig");
1087
1119
  var debugLogger4 = createDebugLogger("SESSION");
1088
1120
  var USER_CANCEL_ABORT_REASON = "qwen:user-cancel";
1089
1121
  var DAEMON_RETRY_META_KEY = "qwen.daemon.retry";
1122
+ var DAEMON_CONTINUE_META_KEY = "qwen.daemon.continueLastTurn";
1090
1123
  function maskApiKeyForDisplay(apiKey) {
1091
1124
  const trimmed = apiKey?.trim() ?? "";
1092
1125
  if (trimmed.length === 0) return "(not set)";
@@ -1102,6 +1135,14 @@ var MAX_MID_TURN_DRAIN_ITEMS = 10;
1102
1135
  var MID_TURN_ATTACHMENT_PROCESSING_FAILURE_TEXT = "[Attachment could not be processed]";
1103
1136
  var MAX_MID_TURN_RESOURCE_TEXT_LENGTH = 1e5;
1104
1137
  var MID_TURN_QUEUE_DRAIN_MAX_TIMEOUT_STRIKES = 3;
1138
+ var TRANSIENT_FS_CODES = [
1139
+ "EACCES",
1140
+ "EIO",
1141
+ "EBUSY",
1142
+ "EPERM",
1143
+ "EISDIR",
1144
+ "ENOTDIR"
1145
+ ];
1105
1146
  function isRecord(value) {
1106
1147
  return value !== null && typeof value === "object";
1107
1148
  }
@@ -1328,6 +1369,18 @@ function isUserPromptRecord(record) {
1328
1369
  ) ?? false;
1329
1370
  }
1330
1371
  __name(isUserPromptRecord, "isUserPromptRecord");
1372
+ var AT_TOKEN_RE = /@([^\s,;!?()[\]{}]+)/g;
1373
+ function collectExtensionMentionRefs(text, mentions) {
1374
+ for (const match of text.matchAll(AT_TOKEN_RE)) {
1375
+ const pathName = match[1];
1376
+ if (!pathName) continue;
1377
+ const ref = parseExtensionRef(pathName);
1378
+ if (ref) {
1379
+ mentions.set(ref.name.toLowerCase(), ref.name);
1380
+ }
1381
+ }
1382
+ }
1383
+ __name(collectExtensionMentionRefs, "collectExtensionMentionRefs");
1331
1384
  async function buildAvailableCommandsSnapshot(config, abortSignal = AbortSignal.timeout(1e4), settings) {
1332
1385
  const slashCommands = await getAvailableCommands(
1333
1386
  config,
@@ -1347,7 +1400,12 @@ async function buildAvailableCommandsSnapshot(config, abortSignal = AbortSignal.
1347
1400
  sourceLabel: cmd.sourceLabel,
1348
1401
  supportedModes: getEffectiveSupportedModes(cmd),
1349
1402
  subcommands: getCommandSubcommandNames(cmd),
1350
- modelInvocable: cmd.modelInvocable === true
1403
+ modelInvocable: cmd.modelInvocable === true,
1404
+ // Carry aliases so a channel consumer (which only sees the wire snapshot,
1405
+ // not the command registry) can recognize an aliased command and avoid
1406
+ // tagging it. _meta is ACP's extension point; omitted when there are none
1407
+ // so command entries without aliases stay byte-identical on the wire.
1408
+ ...cmd.altNames && cmd.altNames.length > 0 ? { altNames: cmd.altNames } : {}
1351
1409
  }
1352
1410
  };
1353
1411
  });
@@ -1442,12 +1500,23 @@ var Session = class {
1442
1500
  cronQueue = [];
1443
1501
  cronProcessing = false;
1444
1502
  cronAbortController = null;
1503
+ // Resolves the `<<loop.md>>` / `<<loop.md-dynamic>>` sentinels at fire time.
1504
+ // Lazily created on the first loop tick; its content cache is reset on
1505
+ // compaction (see #sendMessageStreamWithAutoCompression) and it is rebuilt if
1506
+ // the working dir changes (e.g. /cd) so it always reads the current project's
1507
+ // loop.md.
1508
+ loopTickResolver = null;
1509
+ loopTickResolverRoot = null;
1445
1510
  cronCompletion = null;
1446
1511
  cronDisabledByTokenLimit = false;
1447
1512
  lastPromptTokenCount = 0;
1448
1513
  lastPromptTokenCountChat = null;
1449
1514
  midTurnDrainUnavailable = false;
1450
1515
  midTurnDrainTimeoutStrikes = 0;
1516
+ // ACP can continue one logical conversation through prompt, cron, and
1517
+ // background loops, so keep this with the session instead of a single
1518
+ // runToolCalls invocation.
1519
+ duplicateProviderToolCallResponseIds = /* @__PURE__ */ new Set();
1451
1520
  // Messages from a drain that the daemon answered but we timed out waiting for
1452
1521
  // (the daemon already spliced + SSE-published them). Re-injected on the next
1453
1522
  // batch so a transient stall can't silently lose them. See
@@ -1751,6 +1820,7 @@ var Session = class {
1751
1820
  if (pendingSend.signal.aborted) {
1752
1821
  return { stopReason: "cancelled" };
1753
1822
  }
1823
+ this.duplicateProviderToolCallResponseIds.clear();
1754
1824
  let resolveCompletion;
1755
1825
  this.pendingPromptCompletion = new Promise((resolve3) => {
1756
1826
  resolveCompletion = resolve3;
@@ -1769,6 +1839,36 @@ var Session = class {
1769
1839
  this.pendingPromptCompletion = null;
1770
1840
  }
1771
1841
  }
1842
+ /**
1843
+ * Classify whether an unfinished previous turn can be resumed — an
1844
+ * interrupted prompt (the model never answered) or a turn left with dangling
1845
+ * tool calls — without injecting a synthetic "continue" user message.
1846
+ * Classifies from persisted history. Idempotent no-op (accepted:false) when
1847
+ * the last turn ended cleanly or a prompt is already in flight.
1848
+ *
1849
+ * This is the accept/reject pre-check only — it does NOT fire the turn. When
1850
+ * accepted, the daemon bridge drives the continuation through the normal
1851
+ * prompt-admission path (`sendPrompt` with the trusted continue meta) so it is
1852
+ * tracked like any other prompt; `prompt()` then re-detects/strips
1853
+ * authoritatively. Powers `qwen/control/session/continue`.
1854
+ */
1855
+ async continueLastTurn() {
1856
+ const geminiClient = this.config.getGeminiClient();
1857
+ if (!geminiClient || !geminiClient.isInitialized()) {
1858
+ return { accepted: false, interruption: "none" };
1859
+ }
1860
+ const chat = this.#getCurrentChat();
1861
+ const detection = detectTurnInterruption(
1862
+ chat.getHistoryTailShallow?.(TURN_INTERRUPTION_HISTORY_TAIL_COUNT) ?? chat.getHistoryTail(TURN_INTERRUPTION_HISTORY_TAIL_COUNT)
1863
+ );
1864
+ if (detection.kind === "none") {
1865
+ return { accepted: false, interruption: "none" };
1866
+ }
1867
+ if (this.pendingPrompt && !this.pendingPrompt.signal.aborted) {
1868
+ return { accepted: false, interruption: detection.kind };
1869
+ }
1870
+ return { accepted: true, interruption: detection.kind };
1871
+ }
1772
1872
  /**
1773
1873
  * Generate a server-side follow-up suggestion for the just-completed
1774
1874
  * turn and push it to attached clients via the daemon's
@@ -1886,7 +1986,40 @@ var Session = class {
1886
1986
  )
1887
1987
  );
1888
1988
  const isRetry = params.retry === true || params._meta?.[DAEMON_RETRY_META_KEY] === true;
1889
- if (isRetry) {
1989
+ const isContinue = params._meta?.[DAEMON_CONTINUE_META_KEY] === true;
1990
+ let continuationParts = null;
1991
+ let strippedOrphanEntries = null;
1992
+ let orphanPushCountSnapshot = 0;
1993
+ if (isContinue) {
1994
+ const detection = detectTurnInterruption(
1995
+ this.#getCurrentChat().getHistory()
1996
+ );
1997
+ if (detection.kind === "none") {
1998
+ debugLogger4.warn(
1999
+ `[Session] continue ${promptId}: no interrupted turn on re-detection, nothing to continue`
2000
+ );
2001
+ logConversationFinishedEvent(
2002
+ this.config,
2003
+ new ConversationFinishedEvent(
2004
+ this.config.getApprovalMode(),
2005
+ 0
2006
+ )
2007
+ );
2008
+ return { stopReason: "end_turn" };
2009
+ }
2010
+ if (detection.kind === "interrupted_prompt") {
2011
+ strippedOrphanEntries = this.#getCurrentChat().stripOrphanedUserEntriesFromHistory() ?? null;
2012
+ orphanPushCountSnapshot = this.#getCurrentChat().getUserContentPushCount?.() ?? 0;
2013
+ continuationParts = detection.parts;
2014
+ } else {
2015
+ continuationParts = buildSyntheticToolResponseParts(
2016
+ detection.danglingCalls,
2017
+ ORPHAN_TOOL_USE_REPAIR_REASON
2018
+ );
2019
+ }
2020
+ }
2021
+ if (isContinue) {
2022
+ } else if (isRetry) {
1890
2023
  this.#getCurrentChat().stripOrphanedUserEntriesFromHistory();
1891
2024
  } else {
1892
2025
  this.config.getChatRecordingService()?.recordUserMessage(promptText);
@@ -1896,7 +2029,9 @@ var Session = class {
1896
2029
  );
1897
2030
  const inputText = firstTextBlock?.text || "";
1898
2031
  let parts;
1899
- if (isSlashCommand(inputText)) {
2032
+ if (isContinue) {
2033
+ parts = continuationParts;
2034
+ } else if (isSlashCommand(inputText)) {
1900
2035
  const slashCommandResult = await handleSlashCommand(
1901
2036
  inputText,
1902
2037
  pendingSend,
@@ -1918,7 +2053,7 @@ var Session = class {
1918
2053
  }
1919
2054
  const hooksEnabled = !this.config.getDisableAllHooks?.();
1920
2055
  const messageBus = this.config.getMessageBus?.();
1921
- if (hooksEnabled && messageBus && this.config.hasHooksForEvent?.("UserPromptSubmit")) {
2056
+ if (!isContinue && hooksEnabled && messageBus && this.config.hasHooksForEvent?.("UserPromptSubmit")) {
1922
2057
  const response = await messageBus.request(
1923
2058
  {
1924
2059
  type: "hook-execution-request" /* HOOK_EXECUTION_REQUEST */,
@@ -1959,19 +2094,22 @@ var Session = class {
1959
2094
  }
1960
2095
  const systemReminders = await this.#buildInitialSystemReminders();
1961
2096
  if (systemReminders.length > 0) {
1962
- parts = [...systemReminders, ...parts];
2097
+ const alreadyHasReminder = isContinue && parts.some(
2098
+ (part) => isSystemReminderContent({ role: "user", parts: [part] })
2099
+ );
2100
+ if (!alreadyHasReminder) {
2101
+ parts = insertAfterFunctionResponses(parts, systemReminders);
2102
+ }
1963
2103
  }
1964
2104
  if (this.pendingWorktreeNotice) {
1965
- parts = [
1966
- {
1967
- text: `<system-reminder>
2105
+ const noticePart = {
2106
+ text: `<system-reminder>
1968
2107
  ${this.pendingWorktreeNotice}
1969
2108
  </system-reminder>
1970
2109
 
1971
2110
  `
1972
- },
1973
- ...parts
1974
- ];
2111
+ };
2112
+ parts = insertAfterFunctionResponses(parts, [noticePart]);
1975
2113
  this.pendingWorktreeNotice = null;
1976
2114
  }
1977
2115
  let nextMessage = { role: "user", parts };
@@ -1995,7 +2133,7 @@ ${this.pendingWorktreeNotice}
1995
2133
  if (!sendResult.responseStream) {
1996
2134
  this.#preserveUnsentMessageHistory(
1997
2135
  nextMessage,
1998
- sendResult.stopReason === "cancelled"
2136
+ isContinue || sendResult.stopReason === "cancelled"
1999
2137
  );
2000
2138
  return { stopReason: sendResult.stopReason };
2001
2139
  }
@@ -2026,6 +2164,12 @@ ${this.pendingWorktreeNotice}
2026
2164
  }
2027
2165
  }
2028
2166
  } catch (error) {
2167
+ if (strippedOrphanEntries && (this.#getCurrentChat().getUserContentPushCount?.() ?? 0) <= orphanPushCountSnapshot) {
2168
+ for (const entry of strippedOrphanEntries) {
2169
+ this.#getCurrentChat().addHistory(entry);
2170
+ }
2171
+ strippedOrphanEntries = null;
2172
+ }
2029
2173
  if (pendingSend.signal.aborted && pendingSend.signal.reason === USER_CANCEL_ABORT_REASON && this.#isAbortError(error)) {
2030
2174
  return { stopReason: "cancelled" };
2031
2175
  }
@@ -2075,15 +2219,10 @@ ${this.pendingWorktreeNotice}
2075
2219
  );
2076
2220
  return { stopReason: "end_turn" };
2077
2221
  }
2078
- nextMessage = {
2079
- role: "user",
2080
- parts: [
2081
- ...toolRun.parts,
2082
- ...await this.#drainMidTurnUserMessages(
2083
- pendingSend.signal
2084
- )
2085
- ]
2086
- };
2222
+ nextMessage = await this.#buildNextMessageAfterToolRun(
2223
+ toolRun,
2224
+ pendingSend.signal
2225
+ );
2087
2226
  }
2088
2227
  }
2089
2228
  if (this.messageRewriter) {
@@ -2131,13 +2270,18 @@ ${this.pendingWorktreeNotice}
2131
2270
  return { stopReason: "end_turn" };
2132
2271
  }
2133
2272
  const responseText = this.#getCurrentChat().getLastModelMessageText?.() || "[no response text]";
2273
+ const contextUsage = buildContextUsage(
2274
+ this.config.getContentGeneratorConfig()?.contextWindowSize ?? DEFAULT_TOKEN_LIMIT,
2275
+ this.lastPromptTokenCount
2276
+ );
2134
2277
  const response = await messageBus.request(
2135
2278
  {
2136
2279
  type: "hook-execution-request" /* HOOK_EXECUTION_REQUEST */,
2137
2280
  eventName: "Stop",
2138
2281
  input: {
2139
2282
  stop_hook_active: true,
2140
- last_assistant_message: responseText
2283
+ last_assistant_message: responseText,
2284
+ ...contextUsage
2141
2285
  },
2142
2286
  signal: pendingSend.signal
2143
2287
  },
@@ -2270,13 +2414,10 @@ ${this.pendingWorktreeNotice}
2270
2414
  );
2271
2415
  return { stopReason: "end_turn" };
2272
2416
  }
2273
- nextMessage = {
2274
- role: "user",
2275
- parts: [
2276
- ...toolRun.parts,
2277
- ...await this.#drainMidTurnUserMessages(pendingSend.signal)
2278
- ]
2279
- };
2417
+ nextMessage = await this.#buildNextMessageAfterToolRun(
2418
+ toolRun,
2419
+ pendingSend.signal
2420
+ );
2280
2421
  }
2281
2422
  }
2282
2423
  continue;
@@ -2317,6 +2458,7 @@ ${this.pendingWorktreeNotice}
2317
2458
  compressionInfo = compressed;
2318
2459
  this.#recordCompressionTokenCount(compressed);
2319
2460
  if (compressed.compressionStatus === 1 /* COMPRESSED */) {
2461
+ this.loopTickResolver?.resetCache();
2320
2462
  const reasonClause = compressed.triggerReason === "image_overflow" ? `accumulated enough tool screenshots to trigger compaction for ${this.config.getModel()}` : `approached the input token limit for ${this.config.getModel()}`;
2321
2463
  compressionDiagnostic = `IMPORTANT: This conversation ${reasonClause}. A compressed context will be sent for future messages (compressed from: ${compressed.originalTokenCount ?? "unknown"} to ${compressed.newTokenCount ?? "unknown"} tokens).`;
2322
2464
  }
@@ -2410,6 +2552,19 @@ ${this.pendingWorktreeNotice}
2410
2552
  );
2411
2553
  await this.messageRewriter?.waitForPendingRewrites();
2412
2554
  }
2555
+ async #buildNextMessageAfterToolRun(toolRun, abortSignal) {
2556
+ if (toolRun.repeatedDuplicateProviderToolCall) {
2557
+ debugLogger4.debug(
2558
+ "Stopping ACP turn after dropping repeated duplicate provider tool-call response."
2559
+ );
2560
+ return null;
2561
+ }
2562
+ const parts = [
2563
+ ...toolRun.parts,
2564
+ ...await this.#drainMidTurnUserMessages(abortSignal)
2565
+ ];
2566
+ return { role: "user", parts };
2567
+ }
2413
2568
  #recordCompressionTokenCount(info) {
2414
2569
  this.#syncPromptTokenCountWithCurrentChat();
2415
2570
  const tokenCount = this.#extractCompressionTokenCount(info);
@@ -2673,6 +2828,28 @@ ${this.pendingWorktreeNotice}
2673
2828
  }
2674
2829
  }
2675
2830
  }
2831
+ #getLoopTickResolver() {
2832
+ const root = this.config.getWorkingDir();
2833
+ if (!this.loopTickResolver || this.loopTickResolverRoot !== root) {
2834
+ const homeQwenDir = Storage.getGlobalQwenDir();
2835
+ const homeConfineRoot = (process.env["QWEN_HOME"] ? homeQwenDir : os.homedir()) || path.dirname(homeQwenDir);
2836
+ this.loopTickResolver = new LoopTickResolver({
2837
+ projectRoot: root,
2838
+ homeDir: homeConfineRoot,
2839
+ homeQwenDir,
2840
+ // The project `.qwen/loop.md` is repo-controlled, so an untrusted folder
2841
+ // must not read it and feed it to the model (mirrors getProjectHooks()'s
2842
+ // trust gate). The home/global `~/.qwen/loop.md` is user-owned and stays
2843
+ // allowed. Pass a getter, not a snapshot: isTrustedFolder() can flip
2844
+ // mid-session on an IDE workspace-trust update, and the resolver outlives
2845
+ // a single tick — re-read it on every resolve() so a trusted→untrusted
2846
+ // flip stops reading the project file immediately.
2847
+ allowProjectFile: /* @__PURE__ */ __name(() => this.config.isTrustedFolder(), "allowProjectFile")
2848
+ });
2849
+ this.loopTickResolverRoot = root;
2850
+ }
2851
+ return this.loopTickResolver;
2852
+ }
2676
2853
  /**
2677
2854
  * Executes a single cron-fired prompt: echoes it as a user message with
2678
2855
  * `_meta.source='cron'`, streams the model response, and handles tool calls.
@@ -2703,15 +2880,56 @@ ${this.pendingWorktreeNotice}
2703
2880
  async () => {
2704
2881
  let turnCount = 0;
2705
2882
  try {
2883
+ const loopMode = detectLoopSentinel(prompt);
2884
+ let loopTick = null;
2885
+ if (loopMode) {
2886
+ const resolver = this.#getLoopTickResolver();
2887
+ const trustedAtResolve = this.config.isTrustedFolder();
2888
+ try {
2889
+ loopTick = await resolver.resolve(loopMode, trustedAtResolve);
2890
+ } catch (resolveErr) {
2891
+ const code = resolveErr.code ?? "unknown";
2892
+ debugLogger4.warn(
2893
+ `loop.md sentinel resolution failed (mode=${loopMode}, code=${code}) \u2014 check .qwen/loop.md permissions/IO`,
2894
+ resolveErr
2895
+ );
2896
+ if (loopMode === "dynamic" && TRANSIENT_FS_CODES.includes(code)) {
2897
+ loopTick = resolver.buildTransientErrorTick(
2898
+ loopMode,
2899
+ trustedAtResolve,
2900
+ code
2901
+ );
2902
+ } else {
2903
+ throw new Error(
2904
+ `loop.md resolution failed (${code}) for ${resolver.absentLocations(
2905
+ trustedAtResolve
2906
+ )}`
2907
+ );
2908
+ }
2909
+ }
2910
+ }
2911
+ const modelText = loopTick ? loopTick.modelText : prompt;
2912
+ if (loopTick) {
2913
+ debugLogger4.debug(
2914
+ `loop tick: mode=${loopMode} delivery=${loopTick.full ? "full" : loopTick.sourceLabel ? "reminder" : "absent"} source=${loopTick.sourceLabel ?? "none"} transient=${loopTick.transientError ?? false}`
2915
+ );
2916
+ }
2917
+ const echoText = loopTick ? loopTick.sourceLabel ? `Loop tick \u2014 tasks from ${loopTick.sourceLabel}` : (
2918
+ // A transient-error tick (buildTransientErrorTick) resolved a
2919
+ // file but couldn't read it this tick; it deliberately omits
2920
+ // sourceLabel, so don't conflate it with a genuinely-absent
2921
+ // loop.md. No errno/path here — those stay in the model text.
2922
+ loopTick.transientError ? "Loop tick \u2014 loop.md temporarily unavailable" : "Loop tick \u2014 loop.md not present"
2923
+ ) : prompt;
2706
2924
  await this.sendUpdate({
2707
2925
  sessionUpdate: "user_message_chunk",
2708
- content: { type: "text", text: prompt },
2926
+ content: { type: "text", text: echoText },
2709
2927
  _meta: { source: item.source }
2710
2928
  });
2711
2929
  const cronReminders = await this.#buildInitialSystemReminders();
2712
2930
  let nextMessage = {
2713
2931
  role: "user",
2714
- parts: [...cronReminders, { text: prompt }]
2932
+ parts: [...cronReminders, { text: modelText }]
2715
2933
  };
2716
2934
  while (nextMessage !== null) {
2717
2935
  turnCount++;
@@ -2735,6 +2953,9 @@ ${this.pendingWorktreeNotice}
2735
2953
  return;
2736
2954
  }
2737
2955
  const responseStream = sendResult.responseStream;
2956
+ if (loopTick && turnCount === 1) {
2957
+ this.loopTickResolver?.markDelivered();
2958
+ }
2738
2959
  nextMessage = null;
2739
2960
  for await (const resp of responseStream) {
2740
2961
  if (ac.signal.aborted) return;
@@ -2781,13 +3002,10 @@ ${this.pendingWorktreeNotice}
2781
3002
  );
2782
3003
  return;
2783
3004
  }
2784
- nextMessage = {
2785
- role: "user",
2786
- parts: [
2787
- ...toolRun.parts,
2788
- ...await this.#drainMidTurnUserMessages(ac.signal)
2789
- ]
2790
- };
3005
+ nextMessage = await this.#buildNextMessageAfterToolRun(
3006
+ toolRun,
3007
+ ac.signal
3008
+ );
2791
3009
  }
2792
3010
  }
2793
3011
  } catch (error) {
@@ -3020,13 +3238,10 @@ ${this.pendingWorktreeNotice}
3020
3238
  await this.#emitBackgroundNotificationEndTurn("end_turn");
3021
3239
  return;
3022
3240
  }
3023
- nextMessage = {
3024
- role: "user",
3025
- parts: [
3026
- ...toolRun.parts,
3027
- ...await this.#drainMidTurnUserMessages(ac.signal)
3028
- ]
3029
- };
3241
+ nextMessage = await this.#buildNextMessageAfterToolRun(
3242
+ toolRun,
3243
+ ac.signal
3244
+ );
3030
3245
  }
3031
3246
  }
3032
3247
  if (this.messageRewriter) {
@@ -3270,10 +3485,32 @@ ${this.pendingWorktreeNotice}
3270
3485
  const handledProviderToolCallIds = new Set(
3271
3486
  this.#getCurrentChat().getHistoryFunctionResponseIds()
3272
3487
  );
3488
+ const repeatedDuplicateCall = findRepeatedDuplicateProviderToolCall(
3489
+ dedupedFunctionCalls,
3490
+ (fc) => getProviderToolCallId(fc) ?? fc.id,
3491
+ handledProviderToolCallIds,
3492
+ this.duplicateProviderToolCallResponseIds
3493
+ );
3494
+ if (repeatedDuplicateCall) {
3495
+ const providerCallId = getProviderToolCallId(repeatedDuplicateCall) ?? repeatedDuplicateCall.id;
3496
+ debugLogger4.debug(
3497
+ `[Session.runToolCalls] Dropping batch after repeated duplicate provider tool-call id: ${providerCallId} (tool: ${repeatedDuplicateCall.name ?? "unknown_tool"})`
3498
+ );
3499
+ return {
3500
+ parts: [],
3501
+ stopAfterPermissionCancel: false,
3502
+ repeatedDuplicateProviderToolCall: true
3503
+ };
3504
+ }
3273
3505
  const pushDuplicateBatch = /* @__PURE__ */ __name((request) => {
3506
+ const providerCallId = request.providerCallId ?? request.callId;
3507
+ markDuplicateProviderToolCallResponseSent(
3508
+ providerCallId,
3509
+ this.duplicateProviderToolCallResponseIds
3510
+ );
3274
3511
  const response = createDuplicateProviderToolCallResponse(request);
3275
3512
  debugLogger4.debug(
3276
- `[Session.runToolCalls] Suppressing duplicate provider tool-call id: ${request.providerCallId} (tool: ${request.name})`
3513
+ `[Session.runToolCalls] Suppressing duplicate provider tool-call id: ${providerCallId} (tool: ${request.name})`
3277
3514
  );
3278
3515
  batches.push({ kind: "duplicate", request, response });
3279
3516
  }, "pushDuplicateBatch");
@@ -3459,7 +3696,11 @@ ${this.pendingWorktreeNotice}
3459
3696
  }
3460
3697
  if (shouldStop) {
3461
3698
  await appendSkippedAfter(parts, batch.calls[batch.calls.length - 1]);
3462
- return { parts, stopAfterPermissionCancel: true };
3699
+ return {
3700
+ parts,
3701
+ stopAfterPermissionCancel: true,
3702
+ repeatedDuplicateProviderToolCall: false
3703
+ };
3463
3704
  }
3464
3705
  } else {
3465
3706
  for (const fc of batch.calls) {
@@ -3467,12 +3708,20 @@ ${this.pendingWorktreeNotice}
3467
3708
  parts.push(...r.parts);
3468
3709
  if (r.stopAfterPermissionCancel) {
3469
3710
  await appendSkippedAfter(parts, fc);
3470
- return { parts, stopAfterPermissionCancel: true };
3711
+ return {
3712
+ parts,
3713
+ stopAfterPermissionCancel: true,
3714
+ repeatedDuplicateProviderToolCall: false
3715
+ };
3471
3716
  }
3472
3717
  }
3473
3718
  }
3474
3719
  }
3475
- return { parts, stopAfterPermissionCancel: false };
3720
+ return {
3721
+ parts,
3722
+ stopAfterPermissionCancel: false,
3723
+ repeatedDuplicateProviderToolCall: false
3724
+ };
3476
3725
  }
3477
3726
  /**
3478
3727
  * Assemble the per-turn system reminders the model needs to see at the
@@ -4245,9 +4494,11 @@ ${this.pendingWorktreeNotice}
4245
4494
  async #resolvePrompt(message, abortSignal) {
4246
4495
  const FILE_URI_SCHEME = "file://";
4247
4496
  const embeddedContext = [];
4497
+ const extensionMentions = /* @__PURE__ */ new Map();
4248
4498
  const parts = message.map((part) => {
4249
4499
  switch (part.type) {
4250
4500
  case "text":
4501
+ collectExtensionMentionRefs(part.text, extensionMentions);
4251
4502
  return { text: part.text };
4252
4503
  case "image":
4253
4504
  case "audio":
@@ -4281,9 +4532,16 @@ ${this.pendingWorktreeNotice}
4281
4532
  }
4282
4533
  });
4283
4534
  const atPathCommandParts = parts.filter((part) => "fileData" in part);
4284
- if (atPathCommandParts.length === 0 && embeddedContext.length === 0) {
4535
+ const extensionParts = await this.#resolveExtensionMentionParts(
4536
+ extensionMentions,
4537
+ abortSignal
4538
+ );
4539
+ if (atPathCommandParts.length === 0 && embeddedContext.length === 0 && extensionParts.length === 0) {
4285
4540
  return parts;
4286
4541
  }
4542
+ if (atPathCommandParts.length === 0 && embeddedContext.length === 0) {
4543
+ return [...parts, ...extensionParts];
4544
+ }
4287
4545
  const pathSpecsToRead = atPathCommandParts.map(
4288
4546
  (part) => part.fileData.fileUri
4289
4547
  );
@@ -4308,6 +4566,7 @@ ${this.pendingWorktreeNotice}
4308
4566
  });
4309
4567
  const contentParts = Array.isArray(readResult.contentParts) ? readResult.contentParts : [readResult.contentParts];
4310
4568
  processedQueryParts.push({ text: initialQueryText });
4569
+ processedQueryParts.push(...extensionParts);
4311
4570
  for (const part of contentParts) {
4312
4571
  if (typeof part === "string") {
4313
4572
  processedQueryParts.push({ text: part });
@@ -4317,6 +4576,7 @@ ${this.pendingWorktreeNotice}
4317
4576
  }
4318
4577
  } else {
4319
4578
  processedQueryParts.push({ text: initialQueryText.trim() });
4579
+ processedQueryParts.push(...extensionParts);
4320
4580
  }
4321
4581
  for (const contextPart of embeddedContext) {
4322
4582
  if ("text" in contextPart && contextPart.text) {
@@ -4338,6 +4598,33 @@ ${contextPart.text}`
4338
4598
  }
4339
4599
  return processedQueryParts;
4340
4600
  }
4601
+ async #resolveExtensionMentionParts(extensionMentions, abortSignal) {
4602
+ if (extensionMentions.size === 0) return [];
4603
+ const activeExtensions = this.config.getActiveExtensions?.() ?? [];
4604
+ if (activeExtensions.length === 0) return [];
4605
+ const extensionParts = [];
4606
+ const resolvedExtensionNames = /* @__PURE__ */ new Set();
4607
+ let remainingBudget = EXTENSION_CONTEXT_BUDGET;
4608
+ for (const name of extensionMentions.values()) {
4609
+ const extension = matchExtensionByRef(name, activeExtensions);
4610
+ if (!extension) {
4611
+ this.debug(
4612
+ `Extension "${name}" not found among active extensions. Available: ${activeExtensions.map((e) => e.name).join(", ") || "(none)"}`
4613
+ );
4614
+ continue;
4615
+ }
4616
+ if (resolvedExtensionNames.has(extension.name)) continue;
4617
+ resolvedExtensionNames.add(extension.name);
4618
+ const context = await buildExtensionMentionContext(extension, {
4619
+ remainingBudget,
4620
+ signal: abortSignal,
4621
+ onDebugMessage: /* @__PURE__ */ __name((message) => this.debug(message), "onDebugMessage")
4622
+ });
4623
+ remainingBudget = context.remainingBudget;
4624
+ extensionParts.push({ text: context.text });
4625
+ }
4626
+ return extensionParts;
4627
+ }
4341
4628
  debug(msg) {
4342
4629
  if (this.config.getDebugMode()) {
4343
4630
  debugLogger4.warn(msg);
@@ -4527,6 +4814,9 @@ var QWEN_CORE_SETTING_DEFINITIONS = {
4527
4814
  "memory.enableManagedAutoMemory": { type: "boolean" },
4528
4815
  "memory.enableManagedAutoDream": { type: "boolean" },
4529
4816
  "memory.enableAutoSkill": { type: "boolean" },
4817
+ "memory.autoSkillConfirm": { type: "boolean" },
4818
+ "memory.enableTeamMemory": { type: "boolean" },
4819
+ "memory.enableTeamMemorySync": { type: "boolean" },
4530
4820
  disableAllHooks: { type: "boolean" }
4531
4821
  };
4532
4822
  var QWEN_CORE_SETTING_KEYS = Object.keys(
@@ -4536,12 +4826,18 @@ var QWEN_HOOK_EVENTS = Object.values(HookEventName);
4536
4826
  var DEFAULT_QWEN_MEMORY_SETTINGS = {
4537
4827
  enableManagedAutoMemory: true,
4538
4828
  enableManagedAutoDream: true,
4539
- enableAutoSkill: true
4829
+ enableAutoSkill: true,
4830
+ autoSkillConfirm: true,
4831
+ enableTeamMemory: false,
4832
+ enableTeamMemorySync: false
4540
4833
  };
4541
4834
  var QWEN_MEMORY_SETTING_KEYS = [
4542
4835
  "enableManagedAutoMemory",
4543
4836
  "enableManagedAutoDream",
4544
- "enableAutoSkill"
4837
+ "enableAutoSkill",
4838
+ "autoSkillConfirm",
4839
+ "enableTeamMemory",
4840
+ "enableTeamMemorySync"
4545
4841
  ];
4546
4842
  function normalizeQwenMemorySettings(value) {
4547
4843
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -4551,7 +4847,10 @@ function normalizeQwenMemorySettings(value) {
4551
4847
  return {
4552
4848
  enableManagedAutoMemory: typeof record["enableManagedAutoMemory"] === "boolean" ? record["enableManagedAutoMemory"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableManagedAutoMemory,
4553
4849
  enableManagedAutoDream: typeof record["enableManagedAutoDream"] === "boolean" ? record["enableManagedAutoDream"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableManagedAutoDream,
4554
- enableAutoSkill: typeof record["enableAutoSkill"] === "boolean" ? record["enableAutoSkill"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableAutoSkill
4850
+ enableAutoSkill: typeof record["enableAutoSkill"] === "boolean" ? record["enableAutoSkill"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableAutoSkill,
4851
+ autoSkillConfirm: typeof record["autoSkillConfirm"] === "boolean" ? record["autoSkillConfirm"] : DEFAULT_QWEN_MEMORY_SETTINGS.autoSkillConfirm,
4852
+ enableTeamMemory: typeof record["enableTeamMemory"] === "boolean" ? record["enableTeamMemory"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableTeamMemory,
4853
+ enableTeamMemorySync: typeof record["enableTeamMemorySync"] === "boolean" ? record["enableTeamMemorySync"] : DEFAULT_QWEN_MEMORY_SETTINGS.enableTeamMemorySync
4555
4854
  };
4556
4855
  }
4557
4856
  __name(normalizeQwenMemorySettings, "normalizeQwenMemorySettings");
@@ -4583,7 +4882,7 @@ function readRequiredString(value, fieldName) {
4583
4882
  }
4584
4883
  __name(readRequiredString, "readRequiredString");
4585
4884
  function validateSkillSlug(slug) {
4586
- if (!slug || slug === "." || slug === ".." || slug.includes("/") || slug.includes(path.sep) || !/^[a-zA-Z0-9._-]+$/.test(slug)) {
4885
+ if (!slug || slug === "." || slug === ".." || slug.includes("/") || slug.includes(path2.sep) || !/^[a-zA-Z0-9._-]+$/.test(slug)) {
4587
4886
  throw RequestError.invalidParams(void 0, "Invalid skill.slug");
4588
4887
  }
4589
4888
  }
@@ -5052,7 +5351,7 @@ async function downloadGitHubSkillDirectoryFromApi(githubUrl, directoryPath, rel
5052
5351
  const name = readRequiredString(record["name"], "github.name");
5053
5352
  const itemPath = readRequiredString(record["path"], "github.path");
5054
5353
  const type = readRequiredString(record["type"], "github.type");
5055
- const relativePath = relativeRoot ? path.posix.join(relativeRoot, name) : name;
5354
+ const relativePath = relativeRoot ? path2.posix.join(relativeRoot, name) : name;
5056
5355
  if (type === "dir") {
5057
5356
  files.push(
5058
5357
  ...await downloadGitHubSkillDirectoryFromApi(
@@ -5112,10 +5411,10 @@ __name(downloadGitHubSkillDirectory, "downloadGitHubSkillDirectory");
5112
5411
  async function downloadSkill(sourceUrl) {
5113
5412
  assertAllowedSkillSourceUrl(sourceUrl);
5114
5413
  const githubUrl = parseGitHubBlobSkillUrl(sourceUrl);
5115
- if (!githubUrl || path.posix.basename(githubUrl.filePath) !== "SKILL.md") {
5414
+ if (!githubUrl || path2.posix.basename(githubUrl.filePath) !== "SKILL.md") {
5116
5415
  return downloadSingleSkillFile(sourceUrl);
5117
5416
  }
5118
- const skillDirectory = path.posix.dirname(githubUrl.filePath);
5417
+ const skillDirectory = path2.posix.dirname(githubUrl.filePath);
5119
5418
  const files = await downloadGitHubSkillDirectory(githubUrl, skillDirectory);
5120
5419
  const skillFile = files.find((file) => file.relativePath === "SKILL.md");
5121
5420
  if (!skillFile) {
@@ -5131,9 +5430,9 @@ async function downloadSkill(sourceUrl) {
5131
5430
  }
5132
5431
  __name(downloadSkill, "downloadSkill");
5133
5432
  function resolveSkillInstallPath(skillDir, relativePath) {
5134
- const root = path.resolve(skillDir);
5135
- const target = path.resolve(skillDir, relativePath);
5136
- if (target !== root && !target.startsWith(root + path.sep)) {
5433
+ const root = path2.resolve(skillDir);
5434
+ const target = path2.resolve(skillDir, relativePath);
5435
+ if (target !== root && !target.startsWith(root + path2.sep)) {
5137
5436
  throw RequestError.invalidParams(
5138
5437
  void 0,
5139
5438
  `Invalid skill file path: ${relativePath}`
@@ -5143,9 +5442,9 @@ function resolveSkillInstallPath(skillDir, relativePath) {
5143
5442
  }
5144
5443
  __name(resolveSkillInstallPath, "resolveSkillInstallPath");
5145
5444
  function resolveManagedSkillDir(skillsBaseDir, slug) {
5146
- const root = path.resolve(skillsBaseDir);
5147
- const skillDir = path.resolve(skillsBaseDir, slug);
5148
- if (!skillDir.startsWith(root + path.sep)) {
5445
+ const root = path2.resolve(skillsBaseDir);
5446
+ const skillDir = path2.resolve(skillsBaseDir, slug);
5447
+ if (!skillDir.startsWith(root + path2.sep)) {
5149
5448
  throw RequestError.invalidParams(void 0, "Invalid skill.slug");
5150
5449
  }
5151
5450
  return skillDir;
@@ -5822,14 +6121,14 @@ function readScopeSettings(settings, scope) {
5822
6121
  __name(readScopeSettings, "readScopeSettings");
5823
6122
  async function resolvePreferredMemoryFile(dir, fallbackFilename) {
5824
6123
  for (const filename of getAllGeminiMdFilenames()) {
5825
- const filePath = path.join(dir, filename);
6124
+ const filePath = path2.join(dir, filename);
5826
6125
  try {
5827
6126
  await fs.access(filePath);
5828
6127
  return filePath;
5829
6128
  } catch {
5830
6129
  }
5831
6130
  }
5832
- return path.join(dir, fallbackFilename);
6131
+ return path2.join(dir, fallbackFilename);
5833
6132
  }
5834
6133
  __name(resolvePreferredMemoryFile, "resolvePreferredMemoryFile");
5835
6134
  async function resolveQwenMemoryPaths(params) {
@@ -5850,13 +6149,37 @@ async function resolveQwenMemoryPaths(params) {
5850
6149
  };
5851
6150
  }
5852
6151
  __name(resolveQwenMemoryPaths, "resolveQwenMemoryPaths");
6152
+ async function deliverClientMcpMessage(connection, serverName, message) {
6153
+ if (!connection) {
6154
+ throw new Error(
6155
+ `client MCP server '${serverName}' has no ACP connection yet`
6156
+ );
6157
+ }
6158
+ const response = await connection.extMethod(
6159
+ SERVE_CONTROL_EXT_METHODS.clientMcpMessage,
6160
+ { server: serverName, payload: message }
6161
+ );
6162
+ const payload = response["payload"];
6163
+ if (payload === void 0 || payload === null) {
6164
+ throw new Error(
6165
+ `client_mcp/message returned no payload for server '${serverName}'`
6166
+ );
6167
+ }
6168
+ return payload;
6169
+ }
6170
+ __name(deliverClientMcpMessage, "deliverClientMcpMessage");
5853
6171
  async function runAcpAgent(config, settings, argv) {
6172
+ let acpConnection;
6173
+ const bootstrapClientMcpSender = /* @__PURE__ */ __name((serverName, message) => deliverClientMcpMessage(acpConnection, serverName, message), "bootstrapClientMcpSender");
5854
6174
  await config.initialize({
5855
6175
  skipGeminiInitialization: true,
5856
6176
  // Bootstrap skips MCP discovery — each session runs its own
5857
6177
  // pool-routed discovery, so bootstrap-level spawns would be
5858
6178
  // redundant subprocess leaks (W119).
5859
- skipMcpDiscovery: true
6179
+ skipMcpDiscovery: true,
6180
+ // Bind the workspace-level manager's SDK callback so a runtime-added
6181
+ // client-hosted MCP server (#5626) round-trips over the parent WS.
6182
+ sendSdkMcpMessage: bootstrapClientMcpSender
5860
6183
  });
5861
6184
  const stdout = Writable.toWeb(process.stdout);
5862
6185
  const stdin = Readable.toWeb(process.stdin);
@@ -5866,6 +6189,7 @@ async function runAcpAgent(config, settings, argv) {
5866
6189
  const stream = ndJsonStream(stdout, stdin);
5867
6190
  let agentInstance;
5868
6191
  const connection = new AgentSideConnection((conn) => {
6192
+ acpConnection = conn;
5869
6193
  agentInstance = new QwenAgent(config, settings, argv, conn);
5870
6194
  return agentInstance;
5871
6195
  }, stream);
@@ -6179,7 +6503,7 @@ var QwenAgent = class {
6179
6503
  async initialize(args) {
6180
6504
  this.clientCapabilities = args.clientCapabilities;
6181
6505
  const authMethods = buildAuthMethods();
6182
- const version = "0.19.2";
6506
+ const version = "0.19.3-nightly.20260630.e00fe6a27";
6183
6507
  return {
6184
6508
  protocolVersion: PROTOCOL_VERSION,
6185
6509
  agentInfo: {
@@ -6774,6 +7098,16 @@ var QwenAgent = class {
6774
7098
  status: this.mcpStatus(e.status)
6775
7099
  }));
6776
7100
  }
7101
+ if (!disabled) {
7102
+ out.resourceCount = this.resolveServerMcpResources(
7103
+ config,
7104
+ name
7105
+ ).length;
7106
+ out.promptCount = this.resolveServerMcpPrompts(
7107
+ config,
7108
+ name
7109
+ ).length;
7110
+ }
6777
7111
  return out;
6778
7112
  })
6779
7113
  ),
@@ -6880,6 +7214,102 @@ var QwenAgent = class {
6880
7214
  };
6881
7215
  }
6882
7216
  }
7217
+ /**
7218
+ * Resolve the resources discovered for one server, with the same
7219
+ * pool-mode fallback `buildWorkspaceMcpToolsStatus` uses for tools: the
7220
+ * workspace `Config`'s `ResourceRegistry` is authoritative in
7221
+ * single-session mode, but in pool mode resources are registered into
7222
+ * per-session registries (`SessionMcpView.applyResources`), leaving the
7223
+ * workspace registry empty. Fall back to the first active session that
7224
+ * has this server's resources.
7225
+ */
7226
+ resolveServerMcpResources(config, serverName) {
7227
+ const resources = config.getResourceRegistry?.()?.getResourcesByServer(serverName) ?? [];
7228
+ if (resources.length > 0) {
7229
+ return resources;
7230
+ }
7231
+ for (const session of this.getActiveSessions()) {
7232
+ try {
7233
+ const sessionResources = session.getConfig().getResourceRegistry?.()?.getResourcesByServer(serverName) ?? [];
7234
+ if (sessionResources.length > 0) {
7235
+ return sessionResources;
7236
+ }
7237
+ } catch {
7238
+ }
7239
+ }
7240
+ return resources;
7241
+ }
7242
+ /**
7243
+ * Resolve the prompts discovered for one server, mirroring
7244
+ * {@link resolveServerMcpResources}. Used only for the per-server
7245
+ * `promptCount` on the base status — prompts have no drill-down
7246
+ * endpoint (they surface as slash commands).
7247
+ */
7248
+ resolveServerMcpPrompts(config, serverName) {
7249
+ const prompts = config.getPromptRegistry?.()?.getPromptsByServer(serverName) ?? [];
7250
+ if (prompts.length > 0) {
7251
+ return prompts;
7252
+ }
7253
+ for (const session of this.getActiveSessions()) {
7254
+ try {
7255
+ const sessionPrompts = session.getConfig().getPromptRegistry?.()?.getPromptsByServer(serverName) ?? [];
7256
+ if (sessionPrompts.length > 0) {
7257
+ return sessionPrompts;
7258
+ }
7259
+ } catch {
7260
+ }
7261
+ }
7262
+ return prompts;
7263
+ }
7264
+ buildWorkspaceMcpResourcesStatus(config, serverName) {
7265
+ const workspaceCwd = this.safeWorkspaceCwd(config);
7266
+ try {
7267
+ const servers = config.getMcpServers() ?? {};
7268
+ if (!Object.prototype.hasOwnProperty.call(servers, serverName)) {
7269
+ return {
7270
+ v: STATUS_SCHEMA_VERSION,
7271
+ workspaceCwd,
7272
+ serverName,
7273
+ initialized: true,
7274
+ acpChannelLive: true,
7275
+ resources: [],
7276
+ errors: [
7277
+ {
7278
+ kind: "mcp_resources",
7279
+ status: "error",
7280
+ error: `MCP server not configured: ${serverName}`
7281
+ }
7282
+ ]
7283
+ };
7284
+ }
7285
+ const resources = this.resolveServerMcpResources(config, serverName).map((resource) => ({
7286
+ uri: resource.uri,
7287
+ ...typeof resource.name === "string" ? { name: resource.name } : {},
7288
+ ...typeof resource.title === "string" ? { title: resource.title } : {},
7289
+ ...typeof resource.description === "string" ? { description: resource.description } : {},
7290
+ ...typeof resource.mimeType === "string" ? { mimeType: resource.mimeType } : {},
7291
+ ...typeof resource.size === "number" ? { size: resource.size } : {}
7292
+ }));
7293
+ return {
7294
+ v: STATUS_SCHEMA_VERSION,
7295
+ workspaceCwd,
7296
+ serverName,
7297
+ initialized: true,
7298
+ acpChannelLive: true,
7299
+ resources
7300
+ };
7301
+ } catch (error) {
7302
+ return {
7303
+ v: STATUS_SCHEMA_VERSION,
7304
+ workspaceCwd,
7305
+ serverName,
7306
+ initialized: true,
7307
+ acpChannelLive: true,
7308
+ resources: [],
7309
+ errors: [this.errorCell("mcp_resources", error)]
7310
+ };
7311
+ }
7312
+ }
6883
7313
  /**
6884
7314
  * Build the MCP budget status cells exposed on `GET /workspace/mcp`.
6885
7315
  *
@@ -6986,7 +7416,7 @@ var QwenAgent = class {
6986
7416
  const currentAuth = activeRuntimeSnapshot?.authType ?? currentAuthType;
6987
7417
  const currentAcpModelId = hasCurrentModel && currentAuth ? formatAcpModelId(currentModelId, currentAuth) : currentModelId || void 0;
6988
7418
  const providers = /* @__PURE__ */ new Map();
6989
- for (const model of config.getAllConfiguredModels()) {
7419
+ for (const model of config.getAllConfiguredModels().filter(isMainSelectableModel)) {
6990
7420
  const authType = String(model.authType);
6991
7421
  let provider = providers.get(authType);
6992
7422
  if (!provider) {
@@ -7480,6 +7910,25 @@ var QwenAgent = class {
7480
7910
  }
7481
7911
  };
7482
7912
  }
7913
+ const skillMetrics = metrics.skills ?? {
7914
+ totalCalls: 0,
7915
+ totalSuccess: 0,
7916
+ totalFail: 0,
7917
+ byName: {}
7918
+ };
7919
+ const skillsByName = {};
7920
+ for (const [name, skill] of Object.entries(skillMetrics.byName)) {
7921
+ Object.defineProperty(skillsByName, name, {
7922
+ value: {
7923
+ count: skill.count,
7924
+ success: skill.success,
7925
+ fail: skill.fail
7926
+ },
7927
+ enumerable: true,
7928
+ configurable: true,
7929
+ writable: true
7930
+ });
7931
+ }
7483
7932
  return {
7484
7933
  v: STATUS_SCHEMA_VERSION,
7485
7934
  sessionId,
@@ -7498,6 +7947,12 @@ var QwenAgent = class {
7498
7947
  files: {
7499
7948
  totalLinesAdded: metrics.files.totalLinesAdded,
7500
7949
  totalLinesRemoved: metrics.files.totalLinesRemoved
7950
+ },
7951
+ skills: {
7952
+ totalCalls: skillMetrics.totalCalls,
7953
+ totalSuccess: skillMetrics.totalSuccess,
7954
+ totalFail: skillMetrics.totalFail,
7955
+ byName: skillsByName
7501
7956
  }
7502
7957
  };
7503
7958
  }
@@ -7681,6 +8136,7 @@ var QwenAgent = class {
7681
8136
  id: ext.id,
7682
8137
  name: ext.name,
7683
8138
  displayName: ext.displayName,
8139
+ ...ext.config.description ? { description: ext.config.description } : {},
7684
8140
  version: ext.version,
7685
8141
  isActive: ext.isActive,
7686
8142
  path: ext.path,
@@ -7727,9 +8183,9 @@ var QwenAgent = class {
7727
8183
  );
7728
8184
  }
7729
8185
  const download = await downloadSkill(request.sourceUrl);
7730
- const skillsBaseDir = path.join(Storage.getGlobalQwenDir(), "skills");
8186
+ const skillsBaseDir = path2.join(Storage.getGlobalQwenDir(), "skills");
7731
8187
  const skillDir = resolveManagedSkillDir(skillsBaseDir, request.slug);
7732
- const skillFile = path.join(skillDir, "SKILL.md");
8188
+ const skillFile = path2.join(skillDir, "SKILL.md");
7733
8189
  const parsed = skillManager.parseSkillContent(
7734
8190
  download.skillContent,
7735
8191
  skillFile,
@@ -7749,7 +8205,7 @@ var QwenAgent = class {
7749
8205
  stagingDir,
7750
8206
  file.relativePath
7751
8207
  );
7752
- await fs.mkdir(path.dirname(targetPath), { recursive: true });
8208
+ await fs.mkdir(path2.dirname(targetPath), { recursive: true });
7753
8209
  await fs.writeFile(targetPath, file.content);
7754
8210
  }
7755
8211
  await fs.rm(skillDir, { recursive: true, force: true });
@@ -7788,11 +8244,11 @@ var QwenAgent = class {
7788
8244
  `Skill name "${parsed.name}" does not match requested slug "${request.slug}"`
7789
8245
  );
7790
8246
  }
7791
- const resolvedSkillDir = path.resolve(skillDir);
7792
- const resolvedSkillFile = path.resolve(skillFile);
7793
- const globalDir = path.resolve(Storage.getGlobalQwenDir());
7794
- const isDedicatedSkillDir = resolvedSkillFile === path.join(resolvedSkillDir, "SKILL.md");
7795
- if (!isDedicatedSkillDir || resolvedSkillDir === path.parse(resolvedSkillDir).root || resolvedSkillDir === globalDir) {
8247
+ const resolvedSkillDir = path2.resolve(skillDir);
8248
+ const resolvedSkillFile = path2.resolve(skillFile);
8249
+ const globalDir = path2.resolve(Storage.getGlobalQwenDir());
8250
+ const isDedicatedSkillDir = resolvedSkillFile === path2.join(resolvedSkillDir, "SKILL.md");
8251
+ if (!isDedicatedSkillDir || resolvedSkillDir === path2.parse(resolvedSkillDir).root || resolvedSkillDir === globalDir) {
7796
8252
  throw RequestError.invalidParams(
7797
8253
  void 0,
7798
8254
  `Refusing to delete unexpected skill directory: ${skillDir}`
@@ -7808,10 +8264,10 @@ var QwenAgent = class {
7808
8264
  async readManagedSkillFile(slug, scope, skillManager, cwd) {
7809
8265
  if (scope === "global") {
7810
8266
  const qwenSkillDir = resolveManagedSkillDir(
7811
- path.join(Storage.getGlobalQwenDir(), "skills"),
8267
+ path2.join(Storage.getGlobalQwenDir(), "skills"),
7812
8268
  slug
7813
8269
  );
7814
- const qwenSkillFile = path.join(qwenSkillDir, "SKILL.md");
8270
+ const qwenSkillFile = path2.join(qwenSkillDir, "SKILL.md");
7815
8271
  const qwenContent = await fs.readFile(qwenSkillFile, "utf8").catch(() => void 0);
7816
8272
  if (qwenContent !== void 0) {
7817
8273
  return {
@@ -7847,15 +8303,15 @@ var QwenAgent = class {
7847
8303
  );
7848
8304
  });
7849
8305
  return {
7850
- skillDir: path.dirname(skillFile),
8306
+ skillDir: path2.dirname(skillFile),
7851
8307
  skillFile,
7852
8308
  content
7853
8309
  };
7854
8310
  }
7855
8311
  async findProjectSkillFileFromCwd(slug, cwd, skillManager) {
7856
- const projectRoot = path.resolve(cwd);
8312
+ const projectRoot = path2.resolve(cwd);
7857
8313
  for (const configDir of PROJECT_SKILL_DIRS) {
7858
- const baseDir = path.join(projectRoot, configDir, SKILLS_DIR);
8314
+ const baseDir = path2.join(projectRoot, configDir, SKILLS_DIR);
7859
8315
  const skills = await skillManager.loadSkillsFromDir(baseDir, "project");
7860
8316
  const skill = skills.find((candidate) => candidate.name === slug);
7861
8317
  const skillFile = skill?.filePath;
@@ -7867,7 +8323,7 @@ var QwenAgent = class {
7867
8323
  );
7868
8324
  });
7869
8325
  return {
7870
- skillDir: path.dirname(skillFile),
8326
+ skillDir: path2.dirname(skillFile),
7871
8327
  skillFile,
7872
8328
  content
7873
8329
  };
@@ -7898,7 +8354,7 @@ var QwenAgent = class {
7898
8354
  }
7899
8355
  const nextContent = setSkillFrontmatterEnabled(content, request.enabled);
7900
8356
  skillManager.parseSkillContent(nextContent, skillFile, level);
7901
- if (path.basename(skillFile) !== "SKILL.md") {
8357
+ if (path2.basename(skillFile) !== "SKILL.md") {
7902
8358
  throw RequestError.invalidParams(
7903
8359
  void 0,
7904
8360
  `Refusing to write to unexpected skill file: ${skillFile}`
@@ -7948,19 +8404,25 @@ var QwenAgent = class {
7948
8404
  );
7949
8405
  const persistScope = readProviderConnectScope(params["scope"]);
7950
8406
  const plan = buildInstallPlan(providerConfig, inputs);
8407
+ const adapter = createLoadedSettingsAdapter(
8408
+ this.settings,
8409
+ persistScope
8410
+ );
7951
8411
  await applyProviderInstallPlan(plan, {
7952
- settings: createLoadedSettingsAdapter(this.settings, persistScope),
8412
+ settings: adapter,
7953
8413
  reloadModelProviders: /* @__PURE__ */ __name((modelProviders) => this.config.reloadModelProvidersConfig(modelProviders), "reloadModelProviders"),
7954
8414
  syncAuthState: /* @__PURE__ */ __name((authType, modelId, baseUrl) => this.config.getModelsConfig().syncAfterAuthRefresh(authType, modelId, baseUrl), "syncAuthState"),
7955
8415
  refreshAuth: /* @__PURE__ */ __name((authType) => this.config.refreshAuth(authType), "refreshAuth")
7956
8416
  });
8417
+ const effectiveModelId = adapter.getValue("model.name") ?? plan.modelSelection?.modelId;
8418
+ const effectiveBaseUrl = adapter.getValue("model.baseUrl") ?? plan.modelSelection?.baseUrl;
7957
8419
  return {
7958
8420
  success: true,
7959
8421
  providerId: providerConfig.id,
7960
8422
  providerLabel: providerConfig.label,
7961
8423
  authType: plan.authType,
7962
- modelId: plan.modelSelection?.modelId,
7963
- ...plan.modelSelection?.baseUrl ? { baseUrl: plan.modelSelection.baseUrl } : {}
8424
+ ...effectiveModelId ? { modelId: effectiveModelId } : {},
8425
+ ...effectiveBaseUrl ? { baseUrl: effectiveBaseUrl } : {}
7964
8426
  };
7965
8427
  }
7966
8428
  case "qwen/skills/install": {
@@ -8026,6 +8488,19 @@ var QwenAgent = class {
8026
8488
  serverName
8027
8489
  );
8028
8490
  }
8491
+ case SERVE_STATUS_EXT_METHODS.workspaceMcpResources: {
8492
+ const serverName = params["serverName"];
8493
+ if (typeof serverName !== "string" || serverName.length === 0) {
8494
+ throw RequestError.invalidParams(
8495
+ void 0,
8496
+ "Invalid or missing serverName"
8497
+ );
8498
+ }
8499
+ return this.buildWorkspaceMcpResourcesStatus(
8500
+ this.config,
8501
+ serverName
8502
+ );
8503
+ }
8029
8504
  case SERVE_STATUS_EXT_METHODS.workspaceSkills:
8030
8505
  return await this.buildWorkspaceSkillsStatus(
8031
8506
  this.config
@@ -8481,6 +8956,78 @@ var QwenAgent = class {
8481
8956
  await this.closeStoredSession(sessionId);
8482
8957
  return { sessionId, closed: true };
8483
8958
  }
8959
+ case SERVE_CONTROL_EXT_METHODS.sessionCd: {
8960
+ const sessionId = params["sessionId"];
8961
+ const targetPath = params["path"];
8962
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
8963
+ throw RequestError.invalidParams(
8964
+ void 0,
8965
+ "Invalid or missing sessionId"
8966
+ );
8967
+ }
8968
+ if (typeof targetPath !== "string" || targetPath.length === 0 || !path2.isAbsolute(targetPath) || targetPath.includes("\0")) {
8969
+ throw RequestError.invalidParams(
8970
+ void 0,
8971
+ "Invalid or missing path (must be an absolute path)"
8972
+ );
8973
+ }
8974
+ const session = this.sessionOrThrow(sessionId);
8975
+ const config = session.getConfig();
8976
+ if (config.isRestrictiveSandbox()) {
8977
+ throw new RequestError(-32003, "Restrictive sandbox mode active", {
8978
+ errorKind: "restrictive_sandbox"
8979
+ });
8980
+ }
8981
+ let stats;
8982
+ try {
8983
+ stats = await fs.stat(targetPath);
8984
+ } catch {
8985
+ throw new RequestError(-32002, `Directory not found: ${targetPath}`, {
8986
+ errorKind: "directory_not_found",
8987
+ path: targetPath
8988
+ });
8989
+ }
8990
+ if (!stats.isDirectory()) {
8991
+ throw new RequestError(-32002, `Not a directory: ${targetPath}`, {
8992
+ errorKind: "directory_not_found",
8993
+ path: targetPath
8994
+ });
8995
+ }
8996
+ const canonicalPath = await fs.realpath(targetPath);
8997
+ const previousCwd = config.getTargetDir();
8998
+ if (canonicalPath === previousCwd) {
8999
+ return { previousCwd, newCwd: canonicalPath, warnings: [] };
9000
+ }
9001
+ if (isFolderTrustEnabled(this.settings.merged)) {
9002
+ const trustedFolders = loadTrustedFolders();
9003
+ if (trustedFolders.isPathTrusted(canonicalPath) !== true) {
9004
+ throw new RequestError(
9005
+ -32001,
9006
+ `Directory not trusted: ${canonicalPath}`,
9007
+ { errorKind: "directory_not_trusted", path: canonicalPath }
9008
+ );
9009
+ }
9010
+ }
9011
+ const warnings = [];
9012
+ const relocation = await config.relocateWorkingDirectory(
9013
+ canonicalPath,
9014
+ canonicalPath,
9015
+ { skipProcessChdir: true, skipArtifactMigration: true }
9016
+ );
9017
+ if (relocation.memoryRefreshError) {
9018
+ warnings.push(
9019
+ `Memory refresh failed: ${relocation.memoryRefreshError instanceof Error ? relocation.memoryRefreshError.message : String(relocation.memoryRefreshError)}`
9020
+ );
9021
+ }
9022
+ try {
9023
+ await config.getGeminiClient()?.addWorkingDirectoryChangedContext(previousCwd, canonicalPath);
9024
+ } catch (error) {
9025
+ warnings.push(
9026
+ `Model context refresh failed: ${error instanceof Error ? error.message : String(error)}`
9027
+ );
9028
+ }
9029
+ return { previousCwd, newCwd: canonicalPath, warnings };
9030
+ }
8484
9031
  case SERVE_CONTROL_EXT_METHODS.sessionApprovalMode: {
8485
9032
  const sessionId = params["sessionId"];
8486
9033
  const mode = params["mode"];
@@ -8898,6 +9445,21 @@ ${outputText}
8898
9445
  condition: cleared?.condition
8899
9446
  };
8900
9447
  }
9448
+ case SERVE_CONTROL_EXT_METHODS.sessionContinue: {
9449
+ const sessionId = params["sessionId"];
9450
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
9451
+ throw RequestError.invalidParams(
9452
+ void 0,
9453
+ "Invalid or missing sessionId"
9454
+ );
9455
+ }
9456
+ const session = this.sessionOrThrow(sessionId);
9457
+ const result = await session.continueLastTurn();
9458
+ debugLogger5.info(
9459
+ `sessionContinue sessionId=${sessionId} accepted=${result.accepted} interruption=${result.interruption}`
9460
+ );
9461
+ return result;
9462
+ }
8901
9463
  case SERVE_CONTROL_EXT_METHODS.workspaceMcpRuntimeAdd: {
8902
9464
  const name = params["name"];
8903
9465
  const config = params["config"];
@@ -8908,7 +9470,7 @@ ${outputText}
8908
9470
  "Invalid or missing name"
8909
9471
  );
8910
9472
  }
8911
- if (name.length > 256 || !/^[A-Za-z0-9_-]+$/.test(name) || name === "__proto__" || name === "constructor" || name === "prototype") {
9473
+ if (!isValidServerName(name)) {
8912
9474
  throw RequestError.invalidParams(
8913
9475
  void 0,
8914
9476
  "Server name must be \u2264256 chars, alphanumeric + underscore/hyphen, and not a reserved JS property name"
@@ -8944,13 +9506,37 @@ ${outputText}
8944
9506
  oauth: _oauth,
8945
9507
  headers: _headers,
8946
9508
  type: _type,
9509
+ // Reverse tool channel marker (issue #5626, Phase 2). The parent
9510
+ // serve process stamps this on a client-hosted (extension) MCP
9511
+ // server's runtime config; it never reaches the transport itself.
9512
+ [CLIENT_MCP_OVER_WS_CONFIG_FLAG]: clientMcpOverWs,
8947
9513
  ...safeConfig
8948
9514
  } = config;
9515
+ if (clientMcpOverWs === true) {
9516
+ safeConfig["type"] = "sdk";
9517
+ }
8949
9518
  const result = await manager.addRuntimeMcpServer(
8950
9519
  name,
8951
9520
  safeConfig,
8952
9521
  originatorClientId
8953
9522
  );
9523
+ await Promise.all(
9524
+ this.getActiveSessions().map(async (session) => {
9525
+ const sessionManager = session.getConfig().getToolRegistry()?.getMcpClientManager();
9526
+ if (!sessionManager) return;
9527
+ try {
9528
+ await sessionManager.addRuntimeMcpServer(
9529
+ name,
9530
+ safeConfig,
9531
+ originatorClientId
9532
+ );
9533
+ } catch (sessionErr) {
9534
+ debugLogger5.warn(
9535
+ `workspaceMcpRuntimeAdd: failed to add runtime MCP server '${name}' to active session ${session.getConfig().getSessionId()}: ${sessionErr instanceof Error ? sessionErr.message : String(sessionErr)}`
9536
+ );
9537
+ }
9538
+ })
9539
+ );
8954
9540
  return result;
8955
9541
  } catch (err) {
8956
9542
  if (err instanceof McpBudgetWouldExceedError) {
@@ -8985,7 +9571,7 @@ ${outputText}
8985
9571
  "Invalid or missing name"
8986
9572
  );
8987
9573
  }
8988
- if (name.length > 256 || !/^[A-Za-z0-9_-]+$/.test(name) || name === "__proto__" || name === "constructor" || name === "prototype") {
9574
+ if (!isValidServerName(name)) {
8989
9575
  throw RequestError.invalidParams(
8990
9576
  void 0,
8991
9577
  "Server name must be \u2264256 chars, alphanumeric + underscore/hyphen, and not a reserved JS property name"
@@ -9008,6 +9594,22 @@ ${outputText}
9008
9594
  name,
9009
9595
  originatorClientId
9010
9596
  );
9597
+ await Promise.all(
9598
+ this.getActiveSessions().map(async (session) => {
9599
+ const sessionManager = session.getConfig().getToolRegistry()?.getMcpClientManager();
9600
+ if (!sessionManager) return;
9601
+ try {
9602
+ await sessionManager.removeRuntimeMcpServer(
9603
+ name,
9604
+ originatorClientId
9605
+ );
9606
+ } catch (sessionErr) {
9607
+ debugLogger5.warn(
9608
+ `workspaceMcpRuntimeRemove: failed to remove runtime MCP server '${name}' from active session ${session.getConfig().getSessionId()}: ${sessionErr instanceof Error ? sessionErr.message : String(sessionErr)}`
9609
+ );
9610
+ }
9611
+ })
9612
+ );
9011
9613
  return result;
9012
9614
  }
9013
9615
  case SERVE_CONTROL_EXT_METHODS.workspaceExtensionsRefresh: {
@@ -9576,9 +10178,13 @@ ${outputText}
9576
10178
  }
9577
10179
  const config = session.getConfig();
9578
10180
  const authType = config.getAuthType();
9579
- if (changed.has("modelProviders")) {
10181
+ const providersChanged = changed.has("modelProviders") || changed.has("providerProtocol");
10182
+ if (providersChanged) {
9580
10183
  try {
9581
- config.reloadModelProvidersConfig(newMerged.modelProviders);
10184
+ config.reloadModelProvidersConfig(
10185
+ newMerged.modelProviders,
10186
+ newMerged.providerProtocol ?? {}
10187
+ );
9582
10188
  } catch (err) {
9583
10189
  debugLogger5.warn(
9584
10190
  `reload: reloadModelProvidersConfig failed for session ${id}: ${err}`
@@ -9594,7 +10200,7 @@ ${outputText}
9594
10200
  `reload: switchModel failed for session ${id}: ${err}`
9595
10201
  );
9596
10202
  }
9597
- } else if ((changed.has("modelProviders") || envChanged) && authType) {
10203
+ } else if ((providersChanged || envChanged) && authType) {
9598
10204
  try {
9599
10205
  await config.refreshAuth(authType);
9600
10206
  } catch (err) {
@@ -9657,6 +10263,21 @@ ${outputText}
9657
10263
  }
9658
10264
  }
9659
10265
  // --- private helpers ---
10266
+ /**
10267
+ * Reverse tool channel (issue #5626, Phase 2). Build the session
10268
+ * `McpClientManager`'s `sendSdkMcpMessage` callback. Client-hosted
10269
+ * (extension) MCP servers are registered SDK-type, so the manager routes
10270
+ * their JSON-RPC through this callback. We forward each frame UP to the
10271
+ * parent serve process via the `qwen/control/client_mcp/message` ext-method;
10272
+ * the parent's `BridgeClient.extMethod` hands it to the per-WS-connection
10273
+ * `ClientMcpRegistrar`, which carries it down the daemon WS to the extension
10274
+ * and returns the correlated response (the `payload` field). All SDK-type
10275
+ * servers in this session share one callback — the `serverName` argument
10276
+ * routes to the right client-hosted server in the parent.
10277
+ */
10278
+ buildClientMcpSender() {
10279
+ return (serverName, message) => deliverClientMcpMessage(this.connection, serverName, message);
10280
+ }
9660
10281
  async newSessionConfig(cwd, mcpServers, sessionId, resume) {
9661
10282
  this.settings = loadSettings(cwd);
9662
10283
  const sessionMcpServers = {};
@@ -9710,6 +10331,10 @@ ${outputText}
9710
10331
  continue;
9711
10332
  }
9712
10333
  }
10334
+ const cdpTunnelMcp = buildCdpTunnelMcpServer();
10335
+ if (cdpTunnelMcp && !sessionMcpServers["chrome-devtools"]) {
10336
+ sessionMcpServers["chrome-devtools"] = cdpTunnelMcp;
10337
+ }
9713
10338
  const settings = this.settings.merged;
9714
10339
  const argvForSession = {
9715
10340
  ...this.argv,
@@ -9741,6 +10366,14 @@ ${outputText}
9741
10366
  if (typeof config.enableFileCheckpointing === "function") {
9742
10367
  config.enableFileCheckpointing();
9743
10368
  }
10369
+ if (typeof this.config.getRuntimeMcpServers === "function" && typeof config.addRuntimeMcpServer === "function") {
10370
+ const bootstrapRuntimeMcpServers = this.config.getRuntimeMcpServers();
10371
+ for (const [runtimeServerName, runtimeServerConfig] of Object.entries(
10372
+ bootstrapRuntimeMcpServers
10373
+ )) {
10374
+ config.addRuntimeMcpServer(runtimeServerName, runtimeServerConfig);
10375
+ }
10376
+ }
9744
10377
  if (this.mcpPool !== void 0 && typeof config.setMcpTransportPool === "function") {
9745
10378
  config.setMcpTransportPool(this.mcpPool);
9746
10379
  }
@@ -9760,7 +10393,14 @@ ${outputText}
9760
10393
  });
9761
10394
  });
9762
10395
  }
9763
- await config.initialize();
10396
+ await config.initialize({
10397
+ // Reverse tool channel (issue #5626, Phase 2): bind the session
10398
+ // manager's SDK MCP callback to the `client_mcp/message` ext-method so a
10399
+ // client-hosted (extension) MCP server added at runtime reaches the
10400
+ // daemon WS. Servers that aren't client-hosted never use this callback
10401
+ // (the daemon only adds SDK-type runtime servers for client MCP).
10402
+ sendSdkMcpMessage: this.buildClientMcpSender()
10403
+ });
9764
10404
  await config.waitForMcpReady();
9765
10405
  const failedMcpServers = typeof config.getFailedMcpServerNames === "function" ? config.getFailedMcpServerNames() : [];
9766
10406
  if (failedMcpServers.length > 0) {
@@ -9822,6 +10462,9 @@ ${outputText}
9822
10462
  if (sessionData?.fileHistorySnapshots?.length) {
9823
10463
  config.getFileHistoryService().restoreFromSnapshots(sessionData.fileHistorySnapshots);
9824
10464
  }
10465
+ if (sessionData?.conversation.messages) {
10466
+ config.getChatRecordingService()?.rebuildTurnBoundaries(sessionData.conversation.messages);
10467
+ }
9825
10468
  if (options.replayHistory !== false && sessionData?.conversation.messages) {
9826
10469
  await session.replayHistory(sessionData.conversation.messages);
9827
10470
  }
@@ -9832,7 +10475,7 @@ ${outputText}
9832
10475
  buildAvailableModels(config) {
9833
10476
  const rawCurrentModelId = (config.getModel() || this.config.getModel() || "").trim();
9834
10477
  const currentAuthType = config.getAuthType();
9835
- const allConfiguredModels = config.getAllConfiguredModels();
10478
+ const allConfiguredModels = config.getAllConfiguredModels().filter(isMainSelectableModel);
9836
10479
  const activeRuntimeSnapshot = config.getActiveRuntimeModelSnapshot?.();
9837
10480
  const currentModelId = activeRuntimeSnapshot ? formatAcpModelId(
9838
10481
  activeRuntimeSnapshot.id,
@@ -9868,7 +10511,7 @@ ${outputText}
9868
10511
  }
9869
10512
  buildConfigOptions(config) {
9870
10513
  const currentApprovalMode = config.getApprovalMode();
9871
- const allConfiguredModels = config.getAllConfiguredModels();
10514
+ const allConfiguredModels = config.getAllConfiguredModels().filter(isMainSelectableModel);
9872
10515
  const rawCurrentModelId = (config.getModel() || "").trim();
9873
10516
  const currentAuthType = config.getAuthType?.();
9874
10517
  const activeRuntimeSnapshot = config.getActiveRuntimeModelSnapshot?.();
@@ -9914,6 +10557,10 @@ ${outputText}
9914
10557
  return authType ? formatAcpModelId(baseModelId, authType) : baseModelId;
9915
10558
  }
9916
10559
  };
10560
+ function isMainSelectableModel(model) {
10561
+ return model.fastOnly !== true && model.voiceOnly !== true;
10562
+ }
10563
+ __name(isMainSelectableModel, "isMainSelectableModel");
9917
10564
  function diffSettingsKeys(oldMerged, newMerged) {
9918
10565
  const changed = /* @__PURE__ */ new Set();
9919
10566
  const allKeys = /* @__PURE__ */ new Set([
@@ -9928,10 +10575,52 @@ function diffSettingsKeys(oldMerged, newMerged) {
9928
10575
  return changed;
9929
10576
  }
9930
10577
  __name(diffSettingsKeys, "diffSettingsKeys");
10578
+ function buildCdpTunnelMcpServer() {
10579
+ if (process.env["QWEN_SERVE_CDP_TUNNEL_OVER_WS"] !== "1") return void 0;
10580
+ if (process.env["QWEN_SERVE_CDP_TUNNEL_AUTH_REQUIRED"] === "1") {
10581
+ process.stderr.write(
10582
+ "qwen serve: browser tools (chrome-devtools-mcp) disabled \u2014 the /cdp tunnel requires bearer auth, which is not yet supported for the auto-registered browser MCP server.\n"
10583
+ );
10584
+ return void 0;
10585
+ }
10586
+ const port = Number(process.env["QWEN_SERVE_CDP_TUNNEL_PORT"]);
10587
+ if (!Number.isInteger(port) || port <= 0) {
10588
+ process.stderr.write(
10589
+ `qwen serve: browser tools (chrome-devtools-mcp) disabled \u2014 no valid /cdp tunnel port (QWEN_SERVE_CDP_TUNNEL_PORT=${process.env["QWEN_SERVE_CDP_TUNNEL_PORT"] ?? "<unset>"}). Start the daemon with a fixed --port (ephemeral --port 0 is not supported for the CDP tunnel).
10590
+ `
10591
+ );
10592
+ return void 0;
10593
+ }
10594
+ try {
10595
+ const requireFromHere = createRequire(import.meta.url);
10596
+ const pkgJsonPath = requireFromHere.resolve(
10597
+ "chrome-devtools-mcp/package.json"
10598
+ );
10599
+ const pkg = requireFromHere("chrome-devtools-mcp/package.json");
10600
+ const binRel = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin ?? {})[0];
10601
+ if (!binRel) return void 0;
10602
+ const pkgDir = path2.dirname(pkgJsonPath);
10603
+ const binPath = path2.resolve(pkgDir, binRel);
10604
+ const binRelToPkg = path2.relative(pkgDir, binPath);
10605
+ if (binRelToPkg.startsWith("..") || path2.isAbsolute(binRelToPkg)) {
10606
+ return void 0;
10607
+ }
10608
+ return new MCPServerConfig(process.execPath, [
10609
+ binPath,
10610
+ "--wsEndpoint",
10611
+ `ws://127.0.0.1:${port}/cdp`
10612
+ ]);
10613
+ } catch {
10614
+ return void 0;
10615
+ }
10616
+ }
10617
+ __name(buildCdpTunnelMcpServer, "buildCdpTunnelMcpServer");
9931
10618
  export {
9932
10619
  AUTH_PREFLIGHT_ENV_KEYS,
9933
10620
  AUTH_PREFLIGHT_WAIVED_AUTH_TYPES,
10621
+ buildCdpTunnelMcpServer,
9934
10622
  createWorkspaceMcpBudget,
10623
+ deliverClientMcpMessage,
9935
10624
  extractFilesFromTarGz,
9936
10625
  fetchAllowedGitHub,
9937
10626
  normalizeCoreSettingValue,