@qwen-code/qwen-code 0.19.10 → 0.19.11-nightly.20260717.f8e6e8931

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 (275) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +7 -6
  2. package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
  3. package/bundled/qc-helper/docs/features/channels/dingtalk.md +30 -0
  4. package/bundled/qc-helper/docs/features/channels/overview.md +53 -17
  5. package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
  6. package/bundled/qc-helper/docs/features/sandbox.md +2 -0
  7. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +42 -7
  8. package/bundled/qc-helper/docs/qwen-serve.md +53 -46
  9. package/bundled/review/SKILL.md +163 -403
  10. package/chunks/{MaxSizedBox-67ODZ4SZ.js → MaxSizedBox-JGTP7YJQ.js} +13 -13
  11. package/chunks/{StandaloneSessionPicker-SIPBQT5Z.js → StandaloneSessionPicker-2XQDOYZ5.js} +27 -27
  12. package/chunks/{acpAgent-VPZJXLFX.js → acpAgent-RXRJA7GD.js} +1135 -373
  13. package/chunks/{agent-Z7NWL6XL.js → agent-UQP53UWQ.js} +10 -10
  14. package/chunks/{agent-headless-73HZ6ROQ.js → agent-headless-I52OXDCK.js} +10 -10
  15. package/chunks/{anthropicContentGenerator-56U3YCP2.js → anthropicContentGenerator-HBRXJSP4.js} +76 -14
  16. package/chunks/{artifact-tool-BWZZJ42H.js → artifact-tool-MIZLXBLF.js} +1 -1
  17. package/chunks/{askUserQuestion-WU3S5A5T.js → askUserQuestion-XMJVPNWM.js} +1 -1
  18. package/chunks/{bridge-XFKW6S7Q.js → bridge-3DVRNBSF.js} +14 -16
  19. package/chunks/{ca-C2JTT2N5.js → ca-CODEN7TD.js} +5 -0
  20. package/chunks/channel-worker-group-SOUWTFHC.js +21 -0
  21. package/chunks/{channel-worker-manager-5RWKSGEU.js → channel-worker-manager-LOVSV3WW.js} +34 -10
  22. package/chunks/{channel-worker-supervisor-PCDAZN4D.js → channel-worker-supervisor-XW6MHJBQ.js} +6 -4
  23. package/chunks/{chunk-BBNVFRGD.js → chunk-3DWIFU7L.js} +1 -1
  24. package/chunks/{chunk-ZQTZXVHP.js → chunk-3KSHYS4T.js} +4 -18
  25. package/chunks/{chunk-ZKMGAFYV.js → chunk-3LS57JZI.js} +1 -1
  26. package/chunks/{chunk-B5I2IIWY.js → chunk-46Y6SSQ7.js} +5 -5
  27. package/chunks/{chunk-GDQQRV43.js → chunk-4BJVSIS3.js} +2 -2
  28. package/chunks/{chunk-L37RC7MQ.js → chunk-4HTHLSIH.js} +1 -1
  29. package/chunks/{chunk-DPFBNG72.js → chunk-4UBEB74N.js} +1 -1
  30. package/chunks/{chunk-AAR5SGMD.js → chunk-4YR7FSAM.js} +7 -5
  31. package/chunks/{chunk-OATTJGPJ.js → chunk-5CNYZ7TN.js} +7 -7
  32. package/chunks/{chunk-JSJFKYWT.js → chunk-5VWYKIMW.js} +1 -1
  33. package/chunks/{chunk-6GETGQWP.js → chunk-5WWYHNAH.js} +39 -10
  34. package/chunks/{chunk-65N2J6V2.js → chunk-6ANLV27M.js} +2 -2
  35. package/chunks/{chunk-L62SEJWY.js → chunk-6RV42SFP.js} +4 -4
  36. package/chunks/{chunk-XXJKGHZV.js → chunk-6VMOP2Z7.js} +4 -4
  37. package/chunks/{chunk-URU5UEK6.js → chunk-6WGZDD67.js} +135 -68
  38. package/chunks/{chunk-7NAWTFVY.js → chunk-6WPJRYLZ.js} +2 -2
  39. package/chunks/chunk-6WVLHULT.js +59 -0
  40. package/chunks/{chunk-N6FXRR6P.js → chunk-7ZFXHKKZ.js} +1 -1
  41. package/chunks/{chunk-E67NFMF4.js → chunk-A2HWMJVO.js} +35 -1
  42. package/chunks/{chunk-4FMG7EDJ.js → chunk-AEKHQ3E5.js} +77 -11
  43. package/chunks/{chunk-WIASPMLX.js → chunk-AH3YAJU6.js} +22 -33
  44. package/chunks/{chunk-6GKMJPOC.js → chunk-AHAH5H6D.js} +3 -3
  45. package/chunks/{chunk-3XJFUTNM.js → chunk-AVAU67KP.js} +57 -10
  46. package/chunks/{chunk-LNUXFLLJ.js → chunk-BDHYJ2MM.js} +53 -5
  47. package/chunks/{chunk-P6LART6G.js → chunk-BTSE2DUP.js} +957 -122
  48. package/chunks/{chunk-7MJAZMXK.js → chunk-BZ5D7OVV.js} +28 -77
  49. package/chunks/{chunk-WDWJ4OQJ.js → chunk-CC2UASQ4.js} +3 -3
  50. package/chunks/{chunk-WLXYAKV7.js → chunk-D7KYA6EY.js} +3 -3
  51. package/chunks/{chunk-5LROA5W4.js → chunk-DD45XVOQ.js} +3 -3
  52. package/chunks/{chunk-H3FQOPPS.js → chunk-DOPUYNXO.js} +2 -2
  53. package/chunks/{chunk-SPUYQB4T.js → chunk-DPXB3XRN.js} +1 -1
  54. package/chunks/{chunk-XLIRF7IK.js → chunk-E7ECGLZW.js} +1 -1
  55. package/chunks/{chunk-RDRVMDWV.js → chunk-EMJJBXS7.js} +10 -10
  56. package/chunks/{chunk-TXY2C3D2.js → chunk-F333XEAU.js} +1 -1
  57. package/chunks/chunk-FEOZBUMT.js +77 -0
  58. package/chunks/{chunk-YYPXHMWO.js → chunk-FEYHXPZG.js} +4 -4
  59. package/chunks/{chunk-ZRKBI3DP.js → chunk-FNX3LGAK.js} +1 -1
  60. package/chunks/chunk-FXK3QMRD.js +140 -0
  61. package/chunks/{chunk-422XAKCK.js → chunk-G5ZKRK2E.js} +2 -2
  62. package/chunks/{chunk-DK33QJ3V.js → chunk-GCRFH57X.js} +732 -13
  63. package/chunks/{chunk-EQY6POVO.js → chunk-GLEJW7T2.js} +1 -1
  64. package/chunks/{chunk-FXMC7SL2.js → chunk-I6NOSIVF.js} +1 -1
  65. package/chunks/{chunk-VBRRNQB7.js → chunk-IHJRUIWN.js} +109 -22
  66. package/chunks/{chunk-F7NXQH4Y.js → chunk-IIXEI2VE.js} +1 -1
  67. package/chunks/{chunk-2UUAIFQO.js → chunk-JGUT3LWZ.js} +5 -0
  68. package/chunks/{chunk-5EBKKSBX.js → chunk-JY74T7PW.js} +1 -1
  69. package/chunks/chunk-KSZKSE23.js +226 -0
  70. package/chunks/{chunk-MO7O5722.js → chunk-KW46DBFM.js} +35 -2
  71. package/chunks/{chunk-TISZXPAX.js → chunk-L263ROM6.js} +1 -1
  72. package/chunks/chunk-LXXMOYPL.js +22 -0
  73. package/chunks/{chunk-YX4LLZ3D.js → chunk-NABT4VOY.js} +109 -35
  74. package/chunks/{chunk-W34A5MJH.js → chunk-NROLDLP4.js} +1 -1
  75. package/chunks/{chunk-V7EQTZYR.js → chunk-O3WCEZEN.js} +191 -44
  76. package/chunks/{chunk-K4PZ5F5T.js → chunk-OWT2CAEQ.js} +1 -1
  77. package/chunks/{chunk-4YWLED2A.js → chunk-PNCWEDF6.js} +7 -4
  78. package/chunks/{chunk-WDW64OW3.js → chunk-PSDTLRAV.js} +5 -5
  79. package/chunks/{chunk-7R4DPSRA.js → chunk-R3VWUU2E.js} +1 -1
  80. package/chunks/{chunk-K7CRWKOE.js → chunk-R6AO7HBQ.js} +4617 -4012
  81. package/chunks/{chunk-6OATMEYN.js → chunk-RTV5TUYB.js} +12 -4
  82. package/chunks/{chunk-6W6DI34P.js → chunk-SE6GSFAO.js} +159 -2
  83. package/chunks/{chunk-WTSXKLG5.js → chunk-SUARMD4Q.js} +1 -1
  84. package/chunks/chunk-T4TZQJ7W.js +48 -0
  85. package/chunks/{chunk-LTNI523B.js → chunk-T7CZYIAU.js} +28 -5
  86. package/chunks/{chunk-3MX7D6QN.js → chunk-TIOE2OPE.js} +32 -4
  87. package/chunks/{chunk-TTUO4DNG.js → chunk-UF6ZTWU5.js} +75 -710
  88. package/chunks/{chunk-Q5GLXH5Q.js → chunk-UJG4VV2O.js} +5 -5
  89. package/chunks/{chunk-CJFNEBYB.js → chunk-VFEZWI6F.js} +1 -1
  90. package/chunks/{chunk-UFOKA4PR.js → chunk-VHCSIMTF.js} +114 -4
  91. package/chunks/{chunk-TQBODCFD.js → chunk-VRR65QYW.js} +250 -2
  92. package/chunks/{chunk-CUUXANEQ.js → chunk-W6J7RSCK.js} +6 -1
  93. package/chunks/{chunk-YHN5SUIJ.js → chunk-W7H223ZZ.js} +1 -1
  94. package/chunks/{chunk-WX6SD4IQ.js → chunk-WTNZ6DXB.js} +1 -1
  95. package/chunks/{chunk-GGJII3FM.js → chunk-WZJELXEU.js} +92 -3
  96. package/chunks/{chunk-OFEVHGVU.js → chunk-X5HZX4EP.js} +9 -11
  97. package/chunks/{chunk-KSO42X3Z.js → chunk-X6YQWCIJ.js} +21 -2
  98. package/chunks/{chunk-7L4XBYVW.js → chunk-XK42MWWO.js} +9 -2
  99. package/chunks/{chunk-X362TMXZ.js → chunk-XQDPCQ3A.js} +7 -5
  100. package/chunks/{chunk-YU56QGXX.js → chunk-Y3TNSHKF.js} +1 -1
  101. package/chunks/{chunk-HHEFI4RP.js → chunk-YOJGIRTD.js} +714 -109
  102. package/chunks/{chunk-CEW4HDPK.js → chunk-ZK4AMPKI.js} +2459 -350
  103. package/chunks/{chunk-SXU3KKNI.js → chunk-ZQIYGQCG.js} +251 -54
  104. package/chunks/{computer-use-IYTX45WA.js → computer-use-LTW3VB6L.js} +10 -10
  105. package/chunks/{config-utils-CFT33LTP.js → config-utils-IQQT3GCI.js} +3 -3
  106. package/chunks/{contextCommand-272V77WU.js → contextCommand-GLMC6CTP.js} +12 -12
  107. package/chunks/{create-sub-session-WNX2OQVX.js → create-sub-session-EAB2U5XW.js} +1 -1
  108. package/chunks/{create-sub-session-CBJMQLYP.js → create-sub-session-YMWQAWSN.js} +10 -10
  109. package/chunks/{cron-create-36TIFKRT.js → cron-create-GMVKSXZT.js} +1 -1
  110. package/chunks/{cron-delete-OQD3WULU.js → cron-delete-VDZKUAVK.js} +1 -1
  111. package/chunks/{cron-list-4533T2FH.js → cron-list-UG7C7RAR.js} +1 -1
  112. package/chunks/{daemon-RNGFPMAB.js → daemon-PRB64RP5.js} +303 -71
  113. package/chunks/{daemon-status-provider-L4STG5VO.js → daemon-status-provider-5OMM5JHF.js} +19 -20
  114. package/chunks/{de-2VCDRDGU.js → de-NOXPCSYN.js} +5 -0
  115. package/chunks/{dist-ERCPDVA6.js → dist-4WCQEZIN.js} +4 -51
  116. package/chunks/{dist-MOEC47TR.js → dist-DOPL5LSQ.js} +1 -1
  117. package/chunks/{dist-JZE7F6YR.js → dist-GXJVCOS7.js} +1 -1
  118. package/chunks/{dist-PHEPJLXD.js → dist-PX2ERZ6I.js} +2 -2
  119. package/chunks/{dist-HNN7DR2L.js → dist-V2YVLYOW.js} +58 -30
  120. package/chunks/{dist-3V3ZV6ML.js → dist-VYWUKURL.js} +1 -1
  121. package/chunks/{earlyInputCapture-EN4BRREQ.js → earlyInputCapture-A3WSRN4T.js} +10 -10
  122. package/chunks/{edit-OMAF2QDR.js → edit-7PG4AH27.js} +10 -10
  123. package/chunks/{en-NJCA3TAA.js → en-JFVULHTB.js} +6 -0
  124. package/chunks/{enter-worktree-BBZX52HG.js → enter-worktree-QUSB44RE.js} +10 -10
  125. package/chunks/{enterPlanMode-5NNFMBUY.js → enterPlanMode-NVSIEL7X.js} +10 -10
  126. package/chunks/{environment-7TEWMJYN.js → environment-AHHXHQTI.js} +12 -12
  127. package/chunks/{errors-I4VKVX3F.js → errors-NSWSRXC7.js} +12 -12
  128. package/chunks/{exit-worktree-FUWRJI33.js → exit-worktree-FXYEYHPL.js} +10 -10
  129. package/chunks/{exitPlanMode-IHCJ5EEI.js → exitPlanMode-JI5GK3F6.js} +10 -10
  130. package/chunks/{fast-path-ZA57TOH4.js → fast-path-X7EVDLKZ.js} +2 -2
  131. package/chunks/{fr-5F3E7WKD.js → fr-HVFNU42H.js} +5 -0
  132. package/chunks/{gemini-UOAKVXBG.js → gemini-YRLHY5KS.js} +162 -206
  133. package/chunks/{geminiContentGenerator-G6UCE6MW.js → geminiContentGenerator-SPLFPV5E.js} +1 -1
  134. package/chunks/{glob-4GJQ2UFF.js → glob-WASUBCSA.js} +10 -10
  135. package/chunks/{grep-5QSYXF2E.js → grep-DUVG3NGA.js} +10 -10
  136. package/chunks/{handleAutoUpdate-ULHNWL6R.js → handleAutoUpdate-NGE5AQ2N.js} +14 -14
  137. package/chunks/{i18n-CYDUTF6F.js → i18n-QNVR36NB.js} +11 -11
  138. package/chunks/{initializer-NRFKUGIO.js → initializer-ZY7ORPMH.js} +15 -15
  139. package/chunks/{installationInfo-WELKRHHE.js → installationInfo-4R75MFTB.js} +11 -11
  140. package/chunks/{ja-66J6B53L.js → ja-PY5AF544.js} +5 -0
  141. package/chunks/{list-JVDXEG2E.js → list-36JCMZRS.js} +18 -18
  142. package/chunks/{loadedSettingsAdapter-WAM4VUTG.js → loadedSettingsAdapter-PQIOJUSJ.js} +15 -15
  143. package/chunks/{loop-wakeup-MVUKDVCP.js → loop-wakeup-QXWZSCYM.js} +2 -2
  144. package/chunks/{ls-RXNIAQDE.js → ls-2OUTG3IZ.js} +1 -1
  145. package/chunks/{lsp-HB5LM5IL.js → lsp-4VMNXZW6.js} +1 -1
  146. package/chunks/{mcp-YHOZN3ZM.js → mcp-QXY6XA6H.js} +15 -15
  147. package/chunks/{monitor-R7XZPJHQ.js → monitor-AVEKRSY3.js} +12 -11
  148. package/chunks/{nonInteractiveCli-NSOB6D74.js → nonInteractiveCli-YWIBKX4M.js} +50 -50
  149. package/chunks/{notebook-edit-6RNKE2L2.js → notebook-edit-4SBTJX72.js} +10 -10
  150. package/chunks/{openaiContentGenerator-XNS5S64I.js → openaiContentGenerator-4EBAO7LR.js} +8 -8
  151. package/chunks/{pidfile-XE4RRR2P.js → pidfile-JMIUPXSU.js} +10 -10
  152. package/chunks/processUtils-EOINMEIH.js +29 -0
  153. package/chunks/{pt-TFZO5Y6T.js → pt-A3PRQXMU.js} +5 -0
  154. package/chunks/{qwenContentGenerator-APDPJ3VN.js → qwenContentGenerator-M7UBL3JS.js} +12 -12
  155. package/chunks/{read-file-XSUWXSR7.js → read-file-DXSEFHCV.js} +5 -5
  156. package/chunks/{read-mcp-resource-6LRTZKXI.js → read-mcp-resource-JUFHCKSC.js} +1 -1
  157. package/chunks/{record-artifact-PMDTY4OS.js → record-artifact-DWSMBXYY.js} +1 -1
  158. package/chunks/{ripGrep-APB3CDMU.js → ripGrep-VTRVFMDJ.js} +10 -10
  159. package/chunks/{ru-4L4LFHIT.js → ru-IBCWUTOC.js} +5 -0
  160. package/chunks/{run-qwen-serve-NWTGPERT.js → run-qwen-serve-P7WQDZAS.js} +59 -38
  161. package/chunks/{runtime-EIO3NQKR.js → runtime-UHYO6JGN.js} +19 -19
  162. package/chunks/{scheduler-JJDZBDRN.js → scheduler-WTK7ZLV5.js} +10 -10
  163. package/chunks/{send-message-SR4WSXP2.js → send-message-JZ752NWD.js} +2 -2
  164. package/chunks/{serve-WTIPB3EI.js → serve-AG2AOG56.js} +15 -15
  165. package/chunks/{server-NJPHQHLH.js → server-G5MM2BRI.js} +1157 -225
  166. package/chunks/{session-O4AO7FTS.js → session-NUAGEMVS.js} +51 -51
  167. package/chunks/{settings-HQNDK7TG.js → settings-VQA5PR2M.js} +14 -14
  168. package/chunks/{shell-UIXM6PWG.js → shell-X33RWGLP.js} +12 -10
  169. package/chunks/{skill-3XMB4ULV.js → skill-PHSU2OPP.js} +5 -5
  170. package/chunks/{spawnChannel-3R632QRM.js → spawnChannel-D6TZN4W7.js} +12 -13
  171. package/chunks/{src-USZKPUOC.js → src-6OJFUPTL.js} +95 -34
  172. package/chunks/{standalone-update-L5XW3D7K.js → standalone-update-ZARRW44Y.js} +12 -12
  173. package/chunks/{startInteractiveUI-CPZOL2WB.js → startInteractiveUI-C6IZRTF3.js} +176 -158
  174. package/chunks/{syntheticOutput-YKFNUQZD.js → syntheticOutput-LELY6HAI.js} +2 -2
  175. package/chunks/{task-create-NUFOHU53.js → task-create-QY3BIMNM.js} +3 -3
  176. package/chunks/{task-list-Z2IKQY3S.js → task-list-D2U47WBJ.js} +1 -1
  177. package/chunks/{task-stop-KQFIVQTJ.js → task-stop-N6E5IYLH.js} +1 -1
  178. package/chunks/{task-update-HKADXSTD.js → task-update-HJCQILLB.js} +3 -3
  179. package/chunks/{team-create-XXPRF3IQ.js → team-create-H434NQP2.js} +10 -10
  180. package/chunks/{team-delete-SDNTGZLG.js → team-delete-RCWYDRF4.js} +1 -1
  181. package/chunks/{team-plan-approval-EOTTKHDW.js → team-plan-approval-IIOHXZU6.js} +10 -10
  182. package/chunks/{theme-manager-P6UITO2L.js → theme-manager-IEOPHMX6.js} +10 -10
  183. package/chunks/{todoWrite-YNXB27GB.js → todoWrite-FKCGATPJ.js} +1 -1
  184. package/chunks/{tool-search-DDNGK2LR.js → tool-search-WIIEDALL.js} +6 -6
  185. package/chunks/{total-session-admission-PL5N7DNY.js → total-session-admission-WU3DORRW.js} +15 -17
  186. package/chunks/{trustedFolders-C5LMF3UR.js → trustedFolders-JVUTUAJ3.js} +11 -11
  187. package/chunks/update-relaunch-X5EQKCH5.js +87 -0
  188. package/chunks/{updateCheck-QTVVISH7.js → updateCheck-TGO2X735.js} +14 -12
  189. package/chunks/{validateNonInterActiveAuth-RY4RKBQG.js → validateNonInterActiveAuth-2MEUL2ME.js} +46 -46
  190. package/chunks/{version-U45RYOSD.js → version-KBGQKZWV.js} +1 -1
  191. package/chunks/{web-fetch-ZSPR3PRR.js → web-fetch-CFCWTCAP.js} +2 -3
  192. package/chunks/{workflow-TCIAQYOA.js → workflow-PAOSF4CG.js} +11 -11
  193. package/chunks/{workspace-providers-status-I3G2HYLY.js → workspace-providers-status-AYHJYSVO.js} +18 -18
  194. package/chunks/{workspace-registration-store-IH5GLZ6Y.js → workspace-registration-store-GZMR53QL.js} +1 -1
  195. package/chunks/{workspace-registry-QEKBELIX.js → workspace-registry-C2IXZWPF.js} +15 -17
  196. package/chunks/{workspace-service-ORKHGLP3.js → workspace-service-KDDAW33F.js} +20 -21
  197. package/chunks/{workspace-skills-status-D7QCNDYY.js → workspace-skills-status-WWEZBZXY.js} +16 -16
  198. package/chunks/{write-file-JGRQR5VM.js → write-file-ACN3TAIX.js} +10 -10
  199. package/chunks/{zh-FSAH32JB.js → zh-PAUNIMHQ.js} +6 -0
  200. package/chunks/{zh-TW-D2YIE2LO.js → zh-TW-GNEUIUFF.js} +6 -0
  201. package/cli-entry.js +92 -8
  202. package/cli.js +11 -11
  203. package/locales/ca.js +10 -0
  204. package/locales/de.js +10 -0
  205. package/locales/en.js +11 -0
  206. package/locales/fr.js +10 -0
  207. package/locales/ja.js +10 -0
  208. package/locales/pt.js +10 -0
  209. package/locales/ru.js +10 -0
  210. package/locales/zh-TW.js +11 -0
  211. package/locales/zh.js +11 -0
  212. package/package.json +3 -3
  213. package/web-shell/assets/{arc-CUeDlxvE.js → arc-Blc5_CnD.js} +1 -1
  214. package/web-shell/assets/{architectureDiagram-3BPJPVTR-PiUszkQA.js → architectureDiagram-3BPJPVTR-Dyv1BvGP.js} +1 -1
  215. package/web-shell/assets/{blockDiagram-GPEHLZMM-s2wYSO7e.js → blockDiagram-GPEHLZMM-CVAb8DyB.js} +1 -1
  216. package/web-shell/assets/{c4Diagram-AAUBKEIU-DyLxZoz9.js → c4Diagram-AAUBKEIU-ClHPb_6S.js} +1 -1
  217. package/web-shell/assets/channel-DkPTtnGS.js +1 -0
  218. package/web-shell/assets/{chunk-2J33WTMH-Dsdai7Tk.js → chunk-2J33WTMH-Dad9g3ZA.js} +1 -1
  219. package/web-shell/assets/{chunk-4BX2VUAB-DEosOjV7.js → chunk-4BX2VUAB-IJJSSdDs.js} +1 -1
  220. package/web-shell/assets/{chunk-55IACEB6-sNsRLTXf.js → chunk-55IACEB6-DRcc-Hl9.js} +1 -1
  221. package/web-shell/assets/{chunk-727SXJPM-DkRNZzmh.js → chunk-727SXJPM-DOCFB-6a.js} +1 -1
  222. package/web-shell/assets/{chunk-AQP2D5EJ-BrsRNpzd.js → chunk-AQP2D5EJ-CRZnSjHp.js} +1 -1
  223. package/web-shell/assets/{chunk-FMBD7UC4-CI039lpl.js → chunk-FMBD7UC4-BwUI4Yes.js} +1 -1
  224. package/web-shell/assets/{chunk-ND2GUHAM-M-pkeIfu.js → chunk-ND2GUHAM-DLy8doxd.js} +1 -1
  225. package/web-shell/assets/{chunk-QZHKN3VN-C4ckGNbH.js → chunk-QZHKN3VN-Bhz7iysj.js} +1 -1
  226. package/web-shell/assets/classDiagram-4FO5ZUOK-DBdPU8ix.js +1 -0
  227. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-DBdPU8ix.js +1 -0
  228. package/web-shell/assets/{cose-bilkent-S5V4N54A-BciKUAFq.js → cose-bilkent-S5V4N54A-jT1e8KzN.js} +1 -1
  229. package/web-shell/assets/{dagre-BM42HDAG-C1nTSgU6.js → dagre-BM42HDAG-C1veApQk.js} +1 -1
  230. package/web-shell/assets/{diagram-2AECGRRQ-BDPNWr1m.js → diagram-2AECGRRQ-C_NOwKeT.js} +1 -1
  231. package/web-shell/assets/{diagram-5GNKFQAL-CNFhTszL.js → diagram-5GNKFQAL-Bigfuz1r.js} +1 -1
  232. package/web-shell/assets/{diagram-KO2AKTUF-CjPa4p5a.js → diagram-KO2AKTUF-CpXltPpU.js} +1 -1
  233. package/web-shell/assets/{diagram-LMA3HP47-ZzPykSyG.js → diagram-LMA3HP47-DYawbYbH.js} +1 -1
  234. package/web-shell/assets/{diagram-OG6HWLK6-0UVtZ9A4.js → diagram-OG6HWLK6-D2t-ttd1.js} +1 -1
  235. package/web-shell/assets/{erDiagram-TEJ5UH35-CajDZCat.js → erDiagram-TEJ5UH35-Buc53PB5.js} +1 -1
  236. package/web-shell/assets/{flowDiagram-I6XJVG4X-BRuFBIvL.js → flowDiagram-I6XJVG4X-DwdFsCN7.js} +1 -1
  237. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BevGmJqG.js → ganttDiagram-6RSMTGT7-XhiEKGoP.js} +1 -1
  238. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-DvPMpBMb.js → gitGraphDiagram-PVQCEYII-D6We014a.js} +1 -1
  239. package/web-shell/assets/index-BctAmeF3.js +1143 -0
  240. package/web-shell/assets/{index-DzHwQkQq.js → index-CAWqS-bZ.js} +1 -1
  241. package/web-shell/assets/index-DLyhlZZO.css +5 -0
  242. package/web-shell/assets/{infoDiagram-5YYISTIA-Oixn7tA9.js → infoDiagram-5YYISTIA-C_iugRHQ.js} +1 -1
  243. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BgKpeg-j.js → ishikawaDiagram-YF4QCWOH-CAn9Kaix.js} +1 -1
  244. package/web-shell/assets/{journeyDiagram-JHISSGLW-74mwxIaA.js → journeyDiagram-JHISSGLW-BjDYOkEB.js} +1 -1
  245. package/web-shell/assets/{kanban-definition-UN3LZRKU-D4D6cEqA.js → kanban-definition-UN3LZRKU-Br_oI3Ob.js} +1 -1
  246. package/web-shell/assets/{linear-atZRE_L2.js → linear-BqnWHE9E.js} +1 -1
  247. package/web-shell/assets/{mermaid.core-KKudX-JC.js → mermaid.core-CT-sofSb.js} +5 -5
  248. package/web-shell/assets/{mindmap-definition-RKZ34NQL-CMCej9yG.js → mindmap-definition-RKZ34NQL-BbvrZR4B.js} +1 -1
  249. package/web-shell/assets/{pieDiagram-4H26LBE5-nhx40X7q.js → pieDiagram-4H26LBE5-gAwi3h_Q.js} +1 -1
  250. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-CUmVcN3M.js → quadrantDiagram-W4KKPZXB-CONvBIuO.js} +1 -1
  251. package/web-shell/assets/{requirementDiagram-4Y6WPE33-C_vyEwyy.js → requirementDiagram-4Y6WPE33-lpkrcy1e.js} +1 -1
  252. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-DU6G4VWR.js → sankeyDiagram-5OEKKPKP-Bk6FJHqb.js} +1 -1
  253. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DdeRR_KJ.js → sequenceDiagram-3UESZ5HK-B9b9bBzt.js} +1 -1
  254. package/web-shell/assets/{stateDiagram-AJRCARHV-C6iCI8ps.js → stateDiagram-AJRCARHV-JqBGC-S3.js} +1 -1
  255. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-B_w4fDnm.js +1 -0
  256. package/web-shell/assets/{timeline-definition-PNZ67QCA-B_Ea8Cb7.js → timeline-definition-PNZ67QCA-CCCceXDP.js} +1 -1
  257. package/web-shell/assets/{vennDiagram-CIIHVFJN-BPUVZEJA.js → vennDiagram-CIIHVFJN-EHRnmZ09.js} +1 -1
  258. package/web-shell/assets/{wardley-L42UT6IY-BWEj0lKY.js → wardley-L42UT6IY-CYIcHx3_.js} +1 -1
  259. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-BvDsdIQw.js → wardleyDiagram-YWT4CUSO-B81AuYRl.js} +1 -1
  260. package/web-shell/assets/{xychartDiagram-2RQKCTM6-crz0QhF_.js → xychartDiagram-2RQKCTM6-DOQ6E3z7.js} +1 -1
  261. package/web-shell/index.html +2 -2
  262. package/chunks/channel-worker-group-K7QKH6IG.js +0 -13
  263. package/chunks/chunk-B7NUUEXC.js +0 -311
  264. package/chunks/chunk-CARU2RR2.js +0 -24
  265. package/chunks/chunk-GYTKQYDB.js +0 -23
  266. package/chunks/chunk-LQU7EVFA.js +0 -30
  267. package/chunks/chunk-OCPBI7J5.js +0 -18
  268. package/chunks/chunk-OJAMDVF5.js +0 -66
  269. package/chunks/chunk-TEGEBB2I.js +0 -122
  270. package/web-shell/assets/channel-DkuJJ0qd.js +0 -1
  271. package/web-shell/assets/classDiagram-4FO5ZUOK-CwqHc0TB.js +0 -1
  272. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CwqHc0TB.js +0 -1
  273. package/web-shell/assets/index-Cnvv4VcI.css +0 -5
  274. package/web-shell/assets/index-D1Uyklxa.js +0 -1088
  275. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-C0_6nR6C.js +0 -1
@@ -11,7 +11,7 @@ Run Qwen Code as a local HTTP daemon so multiple clients (IDE plugins, web UIs,
11
11
  ## What it gives you
12
12
 
13
13
  - **Built-in Web Shell UI** — `qwen serve` serves the browser-based Web Shell at its root (`http://127.0.0.1:4170/`) out of the box; run `qwen serve --open` to launch it in your browser automatically. It is served on the same origin as the API, so no second port or reverse proxy is needed. Pass `--no-web` for an API-only daemon.
14
- - **One agent process, many clients** — under the default `sessionScope: 'single'`, every client connecting to the daemon shares one ACP session. Live cross-client collaboration on the same conversation, the same file diffs, the same permission prompts.
14
+ - **Up to one primary ACP child plus one on-demand child per trusted secondary, many clients** — production attempts to preheat the primary bridge and retries on first use after failure; trusted secondary runtimes start their own child on demand, while untrusted secondaries never start one. Under the default `sessionScope: 'single'`, clients targeting the same workspace share one ACP session and collaborate on the same conversation, file diffs, and permission prompts.
15
15
  - **Reconnect-safe streaming** — SSE with `Last-Event-ID` reconnect lets a client drop and pick up exactly where it left off (within the ring's replay window).
16
16
  - **Paged persisted transcripts** — `GET /session/:id/transcript` returns the complete active on-disk transcript as replay pages without attaching a client or changing the live SSE replay window.
17
17
  - **First-responder permissions** — when the agent asks for permission to run a tool, every connected client sees the request; whichever client answers first wins.
@@ -51,7 +51,7 @@ The first npm release of `qwen serve` (v0.16-alpha) is intentionally narrow —
51
51
  - ⏸️ **Prometheus metrics + load test harness** — defers to v0.17 F4 Phase-1 scale instrumentation when 30-50 active sessions becomes a real target.
52
52
  - ⏸️ **`--max-body-size` CLI flag** — daemon enforces `express.json({ limit: '10mb' })` by default which comfortably covers text-only prompts (model context windows are well under 10 MiB of chars). Tunable via flag in v0.16.x.
53
53
 
54
- For the deeper "what we won't fix in Stage 1" enumeration (single-host session-state mutation model + N-parallel-sessions sharing one ACP child), see [Stage 1 scope boundaries](#stage-1-scope-boundaries--what-we-wont-fix-in-stage-15) below.
54
+ For the deeper "what we won't fix in Stage 1" enumeration (single-host session-state mutation model + N parallel sessions sharing one ACP child inside each workspace runtime), see [Stage 1 scope boundaries](#stage-1-scope-boundaries--what-we-wont-fix-in-stage-15) below.
55
55
 
56
56
  ## Quickstart
57
57
 
@@ -64,7 +64,7 @@ qwen serve
64
64
  # → qwen serve: bearer auth disabled (loopback default). Set QWEN_SERVER_TOKEN to enable.
65
65
  ```
66
66
 
67
- The default bind is `127.0.0.1:4170`. Bearer auth is **off** on loopback so local development "just works". The daemon binds to the current working directory; use `--workspace /path/to/dir` to override.
67
+ The default bind is `127.0.0.1:4170`. Bearer auth is **off** on loopback so local development "just works". The daemon registers the current working directory as its primary workspace; use an absolute `--workspace /path/to/dir` to override it, and repeat the flag to register additional isolated runtimes.
68
68
 
69
69
  **Open the Web Shell UI.** Browse to `http://127.0.0.1:4170/` (or start the daemon with `qwen serve --open` to launch it automatically) for the full browser terminal — chat, diffs, tool calls, and permission prompts. The UI is served at the daemon root on the same origin as the API. The rest of this guide uses raw HTTP so you can script against the API directly.
70
70
 
@@ -81,7 +81,7 @@ curl http://127.0.0.1:4170/daemon/status
81
81
  # → {"v":1,"detail":"summary","status":"ok","runtime":{...}}
82
82
  ```
83
83
 
84
- The `workspaceCwd` field surfaces the bound workspace so clients can pre-flight check + omit `cwd` on `POST /session`.
84
+ The `workspaceCwd` field surfaces the primary compatibility workspace so clients can intentionally omit `cwd` on `POST /session`. Current clients should select a trusted entry from `workspaces[]` and send that entry's `cwd` when targeting a runtime explicitly.
85
85
  The `limits.maxPendingPromptsPerSession` field advertises the active per-session prompt admission cap; `null` means the cap is disabled. `limits.maxTotalSessions` advertises the optional daemon-wide fresh-session cap; `null` means unlimited.
86
86
 
87
87
  ### Run channels from the daemon
@@ -90,7 +90,7 @@ The `limits.maxPendingPromptsPerSession` field advertises the active per-session
90
90
  # Start one configured channel under qwen serve
91
91
  qwen serve --channel telegram
92
92
 
93
- # Start several configured channels under one daemon-owned worker
93
+ # Start several configured channels under daemon-owned workspace workers
94
94
  qwen serve --channel telegram --channel feishu
95
95
 
96
96
  # Start all configured channels
@@ -119,6 +119,8 @@ Each selected channel's `cwd` must resolve to a registered workspace, and channe
119
119
 
120
120
  Replacing a selection preflights configuration, ownership, and trust before stopping anything. It keeps workspace workers whose ordered selection is unchanged. If a changed worker cannot start, the daemon stops new workers and restores the old selection. If the daemon cannot confirm that an old child exited even after SIGKILL, it keeps the PID lease and refuses to create a duplicate worker. A worker is still considered ready when at least one requested adapter connects; PUT then returns `partial: true`, and `/daemon/status` reports `channel_worker_partial_connect` for the missing adapters.
121
121
 
122
+ When an adapter rejects `connect()`, current worker snapshots may include `startupFailures` entries with the channel, `phase: "connect"`, an optional adapter code, and a credential-redacted message. `qwen channel set`, `qwen channel reload`, and remote `qwen channel status --daemon-url …` print these reasons. If every adapter fails during a dynamic set or reload, the command receives `502 channel_worker_start_failed`; the response reasons describe that attempt and its `state` describes the result after rollback. The failed attempt is not retained by later status requests. At most 64 reasons are retained per worker startup, and adapter codes should be treated as diagnostic rather than stable categories. Initial `qwen serve --channel …` startup still exits when no adapter connects.
123
+
122
124
  The daemon also exposes read-only runtime snapshots for client UIs and
123
125
  operators: `GET /daemon/status`, `GET /workspace/mcp`,
124
126
  `GET /workspace/skills`, `GET /workspace/providers`, `GET /workspace/env`,
@@ -215,7 +217,7 @@ curl -X POST http://127.0.0.1:4170/session \
215
217
 
216
218
  `cwd` may be omitted — the route falls back to the daemon's primary workspace. Posting a `cwd` that does not canonicalize to any registered workspace returns `400 workspace_mismatch`.
217
219
 
218
- A second client posting to `/session` (any matching `cwd` or none) gets `"attached": true` — they're now sharing the agent.
220
+ A second client posting to `/session` for the same resolved workspace runtime gets `"attached": true` under the default `sessionScope: 'single'` — they are now sharing that runtime's agent session. Omitting `cwd` resolves to primary; selecting another registered workspace creates or attaches to that runtime's separate default session.
219
221
 
220
222
  ### 4. Subscribe to the event stream (in another terminal first)
221
223
 
@@ -325,21 +327,21 @@ Notes:
325
327
  | `--tls-cert <path>` | — | Path to a PEM certificate file. Serve over **HTTPS** instead of HTTP. Must be paired with `--tls-key` (boot fails if only one is given). Unlocks secure-context browser APIs — voice input (`getUserMedia`), WebRTC — over a LAN IP, which browsers otherwise block on plain `http://`. TLS termination only; no auto-generation / ACME. See [HTTPS / TLS](#https--tls-for-mobile--cross-device-access) below. |
326
328
  | `--tls-key <path>` | — | Path to a PEM private key file. Must be paired with `--tls-cert`. |
327
329
  | `--max-sessions <n>` | `20` | Cap on concurrent live sessions. New `POST /session` requests that would spawn a fresh child return `503` (with `Retry-After: 5`) when the cap is hit; attaches to existing sessions are NOT counted. Set to `0` to disable. Sized for single-user / small-team usage; raise it if your deployment has the RAM/FD headroom (~30–50 MB per session). |
328
- | `--max-total-sessions <n>` | derived | Optional non-negative integer daemon-wide cap on fresh session creation across all registered workspace runtimes. It applies to new child sessions, session restore, and branch/fork-created sessions; attaching to an existing live session does not consume a slot. Set to `0` for unlimited. When omitted in multi-workspace mode, the daemon derives a cap from the per-workspace limit and workspace count. |
330
+ | `--max-total-sessions <n>` | derived | Optional non-negative integer daemon-wide cap on fresh session creation across all registered workspace runtimes. It applies to new child sessions, session restore, and branch/fork-created sessions; attaching to an existing live session does not consume a slot. Set to `0` for unlimited. When omitted with several startup/restored workspaces, the daemon derives a fixed cap from the per-workspace limit and the startup workspace count; later dynamic registration does not recompute it. |
329
331
  | `--max-pending-prompts-per-session <n>` | `5` | Per-session cap on prompts accepted by `POST /session/:id/prompt` but not yet settled, including queued prompts and the active prompt. The bridge rejects overflow synchronously with `503`, `Retry-After: 5`, and `code: "prompt_queue_full"` before returning a `promptId`. Set to `0` to disable. `branchSession` serializes on the same FIFO but does not count against this prompt cap. |
330
- | `--workspace <path>` | `process.cwd()` | Workspace path registered by this daemon. Repeat the flag to host multiple workspaces in one process; the first is primary and remains the default when a request omits `cwd`. Relative paths resolve from the process working directory. Session requests whose canonical `cwd` is not registered return `400 workspace_mismatch`. |
332
+ | `--workspace <path>` | `process.cwd()` | Absolute workspace directory registered by this daemon. Repeat the flag to host multiple workspaces in one process; the first is primary and remains the default when a request omits `cwd`. Relative values are rejected. Session requests whose canonical `cwd` is not registered return `400 workspace_mismatch`. |
331
333
  | `--channel <name\|all>` | — | Experimental daemon-managed channel worker. Repeat the flag to select multiple configured channels, or pass `all` to start every configured channel. `all` cannot be combined with named channels. Selected channel `cwd` values must resolve to a registered workspace; a multi-workspace daemon runs one worker per owning workspace. The worker is owned by `qwen serve`; stop the daemon to stop serve-managed channels. |
332
334
  | `--max-connections <n>` | `256` | Listener-level TCP connection cap (`server.maxConnections`). Bounds raw socket count irrespective of session count — slow / phantom SSE clients get rejected at accept time once full. Raise alongside `--max-sessions` if your deployment expects many SSE subscribers per session. |
333
335
  | `--event-ring-size <n>` | `8000` | Per-session SSE replay ring depth (#3803 §02 target). Sets the backlog available to `GET /session/:id/events` with `Last-Event-ID: N`. Larger = more reconnect headroom at the cost of a few hundred KB extra RAM per session. SDK clients can additionally request a larger per-subscriber backlog cap on a specific subscription via `?maxQueued=N` (range `[16, 2048]`, default 256). Daemons also emit a non-terminal `slow_client_warning` SSE frame at 75% queue fill so clients can drain / reconnect before getting evicted. Pre-flight `caps.features.slow_client_warning`. |
334
336
  | `--compacted-replay-max-bytes <n>` | `4194304` | Per-live-session byte cap for the retained replay events in the bounded snapshot returned by `POST /session/:id/load`. The cap applies to `compactedReplay`; the current in-flight `liveJournal` remains uncapped. Values must be positive safe integers; invalid values fail at boot, and the hard ceiling is 256 MiB. When older retained replay is dropped, the snapshot begins with `history_truncated`. This does not limit the on-disk transcript. |
335
- | `--mcp-client-budget <n>` | — | Positive integer cap on live MCP clients **per ACP session** (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14 v1; PR 23 graduates this to per-workspace via the shared MCP pool). Combine with `--mcp-budget-mode`. When unset, no accounting-driven enforcement (but `GET /workspace/mcp` still reports `clientCount`). Distinct from claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` which gates startup concurrency, not the total client count. Pre-flight `caps.features.mcp_guardrails`. |
337
+ | `--mcp-client-budget <n>` | — | Positive integer cap on live MCP clients. When `mcp_workspace_pool` is advertised, the cap and transports are shared per workspace runtime; when the tag is absent, the legacy per-session manager enforces it. Combine with `--mcp-budget-mode`. When unset, no accounting-driven enforcement (but `GET /workspace/mcp` still reports `clientCount`). Distinct from claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE`, which gates startup concurrency rather than total live clients. Pre-flight `caps.features.mcp_guardrails` and `caps.features.mcp_workspace_pool`. |
336
338
  | `--mcp-budget-mode <m>` | `warn` / `off` | How `--mcp-client-budget` is enforced. `warn` (default when budget set): no refusal, snapshot's `budgets[0].status` flips to `warning` at ≥75% of budget. `enforce`: connects past the cap are refused, per-server cell shows `disabledReason: 'budget'`, deterministic by `mcpServers` declaration order. `off` (default when budget unset): pure observability. Boot rejects `enforce` without a budget. |
337
- | `--http-bridge` | `true` | Stage 1 mode: one `qwen --acp` child per registered workspace runtime; sessions targeting that workspace multiplex onto its child via ACP `newSession()`. Stage 2 native in-process becomes available later. |
339
+ | `--http-bridge` | `true` | Stage 1 mode: production attempts to preheat one primary `qwen --acp` child for compatibility and retries on first use after failure, while each trusted secondary can start one child on demand. Sessions targeting a runtime multiplex onto its child via ACP `newSession()`; untrusted secondaries cannot start ACP. Stage 2 native in-process becomes available later. |
338
340
  | `--allow-origin <pat>` | — | T2.4 ([#4514](https://github.com/QwenLM/qwen-code/issues/4514)). Cross-origin allowlist for browser webui clients. Repeatable. Each value is `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended so `/health` and `/demo` are also bearer-gated, since both are pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo / query). **Subdomain wildcards (`https://*.example.com`) are intentionally unsupported** — list each subdomain explicitly, or use `*` with a configured token (and `--require-auth` for full hardening). Matched origins receive CORS response headers (`Access-Control-Allow-Origin`, `Vary: Origin`, methods, headers, max-age, and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as today's wall. `Origin: null` (sandboxed iframes, file:// docs) is always rejected, even under `*`. Pre-flight via `caps.features.allow_origin`. Loopback self-origin hits are unaffected. |
339
341
  | `--web` / `--no-web` | `true` | Serve the built Web Shell SPA at the daemon root (`GET /`, `/assets/*`, and SPA deep-link fallback). The static shell is registered **before** the bearer-auth gate — a browser can't attach a token to a `<script>` subresource or an address-bar navigation, the shell carries no secrets, and every API route stays token-gated regardless. On non-loopback binds a one-line stderr warning notes the UI is reachable without auth. Use `--no-web` for an API-only daemon. No effect when the build omits the Web Shell assets (the daemon logs a breadcrumb and runs API-only). |
340
342
  | `--open` | `false` | After the listener is up, open the Web Shell in your default browser at the daemon URL (with `#token=` appended as a URL fragment when a token is configured — a fragment is never sent to the server, keeping the token out of access logs and Referer headers). No-op with `--no-web`, or in headless / CI / SSH environments where no browser is available. |
341
343
 
342
- > **Sizing the load knobs.** `--max-sessions` is the per-workspace **new-child** cap. `--max-total-sessions`, when set, is the daemon-wide fresh-session cap.
344
+ > **Sizing the load knobs.** `--max-sessions` is the per-workspace fresh-session cap. `--max-total-sessions`, when set, is the daemon-wide fresh-session cap.
343
345
  > Three other layers also limit load — when sizing for a high-concurrency
344
346
  > deployment, tune them together:
345
347
  >
@@ -358,18 +360,20 @@ Notes:
358
360
  > over-capacity client gets a terminal `client_evicted` frame and is
359
361
  > closed (one slow consumer can't pin the daemon).
360
362
  >
361
- > These caps interact: the lower of `--max-sessions` and
362
- > `--max-total-sessions` bounds fresh sessions in today's single-workspace
363
- > daemon. `--max-sessions × 64 subscribers × 256 frames`
364
- > is the worst-case in-flight memory at the EventBus layer, while
365
- > `--max-sessions × --max-pending-prompts-per-session` bounds accepted
366
- > prompt work at the admission layer. Default sizing assumes single-user /
367
- > small-team load; raise progressively (and watch RSS) for multi-tenant
368
- > deployments.
363
+ > These caps interact: each runtime is bounded by `--max-sessions`, while
364
+ > `--max-total-sessions` bounds their aggregate. The effective session ceiling
365
+ > is the lower of any finite daemon-wide cap and the aggregate per-runtime cap
366
+ > (treat that aggregate as unlimited if the per-workspace cap is unlimited). If
367
+ > neither is finite, there is no finite session ceiling. A finite ceiling × 64
368
+ > subscribers × 256 frames is the worst-case in-flight memory at the EventBus
369
+ > layer; multiplying it by
370
+ > `--max-pending-prompts-per-session` bounds accepted prompt work at the
371
+ > admission layer. Default sizing assumes single-user / small-team load; raise
372
+ > progressively (and watch RSS) for larger deployments.
369
373
 
370
374
  > **MCP client guardrails (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14).** A workspace declaring 30 MCP servers in `mcpServers` will start 30 clients with no upstream cap unless you set one. `--mcp-client-budget=N` caps the live MCP client count; `--mcp-budget-mode={enforce,warn,off}` chooses the behavior. Default is `warn` when a budget is set (snapshot surfaces the warning but no client is refused — useful for measuring real-world fanout before flipping on enforcement). Refused servers under `enforce` mode get `disabledReason: 'budget'` on their per-server cell, and the `budgets[0]` cell shows `status: 'error'` + `errorKind: 'budget_exhausted'`. Slot reservation is by server name and survives reconnects / discovery timeouts — a refused server can't take a slot from a healthy one.
371
375
  >
372
- > ⚠️ **v1 scope: per-session, not per-workspace.** Each ACP session inside the daemon has its own `Config`/`McpClientManager` (created via `newSessionConfig` per session). The budget caps live MCP clients **per session**, not aggregated across all sessions in the workspace. Snapshot at `GET /workspace/mcp` reflects the bootstrap session's view (the cell carries `scope: 'session'` for honesty). If you run 5 concurrent ACP sessions with `--mcp-client-budget=10`, you may have up to 50 live MCP clients across the daemon the cap holds per session. **Wave 5 PR 23 (shared MCP pool)** introduces a workspace-scoped manager and graduates this to true per-workspace enforcement.
376
+ > **Current scope is capability-driven.** When `mcp_workspace_pool` is present, all sessions in one workspace runtime share its MCP transport pool and budget controller; `GET /workspace/mcp` emits `scope: 'workspace'`. A second workspace has an independent pool and budget. When the tag is absent (including `QWEN_SERVE_NO_MCP_POOL=1`), the daemon uses the legacy per-session `McpClientManager` and emits `scope: 'session'`; in that fallback, N sessions can each consume the configured cap.
373
377
  >
374
378
  > ```sh
375
379
  > qwen serve --mcp-client-budget=10 --mcp-budget-mode=warn
@@ -377,7 +381,7 @@ Notes:
377
381
  > qwen serve --mcp-client-budget=10 --mcp-budget-mode=enforce
378
382
  > ```
379
383
  >
380
- > This is **not** the same as claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` (which gates startup concurrency); they're orthogonal. PR 23 will add a real shared MCP pool (a `scope: 'workspace'` cell in `budgets[]` alongside the per-session cell); PR 14 v1 is the in-process counter + soft enforcement on the existing per-session manager.
384
+ > This is **not** the same as claude-code's `MCP_SERVER_CONNECTION_BATCH_SIZE` (which gates startup concurrency); they are orthogonal. Clients must branch on `mcp_workspace_pool`, not assume a scope from the protocol version alone.
381
385
  >
382
386
  > **Push events (issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) PR 14b).** SDK clients subscribed to `GET /session/:id/events` receive typed frames when budget thresholds cross — `mcp_budget_warning` (synthetic, fires once per upward 75% crossing with hysteresis re-arm at 37.5%, advertised via `mcp_guardrail_events`) and `mcp_child_refused_batch` (coalesced once per discovery pass under `enforce` mode; length-1 from `readResource` lazy-spawn refusal). The snapshot at `GET /workspace/mcp` is still the source-of-truth for state-after-reconnect; events are change-edges. Useful when dashboarding in real-time without polling.
383
387
 
@@ -389,7 +393,7 @@ Notes:
389
393
  - **Host header allowlist** — on **loopback** binds the daemon checks `Host:` matches `localhost:port` / `127.0.0.1:port` / `[::1]:port` / `host.docker.internal:port` (case-insensitive per RFC 7230 §5.4) to defend against DNS rebinding. **Non-loopback binds (`--hostname 0.0.0.0`) intentionally bypass the Host allowlist** — the operator has chosen the surface area, so the bearer-token gate is the sole authentication layer; reverse proxies / SNI / client cert pinning are the operator's responsibility, not the daemon's. If you need Host-based isolation on a non-loopback bind, terminate TLS + check Host at a front proxy.
390
394
  - **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` and `/demo` remain pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the `/demo` page) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
391
395
  - **Chrome extension browser automation is separate from framing.** `qwen serve --allow-origin chrome-extension://<id>` lets the extension frame the Web Shell and connect to the daemon. Console/network/screenshot/click tools require an external CDP MCP adapter command: `QWEN_CDP_MCP_COMMAND=/path/to/cdp-mcp-adapter qwen serve --allow-origin chrome-extension://<id>`. The main CLI package does not bundle a browser automation adapter; clients can check `caps.features.includes('browser_automation_mcp')` before presenting those tools as available.
392
- - **Spawned `qwen --acp` child inherits the daemon's environment** with one explicit scrub: `QWEN_SERVER_TOKEN` is removed before the child starts (the daemon's own bearer; the agent doesn't need it). Everything else `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `QWEN_*` / `DASHSCOPE_API_KEY` / your custom `modelProviders[].envKey` / etc. passes through, because the agent legitimately needs those to authenticate to the LLM. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc` / `~/.aws/credentials` / `~/.npmrc` is reachable by prompt injection regardless. The env passthrough is not the security boundary; the user-as-trust-root is. Don't run `qwen serve` under an identity that has env-resident credentials you wouldn't trust the agent with.
396
+ - **A spawned `qwen --acp` child receives its owning runtime's effective environment.** The daemon freezes a process-env base, applies that workspace's settings/env-file overlay to a runtime-local snapshot, and never writes the overlay back to `process.env`; same-named keys in another runtime do not cross over. `QWEN_SERVER_TOKEN` is scrubbed before spawn because the agent does not need the daemon bearer. Base credentials such as `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `QWEN_*`, and `DASHSCOPE_API_KEY` otherwise pass through unless the runtime overlay changes them. **This is intentional, not a sandbox.** The agent runs as the same UID with shell-tool access, so anything in `~/.bashrc`, `~/.aws/credentials`, or `~/.npmrc` is reachable by prompt injection regardless. Environment isolation between runtimes is not an operating-system security boundary; do not run `qwen serve` under an identity that has credentials you would not trust the agent with.
393
397
  - **Per-subscriber bounded SSE queues** — a slow client that overflows its queue gets a `client_evicted` terminal frame and is closed; one stuck consumer can't pin the daemon.
394
398
  - **Per-session prompt admission cap** — defaults to 5 accepted-but-unsettled prompts per session. A buggy client cannot enqueue unbounded prompt promises or temporary SSE waits for one session.
395
399
  - **Graceful shutdown** — SIGINT/SIGTERM drain the agent children before closing the listener (10s deadline per child).
@@ -433,27 +437,28 @@ Both flags accept a positive integer in milliseconds; `0`, `NaN`, non-integer, o
433
437
 
434
438
  ## Multi-session & multi-workspace deployment
435
439
 
436
- Pass `--workspace` more than once to register several non-overlapping workspaces in one `qwen serve` process. The first path is primary. Each registered workspace owns an isolated runtime boundary, while the daemon-wide listener, authentication policy, and total-session limit are shared. Trusted workspaces start their own `qwen --acp` child on demand. Requests may select a registered workspace by canonical `cwd`; requests that omit `cwd` use the primary workspace. Use one daemon per user or security principal; workspace trust is an execution gate, not an ACL.
440
+ Pass `--workspace` more than once to register several non-overlapping workspaces in one `qwen serve` process. The first path is primary. Each registered workspace owns an isolated runtime boundary, while the daemon-wide listener, authentication policy, and total-session limit are shared. Production attempts to preheat the primary ACP child for compatibility and retries on first use after failure; trusted secondaries start their own child on demand, and untrusted secondaries do not start ACP. Requests may select a registered workspace by canonical `cwd`; requests that omit `cwd` use the primary workspace. Use one daemon per user or security principal; workspace trust is an execution gate, not an ACL.
437
441
 
438
- An untrusted secondary workspace is visible in Web Shell as `untrusted` and `read-only`. It can be expanded to inspect the persisted session catalog, but it cannot yet be selected or opened in Web Shell, resumed, used to create sessions, or fully exported. The REST API exposes its persisted session-group catalog and, when `workspace_persisted_transcript` is advertised, its active persisted transcript through the bounded workspace-qualified pager. These reads do not include live runtime state or start an ACP child. Full workspace-qualified export requires a trusted workspace and the separate `workspace_session_export` capability. Trust the workspace and restart the daemon before using execution, mutation, or export features. An untrusted primary remains disabled in Web Shell.
442
+ An untrusted secondary workspace is visible in Web Shell as `untrusted` and `read-only`. It can be expanded to inspect the persisted session catalog, but it cannot yet be selected or opened in Web Shell, resumed, used to create sessions, or fully exported. The REST API follows the existing bounded filesystem read policy and also exposes its persisted session-group catalog and, when `workspace_persisted_transcript` is advertised, its active persisted transcript through the bounded workspace-qualified pager. These reads do not include live runtime state or start an ACP child. Full workspace-qualified export requires a trusted workspace and the separate `workspace_session_export` capability. Trust the workspace and restart the daemon before using execution, mutation, or export features. An untrusted primary remains disabled in Web Shell.
439
443
 
440
444
  Use separate daemon processes when you need a smaller fault or security boundary, independent bearer tokens, quotas, audit boundaries, operating-system isolation, or independent resource supervision. Multi-workspace mode is intended for one operator hosting several repos; it is not a multi-tenant isolation boundary. A single daemon token authorizes every route the daemon exposes, including the allowed read-only catalog for all registered workspaces.
441
445
 
442
446
  > **Subscribe BEFORE posting `modelServiceId` on attach.** When a client `POST /session` with a `modelServiceId` and the workspace already has a session running a different model, the daemon issues an internal `setSessionModel` call — failures are NOT propagated as an HTTP error (the session stays operational on its current model). The visible failure signal is a `model_switch_failed` event on the session's SSE stream. If you call `POST /session` and only THEN open `GET /session/:id/events`, you'll miss the failure event and silently keep talking to the wrong model. Open the SSE stream first, or pass `Last-Event-ID: 0` on subscribe to replay the ring's oldest available event.
443
447
 
444
- To handle multiple **users** (each with their own quota, audit log, sandbox) or to scale beyond one process's reach (cold-start budget, FD count, RSS), spawn one daemon per workspace per user behind an external orchestrator. That orchestrator (multi-tenancy / OIDC / Quota / Audit / k8s) is **out of scope** for the qwen-code project — see issue [#3803](https://github.com/QwenLM/qwen-code/issues/3803) "External Reference Architecture" for the design pointers.
448
+ To handle multiple **users or security principals** (each with an independent token, quota, audit log, sandbox, or process fault boundary) or to scale beyond one process's reach (cold-start budget, FD count, RSS), spawn one daemon per principal behind an external orchestrator. Each such daemon may still host several workspaces for that principal. The orchestrator (multi-tenancy / OIDC / Quota / Audit / k8s) is **out of scope** for the qwen-code project — see issue [#3803](https://github.com/QwenLM/qwen-code/issues/3803) "External Reference Architecture" for the design pointers.
445
449
 
446
450
  ## Loading and resuming a persisted session
447
451
 
448
452
  The daemon exposes ACP's `session/load` and resume flow over HTTP, plus a separate read-only transcript pager:
449
453
 
450
- | Route | Use when |
451
- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
452
- | `POST /session/:id/load` | The client has **no** useful local history rendered (cold reconnect, picker-then-open). For a live session, the daemon returns and injects the current bounded replay snapshot window; if older replay was dropped, the snapshot begins with `history_truncated`. Capability tag: `session_load`. |
453
- | `POST /session/:id/resume` | The client already has the turns on screen and only needs the daemon-side handle back. Model context is restored on the agent side without UI replay — the SSE stream stays clean. Capability tag: `session_resume` (`unstable_session_resume` remains a deprecated alias for older clients). |
454
- | `GET /session/:id/transcript` | The client needs the complete active persisted transcript. It returns id-less replay frames in cursor pages and does not call `/load`, attach a client, seed the live EventBus, create a live session, or change the live replay window. Capability tag: `session_transcript`. |
455
- | `GET /workspaces/:workspace/session/:id/transcript` | The client needs an active persisted transcript from a selected workspace without starting ACP or loading workspace settings. Registered untrusted secondary workspaces may use this read-only path. Capability tag: `workspace_persisted_transcript`. |
456
- | `GET /workspaces/:workspace/session/:id/export` | The client needs a complete `html`, `md`, `json`, or `jsonl` attachment from a selected trusted workspace. It reads active persisted storage without starting ACP or falling back to primary. Capability tag: `workspace_session_export`. |
454
+ | Route | Use when |
455
+ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
456
+ | `POST /session/:id/load` | The client has **no** useful local history rendered (cold reconnect, picker-then-open). For a live session, the daemon returns and injects the current bounded replay snapshot window; if older replay was dropped, the snapshot begins with `history_truncated`. Capability tag: `session_load`. |
457
+ | `POST /session/:id/resume` | The client already has the turns on screen and only needs the daemon-side handle back. Model context is restored on the agent side without UI replay — the SSE stream stays clean. Capability tag: `session_resume` (`unstable_session_resume` remains a deprecated alias for older clients). |
458
+ | `GET /session/:id/transcript` | The client needs the complete active persisted transcript. It returns id-less replay frames in cursor pages and does not call `/load`, attach a client, seed the live EventBus, create a live session, or change the live replay window. Capability tag: `session_transcript`. |
459
+ | `GET /workspaces/:workspace/session/:id/transcript` | The client needs an active persisted transcript from a selected workspace without starting ACP or loading workspace settings. Registered untrusted secondary workspaces may use this read-only path. Capability tag: `workspace_persisted_transcript`. |
460
+ | `GET /workspaces/:workspace/session/:id/export` | The client needs a complete `html`, `md`, `json`, or `jsonl` attachment from a selected trusted workspace. It reads active persisted storage without starting ACP or falling back to primary. Capability tag: `workspace_session_export`. |
461
+ | `GET /workspaces/:workspace/session/:id/archive/export` | The client needs the same attachment formats from archived persisted storage in a selected trusted workspace. It does not unarchive, start ACP, or fall back to an active or primary session. Capability tag: `workspace_archived_session_export`. |
457
462
 
458
463
  For load and resume, the TypeScript SDK exposes static factories on
459
464
  `DaemonSessionClient`:
@@ -487,6 +492,8 @@ For a registered workspace, use `client.workspaceById(workspaceId).getSessionTra
487
492
 
488
493
  For a full attachment from a trusted registered workspace, pre-flight `workspace_session_export` and call `client.workspaceById(workspaceId).exportSession(sessionId, { format: 'html' })` or the raw `/workspaces/:workspace/session/:id/export` route. Do not infer support from `session_export` or `workspace_qualified_rest_core`: older daemons can advertise both while retaining primary-only export. The current Web Shell export action remains primary-only; use the SDK or REST route for another workspace.
489
494
 
495
+ For an archived attachment, pre-flight `workspace_archived_session_export` and call `client.workspaceById(workspaceId).exportArchivedSession(sessionId, { format: 'html' })` or `/workspaces/:workspace/session/:id/archive/export`. This path reads archived storage in place and returns `409 session_not_archived` for an active-only id; it does not unarchive the session. Web Shell exposes the same export for archived rows in trusted primary and secondary workspaces when the capability is present.
496
+
490
497
  `limit` counts active chat records, not emitted replay frames; one record can produce several `session_update` events. The first response freezes the JSONL snapshot size and returns `nextCursor` while `hasMore` is true. Later pages ignore appends after page 1, but return `409` if the file is deleted, truncated, replaced, archived, or otherwise conflicts with the frozen cursor. Very large snapshots return `413 transcript_too_large` before indexing so the daemon does not scan unbounded transcript files on the request path.
491
498
 
492
499
  For repeated paging through the legacy singular route, set `--channel-idle-timeout-ms` to a positive value. With the default `0`, an idle workspace's ACP child — and the in-process transcript index cache it holds — is reaped after every page, so each page re-spawns the child and rebuilds the index by re-scanning the whole frozen prefix (`O(snapshotSize)` per page). A positive timeout keeps the child alive across the cursor walk so it reuses its cached transcript index and replay config. The workspace-qualified persisted route never starts an ACP child and is unaffected by this timeout.
@@ -565,26 +572,26 @@ In this mode, TUI is a **"super-client"** — it observes the same agent convers
565
572
 
566
573
  (B) is the more ambitious answer but locks Stage 1.5 into a substantially larger wire surface that must also pass cleanly through the planned in-process refactor. We'd rather walk the smaller scope honestly. The session-state-event taxonomy work — enumerating which TUI flows are local-only by design vs. could plausibly graduate to wire under a future opt-in (B)-flavor extension — moves to [#3803](https://github.com/QwenLM/qwen-code/issues/3803), not Stage 1.5 code.
567
574
 
568
- ### N parallel sessions share one `qwen --acp` child
575
+ ### N parallel sessions share one `qwen --acp` child per workspace runtime
569
576
 
570
- Multiple sessions on the same workspace **share one `qwen --acp` child process** via the agent's native multi-session support (`packages/cli/src/acp-integration/acpAgent.ts:194: private sessions: Map<string, Session>`). The bridge calls `connection.newSession({cwd, mcpServers})` for each session — the agent stores them in its sessions map and demultiplexes per-call sessionId.
577
+ Multiple sessions on the same trusted workspace **share that runtime's `qwen --acp` child process** via the agent's native multi-session support (`packages/cli/src/acp-integration/acpAgent.ts:194: private sessions: Map<string, Session>`). The bridge calls `connection.newSession({cwd, mcpServers})` for each session — the agent stores them in its sessions map and demultiplexes per-call sessionId. Production can own up to one primary child (preheat attempted by default) plus one on-demand child per trusted secondary; untrusted secondaries own none.
571
578
 
572
579
  Concrete cost at N=5 sessions on the same workspace:
573
580
 
574
- | Resource | Per session | At N=5 |
575
- | ------------------------------------ | ----------- | ---------------------------- |
576
- | Daemon Node process | one | **30–50 MB** (one daemon) |
577
- | `qwen --acp` child | shared | **60–100 MB** (one child) |
578
- | MCP server children | per-session | 3×N if configs differ |
579
- | `FileReadCache` (in-child heap) | shared | parsed once |
580
- | `CLAUDE.md` / hierarchy memory parse | shared | parsed once |
581
- | OAuth refresh-token state | shared | **one refresh path** |
582
- | Auto-memory learned facts | shared | one knowledge base per child |
583
- | Cold start | first only | <200 ms after first session |
581
+ | Resource | Per session | At N=5 |
582
+ | ------------------------------------ | ----------------------------------------------------- | ---------------------------------------------------------------- |
583
+ | Daemon Node process | one | **30–50 MB** (one daemon) |
584
+ | `qwen --acp` child | shared | **60–100 MB** (one child) |
585
+ | MCP server children | workspace pool when advertised; otherwise per-session | shared by matching pool entries, or up to 3×N in legacy fallback |
586
+ | `FileReadCache` (in-child heap) | shared | parsed once |
587
+ | `CLAUDE.md` / hierarchy memory parse | shared | parsed once |
588
+ | OAuth refresh-token state | shared | **one refresh path** |
589
+ | Auto-memory learned facts | shared | one knowledge base per child |
590
+ | Cold start | first only | <200 ms after first session |
584
591
 
585
- The bridge keeps **one channel per daemon** (one daemon per workspace, per §02). The channel stays alive while at least one session is live; the last `killSession` (or a channel-level crash) kills the child.
592
+ Each active workspace runtime keeps **one bridge boundary**. Production attempts to preheat the primary channel and retries on first use after failure; a trusted secondary opens its channel and child on demand, while an untrusted secondary never does. A channel stays alive while at least one session is live. After the last `killSession`, the runtime kills its child immediately by default or after the configured channel idle grace; a channel-level crash also tears it down without selecting another runtime.
586
593
 
587
- **MCP server children** are still per-session today each session's config can specify different servers, so they're independently spawned. Stage 1.5 follow-up: refcount MCP server children by `(workspace, config-hash)` so identical configs share. Not in scope for this PR.
594
+ **MCP server children** use the workspace-scoped transport pool when `mcp_workspace_pool` is advertised: matching `(workspace runtime, server name, config fingerprint)` entries are refcounted across sessions. If the capability is absent, the legacy per-session manager independently spawns them.
588
595
 
589
596
  **Peer agents (Cursor / Continue / Claude Code / OpenCode / Gemini CLI) all do single-process multi-session.** qwen-code matches them at the agent layer; the Stage 1 bridge in this PR makes the same architecture visible over HTTP.
590
597