@qwen-code/qwen-code 0.19.8 → 0.19.9-preview.0

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 (451) hide show
  1. package/bundled/qc-helper/SKILL.md +1 -0
  2. package/bundled/qc-helper/docs/configuration/auth.md +40 -55
  3. package/bundled/qc-helper/docs/configuration/model-providers.md +224 -218
  4. package/bundled/qc-helper/docs/configuration/settings.md +68 -51
  5. package/bundled/qc-helper/docs/features/_meta.ts +1 -0
  6. package/bundled/qc-helper/docs/features/channels/dingtalk.md +12 -2
  7. package/bundled/qc-helper/docs/features/channels/overview.md +82 -7
  8. package/bundled/qc-helper/docs/features/channels/wecom.md +6 -0
  9. package/bundled/qc-helper/docs/features/code-review.md +109 -41
  10. package/bundled/qc-helper/docs/features/commands.md +45 -44
  11. package/bundled/qc-helper/docs/features/computer-use.md +77 -0
  12. package/bundled/qc-helper/docs/features/hooks.md +29 -0
  13. package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
  14. package/bundled/qc-helper/docs/features/tool-use-summaries.md +19 -23
  15. package/bundled/qc-helper/docs/integration-vscode.md +2 -2
  16. package/bundled/qc-helper/docs/qwen-serve.md +66 -23
  17. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +2 -2
  18. package/bundled/review/DESIGN.md +303 -46
  19. package/bundled/review/SKILL.md +670 -165
  20. package/chunks/MaxSizedBox-BEVSAWZ6.js +70 -0
  21. package/chunks/{StandaloneSessionPicker-EYRGH6PJ.js → StandaloneSessionPicker-2DA2MDDE.js} +81 -79
  22. package/chunks/{acpAgent-GRFTTRHW.js → acpAgent-G3WJU3PS.js} +1318 -465
  23. package/chunks/agent-DD3WSHXE.js +68 -0
  24. package/chunks/agent-headless-MHI7U2CU.js +62 -0
  25. package/chunks/{anthropicContentGenerator-CPF22MA7.js → anthropicContentGenerator-56U3YCP2.js} +187 -31
  26. package/chunks/{artifact-tool-D233YJFH.js → artifact-tool-MIZLXBLF.js} +5 -5
  27. package/chunks/{askUserQuestion-MKL5ZTMC.js → askUserQuestion-XMJVPNWM.js} +6 -6
  28. package/chunks/bridge-HKEWPNB5.js +78 -0
  29. package/chunks/{ca-MKD32FQL.js → ca-C2JTT2N5.js} +68 -6
  30. package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
  31. package/chunks/channel-worker-manager-YSFB4HUU.js +418 -0
  32. package/chunks/channel-worker-supervisor-QCKIOYZD.js +20 -0
  33. package/chunks/chunk-2FMQQXMM.js +38 -0
  34. package/chunks/{chunk-CSOTA7KX.js → chunk-2FO5GFKZ.js} +2 -2
  35. package/chunks/{chunk-QQDPRDVW.js → chunk-2HRYPZT5.js} +1 -1
  36. package/chunks/{chunk-UXEW557D.js → chunk-2J4ZWME4.js} +3 -3
  37. package/chunks/{chunk-P3XEEI3X.js → chunk-2TQXXQMI.js} +36 -7
  38. package/chunks/{chunk-GSHQYYIV.js → chunk-2UW5RFRP.js} +6 -26
  39. package/chunks/{chunk-6IAWPIQ6.js → chunk-2W3OOD4W.js} +5 -3
  40. package/chunks/{chunk-2PSWA5ID.js → chunk-2X56YUSZ.js} +1 -1
  41. package/chunks/{chunk-NQKLOAVJ.js → chunk-2Z5UX4KI.js} +2 -2
  42. package/chunks/chunk-3MX7D6QN.js +516 -0
  43. package/chunks/{chunk-EEN2TKST.js → chunk-43RXPU5Q.js} +2 -2
  44. package/chunks/{chunk-55ZMG67I.js → chunk-4LD5APFL.js} +4 -4
  45. package/chunks/{chunk-WF4FAXDL.js → chunk-4QZ3XHWE.js} +62 -62
  46. package/chunks/chunk-4QZADKJS.js +34 -0
  47. package/chunks/{chunk-UIDXQNMV.js → chunk-4WGODMVR.js} +1 -1
  48. package/chunks/{chunk-E6US47KI.js → chunk-4WKAA4KS.js} +1 -1
  49. package/chunks/{chunk-TI3BWD4D.js → chunk-54UZQ57N.js} +39 -19
  50. package/chunks/{chunk-3GONHQOA.js → chunk-57OAHC2Y.js} +1 -1
  51. package/chunks/{chunk-JZSY4WP3.js → chunk-5DTTYNB7.js} +1 -1
  52. package/chunks/chunk-5HBA2Z7V.js +28 -0
  53. package/chunks/{chunk-SKAZWEV5.js → chunk-5M6IDOMF.js} +35 -98
  54. package/chunks/{chunk-A4BMJM77.js → chunk-5O2XNYP6.js} +1 -0
  55. package/chunks/{chunk-FQNC62B2.js → chunk-5VHASII5.js} +11 -11
  56. package/chunks/{chunk-GO6LNQXT.js → chunk-6AM5D4ME.js} +1 -1
  57. package/chunks/{chunk-BJBWRCSK.js → chunk-6H67XLET.js} +1 -1
  58. package/chunks/{chunk-O7FIRWJV.js → chunk-6JPDCEDB.js} +3 -3
  59. package/chunks/{chunk-3UP777ZS.js → chunk-6RLROE6G.js} +1 -1
  60. package/chunks/{chunk-GN3F6PIU.js → chunk-6WPJRYLZ.js} +5 -5
  61. package/chunks/{chunk-ZERZSAZL.js → chunk-75DOP5OR.js} +2 -2
  62. package/chunks/chunk-7DKX4A5Z.js +91 -0
  63. package/chunks/{chunk-M7S4GK5Z.js → chunk-7IDCQ35Q.js} +147 -30
  64. package/chunks/{chunk-22MNNNXE.js → chunk-7NFB7LBQ.js} +11 -3
  65. package/chunks/{chunk-ZL5HN75Q.js → chunk-7R4DPSRA.js} +37 -3
  66. package/chunks/{chunk-VZ7HY3YU.js → chunk-7STBROEV.js} +3 -3
  67. package/chunks/{chunk-SAIILPQ3.js → chunk-7X7TEQNX.js} +5 -3
  68. package/chunks/{chunk-RMLZAUWH.js → chunk-A3U2TQUL.js} +10 -12
  69. package/chunks/{chunk-IRJWHZWU.js → chunk-A4UCTEB5.js} +2 -2
  70. package/chunks/{chunk-BOBRZZKD.js → chunk-A7W4GQRW.js} +5 -5
  71. package/chunks/{chunk-O33TBKDC.js → chunk-AAUZBE5Y.js} +155 -19
  72. package/chunks/{chunk-SQ2UATK7.js → chunk-ADLYZJYZ.js} +11 -11
  73. package/chunks/{chunk-QYUE6W3T.js → chunk-ALGGS7UH.js} +2 -39
  74. package/chunks/{chunk-WMPVYQ4P.js → chunk-ARKANCNX.js} +3 -2
  75. package/chunks/{chunk-IBY3Q3HG.js → chunk-AU4R7ACM.js} +967 -181
  76. package/chunks/{channel-worker-supervisor-NZQUOEFJ.js → chunk-B7MFJBKE.js} +190 -34
  77. package/chunks/{chunk-HW4N45EE.js → chunk-B7NUUEXC.js} +38 -11
  78. package/chunks/{chunk-3B26UVCX.js → chunk-BLPMRN4B.js} +39 -10
  79. package/chunks/{chunk-ZN5T4BHI.js → chunk-BPZALHVR.js} +2 -2
  80. package/chunks/{chunk-BVYU3ZTI.js → chunk-BXT6PQ73.js} +1020 -942
  81. package/chunks/{chunk-OFEVLU4C.js → chunk-CARU2RR2.js} +1 -1
  82. package/chunks/{chunk-HDOH3QYE.js → chunk-CEGKYZDB.js} +2 -2
  83. package/chunks/{chunk-GLE2YUPU.js → chunk-COH43MRJ.js} +1 -1
  84. package/chunks/{chunk-E5A7LHNN.js → chunk-CPBF7KYF.js} +1 -1
  85. package/chunks/{chunk-UWCTAVOD.js → chunk-CR3C7WXL.js} +1 -1
  86. package/chunks/{chunk-IWKSG2AR.js → chunk-CXAOG665.js} +1 -1
  87. package/chunks/{chunk-64WXLC72.js → chunk-DJ2GSRLV.js} +1 -1
  88. package/chunks/{chunk-QN5NZ3UQ.js → chunk-DMTGGOSA.js} +2 -2
  89. package/chunks/{chunk-27BHARDE.js → chunk-DMVA55W5.js} +2124 -30
  90. package/chunks/{chunk-JPALE3PA.js → chunk-DQCCLVQK.js} +6 -6
  91. package/chunks/{chunk-X2XNQQJI.js → chunk-E2UVIFI2.js} +186 -399
  92. package/chunks/{chunk-KHDZHZMH.js → chunk-E5Z2AVNV.js} +1 -1
  93. package/chunks/{chunk-E7EMCSUG.js → chunk-EAHMOXLL.js} +64 -42
  94. package/chunks/{chunk-VGGOPZUL.js → chunk-EJ3KGYWL.js} +36 -8
  95. package/chunks/{chunk-DIWVZ3VM.js → chunk-ERTHKDKN.js} +5 -5
  96. package/chunks/{chunk-UX6OTBVD.js → chunk-EX5OULP3.js} +2 -2
  97. package/chunks/{chunk-5MBO76SL.js → chunk-F333XEAU.js} +3 -3
  98. package/chunks/{chunk-OACJLMLD.js → chunk-FBU7WRZI.js} +18 -2
  99. package/chunks/{chunk-5IFG2VC4.js → chunk-FCMNKVXT.js} +1 -1
  100. package/chunks/chunk-FEOBU3FA.js +253 -0
  101. package/chunks/{chunk-LAXNEOBG.js → chunk-FI2WSOWX.js} +19 -3
  102. package/chunks/{chunk-E7KNELIZ.js → chunk-FSA7ERJ2.js} +2 -2
  103. package/chunks/{chunk-44NROQYV.js → chunk-GDQQRV43.js} +4 -4
  104. package/chunks/{chunk-ZE6E424U.js → chunk-GN5HJJBO.js} +2 -2
  105. package/chunks/{chunk-O2YT7VB4.js → chunk-GOXKNSDZ.js} +2 -65
  106. package/chunks/{chunk-V35MD7KN.js → chunk-GRC5HGPI.js} +1 -1
  107. package/chunks/{chunk-ON3JA3RU.js → chunk-GTENQOEJ.js} +7 -9
  108. package/chunks/{chunk-S6RLAIUR.js → chunk-GYTKQYDB.js} +1 -1
  109. package/chunks/{chunk-A2X3KLC3.js → chunk-GZXCZHCT.js} +3 -3
  110. package/chunks/{chunk-K5PGHDBN.js → chunk-H6XPXXMH.js} +1 -1
  111. package/chunks/{chunk-PMFULMLX.js → chunk-HCJTURZD.js} +2262 -384
  112. package/chunks/chunk-HGG2RRXD.js +445 -0
  113. package/chunks/{chunk-II73RK2S.js → chunk-HGT6JR3U.js} +20 -1
  114. package/chunks/{chunk-DICGXFAI.js → chunk-HJCVNZLQ.js} +11 -9
  115. package/chunks/{chunk-3GNOQZDC.js → chunk-HJUDVNCO.js} +17663 -14877
  116. package/chunks/{chunk-AYNCLGTW.js → chunk-HRUGYOJN.js} +8 -51
  117. package/chunks/{chunk-KYMBIKIW.js → chunk-HTHUX2T5.js} +1 -1
  118. package/chunks/{chunk-LQ7TMOCE.js → chunk-HTO4JFDZ.js} +1 -1
  119. package/chunks/{chunk-BUZ6HGL4.js → chunk-HWTL6MPR.js} +357 -59
  120. package/chunks/chunk-IDS7MSUP.js +74 -0
  121. package/chunks/{chunk-4CGOWHKM.js → chunk-J4MOFEOK.js} +2 -2
  122. package/chunks/chunk-JCD4FM7K.js +296 -0
  123. package/chunks/{chunk-22IFUCVR.js → chunk-JESCGQM3.js} +1 -1
  124. package/chunks/{chunk-JZHIQJOE.js → chunk-JGO6RFI2.js} +6 -6
  125. package/chunks/{chunk-X3YGAX7V.js → chunk-JGUT3LWZ.js} +9 -2
  126. package/chunks/{chunk-JRQ7EVGE.js → chunk-JW7OOJC6.js} +2 -2
  127. package/chunks/{chunk-OQXDAMKY.js → chunk-KF5MMGG4.js} +8 -8
  128. package/chunks/{chunk-42XGFRJS.js → chunk-KKRTYONM.js} +8 -6
  129. package/chunks/{chunk-GGQQA4JW.js → chunk-KSO42X3Z.js} +15 -2
  130. package/chunks/{chunk-MRO43B25.js → chunk-KW7NOTN6.js} +1 -1
  131. package/chunks/{chunk-54YZOP7P.js → chunk-L573Z2QZ.js} +11894 -5190
  132. package/chunks/{chunk-TLWA7TPR.js → chunk-L5U3ELZX.js} +2 -2
  133. package/chunks/{chunk-YHKAK72D.js → chunk-LHEOLOXU.js} +251 -63
  134. package/chunks/{chunk-H6EMK6QK.js → chunk-LQIDP6K5.js} +11913 -5207
  135. package/chunks/{chunk-I6WGFJJ3.js → chunk-LSEJG6AM.js} +73 -19
  136. package/chunks/{chunk-MZ7BABX3.js → chunk-LXLTBIDP.js} +44 -7
  137. package/chunks/{chunk-HLKG6CZN.js → chunk-M5GB774H.js} +1 -1
  138. package/chunks/{chunk-JCH35JB3.js → chunk-MKK4XGLF.js} +2 -2
  139. package/chunks/{chunk-YKZIAK7C.js → chunk-MO7O5722.js} +424 -40
  140. package/chunks/chunk-MR3PXB6E.js +48 -0
  141. package/chunks/{chunk-A5JOJ77H.js → chunk-MRYWYBQ4.js} +38 -15
  142. package/chunks/{chunk-332PWN27.js → chunk-NHDKSOEY.js} +1 -1
  143. package/chunks/{chunk-TSPB77TG.js → chunk-NRAFASYX.js} +1016 -2967
  144. package/chunks/{chunk-BMFMJINR.js → chunk-OA4JVLSA.js} +28 -2
  145. package/chunks/{chunk-P7M4GA57.js → chunk-OCPBI7J5.js} +1 -1
  146. package/chunks/chunk-OJAMDVF5.js +66 -0
  147. package/chunks/{chunk-IJRL2S3D.js → chunk-OKAIGAYW.js} +6 -6
  148. package/chunks/{chunk-FBET5XZ2.js → chunk-PEJWA3QQ.js} +29 -10
  149. package/chunks/{chunk-L4AMBVQG.js → chunk-PMKW35AT.js} +54 -22
  150. package/chunks/{chunk-AGHU5VRK.js → chunk-PZL23GTM.js} +1 -1
  151. package/chunks/{chunk-PC4ZXHU2.js → chunk-Q6TUALBE.js} +3 -3
  152. package/chunks/{chunk-FXGLL2HL.js → chunk-Q7YDKOGY.js} +1 -1
  153. package/chunks/{chunk-XOHNA2S6.js → chunk-QAW7PIHT.js} +3 -3
  154. package/chunks/{chunk-XYR5RUA5.js → chunk-QE2WJ7FS.js} +10 -3
  155. package/chunks/{chunk-LGFAYIKX.js → chunk-QHTIBUWB.js} +1 -1
  156. package/chunks/{chunk-P3MYAZBY.js → chunk-QMGX2KO2.js} +1 -1
  157. package/chunks/{chunk-Z3I3QJK3.js → chunk-QRUIS3DN.js} +1 -1
  158. package/chunks/{chunk-ITOGNELQ.js → chunk-QSWDGAIC.js} +2 -2
  159. package/chunks/{chunk-PUVCVELY.js → chunk-QUJOI7SR.js} +70 -8
  160. package/chunks/{chunk-GHOTR7HL.js → chunk-QUPXZXLV.js} +1 -1
  161. package/chunks/{chunk-6VK6FIMQ.js → chunk-R5D5JOAM.js} +415 -379
  162. package/chunks/{chunk-CD6USWHZ.js → chunk-R5XLNDE2.js} +2 -2
  163. package/chunks/{chunk-W7EEOR7D.js → chunk-RCEEXIOO.js} +8 -6
  164. package/chunks/{chunk-TLRYABYP.js → chunk-RKUWKYED.js} +1 -1
  165. package/chunks/{chunk-RNBYOUGV.js → chunk-RXFQM6FQ.js} +1 -1
  166. package/chunks/{chunk-QXPI7FEC.js → chunk-S3TWXGKA.js} +4 -4
  167. package/chunks/{chunk-2EM7ECZD.js → chunk-SMSFWUFY.js} +309 -80
  168. package/chunks/{chunk-FV7425LN.js → chunk-SPJQO2CE.js} +18 -5
  169. package/chunks/{chunk-MLZQVCF3.js → chunk-SZRN75WQ.js} +1 -1
  170. package/chunks/{chunk-7RYW5LQV.js → chunk-T2NCM2ET.js} +2 -2
  171. package/chunks/{chunk-Z2Z3GUXZ.js → chunk-TB6UDU4T.js} +1 -1
  172. package/chunks/{chunk-EXPMGZZV.js → chunk-TEGEBB2I.js} +1 -1
  173. package/chunks/{chunk-MX2YXRER.js → chunk-TJTKSVIV.js} +1 -1
  174. package/chunks/{chunk-CCGOFQV3.js → chunk-TQBODCFD.js} +8 -7
  175. package/chunks/chunk-TV6K2FB4.js +224 -0
  176. package/chunks/{chunk-H6BD2ELD.js → chunk-TYAMGABM.js} +2 -2
  177. package/chunks/{chunk-QYNNN7BK.js → chunk-TYLOFD2U.js} +2 -2
  178. package/chunks/{chunk-VRDMOSQS.js → chunk-UDXSXLER.js} +2 -2
  179. package/chunks/{chunk-DHOLNQLC.js → chunk-UFDX27PL.js} +60 -40
  180. package/chunks/{chunk-WHJQ3JUS.js → chunk-UGN6CTNZ.js} +10 -10
  181. package/chunks/{chunk-CHB5SLZZ.js → chunk-UNLRKDMW.js} +4 -4
  182. package/chunks/{chunk-CJCKDMWO.js → chunk-URK542T4.js} +1 -1
  183. package/chunks/{chunk-AHNXYU4O.js → chunk-V6WHFGST.js} +1 -1
  184. package/chunks/{chunk-ZTQ26VBE.js → chunk-VDDGDZMA.js} +1 -1
  185. package/chunks/{chunk-BOBOCR5H.js → chunk-VEETSXYX.js} +4 -4
  186. package/chunks/{chunk-OMX7CUOE.js → chunk-VGC4I5JJ.js} +1 -1
  187. package/chunks/{chunk-43W4YSO6.js → chunk-VJNBRRZG.js} +2 -2
  188. package/chunks/{chunk-WQTHLB5T.js → chunk-VKS7EIOA.js} +7 -7
  189. package/chunks/{chunk-J7RCB6N5.js → chunk-VVDNGM6X.js} +2 -2
  190. package/chunks/{chunk-ER3BKOLB.js → chunk-W7FJ3N32.js} +1 -1
  191. package/chunks/{chunk-3HX5LZ6R.js → chunk-WBL3FJEU.js} +2 -2
  192. package/chunks/{chunk-7LTB54MK.js → chunk-WIEO4CWB.js} +2 -2
  193. package/chunks/chunk-WMC6HH7Y.js +493 -0
  194. package/chunks/{chunk-FEJ2FZ3U.js → chunk-WTNZ6DXB.js} +2 -2
  195. package/chunks/{chunk-L46XKEGM.js → chunk-X6ODDESK.js} +5 -8
  196. package/chunks/chunk-XDPYM5DE.js +71 -0
  197. package/chunks/{chunk-3RW4AZJV.js → chunk-XFSFZCM5.js} +1 -1
  198. package/chunks/{chunk-2MPVVENX.js → chunk-XU457J4V.js} +2 -2
  199. package/chunks/{chunk-SIUQ3YYX.js → chunk-XVNQMZ2I.js} +1 -1
  200. package/chunks/{chunk-SYCJMSIJ.js → chunk-XWRJCPHC.js} +1 -1
  201. package/chunks/{chunk-SUAKHHK7.js → chunk-Y66VOBRP.js} +3 -3
  202. package/chunks/chunk-YAF2MQZ6.js +19 -0
  203. package/chunks/chunk-YHN5SUIJ.js +219 -0
  204. package/chunks/{chunk-BR4QREVK.js → chunk-YQ3U5MUC.js} +1 -1
  205. package/chunks/{chunk-Y6Z2O3WR.js → chunk-YUZI3WAC.js} +1 -1
  206. package/chunks/{chunk-YDOXPLYL.js → chunk-ZA74ZTQU.js} +4564 -1326
  207. package/chunks/{chunk-DCZWC4PF.js → chunk-ZGE3222J.js} +5 -5
  208. package/chunks/chunk-ZP4ZZJJG.js +448 -0
  209. package/chunks/{chunk-AHNJGLFV.js → chunk-ZPAHLFZU.js} +3 -3
  210. package/chunks/cli-entry-path-4VJ3Y6T2.js +10 -0
  211. package/chunks/{computer-use-WMY3UOBX.js → computer-use-SHA6C3ES.js} +50 -50
  212. package/chunks/config-utils-XSHOMMK4.js +24 -0
  213. package/chunks/contextCommand-HOAF5LUC.js +68 -0
  214. package/chunks/create-sub-session-EAB2U5XW.js +207 -0
  215. package/chunks/create-sub-session-WJOWBFEP.js +375 -0
  216. package/chunks/{cron-create-JSXEIPVS.js → cron-create-GMVKSXZT.js} +9 -9
  217. package/chunks/{cron-delete-OIFVEPGU.js → cron-delete-VDZKUAVK.js} +7 -7
  218. package/chunks/{cron-list-D4ZX4IOE.js → cron-list-UG7C7RAR.js} +14 -10
  219. package/chunks/{daemon-WPAENEBW.js → daemon-MI5HF26N.js} +1074 -61
  220. package/chunks/daemon-status-provider-KFL3LRTP.js +76 -0
  221. package/chunks/{de-ZFPPQVSF.js → de-2VCDRDGU.js} +68 -6
  222. package/chunks/{devtools-FM6GJPYG.js → devtools-4QFYJT6U.js} +3 -3
  223. package/chunks/{dist-O2IRTRPP.js → dist-IEXZC5ZR.js} +10 -10
  224. package/chunks/{dist-SCFLLYMK.js → dist-PQK4GCKA.js} +12 -11
  225. package/chunks/{dist-63IS3ZMI.js → dist-PZV5RKM6.js} +4 -4
  226. package/chunks/{dist-E6UANPIM.js → dist-U75JK3PF.js} +1011 -197
  227. package/chunks/{dist-H2AEJCZ5.js → dist-VXO7QBON.js} +5 -5
  228. package/chunks/{dist-Z34QPAQW.js → dist-WH4TZSH3.js} +529 -79
  229. package/chunks/{dist-BEXOZXLQ.js → dist-X2ABIW5R.js} +36 -15
  230. package/chunks/earlyInputCapture-PKAQJMIP.js +69 -0
  231. package/chunks/{edit-OTYWAXGP.js → edit-6TXLYHJ2.js} +51 -51
  232. package/chunks/{en-N4EPZAQI.js → en-NJCA3TAA.js} +78 -6
  233. package/chunks/{enter-worktree-HNYBDVCX.js → enter-worktree-ZTILGPJX.js} +50 -50
  234. package/chunks/{enterPlanMode-CJCNGT63.js → enterPlanMode-62HRAMCH.js} +66 -51
  235. package/chunks/environment-OYA3ZVEL.js +89 -0
  236. package/chunks/errors-BFXOUUUR.js +75 -0
  237. package/chunks/{exit-worktree-DUUKOE3X.js → exit-worktree-HHJ5M6MV.js} +50 -50
  238. package/chunks/{exitPlanMode-AMMSXOAJ.js → exitPlanMode-M3SWHCL7.js} +51 -51
  239. package/chunks/{fast-path-OV6NIP3K.js → fast-path-3VMPLM74.js} +8 -8
  240. package/chunks/{fast-path-settings-7RIFI3PK.js → fast-path-settings-DAOVFADC.js} +8 -6
  241. package/chunks/{fileFromPath-IBEHA3CO.js → fileFromPath-UDALK7FM.js} +3 -3
  242. package/chunks/{fr-5WWMY53B.js → fr-5F3E7WKD.js} +68 -6
  243. package/chunks/{gemini-NQ3WWBKB.js → gemini-ZCGVYOJL.js} +181 -110
  244. package/chunks/{geminiContentGenerator-CDUNEJQE.js → geminiContentGenerator-XBYBAIDQ.js} +9 -9
  245. package/chunks/{getMachineId-bsd-4CASPIU4.js → getMachineId-bsd-EXV7SWPA.js} +3 -3
  246. package/chunks/{getMachineId-darwin-HPQPEMZR.js → getMachineId-darwin-IUOMFXU3.js} +3 -3
  247. package/chunks/{getMachineId-linux-AUARKYHL.js → getMachineId-linux-K7XJYFHL.js} +2 -2
  248. package/chunks/{getMachineId-unsupported-S32ZDA2T.js → getMachineId-unsupported-EA5FDRJ6.js} +2 -2
  249. package/chunks/{getMachineId-win-4EFLHYIJ.js → getMachineId-win-KBA6RAI5.js} +3 -3
  250. package/chunks/{glob-ROV3YS4R.js → glob-UOEYQNHN.js} +97 -75
  251. package/chunks/{grep-NRITKDCD.js → grep-OQM3CH7W.js} +50 -50
  252. package/chunks/handleAutoUpdate-ORBYVJHZ.js +69 -0
  253. package/chunks/i18n-NBP574CO.js +84 -0
  254. package/chunks/initializer-CWD7TCCD.js +73 -0
  255. package/chunks/installationInfo-CHPDUPWC.js +65 -0
  256. package/chunks/{ja-CUHZOLEJ.js → ja-66J6B53L.js} +69 -7
  257. package/chunks/{keychain-token-storage-UJV5XP4Z.js → keychain-token-storage-AU22CQI6.js} +4 -4
  258. package/chunks/{kittyProtocolDetector-OJRCJLIU.js → kittyProtocolDetector-HCNNKJTI.js} +2 -2
  259. package/chunks/list-ZTTO362W.js +76 -0
  260. package/chunks/loadedSettingsAdapter-V4ZTRKUO.js +70 -0
  261. package/chunks/{loop-wakeup-OHWEMFP5.js → loop-wakeup-C4EXLYVA.js} +10 -10
  262. package/chunks/{lowlight-FYAAUU5J.js → lowlight-J2OZNPCA.js} +1 -1
  263. package/chunks/{ls-7MFU2QYW.js → ls-2OUTG3IZ.js} +6 -6
  264. package/chunks/{lsp-XHDTPTGV.js → lsp-4VMNXZW6.js} +4 -4
  265. package/chunks/mcp-UH5PSGIK.js +70 -0
  266. package/chunks/{monitor-FL2ZO33W.js → monitor-F4NYEU5J.js} +50 -50
  267. package/chunks/{multipart-parser-AJ4WASWR.js → multipart-parser-AWZKXSQN.js} +3 -3
  268. package/chunks/nonInteractiveCli-7IHPXVNH.js +129 -0
  269. package/chunks/{notebook-edit-6PULTHL5.js → notebook-edit-HPDXNGQH.js} +51 -51
  270. package/chunks/openaiContentGenerator-OBDNNOE2.js +56 -0
  271. package/chunks/pidfile-AUMGYIOK.js +73 -0
  272. package/chunks/{pt-OLYN42DS.js → pt-TFZO5Y6T.js} +68 -6
  273. package/chunks/{qwenContentGenerator-NX2E7PB7.js → qwenContentGenerator-LH2U2YRG.js} +52 -52
  274. package/chunks/{qwenOAuth2-ZV7YLMND.js → qwenOAuth2-LEYOU7RU.js} +9 -9
  275. package/chunks/read-file-HUUFBLEO.js +30 -0
  276. package/chunks/{read-mcp-resource-CNQHBSJM.js → read-mcp-resource-JUFHCKSC.js} +5 -5
  277. package/chunks/{read-package-up-ER5OJUGP.js → read-package-up-TCM6I7S2.js} +2 -2
  278. package/chunks/{record-artifact-SQ2OKRJW.js → record-artifact-DWSMBXYY.js} +4 -4
  279. package/chunks/ripGrep-C7X33LU6.js +60 -0
  280. package/chunks/{ru-LDM3GWVQ.js → ru-4L4LFHIT.js} +68 -6
  281. package/chunks/{run-qwen-serve-JK2DL7PI.js → run-qwen-serve-DGW5AFDJ.js} +1465 -283
  282. package/chunks/runtime-NYUSLBEZ.js +99 -0
  283. package/chunks/{scheduler-O4IGVZKK.js → scheduler-5VKDXULT.js} +51 -51
  284. package/chunks/{send-message-76GT3JMC.js → send-message-JZ752NWD.js} +7 -7
  285. package/chunks/serve-UTAHSFXH.js +76 -0
  286. package/chunks/{server-SGNPKX2O.js → server-VUHSYSUV.js} +9088 -1817
  287. package/chunks/{session-5BNM25EZ.js → session-QSGSSNFB.js} +340 -135
  288. package/chunks/settings-X24RYEED.js +120 -0
  289. package/chunks/shell-4MSI2R4O.js +70 -0
  290. package/chunks/{skill-I22QK5XS.js → skill-JR3GTNVZ.js} +24 -24
  291. package/chunks/spawnChannel-RFAAO44J.js +70 -0
  292. package/chunks/{src-7XL4G4DC.js → src-VLI3TKEY.js} +4 -4
  293. package/chunks/{src-BBQSM46M.js → src-YDBNMIIM.js} +183 -53
  294. package/chunks/standalone-update-4CY4HKGC.js +79 -0
  295. package/chunks/{startInteractiveUI-JII36UGN.js → startInteractiveUI-FOD7MMVB.js} +2368 -1923
  296. package/chunks/stdioHelpers-UMY72QRP.js +14 -0
  297. package/chunks/{syntheticOutput-F7LSDCAR.js → syntheticOutput-LELY6HAI.js} +5 -5
  298. package/chunks/task-create-QY3BIMNM.js +23 -0
  299. package/chunks/{task-list-TGGJX7EA.js → task-list-D2U47WBJ.js} +11 -10
  300. package/chunks/{task-stop-W7NGTMYQ.js → task-stop-N6E5IYLH.js} +4 -4
  301. package/chunks/{task-update-XYWMHJGJ.js → task-update-HJCQILLB.js} +13 -12
  302. package/chunks/{team-create-A7NUU5AQ.js → team-create-ZLQSU2E3.js} +50 -50
  303. package/chunks/{team-delete-UHQQ2QQX.js → team-delete-RCWYDRF4.js} +11 -10
  304. package/chunks/{team-plan-approval-TOQRJ2KI.js → team-plan-approval-YUAYBYLS.js} +50 -50
  305. package/chunks/theme-manager-SKNEBMOG.js +64 -0
  306. package/chunks/{todoWrite-C4ZAMSR3.js → todoWrite-FKCGATPJ.js} +6 -6
  307. package/chunks/{tool-search-SZ4EFS2T.js → tool-search-V5J3TGWY.js} +24 -24
  308. package/chunks/total-session-admission-2WIH72I3.js +72 -0
  309. package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
  310. package/chunks/trustedFolders-JF265CRI.js +80 -0
  311. package/chunks/types-ML3TRJQ5.js +16 -0
  312. package/chunks/updateCheck-AMXNPBP6.js +69 -0
  313. package/chunks/updateEventEmitter-5MKC7BLQ.js +10 -0
  314. package/chunks/validateNonInterActiveAuth-6YHQO7PD.js +194 -0
  315. package/chunks/{version-NO2XSNNP.js → version-UEJJK7PE.js} +3 -3
  316. package/chunks/{web-fetch-UYGMOHW4.js → web-fetch-QGODBB6S.js} +8 -8
  317. package/chunks/{workflow-WO2H6NRI.js → workflow-5YFA5V4M.js} +51 -51
  318. package/chunks/workspace-providers-status-LMBLBNR7.js +73 -0
  319. package/chunks/workspace-registration-store-VV2S4MSV.js +27 -0
  320. package/chunks/workspace-registry-BVMPYRLN.js +76 -0
  321. package/chunks/workspace-service-PUYIZ3J4.js +86 -0
  322. package/chunks/workspace-skills-status-CJ7J2KPP.js +72 -0
  323. package/chunks/{write-file-PX2Z7IBE.js → write-file-OV77M6X7.js} +51 -51
  324. package/chunks/{yargs-B64EYTCF.js → yargs-6H2AUULL.js} +2 -2
  325. package/chunks/{zh-J4F6QWQV.js → zh-FSAH32JB.js} +79 -7
  326. package/chunks/{zh-TW-XVDWOLSW.js → zh-TW-D2YIE2LO.js} +79 -7
  327. package/cli.js +18 -17
  328. package/locales/ca.js +91 -7
  329. package/locales/de.js +90 -7
  330. package/locales/en.js +109 -7
  331. package/locales/fr.js +91 -7
  332. package/locales/ja.js +93 -7
  333. package/locales/pt.js +90 -7
  334. package/locales/ru.js +90 -7
  335. package/locales/zh-TW.js +106 -7
  336. package/locales/zh.js +106 -7
  337. package/package.json +3 -6
  338. package/web-shell/assets/{arc-BWyoJpY2.js → arc-CObt_TK9.js} +1 -1
  339. package/web-shell/assets/{architectureDiagram-3BPJPVTR-BT0mGrz2.js → architectureDiagram-3BPJPVTR-B7aiJ6CK.js} +1 -1
  340. package/web-shell/assets/{blockDiagram-GPEHLZMM-BLgUWvyf.js → blockDiagram-GPEHLZMM-BSK2CrID.js} +1 -1
  341. package/web-shell/assets/{c4Diagram-AAUBKEIU-DYx9M7oU.js → c4Diagram-AAUBKEIU-Bhx2p7T_.js} +1 -1
  342. package/web-shell/assets/channel-BBaLq8MV.js +1 -0
  343. package/web-shell/assets/{chunk-2J33WTMH-CfMHWbuZ.js → chunk-2J33WTMH-c3Hzv0Ni.js} +1 -1
  344. package/web-shell/assets/{chunk-4BX2VUAB-B1URoqEV.js → chunk-4BX2VUAB-DNXaK7ZF.js} +1 -1
  345. package/web-shell/assets/{chunk-55IACEB6-DAIaM4QF.js → chunk-55IACEB6-BXjvDj_i.js} +1 -1
  346. package/web-shell/assets/{chunk-727SXJPM-B2X34knw.js → chunk-727SXJPM-B6CaKFp-.js} +1 -1
  347. package/web-shell/assets/{chunk-AQP2D5EJ-Cif-zLTQ.js → chunk-AQP2D5EJ-tij6Mz9B.js} +1 -1
  348. package/web-shell/assets/{chunk-FMBD7UC4-H18WCXdY.js → chunk-FMBD7UC4-DdlsGk2h.js} +1 -1
  349. package/web-shell/assets/{chunk-ND2GUHAM-YFtetHi0.js → chunk-ND2GUHAM-CdgGZSHE.js} +1 -1
  350. package/web-shell/assets/{chunk-QZHKN3VN-By2hiH3r.js → chunk-QZHKN3VN-D8oJn1C0.js} +1 -1
  351. package/web-shell/assets/classDiagram-4FO5ZUOK-B2ZK6sWE.js +1 -0
  352. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B2ZK6sWE.js +1 -0
  353. package/web-shell/assets/{cose-bilkent-S5V4N54A-VrcnnLZu.js → cose-bilkent-S5V4N54A-BUVmNp1Y.js} +1 -1
  354. package/web-shell/assets/{dagre-BM42HDAG-CGo-IaVV.js → dagre-BM42HDAG-CO4q310O.js} +1 -1
  355. package/web-shell/assets/{diagram-2AECGRRQ-Dl4QjzIB.js → diagram-2AECGRRQ-C6gFvWkg.js} +1 -1
  356. package/web-shell/assets/{diagram-5GNKFQAL-qMLmsO0u.js → diagram-5GNKFQAL-NG2I_c0h.js} +1 -1
  357. package/web-shell/assets/{diagram-KO2AKTUF-CHlmuxPI.js → diagram-KO2AKTUF-DFKMS6I9.js} +1 -1
  358. package/web-shell/assets/{diagram-LMA3HP47-BUwU3GwT.js → diagram-LMA3HP47-BiElfsfP.js} +1 -1
  359. package/web-shell/assets/{diagram-OG6HWLK6-HEhwPDUM.js → diagram-OG6HWLK6-zLWDYUqu.js} +1 -1
  360. package/web-shell/assets/{erDiagram-TEJ5UH35-1n0llBmM.js → erDiagram-TEJ5UH35-DoVaazhK.js} +1 -1
  361. package/web-shell/assets/{flowDiagram-I6XJVG4X-BN74uMnt.js → flowDiagram-I6XJVG4X-0RLz-mXg.js} +1 -1
  362. package/web-shell/assets/{ganttDiagram-6RSMTGT7-BoOq78i3.js → ganttDiagram-6RSMTGT7-C-eX1A39.js} +3 -3
  363. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CN8b00c8.js → gitGraphDiagram-PVQCEYII-BauQu1Bu.js} +1 -1
  364. package/web-shell/assets/index-3uAT3ehO.css +5 -0
  365. package/web-shell/assets/index-CVHa2QH7.js +3 -0
  366. package/web-shell/assets/index-D1KigWat.js +1128 -0
  367. package/web-shell/assets/{infoDiagram-5YYISTIA-CCurnIna.js → infoDiagram-5YYISTIA-C800cFvZ.js} +1 -1
  368. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-AwuRqdUP.js → ishikawaDiagram-YF4QCWOH-CFK1Jk6e.js} +1 -1
  369. package/web-shell/assets/{journeyDiagram-JHISSGLW-B7IICk-E.js → journeyDiagram-JHISSGLW-Cjx0WAC4.js} +1 -1
  370. package/web-shell/assets/{kanban-definition-UN3LZRKU-BYF0OKhx.js → kanban-definition-UN3LZRKU-DWMDHbiv.js} +1 -1
  371. package/web-shell/assets/{linear-GWWguGfD.js → linear-vpW4FrZs.js} +1 -1
  372. package/web-shell/assets/{mermaid.core-JqtkxvCl.js → mermaid.core-DsHRUnDd.js} +5 -5
  373. package/web-shell/assets/{mindmap-definition-RKZ34NQL-B0MmHsZ6.js → mindmap-definition-RKZ34NQL-D3Eb1cAK.js} +1 -1
  374. package/web-shell/assets/{pieDiagram-4H26LBE5-DhImUZLQ.js → pieDiagram-4H26LBE5-Cr2-6sWt.js} +1 -1
  375. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DGeSC3DT.js → quadrantDiagram-W4KKPZXB-Yd7yUgVp.js} +1 -1
  376. package/web-shell/assets/{requirementDiagram-4Y6WPE33-DkspY6Re.js → requirementDiagram-4Y6WPE33-BE6SprL8.js} +1 -1
  377. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CaOofS2x.js → sankeyDiagram-5OEKKPKP-DzkuMK8d.js} +1 -1
  378. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DFQ_kFnN.js → sequenceDiagram-3UESZ5HK-wD9A3Dhi.js} +1 -1
  379. package/web-shell/assets/{stateDiagram-AJRCARHV-D3snw0Tz.js → stateDiagram-AJRCARHV-BOp5q1Nm.js} +1 -1
  380. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BDsWUmPG.js +1 -0
  381. package/web-shell/assets/{timeline-definition-PNZ67QCA-l4zH8nLM.js → timeline-definition-PNZ67QCA-Btc08sUA.js} +1 -1
  382. package/web-shell/assets/{vennDiagram-CIIHVFJN-BnRlA98M.js → vennDiagram-CIIHVFJN-Bv6upsOA.js} +1 -1
  383. package/web-shell/assets/{wardley-L42UT6IY-BS0xUdmd.js → wardley-L42UT6IY-D-XamnCK.js} +1 -1
  384. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-DKGBUWyQ.js → wardleyDiagram-YWT4CUSO-BbP_5Wfp.js} +1 -1
  385. package/web-shell/assets/{xychartDiagram-2RQKCTM6-DVb2HuOB.js → xychartDiagram-2RQKCTM6-CO5Hh28b.js} +1 -1
  386. package/web-shell/index.html +16 -4
  387. package/chunks/MaxSizedBox-5DT2SD7B.js +0 -71
  388. package/chunks/agent-H2DGKS77.js +0 -68
  389. package/chunks/agent-headless-KFMFIT6J.js +0 -62
  390. package/chunks/bridge-NA3ZQQKJ.js +0 -78
  391. package/chunks/chunk-5P5XGNYH.js +0 -93
  392. package/chunks/chunk-6SHO7WFF.js +0 -79
  393. package/chunks/chunk-IFEWJXFS.js +0 -37
  394. package/chunks/chunk-XNXVCNAT.js +0 -88
  395. package/chunks/contextCommand-LXFZRP4L.js +0 -68
  396. package/chunks/daemon-status-provider-GJRXY5EN.js +0 -76
  397. package/chunks/earlyInputCapture-KNOYZ4MJ.js +0 -69
  398. package/chunks/environment-ATFTYMLZ.js +0 -88
  399. package/chunks/errors-A54HAADA.js +0 -75
  400. package/chunks/handleAutoUpdate-CEZJAARW.js +0 -65
  401. package/chunks/initializer-BRFJKRRX.js +0 -71
  402. package/chunks/list-KVHF7O4X.js +0 -73
  403. package/chunks/loadedSettingsAdapter-LL5PSFKX.js +0 -68
  404. package/chunks/mcp-3GCXRTOQ.js +0 -68
  405. package/chunks/nonInteractiveCli-PTQI3DV6.js +0 -119
  406. package/chunks/openaiContentGenerator-YE42PKCY.js +0 -56
  407. package/chunks/pidfile-NZYSCFRK.js +0 -73
  408. package/chunks/read-file-33XGP5HF.js +0 -30
  409. package/chunks/ripGrep-QWZLGTAN.js +0 -60
  410. package/chunks/serve-JTMIGANH.js +0 -74
  411. package/chunks/settings-3MI4XXP6.js +0 -118
  412. package/chunks/shell-YJKBE67T.js +0 -68
  413. package/chunks/spawnChannel-UNV6W4DU.js +0 -70
  414. package/chunks/task-create-WCHTB435.js +0 -22
  415. package/chunks/theme-manager-WZ4RRMMB.js +0 -64
  416. package/chunks/total-session-admission-ULXJWXFV.js +0 -72
  417. package/chunks/trustedFolders-LAZZPZ3D.js +0 -79
  418. package/chunks/types-QX5C3CHJ.js +0 -12
  419. package/chunks/updateCheck-KONLM73X.js +0 -65
  420. package/chunks/validateNonInterActiveAuth-MPKSRCXD.js +0 -184
  421. package/chunks/workspace-providers-status-3W7E7DFW.js +0 -71
  422. package/chunks/workspace-registry-SXJZNN3O.js +0 -74
  423. package/chunks/workspace-service-CZRQZ4Q4.js +0 -80
  424. package/chunks/workspace-skills-status-K7WFREPD.js +0 -70
  425. package/node_modules/@qwen-code/audio-capture/dist/index.d.ts +0 -35
  426. package/node_modules/@qwen-code/audio-capture/dist/index.js +0 -48
  427. package/node_modules/@qwen-code/audio-capture/dist/index.js.map +0 -1
  428. package/node_modules/@qwen-code/audio-capture/dist/platform.d.ts +0 -7
  429. package/node_modules/@qwen-code/audio-capture/dist/platform.js +0 -18
  430. package/node_modules/@qwen-code/audio-capture/dist/platform.js.map +0 -1
  431. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/LICENSE +0 -21
  432. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/README.md +0 -58
  433. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/SECURITY.md +0 -5
  434. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/bin.js +0 -84
  435. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/build-test.js +0 -19
  436. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/index.js +0 -6
  437. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/node-gyp-build.js +0 -207
  438. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/optional.js +0 -7
  439. package/node_modules/@qwen-code/audio-capture/node_modules/node-gyp-build/package.json +0 -43
  440. package/node_modules/@qwen-code/audio-capture/package.json +0 -30
  441. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
  442. package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
  443. package/node_modules/@qwen-code/audio-capture/prebuilds/linux-arm64/@qwen-code+audio-capture.node +0 -0
  444. package/node_modules/@qwen-code/audio-capture/prebuilds/linux-x64/@qwen-code+audio-capture.node +0 -0
  445. package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
  446. package/web-shell/assets/channel-wmPUGHtg.js +0 -1
  447. package/web-shell/assets/classDiagram-4FO5ZUOK-BA2ljEjW.js +0 -1
  448. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BA2ljEjW.js +0 -1
  449. package/web-shell/assets/index-CNwoO1Cn.js +0 -783
  450. package/web-shell/assets/index-CWQ0z6kZ.css +0 -5
  451. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BbSm_9d0.js +0 -1
@@ -3,15 +3,13 @@
3
3
  import {
4
4
  DaemonMetricsRing,
5
5
  computeCpuPercent
6
- } from "./chunk-II73RK2S.js";
7
- import {
8
- findCliEntryPath
9
- } from "./chunk-AHNXYU4O.js";
6
+ } from "./chunk-HGT6JR3U.js";
10
7
  import {
11
8
  CAPABILITIES_SCHEMA_VERSION,
12
9
  ClientMcpSenderRegistry,
13
10
  PathMutexRegistry,
14
11
  SERVE_CAPABILITY_REGISTRY,
12
+ WorkspaceVoiceCoordinator,
15
13
  allowOriginCors,
16
14
  allowOriginMode,
17
15
  bearerAuth,
@@ -22,71 +20,92 @@ import {
22
20
  getRateLimiter,
23
21
  getServeProtocolVersions,
24
22
  hostAllowlist,
23
+ isBrowserAutomationMcpAvailable,
25
24
  listenerMaxConnections,
26
25
  parseAllowOriginPatterns,
27
26
  parseDaemonStatusDetail,
28
27
  positiveFiniteOrNull,
29
28
  require_express,
30
29
  resolveWebShellDir
31
- } from "./chunk-YKZIAK7C.js";
30
+ } from "./chunk-MO7O5722.js";
32
31
  import {
33
32
  isLoopbackBind
34
- } from "./chunk-RNBYOUGV.js";
35
- import "./chunk-3HX5LZ6R.js";
36
- import "./chunk-7RYW5LQV.js";
33
+ } from "./chunk-RXFQM6FQ.js";
37
34
  import {
38
35
  RUNTIME_STARTUP_CANCELLED_MESSAGE
39
- } from "./chunk-GHOTR7HL.js";
36
+ } from "./chunk-QUPXZXLV.js";
40
37
  import {
41
38
  LOAD_REPLAY_META_KEY
42
- } from "./chunk-AGHU5VRK.js";
39
+ } from "./chunk-PZL23GTM.js";
43
40
  import {
44
41
  DEFAULT_COMPACTED_REPLAY_MAX_BYTES,
45
42
  normalizeCompactedReplayMaxBytes
46
- } from "./chunk-GLE2YUPU.js";
43
+ } from "./chunk-COH43MRJ.js";
44
+ import "./chunk-WBL3FJEU.js";
47
45
  import {
48
- canonicalizeWorkspace
49
- } from "./chunk-ER3BKOLB.js";
46
+ resolveChannelCwd
47
+ } from "./chunk-4QZADKJS.js";
50
48
  import {
51
- loadServeFastPathSettings,
52
- preResolveServeFastPathHomeEnvOverrides
53
- } from "./chunk-FBET5XZ2.js";
49
+ MAX_REGISTERED_WORKSPACES,
50
+ resolveWorkspaceInputs,
51
+ workspaceRegistrationId
52
+ } from "./chunk-WMC6HH7Y.js";
53
+ import {
54
+ canonicalizeWorkspace
55
+ } from "./chunk-W7FJ3N32.js";
56
+ import "./chunk-3MX7D6QN.js";
54
57
  import {
55
58
  QWEN_SERVER_TOKEN_ENV
56
- } from "./chunk-S6RLAIUR.js";
59
+ } from "./chunk-GYTKQYDB.js";
57
60
  import {
58
61
  channelSelectionNames
59
- } from "./chunk-MX2YXRER.js";
62
+ } from "./chunk-TJTKSVIV.js";
63
+ import "./chunk-5HBA2Z7V.js";
64
+ import {
65
+ ChannelWebhookEnqueueError
66
+ } from "./chunk-OJAMDVF5.js";
67
+ import "./chunk-T2NCM2ET.js";
68
+ import {
69
+ sanitizeLogText
70
+ } from "./chunk-AU4R7ACM.js";
71
+ import "./chunk-UDXSXLER.js";
72
+ import {
73
+ loadServeFastPathSettings,
74
+ preResolveServeFastPathHomeEnvOverrides
75
+ } from "./chunk-PEJWA3QQ.js";
76
+ import "./chunk-GOXKNSDZ.js";
60
77
  import {
61
78
  getGlobalQwenDirLite,
62
79
  resolveConfigPathLite
63
- } from "./chunk-O2YT7VB4.js";
64
- import "./chunk-Z3I3QJK3.js";
80
+ } from "./chunk-IDS7MSUP.js";
81
+ import "./chunk-QRUIS3DN.js";
82
+ import "./chunk-ALGGS7UH.js";
65
83
  import {
66
- getCliVersion
67
- } from "./chunk-UXEW557D.js";
68
- import "./chunk-43W4YSO6.js";
84
+ isWithinRoot
85
+ } from "./chunk-MR3PXB6E.js";
69
86
  import {
70
87
  writeStderrLine,
71
88
  writeStdoutLine
72
- } from "./chunk-Y6Z2O3WR.js";
89
+ } from "./chunk-YUZI3WAC.js";
73
90
  import {
74
- isWithinRoot
75
- } from "./chunk-QYUE6W3T.js";
76
- import "./chunk-5P5XGNYH.js";
77
- import "./chunk-SKAZWEV5.js";
78
- import "./chunk-UWCTAVOD.js";
79
- import "./chunk-SYCJMSIJ.js";
91
+ getCliVersion
92
+ } from "./chunk-2J4ZWME4.js";
93
+ import "./chunk-VJNBRRZG.js";
94
+ import "./chunk-H6XPXXMH.js";
95
+ import "./chunk-5M6IDOMF.js";
96
+ import "./chunk-E2UVIFI2.js";
97
+ import "./chunk-CR3C7WXL.js";
98
+ import "./chunk-XWRJCPHC.js";
80
99
  import {
81
100
  finalizeStartupProfile,
82
101
  profileCheckpoint
83
- } from "./chunk-ITOGNELQ.js";
84
- import "./chunk-FXGLL2HL.js";
85
- import "./chunk-QN5NZ3UQ.js";
86
- import "./chunk-BR4QREVK.js";
102
+ } from "./chunk-QSWDGAIC.js";
103
+ import "./chunk-Q7YDKOGY.js";
104
+ import "./chunk-DMTGGOSA.js";
105
+ import "./chunk-YQ3U5MUC.js";
87
106
  import {
88
107
  init_esbuild_shims
89
- } from "./chunk-A4BMJM77.js";
108
+ } from "./chunk-5O2XNYP6.js";
90
109
  import {
91
110
  __name,
92
111
  __toESM
@@ -95,99 +114,13 @@ import {
95
114
  // packages/cli/src/serve/run-qwen-serve.ts
96
115
  init_esbuild_shims();
97
116
  var import_express = __toESM(require_express(), 1);
98
- import { X509Certificate } from "node:crypto";
117
+ import { X509Certificate, createHash as createHash2, timingSafeEqual } from "node:crypto";
99
118
  import * as fs from "node:fs";
100
119
  import * as https from "node:https";
101
120
  import * as path from "node:path";
102
121
  import * as os from "node:os";
103
122
  import { monitorEventLoopDelay, performance } from "node:perf_hooks";
104
123
 
105
- // packages/cli/src/serve/workspace-inputs.ts
106
- init_esbuild_shims();
107
- var DuplicateWorkspaceInputError = class extends Error {
108
- static {
109
- __name(this, "DuplicateWorkspaceInputError");
110
- }
111
- constructor(workspace) {
112
- super(
113
- `Duplicate --workspace value resolves to ${JSON.stringify(workspace)}. Pass distinct --workspace values.`
114
- );
115
- this.name = "DuplicateWorkspaceInputError";
116
- }
117
- };
118
- var NestedWorkspaceInputError = class extends Error {
119
- static {
120
- __name(this, "NestedWorkspaceInputError");
121
- }
122
- constructor(parent, child) {
123
- super(
124
- `Nested --workspace values are not supported yet: ${JSON.stringify(child)} is inside ${JSON.stringify(parent)}. Pass non-nested --workspace values.`
125
- );
126
- this.name = "NestedWorkspaceInputError";
127
- }
128
- };
129
- var MissingWorkspaceInputError = class extends Error {
130
- static {
131
- __name(this, "MissingWorkspaceInputError");
132
- }
133
- constructor() {
134
- super("--workspace requires a value.");
135
- this.name = "MissingWorkspaceInputError";
136
- }
137
- };
138
- function normalizeWorkspaceInputs(workspace) {
139
- if (Array.isArray(workspace)) {
140
- if (workspace.length === 0) {
141
- throw new MissingWorkspaceInputError();
142
- }
143
- return workspace.map((value) => String(value));
144
- }
145
- if (workspace === void 0) return [process.cwd()];
146
- return [String(workspace)];
147
- }
148
- __name(normalizeWorkspaceInputs, "normalizeWorkspaceInputs");
149
- function isNestedWorkspace(parent, child) {
150
- return parent !== child && isWithinRoot(child, parent);
151
- }
152
- __name(isNestedWorkspace, "isNestedWorkspace");
153
- function rejectDuplicateOrNestedWorkspaceInputs(workspaces) {
154
- if (workspaces.length <= 1) return;
155
- let canonicalWorkspaces;
156
- try {
157
- canonicalWorkspaces = workspaces.map(
158
- (workspace) => canonicalizeWorkspace(workspace)
159
- );
160
- } catch {
161
- return;
162
- }
163
- const seen = /* @__PURE__ */ new Set();
164
- for (const workspace of canonicalWorkspaces) {
165
- if (seen.has(workspace)) {
166
- throw new DuplicateWorkspaceInputError(workspace);
167
- }
168
- seen.add(workspace);
169
- }
170
- for (let i = 0; i < canonicalWorkspaces.length; i++) {
171
- for (let j = i + 1; j < canonicalWorkspaces.length; j++) {
172
- const first = canonicalWorkspaces[i];
173
- const second = canonicalWorkspaces[j];
174
- if (isNestedWorkspace(first, second)) {
175
- throw new NestedWorkspaceInputError(first, second);
176
- }
177
- if (isNestedWorkspace(second, first)) {
178
- throw new NestedWorkspaceInputError(second, first);
179
- }
180
- }
181
- }
182
- }
183
- __name(rejectDuplicateOrNestedWorkspaceInputs, "rejectDuplicateOrNestedWorkspaceInputs");
184
- function resolveWorkspaceInputs(workspace) {
185
- const workspaces = normalizeWorkspaceInputs(workspace);
186
- rejectDuplicateOrNestedWorkspaceInputs(workspaces);
187
- return workspaces;
188
- }
189
- __name(resolveWorkspaceInputs, "resolveWorkspaceInputs");
190
-
191
124
  // packages/cli/src/serve/permission-audit.ts
192
125
  init_esbuild_shims();
193
126
  var DEFAULT_PERMISSION_AUDIT_RING_SIZE = 512;
@@ -885,6 +818,120 @@ function asRecord(value) {
885
818
  }
886
819
  __name(asRecord, "asRecord");
887
820
 
821
+ // packages/cli/src/serve/channel-workspace-grouping.ts
822
+ init_esbuild_shims();
823
+ function resolveChannelOwnerCwd(rawCwd, workspaceCwd) {
824
+ return canonicalizeWorkspace(resolveChannelCwd(rawCwd, workspaceCwd));
825
+ }
826
+ __name(resolveChannelOwnerCwd, "resolveChannelOwnerCwd");
827
+ function rawChannelCwd(entry) {
828
+ if (!entry || typeof entry !== "object") return void 0;
829
+ const cwd = entry.cwd;
830
+ return typeof cwd === "string" && cwd.length > 0 ? cwd : void 0;
831
+ }
832
+ __name(rawChannelCwd, "rawChannelCwd");
833
+ function resolveChannelWorkspaceGroups(input) {
834
+ const { workspaces, selection, loadChannelsConfig } = input;
835
+ const primary = workspaces.find((workspace) => workspace.primary);
836
+ if (!primary) {
837
+ return {
838
+ ok: false,
839
+ error: {
840
+ code: "no_primary_workspace",
841
+ message: "No primary workspace is registered."
842
+ }
843
+ };
844
+ }
845
+ if (selection.mode === "all") {
846
+ if (!primary.trusted) {
847
+ return {
848
+ ok: false,
849
+ error: {
850
+ code: "untrusted_workspace",
851
+ message: `Primary workspace "${primary.workspaceCwd}" is not trusted; cannot host channels.`
852
+ }
853
+ };
854
+ }
855
+ return {
856
+ ok: true,
857
+ groups: [
858
+ { workspaceCwd: primary.workspaceCwd, selection: { mode: "all" } }
859
+ ]
860
+ };
861
+ }
862
+ const channelsConfigByWorkspace = /* @__PURE__ */ new Map();
863
+ for (const workspace of workspaces) {
864
+ channelsConfigByWorkspace.set(
865
+ workspace.workspaceCwd,
866
+ loadChannelsConfig(workspace.workspaceCwd)
867
+ );
868
+ }
869
+ const namesByWorkspace = /* @__PURE__ */ new Map();
870
+ for (const name of selection.names) {
871
+ const owners = [];
872
+ for (const workspace of workspaces) {
873
+ const entry = (channelsConfigByWorkspace.get(workspace.workspaceCwd) ?? {})[name];
874
+ if (!entry || typeof entry !== "object") continue;
875
+ let ownerCwd;
876
+ try {
877
+ ownerCwd = resolveChannelOwnerCwd(
878
+ rawChannelCwd(entry),
879
+ workspace.workspaceCwd
880
+ );
881
+ } catch {
882
+ continue;
883
+ }
884
+ if (ownerCwd === workspace.workspaceCwd) {
885
+ owners.push(workspace);
886
+ }
887
+ }
888
+ if (owners.length === 0) {
889
+ return {
890
+ ok: false,
891
+ error: {
892
+ code: "channel_workspace_mismatch",
893
+ channel: name,
894
+ message: `Channel "${name}" is not configured in any registered workspace, or its "cwd" points outside them.`
895
+ }
896
+ };
897
+ }
898
+ if (owners.length > 1) {
899
+ return {
900
+ ok: false,
901
+ error: {
902
+ code: "ambiguous_channel_workspace",
903
+ channel: name,
904
+ message: `Channel "${name}" is configured in multiple registered workspaces (${owners.map((owner2) => owner2.workspaceCwd).join(
905
+ ", "
906
+ )}). Define it in one workspace's settings or set an explicit "cwd".`
907
+ }
908
+ };
909
+ }
910
+ const owner = owners[0];
911
+ if (!owner.trusted) {
912
+ return {
913
+ ok: false,
914
+ error: {
915
+ code: "untrusted_workspace",
916
+ channel: name,
917
+ message: `Channel "${name}" targets untrusted workspace "${owner.workspaceCwd}".`
918
+ }
919
+ };
920
+ }
921
+ const names = namesByWorkspace.get(owner.workspaceCwd) ?? [];
922
+ names.push(name);
923
+ namesByWorkspace.set(owner.workspaceCwd, names);
924
+ }
925
+ return {
926
+ ok: true,
927
+ groups: [...namesByWorkspace.entries()].map(([workspaceCwd, names]) => ({
928
+ workspaceCwd,
929
+ selection: { mode: "names", names }
930
+ }))
931
+ };
932
+ }
933
+ __name(resolveChannelWorkspaceGroups, "resolveChannelWorkspaceGroups");
934
+
888
935
  // packages/cli/src/serve/run-qwen-serve.ts
889
936
  var QWEN_SERVE_CLIENT_MCP_OVER_WS_ENV = "QWEN_SERVE_CLIENT_MCP_OVER_WS";
890
937
  var QWEN_SERVE_CDP_TUNNEL_OVER_WS_ENV = "QWEN_SERVE_CDP_TUNNEL_OVER_WS";
@@ -1074,6 +1121,10 @@ function extractContextFilename(value) {
1074
1121
  return void 0;
1075
1122
  }
1076
1123
  __name(extractContextFilename, "extractContextFilename");
1124
+ function sessionArtifactsPersistenceAvailableFromSettings(settings) {
1125
+ return settings?.general?.chatRecording !== false;
1126
+ }
1127
+ __name(sessionArtifactsPersistenceAvailableFromSettings, "sessionArtifactsPersistenceAvailableFromSettings");
1077
1128
  var settingsWriteLocks = /* @__PURE__ */ new Map();
1078
1129
  function withSettingsLock(workspace, fn) {
1079
1130
  const prev = settingsWriteLocks.get(workspace) ?? Promise.resolve();
@@ -1085,12 +1136,29 @@ __name(withSettingsLock, "withSettingsLock");
1085
1136
  var channelWorkerRuntimePromise;
1086
1137
  async function loadChannelWorkerRuntime() {
1087
1138
  channelWorkerRuntimePromise ??= Promise.all([
1088
- import("./channel-worker-supervisor-NZQUOEFJ.js"),
1089
- import("./pidfile-NZYSCFRK.js")
1090
- ]).then(([supervisor, pidfile]) => ({
1091
- createChannelWorkerSupervisor: supervisor.createChannelWorkerSupervisor,
1092
- channelServicePidfile: pidfile
1093
- })).catch((err) => {
1139
+ import("./channel-worker-supervisor-QCKIOYZD.js"),
1140
+ import("./pidfile-AUMGYIOK.js"),
1141
+ import("./runtime-NYUSLBEZ.js"),
1142
+ import("./cli-entry-path-4VJ3Y6T2.js"),
1143
+ import("./channel-worker-group-K7QKH6IG.js"),
1144
+ import("./channel-worker-manager-YSFB4HUU.js")
1145
+ ]).then(
1146
+ ([
1147
+ supervisor,
1148
+ pidfile,
1149
+ channelRuntime,
1150
+ cliEntryPath,
1151
+ workerGroup,
1152
+ workerManager
1153
+ ]) => ({
1154
+ createChannelWorkerSupervisor: supervisor.createChannelWorkerSupervisor,
1155
+ channelServicePidfile: pidfile,
1156
+ loadChannelsConfig: channelRuntime.loadChannelsConfig,
1157
+ createChannelWorkerGroup: workerGroup.createChannelWorkerGroup,
1158
+ createChannelWorkerManager: workerManager.createChannelWorkerManager,
1159
+ findCliEntryPath: cliEntryPath.findCliEntryPath
1160
+ })
1161
+ ).catch((err) => {
1094
1162
  channelWorkerRuntimePromise = void 0;
1095
1163
  throw err;
1096
1164
  });
@@ -1108,9 +1176,18 @@ function createDisabledChannelWorkerSupervisor() {
1108
1176
  },
1109
1177
  async stop() {
1110
1178
  },
1179
+ async restart() {
1180
+ return { ...snapshot, channels: [] };
1181
+ },
1111
1182
  killAllSync() {
1112
1183
  },
1113
- snapshot: /* @__PURE__ */ __name(() => ({ ...snapshot, channels: [] }), "snapshot")
1184
+ snapshot: /* @__PURE__ */ __name(() => ({ ...snapshot, channels: [] }), "snapshot"),
1185
+ async enqueueWebhookTask() {
1186
+ throw new ChannelWebhookEnqueueError(
1187
+ "channel_worker_unavailable",
1188
+ "Channel worker is not running."
1189
+ );
1190
+ }
1114
1191
  };
1115
1192
  }
1116
1193
  __name(createDisabledChannelWorkerSupervisor, "createDisabledChannelWorkerSupervisor");
@@ -1123,11 +1200,23 @@ function writeServeChannelReservation(channelServicePidfile, channels) {
1123
1200
  __name(writeServeChannelReservation, "writeServeChannelReservation");
1124
1201
  function channelServicePidfileConflictError(info) {
1125
1202
  const owner = info.owner === "serve" ? "qwen serve" : "qwen channel start";
1126
- return new Error(
1127
- `Channel service is already running under ${owner} (PID ${info.pid}). Stop it before starting qwen serve --channel.`
1203
+ return Object.assign(
1204
+ new Error(
1205
+ `Channel service is already running under ${owner} (PID ${info.pid}). Stop it before enabling daemon-managed channels.`
1206
+ ),
1207
+ { code: "channel_service_conflict", owner: info.owner, pid: info.pid }
1128
1208
  );
1129
1209
  }
1130
1210
  __name(channelServicePidfileConflictError, "channelServicePidfileConflictError");
1211
+ function channelServiceStartingConflictError() {
1212
+ return Object.assign(
1213
+ new Error(
1214
+ "Channel service is already starting. Retry after the current startup finishes."
1215
+ ),
1216
+ { code: "channel_service_conflict" }
1217
+ );
1218
+ }
1219
+ __name(channelServiceStartingConflictError, "channelServiceStartingConflictError");
1131
1220
  function normalizeInstallModelIds(req, provider, getDefaultModelIds) {
1132
1221
  const fromRequest = req.modelIds?.map((id) => id.trim()).filter((id) => id.length > 0);
1133
1222
  const modelIds = fromRequest && fromRequest.length > 0 ? fromRequest : getDefaultModelIds(provider);
@@ -1157,7 +1246,7 @@ function shouldPreheatBridge(deps) {
1157
1246
  __name(shouldPreheatBridge, "shouldPreheatBridge");
1158
1247
  var coreRuntimePromise;
1159
1248
  function loadCoreRuntime() {
1160
- coreRuntimePromise ??= import("./src-BBQSM46M.js");
1249
+ coreRuntimePromise ??= import("./src-YDBNMIIM.js");
1161
1250
  return coreRuntimePromise;
1162
1251
  }
1163
1252
  __name(loadCoreRuntime, "loadCoreRuntime");
@@ -1187,10 +1276,10 @@ __name(resolveDaemonLogBaseDirForRun, "resolveDaemonLogBaseDirForRun");
1187
1276
  var settingsRuntimePromise;
1188
1277
  function loadSettingsRuntimeModules() {
1189
1278
  settingsRuntimePromise ??= Promise.all([
1190
- import("./settings-3MI4XXP6.js"),
1191
- import("./environment-ATFTYMLZ.js"),
1192
- import("./loadedSettingsAdapter-LL5PSFKX.js"),
1193
- import("./trustedFolders-LAZZPZ3D.js")
1279
+ import("./settings-X24RYEED.js"),
1280
+ import("./environment-OYA3ZVEL.js"),
1281
+ import("./loadedSettingsAdapter-V4ZTRKUO.js"),
1282
+ import("./trustedFolders-JF265CRI.js")
1194
1283
  ]).then(([settings, environment, loadedSettingsAdapter, trustedFolders]) => ({
1195
1284
  settings,
1196
1285
  environment,
@@ -1200,6 +1289,21 @@ function loadSettingsRuntimeModules() {
1200
1289
  return settingsRuntimePromise;
1201
1290
  }
1202
1291
  __name(loadSettingsRuntimeModules, "loadSettingsRuntimeModules");
1292
+ var channelWebhookConfigRuntimePromise;
1293
+ function loadChannelWebhookConfigRuntime() {
1294
+ channelWebhookConfigRuntimePromise ??= Promise.all([
1295
+ import("./runtime-NYUSLBEZ.js"),
1296
+ import("./config-utils-XSHOMMK4.js")
1297
+ ]).then(([channelRuntime, configUtils]) => ({
1298
+ loadChannelsConfig: channelRuntime.loadChannelsConfig,
1299
+ parseChannelWebhookConfig: configUtils.parseChannelWebhookConfig
1300
+ })).catch((err) => {
1301
+ channelWebhookConfigRuntimePromise = void 0;
1302
+ throw err;
1303
+ });
1304
+ return channelWebhookConfigRuntimePromise;
1305
+ }
1306
+ __name(loadChannelWebhookConfigRuntime, "loadChannelWebhookConfigRuntime");
1203
1307
  async function loadServeRuntimeModules() {
1204
1308
  const [
1205
1309
  serverModule,
@@ -1213,16 +1317,16 @@ async function loadServeRuntimeModules() {
1213
1317
  totalSessionAdmissionModule,
1214
1318
  workspaceRegistryModule
1215
1319
  ] = await Promise.all([
1216
- import("./server-SGNPKX2O.js"),
1217
- import("./bridge-NA3ZQQKJ.js"),
1218
- import("./spawnChannel-UNV6W4DU.js"),
1219
- import("./workspace-service-CZRQZ4Q4.js"),
1220
- import("./types-QX5C3CHJ.js"),
1221
- import("./daemon-status-provider-GJRXY5EN.js"),
1222
- import("./workspace-providers-status-3W7E7DFW.js"),
1223
- import("./workspace-skills-status-K7WFREPD.js"),
1224
- import("./total-session-admission-ULXJWXFV.js"),
1225
- import("./workspace-registry-SXJZNN3O.js")
1320
+ import("./server-VUHSYSUV.js"),
1321
+ import("./bridge-HKEWPNB5.js"),
1322
+ import("./spawnChannel-RFAAO44J.js"),
1323
+ import("./workspace-service-PUYIZ3J4.js"),
1324
+ import("./types-ML3TRJQ5.js"),
1325
+ import("./daemon-status-provider-KFL3LRTP.js"),
1326
+ import("./workspace-providers-status-LMBLBNR7.js"),
1327
+ import("./workspace-skills-status-CJ7J2KPP.js"),
1328
+ import("./total-session-admission-2WIH72I3.js"),
1329
+ import("./workspace-registry-BVMPYRLN.js")
1226
1330
  ]);
1227
1331
  return {
1228
1332
  createServeApp: serverModule.createServeApp,
@@ -1233,11 +1337,13 @@ async function loadServeRuntimeModules() {
1233
1337
  createSpawnChannelFactory: spawnChannelModule.createSpawnChannelFactory,
1234
1338
  createDaemonWorkspaceService: workspaceModule.createDaemonWorkspaceService,
1235
1339
  WorkspaceSettingsPartialPersistError: workspaceTypesModule.WorkspaceSettingsPartialPersistError,
1340
+ WorkspaceSkillNotToggleableError: workspaceTypesModule.WorkspaceSkillNotToggleableError,
1236
1341
  createDaemonStatusProvider: daemonStatusProviderModule.createDaemonStatusProvider,
1237
1342
  createWorkspaceProvidersStatusProvider: workspaceProvidersStatusModule.createWorkspaceProvidersStatusProvider,
1238
1343
  createWorkspaceSkillsStatusProvider: workspaceSkillsStatusModule.createWorkspaceSkillsStatusProvider,
1239
1344
  createTotalSessionAdmissionController: totalSessionAdmissionModule.createTotalSessionAdmissionController,
1240
- createWorkspaceRegistry: workspaceRegistryModule.createWorkspaceRegistry
1345
+ createWorkspaceRegistry: workspaceRegistryModule.createWorkspaceRegistry,
1346
+ createWorkspaceSessionOwnerIndex: workspaceRegistryModule.createWorkspaceSessionOwnerIndex
1241
1347
  };
1242
1348
  }
1243
1349
  __name(loadServeRuntimeModules, "loadServeRuntimeModules");
@@ -1261,7 +1367,7 @@ function sessionIdleTimeoutMs(value) {
1261
1367
  return value !== void 0 ? channelIdleTimeoutMs(value) : DEFAULT_SESSION_IDLE_TIMEOUT_MS;
1262
1368
  }
1263
1369
  __name(sessionIdleTimeoutMs, "sessionIdleTimeoutMs");
1264
- function currentServeFeaturesForRunQwenServe(opts, sessionShellCommandEnabled) {
1370
+ function currentServeFeaturesForRunQwenServe(opts, sessionShellCommandEnabled, sessionArtifactsPersistenceAvailable, env) {
1265
1371
  return getAdvertisedServeFeatures(void 0, {
1266
1372
  requireAuth: opts.requireAuth === true,
1267
1373
  mcpPoolActive: opts.mcpPoolActive !== false,
@@ -1270,12 +1376,18 @@ function currentServeFeaturesForRunQwenServe(opts, sessionShellCommandEnabled) {
1270
1376
  ...opts.writerIdleTimeoutMs !== void 0 ? { writerIdleTimeoutMs: opts.writerIdleTimeoutMs } : {},
1271
1377
  persistSettingAvailable: true,
1272
1378
  sessionShellCommandEnabled,
1379
+ sessionArtifactsPersistenceAvailable,
1273
1380
  rateLimit: opts.rateLimit === true,
1274
1381
  reloadAvailable: true,
1382
+ channelReloadAvailable: opts.channelSelection !== void 0,
1383
+ channelControlAvailable: true,
1384
+ persistentWorkspaceRegistrationAvailable: true,
1385
+ workspaceRuntimeRemovalAvailable: true,
1275
1386
  // Advertise the same WS feature flags as the runtime path (serve-features.ts)
1276
1387
  // so the bootstrap `/capabilities` window doesn't briefly under-report them.
1277
1388
  clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
1278
- cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true
1389
+ cdpTunnelOverWsEnabled: opts.cdpTunnelOverWs === true,
1390
+ browserAutomationMcpAvailable: isBrowserAutomationMcpAvailable(opts, env)
1279
1391
  });
1280
1392
  }
1281
1393
  __name(currentServeFeaturesForRunQwenServe, "currentServeFeaturesForRunQwenServe");
@@ -1287,7 +1399,9 @@ function createBootstrapCapabilities(input) {
1287
1399
  mode: input.opts.mode,
1288
1400
  features: currentServeFeaturesForRunQwenServe(
1289
1401
  input.opts,
1290
- input.sessionShellCommandEnabled
1402
+ input.sessionShellCommandEnabled,
1403
+ input.sessionArtifactsPersistenceAvailable,
1404
+ input.env
1291
1405
  ),
1292
1406
  modelServices: [],
1293
1407
  workspaceCwd: input.boundWorkspace,
@@ -1432,10 +1546,12 @@ function createBootstrapServeApp(input) {
1432
1546
  daemonLog,
1433
1547
  qwenCodeVersion,
1434
1548
  sessionShellCommandEnabled,
1549
+ sessionArtifactsPersistenceAvailable,
1435
1550
  permissionPolicy,
1436
1551
  multiWorkspaceCapabilitiesRequireRuntime,
1437
1552
  getRuntimeError,
1438
1553
  getChannelWorkerSnapshot,
1554
+ getChannelWorkerSnapshots,
1439
1555
  onHealthServed
1440
1556
  } = input;
1441
1557
  const app = (0, import_express.default)();
@@ -1487,7 +1603,9 @@ function createBootstrapServeApp(input) {
1487
1603
  boundWorkspace,
1488
1604
  qwenCodeVersion,
1489
1605
  sessionShellCommandEnabled,
1490
- permissionPolicy
1606
+ sessionArtifactsPersistenceAvailable,
1607
+ permissionPolicy,
1608
+ env: process.env
1491
1609
  })
1492
1610
  );
1493
1611
  });
@@ -1502,6 +1620,7 @@ function createBootstrapServeApp(input) {
1502
1620
  }
1503
1621
  const runtimeError = getRuntimeError();
1504
1622
  const channelWorker = getChannelWorkerSnapshot();
1623
+ const channelWorkers = getChannelWorkerSnapshots();
1505
1624
  const runtimeFailed = runtimeError !== void 0;
1506
1625
  const issue = runtimeError ? {
1507
1626
  code: "daemon_runtime_failed",
@@ -1558,7 +1677,9 @@ function createBootstrapServeApp(input) {
1558
1677
  protocolVersions: getServeProtocolVersions(),
1559
1678
  features: currentServeFeaturesForRunQwenServe(
1560
1679
  opts,
1561
- sessionShellCommandEnabled
1680
+ sessionShellCommandEnabled,
1681
+ sessionArtifactsPersistenceAvailable,
1682
+ process.env
1562
1683
  )
1563
1684
  },
1564
1685
  runtime: {
@@ -1571,6 +1692,7 @@ function createBootstrapServeApp(input) {
1571
1692
  },
1572
1693
  channel: { live: false },
1573
1694
  channelWorker,
1695
+ ...channelWorkers.length > 0 ? { channelWorkers } : {},
1574
1696
  transport: {
1575
1697
  restSseActive: 0,
1576
1698
  acp: {
@@ -1630,13 +1752,12 @@ function createDelegatingServeApp(bootstrapApp, getRuntimeApp, options = {}) {
1630
1752
  const dispatch = /* @__PURE__ */ __name(async () => {
1631
1753
  let target = getRuntimeApp();
1632
1754
  if (!target && options.waitForDeferredRuntimeRoutes === true && !isBootstrapServeRoute(req) && !isCorsPreflightRequest(req) && options.startRuntime && options.runtimeReady) {
1633
- if (options.authenticateDeferredRuntimeRequest && !runSynchronousRequestGate(
1634
- options.authenticateDeferredRuntimeRequest,
1635
- req,
1636
- res,
1637
- next
1638
- )) {
1639
- return;
1755
+ const webhookRequest = isChannelWebhookRequest(req);
1756
+ const authGate = webhookRequest ? options.authenticateDeferredChannelWebhookRequest ?? options.authenticateDeferredRuntimeRequest : options.authenticateDeferredRuntimeRequest;
1757
+ if (authGate) {
1758
+ if (!runSynchronousRequestGate(authGate, req, res, next)) {
1759
+ return;
1760
+ }
1640
1761
  }
1641
1762
  options.startRuntime();
1642
1763
  try {
@@ -1658,6 +1779,83 @@ function isBootstrapServeRoute(req) {
1658
1779
  return BOOTSTRAP_SERVE_PATHS.has(path2);
1659
1780
  }
1660
1781
  __name(isBootstrapServeRoute, "isBootstrapServeRoute");
1782
+ function isChannelWebhookRequest(req) {
1783
+ return req.method === "POST" && /^\/channels\/[^/]+\/webhooks\/[^/]+\/?$/u.test(req.path);
1784
+ }
1785
+ __name(isChannelWebhookRequest, "isChannelWebhookRequest");
1786
+ function createDeferredChannelWebhookAuth(resolveSource, runtime, daemonLog) {
1787
+ return (req, res, next) => {
1788
+ const match = /^\/channels\/([^/]+)\/webhooks\/([^/]+)\/?$/u.exec(req.path);
1789
+ const channelName = decodeDeferredWebhookPathSegment(match?.[1]);
1790
+ const source = decodeDeferredWebhookPathSegment(match?.[2]);
1791
+ if (!channelName || !source) {
1792
+ daemonLog.warn("deferred webhook auth failed", {
1793
+ channelName: channelName ?? "unknown",
1794
+ source: source ?? "unknown",
1795
+ reason: "invalid webhook path"
1796
+ });
1797
+ res.status(401).json({ error: "Invalid webhook secret" });
1798
+ return;
1799
+ }
1800
+ const configSource = resolveSource(channelName);
1801
+ const secret = readDeferredWebhookSecret(
1802
+ runtime,
1803
+ configSource.workspaceCwd,
1804
+ channelName,
1805
+ source,
1806
+ configSource.env
1807
+ );
1808
+ if (!matchesWebhookSecret(req.get("x-qwen-webhook-secret"), secret)) {
1809
+ daemonLog.warn("deferred webhook auth failed", {
1810
+ channelName,
1811
+ source,
1812
+ reason: secret ? "secret mismatch" : "source not configured"
1813
+ });
1814
+ res.status(401).json({ error: "Invalid webhook secret" });
1815
+ return;
1816
+ }
1817
+ next();
1818
+ };
1819
+ }
1820
+ __name(createDeferredChannelWebhookAuth, "createDeferredChannelWebhookAuth");
1821
+ function decodeDeferredWebhookPathSegment(segment) {
1822
+ if (segment === void 0) return void 0;
1823
+ try {
1824
+ return decodeURIComponent(segment);
1825
+ } catch {
1826
+ return void 0;
1827
+ }
1828
+ }
1829
+ __name(decodeDeferredWebhookPathSegment, "decodeDeferredWebhookPathSegment");
1830
+ function readDeferredWebhookSecret(runtime, workspace, channelName, source, env) {
1831
+ try {
1832
+ const rawConfig = runtime.loadChannelsConfig(workspace)[channelName];
1833
+ if (typeof rawConfig !== "object" || rawConfig === null) {
1834
+ return void 0;
1835
+ }
1836
+ return runtime.parseChannelWebhookConfig(
1837
+ channelName,
1838
+ rawConfig,
1839
+ env
1840
+ )?.sources[source]?.secret;
1841
+ } catch (err) {
1842
+ const reason = err instanceof Error ? err.message : String(err);
1843
+ writeStderrLine(
1844
+ `[webhook-secret] failed to read deferred webhook secret for ${sanitizeLogText(channelName, 128)}/${sanitizeLogText(source, 128)}: ${sanitizeLogText(reason, 512)}`
1845
+ );
1846
+ return void 0;
1847
+ }
1848
+ }
1849
+ __name(readDeferredWebhookSecret, "readDeferredWebhookSecret");
1850
+ function matchesWebhookSecret(candidate, expected) {
1851
+ if (typeof candidate !== "string" || typeof expected !== "string" || expected.length === 0) {
1852
+ return false;
1853
+ }
1854
+ const expectedDigest = createHash2("sha256").update(expected).digest();
1855
+ const candidateDigest = createHash2("sha256").update(candidate).digest();
1856
+ return timingSafeEqual(expectedDigest, candidateDigest);
1857
+ }
1858
+ __name(matchesWebhookSecret, "matchesWebhookSecret");
1661
1859
  function isCorsPreflightRequest(req) {
1662
1860
  return req.method === "OPTIONS" && Boolean(req.headers.origin) && Boolean(
1663
1861
  req.headers["access-control-request-method"] || req.headers["access-control-request-headers"]
@@ -1723,30 +1921,42 @@ async function runQwenServe(optsIn, deps = {}) {
1723
1921
  clientMcpOverWs: optsIn.clientMcpOverWs ?? (!envFlagDisabled(clientMcpOverWsEnv) && clientMcpOverWsEnv !== void 0),
1724
1922
  cdpTunnelOverWs: optsIn.cdpTunnelOverWs ?? (!envFlagDisabled(cdpTunnelOverWsEnv) && (cdpTunnelOverWsEnv !== void 0 || chromeExtensionOriginAllowed))
1725
1923
  };
1726
- const channelRuntime = opts.channelSelection ? await loadChannelWorkerRuntime() : void 0;
1727
- const channelServicePidfile = deps.channelServicePidfile ?? channelRuntime?.channelServicePidfile;
1924
+ let channelRuntime = opts.channelSelection ? await loadChannelWorkerRuntime() : void 0;
1925
+ let channelServicePidfile = deps.channelServicePidfile ?? channelRuntime?.channelServicePidfile;
1926
+ const ensureChannelRuntime = /* @__PURE__ */ __name(async () => {
1927
+ channelRuntime ??= await loadChannelWorkerRuntime();
1928
+ channelServicePidfile ??= channelRuntime.channelServicePidfile;
1929
+ return channelRuntime;
1930
+ }, "ensureChannelRuntime");
1728
1931
  let channelPidfileReserved = false;
1729
1932
  const removeCurrentServePidfile = /* @__PURE__ */ __name(() => {
1730
- if (!opts.channelSelection || !channelServicePidfile) return;
1933
+ if (!channelServicePidfile) return;
1731
1934
  if (!channelPidfileReserved) return;
1732
1935
  if (channelServicePidfile.removeServeServiceInfo) {
1733
1936
  if (channelServicePidfile.removeServeServiceInfo(process.pid)) {
1734
1937
  channelPidfileReserved = false;
1938
+ } else {
1939
+ const info2 = channelServicePidfile.readServiceInfo();
1940
+ if (!info2 || info2.owner !== "serve" || info2.pid !== process.pid || info2.servePid !== process.pid) {
1941
+ channelPidfileReserved = false;
1942
+ }
1735
1943
  }
1736
1944
  return;
1737
1945
  }
1738
1946
  const info = channelServicePidfile.readServiceInfo();
1739
1947
  if (info?.owner === "serve" && info.pid === process.pid && info.servePid === process.pid) {
1740
1948
  channelServicePidfile.removeServiceInfo();
1949
+ const remaining = channelServicePidfile.readServiceInfo();
1950
+ channelPidfileReserved = remaining?.owner === "serve" && remaining.pid === process.pid && remaining.servePid === process.pid;
1951
+ } else {
1741
1952
  channelPidfileReserved = false;
1742
1953
  }
1743
1954
  }, "removeCurrentServePidfile");
1744
- const reserveChannelServicePidfile = /* @__PURE__ */ __name(() => {
1745
- if (!opts.channelSelection) return;
1955
+ const reserveChannelServicePidfile = /* @__PURE__ */ __name((selection) => {
1746
1956
  if (!channelServicePidfile) {
1747
1957
  throw new Error("Channel service pidfile runtime is not available.");
1748
1958
  }
1749
- const channelPidfileNames = channelSelectionNames(opts.channelSelection);
1959
+ const channelPidfileNames = channelSelectionNames(selection);
1750
1960
  const existingChannelService = channelServicePidfile.readServiceInfo();
1751
1961
  if (existingChannelService) {
1752
1962
  throw channelServicePidfileConflictError(existingChannelService);
@@ -1771,9 +1981,7 @@ async function runQwenServe(optsIn, deps = {}) {
1771
1981
  return;
1772
1982
  } catch (retryErr) {
1773
1983
  if (retryErr && typeof retryErr === "object" && "code" in retryErr && retryErr.code === "EEXIST") {
1774
- throw new Error(
1775
- "Channel service is already starting. Retry after the current startup finishes."
1776
- );
1984
+ throw channelServiceStartingConflictError();
1777
1985
  }
1778
1986
  throw retryErr;
1779
1987
  }
@@ -1892,7 +2100,9 @@ async function runQwenServe(optsIn, deps = {}) {
1892
2100
  }, "validateAndCanonicalizeWorkspace");
1893
2101
  const workspaceInputs = rawWorkspaces.map((workspace) => ({
1894
2102
  raw: workspace,
1895
- cwd: validateAndCanonicalizeWorkspace(workspace)
2103
+ cwd: validateAndCanonicalizeWorkspace(workspace),
2104
+ removable: false,
2105
+ registrationIds: []
1896
2106
  }));
1897
2107
  const boundWorkspace = workspaceInputs[0].cwd;
1898
2108
  const seenCanonicalWorkspaces = /* @__PURE__ */ new Set();
@@ -1924,6 +2134,71 @@ async function runQwenServe(optsIn, deps = {}) {
1924
2134
  }
1925
2135
  }
1926
2136
  }
2137
+ if (workspaceInputs.length > MAX_REGISTERED_WORKSPACES) {
2138
+ throw new Error(
2139
+ `At most ${MAX_REGISTERED_WORKSPACES} --workspace values may be registered.`
2140
+ );
2141
+ }
2142
+ let workspaceRegistrationStore = deps.workspaceRegistrationStore;
2143
+ if (workspaceRegistrationStore === void 0 && process.env["QWEN_SERVE_NO_PERSISTENT_REGISTRATION"] !== "1") {
2144
+ const { WorkspaceRegistrationStore } = await import("./workspace-registration-store-VV2S4MSV.js");
2145
+ workspaceRegistrationStore = new WorkspaceRegistrationStore(boundWorkspace);
2146
+ }
2147
+ if (workspaceRegistrationStore) {
2148
+ try {
2149
+ const stored = await workspaceRegistrationStore.read();
2150
+ for (const storedWorkspace of stored.workspaces) {
2151
+ const registrationId = workspaceRegistrationId(storedWorkspace);
2152
+ let cwd;
2153
+ try {
2154
+ cwd = validateAndCanonicalizeWorkspace(storedWorkspace);
2155
+ } catch (err) {
2156
+ writeStderrLine(
2157
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2158
+ storedWorkspace
2159
+ )}: ${err instanceof Error ? err.message : String(err)}`
2160
+ );
2161
+ continue;
2162
+ }
2163
+ const existingInput = workspaceInputs.find(
2164
+ (workspace) => workspace.cwd === cwd
2165
+ );
2166
+ if (existingInput) {
2167
+ existingInput.registrationIds.push(registrationId);
2168
+ continue;
2169
+ }
2170
+ const nested = workspaceInputs.some(
2171
+ (workspace) => isWithinRoot(cwd, workspace.cwd) || isWithinRoot(workspace.cwd, cwd)
2172
+ );
2173
+ if (nested) {
2174
+ writeStderrLine(
2175
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2176
+ storedWorkspace
2177
+ )}: path nests with an explicit or earlier restored workspace`
2178
+ );
2179
+ continue;
2180
+ }
2181
+ if (workspaceInputs.length >= MAX_REGISTERED_WORKSPACES) {
2182
+ writeStderrLine(
2183
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2184
+ storedWorkspace
2185
+ )}: workspace limit reached`
2186
+ );
2187
+ continue;
2188
+ }
2189
+ workspaceInputs.push({
2190
+ raw: storedWorkspace,
2191
+ cwd,
2192
+ removable: true,
2193
+ registrationIds: [registrationId]
2194
+ });
2195
+ }
2196
+ } catch (err) {
2197
+ writeStderrLine(
2198
+ `qwen serve: failed to read persisted workspace registrations: ${err instanceof Error ? err.message : String(err)}; continuing with explicit workspaces only`
2199
+ );
2200
+ }
2201
+ }
1927
2202
  if (workspaceInputs.length > 1 && deps.bridge) {
1928
2203
  throw new Error(
1929
2204
  "Injected bridge dependencies are only supported with a single workspace; multiple --workspace values require runQwenServe to construct one bridge per workspace."
@@ -1933,8 +2208,10 @@ async function runQwenServe(optsIn, deps = {}) {
1933
2208
  let permissionPolicy;
1934
2209
  let permissionConsensusQuorum;
1935
2210
  let bootSettings;
2211
+ let sessionArtifactsPersistenceAvailable = true;
1936
2212
  try {
1937
2213
  bootSettings = deps.bootSettings ?? loadServeFastPathSettings(boundWorkspace);
2214
+ sessionArtifactsPersistenceAvailable = sessionArtifactsPersistenceAvailableFromSettings(bootSettings);
1938
2215
  contextFilenameForInit = extractContextFilename(
1939
2216
  bootSettings.context?.fileName
1940
2217
  );
@@ -2107,20 +2384,139 @@ async function runQwenServe(optsIn, deps = {}) {
2107
2384
  void runtimeReady.catch(() => {
2108
2385
  });
2109
2386
  const disposeDaemonEventLoopMonitor = /* @__PURE__ */ __name(() => {
2110
- daemonEventLoopMonitor?.dispose();
2387
+ const eventLoopMonitor = daemonEventLoopMonitor;
2111
2388
  daemonEventLoopMonitor = void 0;
2112
- daemonMetricsSampler?.dispose();
2389
+ const metricsSampler = daemonMetricsSampler;
2113
2390
  daemonMetricsSampler = void 0;
2391
+ try {
2392
+ eventLoopMonitor?.dispose();
2393
+ } catch (err) {
2394
+ daemonLog.warn(
2395
+ `event loop monitor dispose error: ${err instanceof Error ? err.message : String(err)}`
2396
+ );
2397
+ }
2398
+ try {
2399
+ metricsSampler?.dispose();
2400
+ } catch (err) {
2401
+ daemonLog.warn(
2402
+ `metrics sampler dispose error: ${err instanceof Error ? err.message : String(err)}`
2403
+ );
2404
+ }
2114
2405
  }, "disposeDaemonEventLoopMonitor");
2115
- let channelWorker = createDisabledChannelWorkerSupervisor();
2116
- const getChannelWorkerSnapshot = /* @__PURE__ */ __name(() => channelWorker.snapshot(), "getChannelWorkerSnapshot");
2117
- const writeChannelWorkerPidfile = /* @__PURE__ */ __name((snapshot = channelWorker.snapshot(), options = {}) => {
2118
- if (!opts.channelSelection || !channelServicePidfile) return;
2406
+ let channelWorkerManager;
2407
+ let channelWorkerManagerStarting;
2408
+ let channelControlDraining = false;
2409
+ let channelWorkspaceGroups;
2410
+ const channelWebhookEnvByWorkspace = /* @__PURE__ */ new Map();
2411
+ let channelWebhookConfigVersion = 0;
2412
+ let refreshChannelWebhookConfigs;
2413
+ let ensureChannelWorkerManager;
2414
+ const getChannelWebhookConfigSources = /* @__PURE__ */ __name(() => {
2415
+ const app2 = runtimeApp ?? runtimeAppForCleanup;
2416
+ const registry = app2?.locals?.["workspaceRegistry"];
2417
+ return (channelWorkspaceGroups ?? []).map((group) => {
2418
+ const env = registry?.getByWorkspaceCwd(group.workspaceCwd)?.env.effectiveEnv ?? channelWebhookEnvByWorkspace.get(group.workspaceCwd);
2419
+ return {
2420
+ workspaceCwd: group.workspaceCwd,
2421
+ ...group.selection.mode === "names" ? { channelNames: group.selection.names } : {},
2422
+ ...env ? { env } : {}
2423
+ };
2424
+ });
2425
+ }, "getChannelWebhookConfigSources");
2426
+ const resolveChannelWebhookConfigSource = /* @__PURE__ */ __name((channelName) => {
2427
+ const source = getChannelWebhookConfigSources().find(
2428
+ (source2) => !source2.channelNames || source2.channelNames.includes(channelName)
2429
+ );
2430
+ if (source) return source;
2431
+ const env = channelWebhookEnvByWorkspace.get(boundWorkspace);
2432
+ return {
2433
+ workspaceCwd: boundWorkspace,
2434
+ ...env ? { env } : {}
2435
+ };
2436
+ }, "resolveChannelWebhookConfigSource");
2437
+ let closeServerAfterChannelWorkerStartupFailure = false;
2438
+ let runtimeFailureListenerClose;
2439
+ const getChannelWorkerSnapshot = /* @__PURE__ */ __name(() => channelWorkerManager?.primarySnapshot() ?? {
2440
+ enabled: false,
2441
+ state: "disabled",
2442
+ channels: []
2443
+ }, "getChannelWorkerSnapshot");
2444
+ const getChannelWorkerSnapshots = /* @__PURE__ */ __name(() => channelWorkerManager?.snapshots() ?? [], "getChannelWorkerSnapshots");
2445
+ const getChannelWorkerControl = /* @__PURE__ */ __name(() => channelWorkerManager?.state() ?? {
2446
+ enabled: false,
2447
+ selection: null,
2448
+ transition: "idle",
2449
+ workers: []
2450
+ }, "getChannelWorkerControl");
2451
+ const daemonDrainingError = /* @__PURE__ */ __name(() => Object.assign(new Error("Daemon is shutting down."), {
2452
+ code: "daemon_draining"
2453
+ }), "daemonDrainingError");
2454
+ const setChannelWorkerSelection = /* @__PURE__ */ __name(async (selection) => {
2455
+ if (channelControlDraining) throw daemonDrainingError();
2456
+ const manager = await ensureChannelWorkerManager?.();
2457
+ if (!manager) throw new Error("Channel worker manager is unavailable.");
2458
+ if (channelControlDraining) {
2459
+ await manager.shutdown().catch(() => void 0);
2460
+ throw daemonDrainingError();
2461
+ }
2462
+ return manager.setSelection(selection);
2463
+ }, "setChannelWorkerSelection");
2464
+ const stopChannelWorker = /* @__PURE__ */ __name(async () => {
2465
+ if (channelControlDraining) throw daemonDrainingError();
2466
+ const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
2467
+ if (channelControlDraining) {
2468
+ await manager?.shutdown().catch(() => void 0);
2469
+ throw daemonDrainingError();
2470
+ }
2471
+ if (!manager) {
2472
+ return { changed: false, state: getChannelWorkerControl() };
2473
+ }
2474
+ return manager.stopSelection();
2475
+ }, "stopChannelWorker");
2476
+ const reloadChannelWorker = /* @__PURE__ */ __name(async () => {
2477
+ if (channelControlDraining) throw daemonDrainingError();
2478
+ const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
2479
+ if (channelControlDraining) {
2480
+ await manager?.shutdown().catch(() => void 0);
2481
+ throw daemonDrainingError();
2482
+ }
2483
+ if (!manager) {
2484
+ return { enabled: false, state: "disabled", channels: [] };
2485
+ }
2486
+ try {
2487
+ return await manager.reload();
2488
+ } finally {
2489
+ writeChannelWorkerPidfile();
2490
+ }
2491
+ }, "reloadChannelWorker");
2492
+ const isLiveWorker = /* @__PURE__ */ __name((snapshot) => snapshot.state === "running" || snapshot.state === "starting", "isLiveWorker");
2493
+ let channelWorkerPidfileUsesWorkers = workspaceInputs.length > 1;
2494
+ const writeChannelWorkerPidfile = /* @__PURE__ */ __name(() => {
2495
+ if (runtimeStartupError !== void 0) return;
2496
+ if (!channelPidfileReserved || !channelServicePidfile) return;
2497
+ const snapshots = getChannelWorkerSnapshots();
2498
+ const workers = snapshots.map((snapshot) => ({
2499
+ workspaceId: snapshot.workspaceId,
2500
+ workspaceCwd: snapshot.workspaceCwd,
2501
+ channels: snapshot.channels,
2502
+ // Drop a stale pid (worker exited/failed/stopped) so readers never signal
2503
+ // a dead process — mirrors the pre-4b clear-on-exit behavior.
2504
+ ...isLiveWorker(snapshot) && snapshot.pid !== void 0 ? { workerPid: snapshot.pid } : {}
2505
+ }));
2506
+ const channels = [
2507
+ ...new Set(snapshots.flatMap((snapshot) => snapshot.channels))
2508
+ ];
2509
+ const primary = snapshots.find((snapshot) => snapshot.primary);
2510
+ if (workers.length > 1 || snapshots.some((snapshot) => !snapshot.primary)) {
2511
+ channelWorkerPidfileUsesWorkers = true;
2512
+ }
2513
+ const includeWorkers = channelWorkerPidfileUsesWorkers && workers.length > 0;
2119
2514
  try {
2120
2515
  channelServicePidfile.writeServeServiceInfo({
2121
- channels: snapshot.channels,
2516
+ channels,
2122
2517
  servePid: process.pid,
2123
- ...!options.clearWorkerPid && snapshot.pid !== void 0 ? { workerPid: snapshot.pid } : {}
2518
+ ...primary && isLiveWorker(primary) && primary.pid !== void 0 ? { workerPid: primary.pid } : {},
2519
+ ...includeWorkers ? { workers } : {}
2124
2520
  });
2125
2521
  } catch (err) {
2126
2522
  daemonLog.warn(
@@ -2133,11 +2529,83 @@ async function runQwenServe(optsIn, deps = {}) {
2133
2529
  () => runtimeStartupError
2134
2530
  );
2135
2531
  const shutdownBridges = /* @__PURE__ */ new WeakSet();
2532
+ const disposedRuntimeApps = /* @__PURE__ */ new WeakSet();
2533
+ const stoppedRuntimeAppProducers = /* @__PURE__ */ new WeakSet();
2534
+ const stoppedExtensionReconcilers = /* @__PURE__ */ new WeakSet();
2535
+ const stopExtensionReconciler = /* @__PURE__ */ __name((app2) => {
2536
+ if (!app2 || stoppedExtensionReconcilers.has(app2)) return;
2537
+ stoppedExtensionReconcilers.add(app2);
2538
+ const stopExtensionGenerationReconciler = app2.locals?.["stopExtensionGenerationReconciler"];
2539
+ try {
2540
+ stopExtensionGenerationReconciler?.();
2541
+ } catch (err) {
2542
+ daemonLog.warn(
2543
+ `extension generation reconciler dispose error: ${err instanceof Error ? err.message : String(err)}`
2544
+ );
2545
+ }
2546
+ }, "stopExtensionReconciler");
2547
+ const stopRuntimeAppProducers = /* @__PURE__ */ __name((app2) => {
2548
+ if (!app2 || stoppedRuntimeAppProducers.has(app2)) return;
2549
+ stoppedRuntimeAppProducers.add(app2);
2550
+ const locals = app2.locals;
2551
+ const stopSafely = /* @__PURE__ */ __name((name, stop) => {
2552
+ try {
2553
+ stop?.();
2554
+ } catch (err) {
2555
+ daemonLog.warn(
2556
+ `${name} dispose error: ${err instanceof Error ? err.message : String(err)}`
2557
+ );
2558
+ }
2559
+ }, "stopSafely");
2560
+ stopSafely("scheduled-task keepalive", locals.stopScheduledTaskKeepalive);
2561
+ stopSafely("workspace git state", locals.stopWorkspaceGitState);
2562
+ for (const stop of locals.subSessionStoppers ?? []) {
2563
+ stopSafely("sub-session launcher", stop);
2564
+ }
2565
+ stopExtensionReconciler(app2);
2566
+ }, "stopRuntimeAppProducers");
2567
+ const disposeRuntimeAppResources = /* @__PURE__ */ __name((app2) => {
2568
+ if (!app2 || disposedRuntimeApps.has(app2)) return;
2569
+ disposedRuntimeApps.add(app2);
2570
+ stopRuntimeAppProducers(app2);
2571
+ const deviceFlowRegistry = getDeviceFlowRegistry(app2);
2572
+ if (deviceFlowRegistry) {
2573
+ try {
2574
+ deviceFlowRegistry.dispose();
2575
+ } catch (err) {
2576
+ daemonLog.warn(
2577
+ `device-flow registry dispose error: ${err instanceof Error ? err.message : String(err)}`
2578
+ );
2579
+ }
2580
+ }
2581
+ const acpHandle = app2.locals?.["acpHandle"];
2582
+ if (acpHandle?.dispose) {
2583
+ try {
2584
+ acpHandle.dispose();
2585
+ } catch (err) {
2586
+ daemonLog.warn(
2587
+ `ACP handle dispose error: ${err instanceof Error ? err.message : String(err)}`
2588
+ );
2589
+ }
2590
+ }
2591
+ const rateLimiter = getRateLimiter(app2);
2592
+ if (rateLimiter) {
2593
+ try {
2594
+ rateLimiter.setDraining(true);
2595
+ rateLimiter.dispose();
2596
+ } catch (err) {
2597
+ daemonLog.warn(
2598
+ `rate limiter dispose error: ${err instanceof Error ? err.message : String(err)}`
2599
+ );
2600
+ }
2601
+ }
2602
+ disposeDaemonEventLoopMonitor();
2603
+ }, "disposeRuntimeAppResources");
2136
2604
  const getRuntimeBridgesForCleanup = /* @__PURE__ */ __name(() => {
2137
2605
  const appForCleanup = runtimeApp ?? runtimeAppForCleanup;
2138
2606
  const registry = appForCleanup?.locals?.["workspaceRegistry"];
2139
2607
  const bridges = [
2140
- ...registry ? registry.list().map((runtime) => runtime.bridge) : [],
2608
+ ...registry ? registry.listManaged().map((runtime) => runtime.bridge) : [],
2141
2609
  ...bridgeRef ? [bridgeRef] : [],
2142
2610
  ...internalRuntimeBridgesForCleanup
2143
2611
  ];
@@ -2319,12 +2787,15 @@ async function runQwenServe(optsIn, deps = {}) {
2319
2787
  // `agent_message_chunk._meta` (`usage` + `durationMs`) at the bridge's
2320
2788
  // single session/update fan-in. Increments (not cumulative), so the ring
2321
2789
  // sums tokens per window (token-burn chart) and pools the round-trip times
2322
- // for the LLM-latency percentiles.
2323
- tokenUsage(inputTokens, outputTokens, durationMs) {
2790
+ // for the LLM-latency percentiles. `apiErrors` / `apiRetries` ride the
2791
+ // same frame (per-round increments, 0 when none) and window into the
2792
+ // model-API-health chart.
2793
+ tokenUsage(inputTokens, outputTokens, durationMs, apiErrors, apiRetries) {
2324
2794
  metricsRing.recordTokens(inputTokens, outputTokens);
2325
2795
  if (typeof durationMs === "number") {
2326
2796
  metricsRing.recordLlmDuration(durationMs);
2327
2797
  }
2798
+ metricsRing.recordApiActivity(apiErrors ?? 0, apiRetries ?? 0);
2328
2799
  }
2329
2800
  };
2330
2801
  return telemetry;
@@ -2414,6 +2885,7 @@ async function runQwenServe(optsIn, deps = {}) {
2414
2885
  getBridges: /* @__PURE__ */ __name(() => runtimeBridges.length > 0 ? runtimeBridges : bridgeRef ? [bridgeRef] : [], "getBridges")
2415
2886
  }
2416
2887
  );
2888
+ const sessionOwnerIndex = runtime.createWorkspaceSessionOwnerIndex();
2417
2889
  const persistDisabledToolsFn = /* @__PURE__ */ __name((workspace, toolName, enabled) => withSettingsLock(workspace, async () => {
2418
2890
  const fresh = settingsRuntime.settings.loadSettings(workspace);
2419
2891
  const wsScope = fresh.forScope(WORKSPACE_SETTING_SCOPE).settings;
@@ -2428,6 +2900,63 @@ async function runQwenServe(optsIn, deps = {}) {
2428
2900
  [...next].sort()
2429
2901
  );
2430
2902
  }), "persistDisabledToolsFn");
2903
+ const persistDisabledSkillsFn = /* @__PURE__ */ __name((workspace, skillName, enabled) => withSettingsLock(workspace, async () => {
2904
+ const fresh = settingsRuntime.settings.loadSettings(workspace);
2905
+ const normalizedName = skillName.trim().toLowerCase();
2906
+ const disabledNames = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.filter(
2907
+ (entry) => typeof entry === "string"
2908
+ ) : [], "disabledNames");
2909
+ const lockedScopes = [
2910
+ ["system", fresh.system.settings.skills?.disabled],
2911
+ ["user", fresh.user.settings.skills?.disabled],
2912
+ ["systemDefaults", fresh.systemDefaults.settings.skills?.disabled]
2913
+ ];
2914
+ for (const [scope, names] of lockedScopes) {
2915
+ if (disabledNames(names).some(
2916
+ (name) => name.trim().toLowerCase() === normalizedName
2917
+ )) {
2918
+ throw new runtime.WorkspaceSkillNotToggleableError(
2919
+ skillName,
2920
+ "locked",
2921
+ scope
2922
+ );
2923
+ }
2924
+ }
2925
+ const workspaceDisabled = disabledNames(
2926
+ fresh.workspace.settings.skills?.disabled
2927
+ );
2928
+ const next = [];
2929
+ let found = false;
2930
+ let changed = false;
2931
+ for (const name of workspaceDisabled) {
2932
+ if (name.trim().toLowerCase() !== normalizedName) {
2933
+ next.push(name);
2934
+ continue;
2935
+ }
2936
+ if (enabled) {
2937
+ changed = true;
2938
+ continue;
2939
+ }
2940
+ if (!found) {
2941
+ next.push(skillName);
2942
+ found = true;
2943
+ if (name !== skillName) changed = true;
2944
+ } else {
2945
+ changed = true;
2946
+ }
2947
+ }
2948
+ if (!enabled && !found) {
2949
+ next.push(skillName);
2950
+ changed = true;
2951
+ }
2952
+ if (!changed) return { changed: false, disabled: workspaceDisabled };
2953
+ fresh.setValue(
2954
+ WORKSPACE_SETTING_SCOPE,
2955
+ "skills.disabled",
2956
+ next.length > 0 ? next : void 0
2957
+ );
2958
+ return { changed: true, disabled: next };
2959
+ }), "persistDisabledSkillsFn");
2431
2960
  const persistSettingFn = /* @__PURE__ */ __name((workspace, scope, key, value) => withSettingsLock(workspace, async () => {
2432
2961
  const fresh = settingsRuntime.settings.loadSettings(workspace);
2433
2962
  fresh.setValue(scope, key, value);
@@ -2460,12 +2989,19 @@ async function runQwenServe(optsIn, deps = {}) {
2460
2989
  );
2461
2990
  }
2462
2991
  }), "persistSettingsFn");
2992
+ const { createSubSessionLauncher } = await import("./create-sub-session-WJOWBFEP.js");
2993
+ const subSessionLauncher = createSubSessionLauncher({
2994
+ getBridge: /* @__PURE__ */ __name(() => bridgeRef, "getBridge"),
2995
+ boundWorkspace
2996
+ });
2463
2997
  const bridge = deps.bridge ?? runtime.createAcpSessionBridge({
2464
2998
  // Reverse tool channel: let `BridgeClient.extMethod` reach the WS
2465
2999
  // connection that hosts a named client MCP server (#5626).
2466
3000
  clientMcpSender: clientMcpSenderRegistry.lookup,
3001
+ onCreateSubSession: subSessionLauncher.launch,
2467
3002
  maxSessions: opts.maxSessions,
2468
3003
  freshSessionAdmission: totalSessionAdmission.admit,
3004
+ sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
2469
3005
  ...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
2470
3006
  ...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
2471
3007
  ...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
@@ -2494,16 +3030,21 @@ async function runQwenServe(optsIn, deps = {}) {
2494
3030
  internalRuntimeBridgesForCleanup.push(bridge);
2495
3031
  }
2496
3032
  runtimeBridges.push(bridge);
3033
+ let invalidatePrimaryServeFeaturesCache = /* @__PURE__ */ __name(() => {
3034
+ }, "invalidatePrimaryServeFeaturesCache");
2497
3035
  const workspaceService = runtime.createDaemonWorkspaceService({
2498
3036
  boundWorkspace,
2499
3037
  contextFilename: contextFilenameForInit ?? "QWEN.md",
2500
3038
  statusProvider,
2501
3039
  workspaceProvidersStatusProvider,
2502
3040
  workspaceSkillsStatusProvider,
3041
+ voiceEnv: runtimeEffectiveEnv,
2503
3042
  isChannelLive: /* @__PURE__ */ __name(() => bridge.isChannelLive(), "isChannelLive"),
2504
3043
  persistDisabledTools: persistDisabledToolsFn,
3044
+ persistDisabledSkills: persistDisabledSkillsFn,
2505
3045
  persistSetting: persistSettingFn,
2506
3046
  persistSettings: persistSettingsFn,
3047
+ preheatAcpChild: /* @__PURE__ */ __name(() => bridge.preheat(), "preheatAcpChild"),
2507
3048
  reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
2508
3049
  const fresh = settingsRuntime.settings.loadSettings(workspace, {
2509
3050
  skipLoadEnvironment: true
@@ -2566,7 +3107,12 @@ async function runQwenServe(optsIn, deps = {}) {
2566
3107
  queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => bridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
2567
3108
  invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => bridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
2568
3109
  refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => bridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
2569
- publishWorkspaceEvent: /* @__PURE__ */ __name((event) => bridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
3110
+ publishWorkspaceEvent: /* @__PURE__ */ __name((event) => {
3111
+ if (event.type === "settings_changed" || event.type === "settings_reloaded") {
3112
+ invalidatePrimaryServeFeaturesCache();
3113
+ }
3114
+ bridge.publishWorkspaceEvent(event);
3115
+ }, "publishWorkspaceEvent")
2570
3116
  });
2571
3117
  const workspaceRuntimes = [
2572
3118
  {
@@ -2574,6 +3120,8 @@ async function runQwenServe(optsIn, deps = {}) {
2574
3120
  workspaceCwd: boundWorkspace,
2575
3121
  primary: true,
2576
3122
  trusted: trustedWorkspace,
3123
+ removable: false,
3124
+ registrationIds: workspaceInputs[0]?.registrationIds ?? [],
2577
3125
  env: primaryRuntimeEnv,
2578
3126
  bridge,
2579
3127
  workspaceService,
@@ -2614,6 +3162,13 @@ async function runQwenServe(optsIn, deps = {}) {
2614
3162
  }
2615
3163
  };
2616
3164
  }, "createRuntimeEnvMetadata");
3165
+ const subSessionStoppers = [];
3166
+ const subSessionStoppersByWorkspace = /* @__PURE__ */ new Map();
3167
+ const runtimeCleanupPromises = /* @__PURE__ */ new WeakMap();
3168
+ const removeArrayValue = /* @__PURE__ */ __name((values, value) => {
3169
+ const index = values.indexOf(value);
3170
+ if (index >= 0) values.splice(index, 1);
3171
+ }, "removeArrayValue");
2617
3172
  for (const workspaceInput of workspaceInputs.slice(1)) {
2618
3173
  let secondarySettings;
2619
3174
  try {
@@ -2667,10 +3222,17 @@ async function runQwenServe(optsIn, deps = {}) {
2667
3222
  ...opts.experimentalLsp === true ? { extraArgs: ["--experimental-lsp"] } : {}
2668
3223
  });
2669
3224
  const secondaryClientMcpSenderRegistry = new ClientMcpSenderRegistry();
3225
+ let secondaryBridgeRef;
3226
+ const secondarySubSessionLauncher = createSubSessionLauncher({
3227
+ getBridge: /* @__PURE__ */ __name(() => secondaryBridgeRef, "getBridge"),
3228
+ boundWorkspace: workspaceInput.cwd
3229
+ });
2670
3230
  const secondaryBridge = runtime.createAcpSessionBridge({
2671
3231
  clientMcpSender: secondaryClientMcpSenderRegistry.lookup,
3232
+ onCreateSubSession: secondarySubSessionLauncher.launch,
2672
3233
  maxSessions: opts.maxSessions,
2673
3234
  freshSessionAdmission: totalSessionAdmission.admit,
3235
+ sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
2674
3236
  ...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
2675
3237
  ...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
2676
3238
  ...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
@@ -2696,8 +3258,14 @@ async function runQwenServe(optsIn, deps = {}) {
2696
3258
  fresh.setValue(WORKSPACE_SETTING_SCOPE, "tools.approvalMode", mode);
2697
3259
  }), "persistApprovalMode")
2698
3260
  });
3261
+ secondaryBridgeRef = secondaryBridge;
2699
3262
  runtimeBridges.push(secondaryBridge);
2700
3263
  internalRuntimeBridgesForCleanup.push(secondaryBridge);
3264
+ subSessionStoppers.push(secondarySubSessionLauncher.stop);
3265
+ subSessionStoppersByWorkspace.set(
3266
+ workspaceInput.cwd,
3267
+ secondarySubSessionLauncher.stop
3268
+ );
2701
3269
  const secondaryWorkspaceService = runtime.createDaemonWorkspaceService({
2702
3270
  boundWorkspace: workspaceInput.cwd,
2703
3271
  contextFilename: contextFilenameForInit ?? "QWEN.md",
@@ -2706,8 +3274,12 @@ async function runQwenServe(optsIn, deps = {}) {
2706
3274
  env: secondaryEnv.effectiveEnv
2707
3275
  }),
2708
3276
  workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
3277
+ voiceEnv: secondaryEnv.effectiveEnv,
3278
+ voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
2709
3279
  isChannelLive: /* @__PURE__ */ __name(() => secondaryBridge.isChannelLive(), "isChannelLive"),
3280
+ preheatAcpChild: /* @__PURE__ */ __name(() => secondaryBridge.preheat(), "preheatAcpChild"),
2710
3281
  persistDisabledTools: persistDisabledToolsFn,
3282
+ persistDisabledSkills: persistDisabledSkillsFn,
2711
3283
  persistSetting: persistSettingFn,
2712
3284
  persistSettings: persistSettingsFn,
2713
3285
  reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
@@ -2765,6 +3337,8 @@ async function runQwenServe(optsIn, deps = {}) {
2765
3337
  workspaceCwd: workspaceInput.cwd,
2766
3338
  primary: false,
2767
3339
  trusted: secondaryTrusted,
3340
+ removable: workspaceInput.removable,
3341
+ registrationIds: workspaceInput.registrationIds,
2768
3342
  env: secondaryEnv.metadata,
2769
3343
  bridge: secondaryBridge,
2770
3344
  workspaceService: secondaryWorkspaceService,
@@ -2772,7 +3346,10 @@ async function runQwenServe(optsIn, deps = {}) {
2772
3346
  clientMcpSenderRegistry: secondaryClientMcpSenderRegistry
2773
3347
  });
2774
3348
  }
2775
- const workspaceRegistry = runtime.createWorkspaceRegistry(workspaceRuntimes);
3349
+ const workspaceRegistry = runtime.createWorkspaceRegistry(workspaceRuntimes, {
3350
+ sessionOwnerIndex
3351
+ });
3352
+ const workspaceVoiceCoordinator = new WorkspaceVoiceCoordinator();
2776
3353
  core.registerDaemonGaugeCallbacks({
2777
3354
  sessionCount: /* @__PURE__ */ __name(() => workspaceRegistry.list().reduce((sum, item) => sum + item.bridge.sessionCount, 0), "sessionCount"),
2778
3355
  sseCount: /* @__PURE__ */ __name(() => runtime.getActiveSseCount(), "sseCount"),
@@ -2801,7 +3378,7 @@ async function runQwenServe(optsIn, deps = {}) {
2801
3378
  prevCpu = cpu;
2802
3379
  prevCpuAt = nowMs;
2803
3380
  }
2804
- const acp = app2.locals?.["acpHandle"]?.registry.getSnapshot();
3381
+ const acp = app2.locals?.["acpHandle"]?.getSnapshot();
2805
3382
  const hits = getRateLimiter(app2)?.getHitCounts();
2806
3383
  const rejectedTotal = hits ? hits.prompt + hits.mutation + hits.read : 0;
2807
3384
  const rateLimitRejected = prevRateRejected === void 0 ? 0 : Math.max(0, rejectedTotal - prevRateRejected);
@@ -2864,8 +3441,317 @@ async function runQwenServe(optsIn, deps = {}) {
2864
3441
  metricsLoopDelay.disable();
2865
3442
  }
2866
3443
  };
3444
+ const createDynamicWorkspaceRuntime = /* @__PURE__ */ __name(async (cwd) => {
3445
+ let wsSettings;
3446
+ try {
3447
+ wsSettings = settingsRuntime.settings.loadSettings(cwd);
3448
+ } catch (err) {
3449
+ writeStderrLine(
3450
+ `qwen serve: could not read full settings for dynamic workspace ${cwd} (${err instanceof Error ? err.message : String(err)}); falling back to defaults.`
3451
+ );
3452
+ }
3453
+ const trusted = wsSettings ? settingsRuntime.trustedFolders.getWorkspaceTrustStatus(
3454
+ wsSettings.merged,
3455
+ cwd
3456
+ ).effective.state === "trusted" : false;
3457
+ const wsEnv = createRuntimeEnvMetadata(cwd, wsSettings);
3458
+ const wsHash = core.hashDaemonWorkspace(cwd);
3459
+ const wsFsFactory = runtime.resolveBridgeFsFactory({
3460
+ boundWorkspaces: [cwd],
3461
+ trusted,
3462
+ emit: deps.fsAuditEmit,
3463
+ pathLocks: sharedPathLocks,
3464
+ ...customIgnoreFiles !== void 0 ? { customIgnoreFiles } : {}
3465
+ });
3466
+ const wsChannelFactory = runtime.createSpawnChannelFactory({
3467
+ sourceEnv: wsEnv.effectiveEnv,
3468
+ onDiagnosticLine: diagnosticSink,
3469
+ pipeHooks: {
3470
+ onMessageSent: /* @__PURE__ */ __name((bytes) => recordPipeMessage("outbound", bytes), "onMessageSent"),
3471
+ onMessageReceived: /* @__PURE__ */ __name((bytes) => recordPipeMessage("inbound", bytes), "onMessageReceived"),
3472
+ onMessageObserved: /* @__PURE__ */ __name(({ direction, bytes, message }) => observeLargePipeFrame({
3473
+ direction: daemonPipeDirection(direction),
3474
+ bytes,
3475
+ message
3476
+ }), "onMessageObserved")
3477
+ },
3478
+ ...opts.experimentalLsp === true ? { extraArgs: ["--experimental-lsp"] } : {}
3479
+ });
3480
+ const wsClientMcpRegistry = new ClientMcpSenderRegistry();
3481
+ let wsBridgeRef;
3482
+ const wsSubSessionLauncher = createSubSessionLauncher({
3483
+ getBridge: /* @__PURE__ */ __name(() => wsBridgeRef, "getBridge"),
3484
+ boundWorkspace: cwd
3485
+ });
3486
+ let wsBridge;
3487
+ try {
3488
+ wsBridge = runtime.createAcpSessionBridge({
3489
+ clientMcpSender: wsClientMcpRegistry.lookup,
3490
+ onCreateSubSession: wsSubSessionLauncher.launch,
3491
+ maxSessions: opts.maxSessions,
3492
+ freshSessionAdmission: totalSessionAdmission.admit,
3493
+ sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
3494
+ ...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
3495
+ ...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
3496
+ ...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
3497
+ ...opts.channelIdleTimeoutMs !== void 0 ? { channelIdleTimeoutMs: opts.channelIdleTimeoutMs } : {},
3498
+ ...opts.sessionReapIntervalMs !== void 0 ? { sessionReapIntervalMs: opts.sessionReapIntervalMs } : {},
3499
+ ...opts.sessionIdleTimeoutMs !== void 0 ? { sessionIdleTimeoutMs: opts.sessionIdleTimeoutMs } : {},
3500
+ ...opts.permissionResponseTimeoutMs !== void 0 ? { permissionResponseTimeoutMs: opts.permissionResponseTimeoutMs } : {},
3501
+ boundWorkspace: cwd,
3502
+ sessionShellCommandEnabled,
3503
+ childEnvOverrides,
3504
+ channelFactory: wsChannelFactory,
3505
+ onDiagnosticLine: diagnosticSink,
3506
+ telemetry: createRuntimeBridgeTelemetry(wsHash),
3507
+ ...permissionPolicy !== void 0 ? { permissionPolicy } : {},
3508
+ ...permissionConsensusQuorum !== void 0 ? { permissionConsensusQuorum } : {},
3509
+ permissionAudit: permissionAuditPublisher,
3510
+ statusProvider: runtime.createDaemonStatusProvider({
3511
+ env: wsEnv.effectiveEnv
3512
+ }),
3513
+ fileSystem: createBridgeFileSystemAdapter(wsFsFactory),
3514
+ persistApprovalMode: /* @__PURE__ */ __name((workspace, mode) => withSettingsLock(workspace, async () => {
3515
+ const fresh = settingsRuntime.settings.loadSettings(workspace);
3516
+ fresh.setValue(
3517
+ WORKSPACE_SETTING_SCOPE,
3518
+ "tools.approvalMode",
3519
+ mode
3520
+ );
3521
+ }), "persistApprovalMode")
3522
+ });
3523
+ } catch (err) {
3524
+ wsSubSessionLauncher.stop();
3525
+ throw err;
3526
+ }
3527
+ wsBridgeRef = wsBridge;
3528
+ let wsService;
3529
+ try {
3530
+ wsService = runtime.createDaemonWorkspaceService({
3531
+ boundWorkspace: cwd,
3532
+ contextFilename: contextFilenameForInit ?? "QWEN.md",
3533
+ statusProvider: runtime.createDaemonStatusProvider({
3534
+ env: wsEnv.effectiveEnv
3535
+ }),
3536
+ workspaceProvidersStatusProvider: runtime.createWorkspaceProvidersStatusProvider({
3537
+ env: wsEnv.effectiveEnv
3538
+ }),
3539
+ workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
3540
+ voiceEnv: wsEnv.effectiveEnv,
3541
+ voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
3542
+ isChannelLive: /* @__PURE__ */ __name(() => wsBridge.isChannelLive(), "isChannelLive"),
3543
+ preheatAcpChild: /* @__PURE__ */ __name(() => wsBridge.preheat(), "preheatAcpChild"),
3544
+ persistDisabledTools: persistDisabledToolsFn,
3545
+ persistDisabledSkills: persistDisabledSkillsFn,
3546
+ persistSetting: persistSettingFn,
3547
+ persistSettings: persistSettingsFn,
3548
+ reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
3549
+ const fresh = settingsRuntime.settings.loadSettings(workspace, {
3550
+ skipLoadEnvironment: true
3551
+ });
3552
+ const result = settingsRuntime.settings.reloadEnvironment(
3553
+ fresh.merged,
3554
+ workspace
3555
+ );
3556
+ try {
3557
+ const refreshedRuntimeEnv = settingsRuntime.environment.buildRuntimeEnvironment(
3558
+ fresh.merged,
3559
+ workspace,
3560
+ daemonRuntimeBaseEnv
3561
+ );
3562
+ logRuntimeEnvFileReadFailures(workspace, refreshedRuntimeEnv);
3563
+ wsEnv.replace(refreshedRuntimeEnv.effectiveEnv);
3564
+ wsEnv.metadata.envFileReadFailed = refreshedRuntimeEnv.envFileReadFailed;
3565
+ wsEnv.metadata.envFileReadFailures.splice(
3566
+ 0,
3567
+ wsEnv.metadata.envFileReadFailures.length,
3568
+ ...refreshedRuntimeEnv.envFileReadFailures
3569
+ );
3570
+ wsEnv.metadata.overlayKeys.splice(
3571
+ 0,
3572
+ wsEnv.metadata.overlayKeys.length,
3573
+ ...refreshedRuntimeEnv.overlayKeys
3574
+ );
3575
+ wsEnv.metadata.envFilePaths.splice(
3576
+ 0,
3577
+ wsEnv.metadata.envFilePaths.length,
3578
+ ...refreshedRuntimeEnv.envFilePaths
3579
+ );
3580
+ delete wsEnv.metadata.fallbackReason;
3581
+ } catch (err) {
3582
+ wsEnv.metadata.fallbackReason = err instanceof Error ? err.message : String(err);
3583
+ daemonLog.warn(
3584
+ "failed to rebuild dynamic runtime env snapshot after daemon env reload; preserving previous runtime env",
3585
+ {
3586
+ workspace,
3587
+ error: wsEnv.metadata.fallbackReason
3588
+ }
3589
+ );
3590
+ }
3591
+ return result;
3592
+ }), "reloadDaemonEnv"),
3593
+ queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => wsBridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
3594
+ invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => wsBridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
3595
+ refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => wsBridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
3596
+ publishWorkspaceEvent: /* @__PURE__ */ __name((event) => wsBridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
3597
+ });
3598
+ } catch (err) {
3599
+ wsSubSessionLauncher.stop();
3600
+ await wsBridge.shutdown().catch(() => {
3601
+ try {
3602
+ wsBridge.killAllSync();
3603
+ } catch {
3604
+ }
3605
+ });
3606
+ throw err;
3607
+ }
3608
+ runtimeBridges.push(wsBridge);
3609
+ internalRuntimeBridgesForCleanup.push(wsBridge);
3610
+ subSessionStoppers.push(wsSubSessionLauncher.stop);
3611
+ subSessionStoppersByWorkspace.set(cwd, wsSubSessionLauncher.stop);
3612
+ return {
3613
+ workspaceId: wsHash,
3614
+ workspaceCwd: cwd,
3615
+ primary: false,
3616
+ trusted,
3617
+ removable: true,
3618
+ registrationIds: [],
3619
+ env: wsEnv.metadata,
3620
+ bridge: wsBridge,
3621
+ workspaceService: wsService,
3622
+ routeFileSystemFactory: wsFsFactory,
3623
+ clientMcpSenderRegistry: wsClientMcpRegistry
3624
+ };
3625
+ }, "createDynamicWorkspaceRuntime");
3626
+ const workspaceRuntimeRemoval = {
3627
+ async runtimeAdded(runtimeAdded) {
3628
+ const app3 = runtimeApp ?? runtimeAppForCleanup;
3629
+ const startScheduledTaskKeepaliveForWorkspace = app3?.locals?.["startScheduledTaskKeepaliveForWorkspace"];
3630
+ startScheduledTaskKeepaliveForWorkspace?.(runtimeAdded);
3631
+ if (!channelWorkerManager) return;
3632
+ try {
3633
+ await channelWorkerManager.restoreWorkspace(
3634
+ runtimeAdded.workspaceCwd
3635
+ );
3636
+ await channelWorkerManager.refreshWorkspaces();
3637
+ } catch (err) {
3638
+ daemonLog.error(
3639
+ "workspace channel worker startup error",
3640
+ err instanceof Error ? err : null
3641
+ );
3642
+ } finally {
3643
+ writeChannelWorkerPidfile();
3644
+ }
3645
+ },
3646
+ beginDrain(runtimeToDrain) {
3647
+ totalSessionAdmission.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
3648
+ channelWorkerManager?.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
3649
+ workspaceVoiceCoordinator.beginWorkspaceDrain(runtimeToDrain);
3650
+ },
3651
+ cancelDrain(runtimeToDrain) {
3652
+ channelWorkerManager?.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
3653
+ totalSessionAdmission.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
3654
+ workspaceVoiceCoordinator.cancelWorkspaceDrain(runtimeToDrain);
3655
+ },
3656
+ completeDrain(runtimeToDrain) {
3657
+ totalSessionAdmission.completeWorkspaceDrain(
3658
+ runtimeToDrain.workspaceCwd
3659
+ );
3660
+ workspaceVoiceCoordinator.completeWorkspaceDrain(runtimeToDrain);
3661
+ },
3662
+ getActivity(runtimeToDrain) {
3663
+ return {
3664
+ pendingSessionStarts: totalSessionAdmission.snapshotForWorkspace(
3665
+ runtimeToDrain.workspaceCwd
3666
+ ).inFlight,
3667
+ channelWorkers: channelWorkerManager?.workspaceActivity(
3668
+ runtimeToDrain.workspaceCwd
3669
+ ) ?? 0,
3670
+ voiceSessions: workspaceVoiceCoordinator.getWorkspaceActivity(runtimeToDrain)
3671
+ };
3672
+ },
3673
+ disposeRuntime(runtimeToDrain, reason = "workspace_removed") {
3674
+ const existing = runtimeCleanupPromises.get(runtimeToDrain);
3675
+ if (existing) return existing;
3676
+ const cleanup = (async () => {
3677
+ await workspaceVoiceCoordinator.disposeRuntime(
3678
+ runtimeToDrain,
3679
+ reason
3680
+ );
3681
+ const stopSubSessions = subSessionStoppersByWorkspace.get(
3682
+ runtimeToDrain.workspaceCwd
3683
+ );
3684
+ try {
3685
+ stopSubSessions?.();
3686
+ } catch {
3687
+ }
3688
+ if (reason === "workspace_removed" && channelWorkerManager) {
3689
+ await channelWorkerManager.removeWorkspace(runtimeToDrain.workspaceCwd).catch((err) => {
3690
+ daemonLog.error(
3691
+ "workspace channel worker cleanup error",
3692
+ err instanceof Error ? err : null
3693
+ );
3694
+ });
3695
+ try {
3696
+ await channelWorkerManager.refreshWorkspaces();
3697
+ } catch (err) {
3698
+ channelWorkspaceGroups = (channelWorkspaceGroups ?? []).filter(
3699
+ (group) => group.workspaceCwd !== runtimeToDrain.workspaceCwd
3700
+ );
3701
+ channelWebhookConfigVersion += 1;
3702
+ refreshChannelWebhookConfigs?.();
3703
+ daemonLog.error(
3704
+ "workspace channel worker topology refresh error",
3705
+ err instanceof Error ? err : null
3706
+ );
3707
+ }
3708
+ writeChannelWorkerPidfile();
3709
+ }
3710
+ if (reason === "workspace_removed") {
3711
+ const app3 = runtimeApp ?? runtimeAppForCleanup;
3712
+ const stopWorkspaceGitStateForWorkspace = app3?.locals?.["stopWorkspaceGitStateForWorkspace"];
3713
+ const stopScheduledTaskKeepaliveForWorkspace = app3?.locals?.["stopScheduledTaskKeepaliveForWorkspace"];
3714
+ stopWorkspaceGitStateForWorkspace?.(runtimeToDrain.workspaceCwd);
3715
+ stopScheduledTaskKeepaliveForWorkspace?.(
3716
+ runtimeToDrain.workspaceCwd
3717
+ );
3718
+ }
3719
+ let bridgeStopped = false;
3720
+ try {
3721
+ if (!shutdownBridges.has(runtimeToDrain.bridge)) {
3722
+ await runtimeToDrain.bridge.shutdown({ reason });
3723
+ }
3724
+ bridgeStopped = true;
3725
+ } finally {
3726
+ if (bridgeStopped || reason === "workspace_removed") {
3727
+ subSessionStoppersByWorkspace.delete(runtimeToDrain.workspaceCwd);
3728
+ if (stopSubSessions) {
3729
+ removeArrayValue(subSessionStoppers, stopSubSessions);
3730
+ }
3731
+ removeArrayValue(runtimeBridges, runtimeToDrain.bridge);
3732
+ removeArrayValue(
3733
+ internalRuntimeBridgesForCleanup,
3734
+ runtimeToDrain.bridge
3735
+ );
3736
+ shutdownBridges.add(runtimeToDrain.bridge);
3737
+ }
3738
+ }
3739
+ })();
3740
+ runtimeCleanupPromises.set(runtimeToDrain, cleanup);
3741
+ void cleanup.catch(() => {
3742
+ if (reason === "daemon_shutdown" && runtimeCleanupPromises.get(runtimeToDrain) === cleanup) {
3743
+ runtimeCleanupPromises.delete(runtimeToDrain);
3744
+ }
3745
+ });
3746
+ return cleanup;
3747
+ }
3748
+ };
2867
3749
  const app2 = runtime.createServeApp(opts, () => actualPort, {
2868
3750
  workspaceRegistry,
3751
+ createWorkspaceRuntime: createDynamicWorkspaceRuntime,
3752
+ workspaceRegistrationStore,
3753
+ workspaceRuntimeRemoval,
3754
+ voiceCoordinator: workspaceVoiceCoordinator,
2869
3755
  bridge,
2870
3756
  webShellDir,
2871
3757
  boundWorkspace,
@@ -2880,6 +3766,27 @@ async function runQwenServe(optsIn, deps = {}) {
2880
3766
  primaryRuntimeEnv,
2881
3767
  daemonLog,
2882
3768
  getChannelWorkerSnapshot,
3769
+ getChannelWorkerSnapshots,
3770
+ getChannelWorkerControl,
3771
+ isChannelControlDraining: /* @__PURE__ */ __name(() => channelControlDraining, "isChannelControlDraining"),
3772
+ isChannelControlInitializing: /* @__PURE__ */ __name(() => channelWorkerManagerStarting !== void 0, "isChannelControlInitializing"),
3773
+ setChannelWorkerSelection,
3774
+ stopChannelWorker,
3775
+ getChannelWebhookConfigSources,
3776
+ getChannelWebhookConfigVersion: /* @__PURE__ */ __name(() => channelWebhookConfigVersion, "getChannelWebhookConfigVersion"),
3777
+ registerChannelWebhookConfigRefresh: /* @__PURE__ */ __name((refresh) => {
3778
+ refreshChannelWebhookConfigs = refresh;
3779
+ }, "registerChannelWebhookConfigRefresh"),
3780
+ enqueueChannelWebhookTask: /* @__PURE__ */ __name(async (task) => {
3781
+ if (!channelWorkerManager) {
3782
+ throw new ChannelWebhookEnqueueError(
3783
+ "channel_worker_unavailable",
3784
+ "Channel worker is not running."
3785
+ );
3786
+ }
3787
+ return channelWorkerManager.enqueueWebhookTask(task);
3788
+ }, "enqueueChannelWebhookTask"),
3789
+ reloadChannelWorker,
2883
3790
  getPerfSnapshot: /* @__PURE__ */ __name(() => ({
2884
3791
  eventLoop: currentDaemonEventLoopMonitor.snapshot(),
2885
3792
  promptQueueWait: {
@@ -2901,8 +3808,12 @@ async function runQwenServe(optsIn, deps = {}) {
2901
3808
  // so the WS provider and the child-answering bridge share one sender map.
2902
3809
  clientMcpSenderRegistry,
2903
3810
  persistDisabledTools: persistDisabledToolsFn,
3811
+ persistDisabledSkills: persistDisabledSkillsFn,
2904
3812
  persistSetting: persistSettingFn,
2905
3813
  persistSettings: persistSettingsFn,
3814
+ sessionArtifactsPersistenceAvailable: sessionArtifactsPersistenceAvailableFromSettings(
3815
+ runtimeBootSettings?.merged
3816
+ ),
2906
3817
  installAuthProvider: /* @__PURE__ */ __name((req) => withSettingsLock(
2907
3818
  boundWorkspace,
2908
3819
  async () => {
@@ -2941,14 +3852,18 @@ async function runQwenServe(optsIn, deps = {}) {
2941
3852
  }
2942
3853
  ), "installAuthProvider")
2943
3854
  });
3855
+ invalidatePrimaryServeFeaturesCache = app2.locals.invalidateServeFeaturesCache ?? invalidatePrimaryServeFeaturesCache;
3856
+ app2.locals.subSessionStoppers = subSessionStoppers;
3857
+ subSessionStoppers.push(subSessionLauncher.stop);
3858
+ subSessionStoppersByWorkspace.set(boundWorkspace, subSessionLauncher.stop);
2944
3859
  return { app: app2, bridge };
2945
3860
  }, "buildRuntime");
2946
3861
  if (deps.bridge) {
2947
3862
  const runtime = await buildRuntime();
2948
3863
  runtimeAppForCleanup = runtime.app;
2949
- runtimeApp = runtime.app;
2950
3864
  bridgeRef = runtime.bridge;
2951
3865
  if (!opts.channelSelection) {
3866
+ runtimeApp = runtime.app;
2952
3867
  runtimeStartupSettled = true;
2953
3868
  markRuntimeReady();
2954
3869
  }
@@ -2962,17 +3877,25 @@ async function runQwenServe(optsIn, deps = {}) {
2962
3877
  daemonLog,
2963
3878
  qwenCodeVersion: cliVersion,
2964
3879
  sessionShellCommandEnabled,
3880
+ sessionArtifactsPersistenceAvailable,
2965
3881
  permissionPolicy,
2966
3882
  multiWorkspaceCapabilitiesRequireRuntime: workspaceInputs.length > 1,
2967
3883
  getRuntimeError: /* @__PURE__ */ __name(() => runtimeStartupError, "getRuntimeError"),
2968
3884
  getChannelWorkerSnapshot,
3885
+ getChannelWorkerSnapshots,
2969
3886
  onHealthServed: deferRuntimeUntilFirstHealth ? () => startRuntimeAfterHealth?.() : void 0
2970
3887
  });
3888
+ const deferredChannelWebhookAuth = deferRuntimeUntilFirstHealth ? createDeferredChannelWebhookAuth(
3889
+ resolveChannelWebhookConfigSource,
3890
+ await loadChannelWebhookConfigRuntime(),
3891
+ daemonLog
3892
+ ) : void 0;
2971
3893
  const app = runtimeApp ?? createDelegatingServeApp(bootstrapApp, () => runtimeApp, {
2972
3894
  waitForDeferredRuntimeRoutes: deferRuntimeUntilFirstHealth,
2973
3895
  startRuntime: /* @__PURE__ */ __name(() => startRuntimeForRequest?.(), "startRuntime"),
2974
3896
  runtimeReady,
2975
- authenticateDeferredRuntimeRequest: bearerAuth(opts.token)
3897
+ authenticateDeferredRuntimeRequest: bearerAuth(opts.token),
3898
+ authenticateDeferredChannelWebhookRequest: deferredChannelWebhookAuth
2976
3899
  });
2977
3900
  let listenHostname = opts.hostname;
2978
3901
  if (opts.hostname.startsWith("[")) {
@@ -2989,7 +3912,70 @@ async function runQwenServe(optsIn, deps = {}) {
2989
3912
  `Invalid maxConnections: ${opts.maxConnections}. Must be >= 0 (0 / Infinity = unlimited).`
2990
3913
  );
2991
3914
  }
2992
- reserveChannelServicePidfile();
3915
+ const channelValidationSettingsRuntime = opts.channelSelection ? await loadSettingsRuntimeModules() : void 0;
3916
+ const resolveChannelWorkspaceGroupsAtListen = /* @__PURE__ */ __name(() => {
3917
+ if (!opts.channelSelection || !channelValidationSettingsRuntime || !channelRuntime) {
3918
+ return void 0;
3919
+ }
3920
+ const settingsByWorkspace = /* @__PURE__ */ new Map();
3921
+ if (workspaceInputs.length === 1) {
3922
+ const workspace = workspaceInputs[0];
3923
+ const settings = channelValidationSettingsRuntime.settings.loadSettings(
3924
+ workspace.cwd
3925
+ );
3926
+ channelWebhookEnvByWorkspace.set(
3927
+ workspace.cwd,
3928
+ channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
3929
+ settings.merged,
3930
+ workspace.cwd,
3931
+ daemonRuntimeBaseEnv
3932
+ ).effectiveEnv
3933
+ );
3934
+ return void 0;
3935
+ }
3936
+ const workspaces = workspaceInputs.map((workspace, index) => {
3937
+ const settings = channelValidationSettingsRuntime.settings.loadSettings(
3938
+ workspace.cwd
3939
+ );
3940
+ settingsByWorkspace.set(workspace.cwd, settings);
3941
+ channelWebhookEnvByWorkspace.set(
3942
+ workspace.cwd,
3943
+ channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
3944
+ settings.merged,
3945
+ workspace.cwd,
3946
+ daemonRuntimeBaseEnv
3947
+ ).effectiveEnv
3948
+ );
3949
+ const trusted = index === 0 && deps.trustedWorkspace !== void 0 ? deps.trustedWorkspace : channelValidationSettingsRuntime.trustedFolders.getWorkspaceTrustStatus(
3950
+ settings.merged,
3951
+ workspace.cwd
3952
+ ).effective.state === "trusted";
3953
+ return {
3954
+ workspaceCwd: workspace.cwd,
3955
+ primary: index === 0,
3956
+ trusted
3957
+ };
3958
+ });
3959
+ const grouping = resolveChannelWorkspaceGroups({
3960
+ workspaces,
3961
+ selection: opts.channelSelection,
3962
+ loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
3963
+ const settings = settingsByWorkspace.get(cwd);
3964
+ if (!settings) return {};
3965
+ return channelRuntime.loadChannelsConfig(cwd, settings);
3966
+ }, "loadChannelsConfig")
3967
+ });
3968
+ if (!grouping.ok) {
3969
+ throw Object.assign(new Error(grouping.error.message), {
3970
+ code: grouping.error.code,
3971
+ ...grouping.error.channel ? { channel: grouping.error.channel } : {}
3972
+ });
3973
+ }
3974
+ return grouping.groups;
3975
+ }, "resolveChannelWorkspaceGroupsAtListen");
3976
+ if (opts.channelSelection) {
3977
+ reserveChannelServicePidfile(opts.channelSelection);
3978
+ }
2993
3979
  return await new Promise((resolve, reject) => {
2994
3980
  const onListening = /* @__PURE__ */ __name(() => {
2995
3981
  startup.listenerReadyAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -3008,45 +3994,14 @@ async function runQwenServe(optsIn, deps = {}) {
3008
3994
  const scheme = tlsOptions ? "https" : "http";
3009
3995
  const url = `${scheme}://${formatHostForUrl(opts.hostname)}:${actualPort}`;
3010
3996
  try {
3011
- if (opts.channelSelection) {
3012
- const createSupervisor = deps.channelWorkerSupervisorFactory ?? channelRuntime?.createChannelWorkerSupervisor;
3013
- if (!createSupervisor) {
3014
- throw new Error(
3015
- "Channel worker supervisor runtime is not available."
3016
- );
3017
- }
3018
- channelWorker = createSupervisor({
3019
- cliEntryPath: findCliEntryPath(),
3020
- daemonUrl: formatChannelWorkerDaemonUrl(opts.hostname, actualPort),
3021
- ...token ? { daemonToken: token } : {},
3022
- workspace: boundWorkspace,
3023
- selection: opts.channelSelection,
3024
- onReady: /* @__PURE__ */ __name((snapshot) => {
3025
- writeChannelWorkerPidfile(snapshot);
3026
- }, "onReady"),
3027
- onLog: /* @__PURE__ */ __name(({ stream, line }) => {
3028
- const message = `channel worker ${stream}: ${line}`;
3029
- if (stream === "stderr") {
3030
- daemonLog.warn(message);
3031
- } else {
3032
- daemonLog.info(message);
3033
- }
3034
- }, "onLog"),
3035
- onExit: /* @__PURE__ */ __name((snapshot) => {
3036
- daemonLog.warn(
3037
- `channel worker exited (state=${snapshot.state}, pid=${snapshot.pid ?? "unknown"}, code=${snapshot.exitCode ?? "null"}, signal=${snapshot.signal ?? "null"}, error=${snapshot.error ?? "none"}, restartCount=${snapshot.restartCount ?? 0}, nextRestartAt=${snapshot.nextRestartAt ?? "none"}, staleHeartbeatAt=${snapshot.staleHeartbeatAt ?? "none"})`
3038
- );
3039
- writeChannelWorkerPidfile(snapshot, { clearWorkerPid: true });
3040
- }, "onExit")
3041
- });
3042
- }
3997
+ channelWorkspaceGroups = resolveChannelWorkspaceGroupsAtListen();
3043
3998
  } catch (err) {
3044
3999
  removeCurrentServePidfile();
3045
4000
  const error = err instanceof Error ? err : new Error(String(err));
3046
4001
  server.close((closeErr) => {
3047
4002
  if (closeErr) {
3048
4003
  daemonLog.error(
3049
- "server close after channel worker setup error failed",
4004
+ "server close after channel worker validation error failed",
3050
4005
  closeErr
3051
4006
  );
3052
4007
  }
@@ -3054,6 +4009,19 @@ async function runQwenServe(optsIn, deps = {}) {
3054
4009
  });
3055
4010
  return;
3056
4011
  }
4012
+ if (channelWorkspaceGroups) {
4013
+ for (const group of channelWorkspaceGroups) {
4014
+ daemonLog.info("channel worker group assigned", {
4015
+ workspace: group.workspaceCwd,
4016
+ channels: group.selection.mode === "all" ? ["all"] : group.selection.names
4017
+ });
4018
+ }
4019
+ if (opts.channelSelection?.mode === "all") {
4020
+ writeStderrLine(
4021
+ "qwen serve: --channel all is primary-workspace only; non-primary workspace channels are not hosted."
4022
+ );
4023
+ }
4024
+ }
3057
4025
  writeStdoutLine(
3058
4026
  `qwen serve listening on ${url} (mode=${opts.mode}, workspace=${boundWorkspace})`
3059
4027
  );
@@ -3129,20 +4097,28 @@ async function runQwenServe(optsIn, deps = {}) {
3129
4097
  }
3130
4098
  }, "shutdownBridgeAfterFailedStartup");
3131
4099
  const stopChannelWorkerAfterFailedStartup = /* @__PURE__ */ __name(async () => {
3132
- await channelWorker.stop().catch((stopErr) => {
4100
+ if (!channelWorkerManager) return true;
4101
+ try {
4102
+ await channelWorkerManager.shutdown();
4103
+ return true;
4104
+ } catch (stopErr) {
3133
4105
  daemonLog.error(
3134
4106
  "channel worker stop after runtime startup error failed",
3135
4107
  stopErr instanceof Error ? stopErr : null
3136
4108
  );
3137
- });
4109
+ return false;
4110
+ }
3138
4111
  }, "stopChannelWorkerAfterFailedStartup");
3139
4112
  const failRuntimeStartup = /* @__PURE__ */ __name(async (err, bridgeForCleanup) => {
3140
4113
  const error = err instanceof Error ? err : new Error(String(err));
3141
4114
  if (runtimeStartupSettled) {
4115
+ disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
3142
4116
  await shutdownBridgeAfterFailedStartup(bridgeForCleanup);
3143
4117
  return;
3144
4118
  }
3145
4119
  runtimeStartupSettled = true;
4120
+ disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
4121
+ runtimeApp = void 0;
3146
4122
  clearRuntimeStartupTimer();
3147
4123
  const message = error.message;
3148
4124
  runtimeStartupError = message;
@@ -3152,14 +4128,28 @@ async function runQwenServe(optsIn, deps = {}) {
3152
4128
  }
3153
4129
  writeStderrLine(`qwen serve: runtime startup failed: ${message}`);
3154
4130
  daemonLog.error("runtime startup failed", error);
3155
- await stopChannelWorkerAfterFailedStartup();
4131
+ markRuntimeFailed(error);
4132
+ if (closeServerAfterChannelWorkerStartupFailure && server.listening) {
4133
+ runtimeFailureListenerClose = new Promise((resolve2) => {
4134
+ server.close((closeErr) => {
4135
+ if (closeErr) {
4136
+ daemonLog.error(
4137
+ "server close after runtime startup error failed",
4138
+ closeErr
4139
+ );
4140
+ }
4141
+ resolve2();
4142
+ });
4143
+ });
4144
+ server.closeAllConnections();
4145
+ }
4146
+ const channelWorkerStopped = await stopChannelWorkerAfterFailedStartup();
3156
4147
  disposeDaemonEventLoopMonitor();
3157
- removeCurrentServePidfile();
4148
+ if (channelWorkerStopped) removeCurrentServePidfile();
3158
4149
  const bridgesForCleanup = bridgeForCleanup ? [bridgeForCleanup, ...getRuntimeBridgesForCleanup()] : getRuntimeBridgesForCleanup();
3159
4150
  for (const bridge of [...new Set(bridgesForCleanup)]) {
3160
4151
  await shutdownBridgeAfterFailedStartup(bridge);
3161
4152
  }
3162
- markRuntimeFailed(error);
3163
4153
  }, "failRuntimeStartup");
3164
4154
  const armRuntimeStartupTimer = /* @__PURE__ */ __name(() => {
3165
4155
  if (runtimeStartupTimeoutMs <= 0 || runtimeStartupTimer) return;
@@ -3172,10 +4162,152 @@ async function runQwenServe(optsIn, deps = {}) {
3172
4162
  }, runtimeStartupTimeoutMs);
3173
4163
  runtimeStartupTimer.unref();
3174
4164
  }, "armRuntimeStartupTimer");
3175
- const completeRuntimeStartup = /* @__PURE__ */ __name(async () => {
4165
+ const resolveRuntimeChannelGroups = /* @__PURE__ */ __name(async (channelSelection, candidateApp, operation) => {
4166
+ const registry = candidateApp.locals?.["workspaceRegistry"];
4167
+ if (!registry) {
4168
+ throw new Error(
4169
+ "Workspace registry is not available for channel workers."
4170
+ );
4171
+ }
4172
+ const runtimes = registry.list();
4173
+ if (runtimes.length <= 1 && operation === "initial") {
4174
+ return [
4175
+ {
4176
+ workspaceCwd: registry.primary.workspaceCwd,
4177
+ selection: channelSelection
4178
+ }
4179
+ ];
4180
+ }
4181
+ const workerRuntime = await ensureChannelRuntime();
4182
+ const settingsRuntime = await loadSettingsRuntimeModules();
4183
+ const settingsByWorkspace = /* @__PURE__ */ new Map();
4184
+ const grouping = resolveChannelWorkspaceGroups({
4185
+ workspaces: runtimes.map((runtime) => {
4186
+ const settings = settingsRuntime.settings.loadSettings(
4187
+ runtime.workspaceCwd
4188
+ );
4189
+ settingsByWorkspace.set(runtime.workspaceCwd, settings);
4190
+ return {
4191
+ workspaceCwd: runtime.workspaceCwd,
4192
+ primary: runtime.primary,
4193
+ trusted: runtime.trusted
4194
+ };
4195
+ }),
4196
+ selection: channelSelection,
4197
+ loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
4198
+ const settings = settingsByWorkspace.get(cwd);
4199
+ return settings ? workerRuntime.loadChannelsConfig(cwd, settings) : {};
4200
+ }, "loadChannelsConfig")
4201
+ });
4202
+ if (!grouping.ok) {
4203
+ throw Object.assign(new Error(grouping.error.message), {
4204
+ code: grouping.error.code,
4205
+ ...grouping.error.channel ? { channel: grouping.error.channel } : {}
4206
+ });
4207
+ }
4208
+ return grouping.groups;
4209
+ }, "resolveRuntimeChannelGroups");
4210
+ ensureChannelWorkerManager = /* @__PURE__ */ __name(() => {
4211
+ if (channelWorkerManager) return Promise.resolve(channelWorkerManager);
4212
+ if (channelWorkerManagerStarting) return channelWorkerManagerStarting;
4213
+ const starting = (async () => {
4214
+ const candidateApp = runtimeApp ?? runtimeAppForCleanup;
4215
+ const registry = candidateApp?.locals?.["workspaceRegistry"];
4216
+ if (!candidateApp || !registry) {
4217
+ throw new Error(
4218
+ "Workspace registry is not available for channels."
4219
+ );
4220
+ }
4221
+ const workerRuntime = await ensureChannelRuntime();
4222
+ const createSupervisor = deps.channelWorkerSupervisorFactory ?? workerRuntime.createChannelWorkerSupervisor;
4223
+ const createGroup = /* @__PURE__ */ __name((groups) => workerRuntime.createChannelWorkerGroup({
4224
+ groups,
4225
+ registry,
4226
+ createSupervisor,
4227
+ shared: {
4228
+ cliEntryPath: workerRuntime.findCliEntryPath(),
4229
+ daemonUrl: formatChannelWorkerDaemonUrl(
4230
+ opts.hostname,
4231
+ actualPort
4232
+ ),
4233
+ ...token ? { daemonToken: token } : {}
4234
+ },
4235
+ onReady: /* @__PURE__ */ __name((snapshot) => {
4236
+ if (runtimeStartupError !== void 0) return;
4237
+ if (workspaceInputs.length > 1) {
4238
+ daemonLog.info("channel worker ready", {
4239
+ workspace: snapshot.workspaceCwd,
4240
+ pid: snapshot.pid,
4241
+ channels: snapshot.channels
4242
+ });
4243
+ }
4244
+ channelWorkerManager?.workerChanged();
4245
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4246
+ }, "onReady"),
4247
+ onExit: /* @__PURE__ */ __name((snapshot) => {
4248
+ const workspacePrefix = workspaceInputs.length > 1 ? `workspace=${snapshot.workspaceCwd}, ` : "";
4249
+ daemonLog.warn(
4250
+ `channel worker exited (${workspacePrefix}state=${snapshot.state}, pid=${snapshot.pid ?? "unknown"}, code=${snapshot.exitCode ?? "null"}, signal=${snapshot.signal ?? "null"}, error=${snapshot.error ?? "none"}, restartCount=${snapshot.restartCount ?? 0}, nextRestartAt=${snapshot.nextRestartAt ?? "none"}, staleHeartbeatAt=${snapshot.staleHeartbeatAt ?? "none"})`
4251
+ );
4252
+ channelWorkerManager?.workerChanged();
4253
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4254
+ }, "onExit"),
4255
+ onStateChange: /* @__PURE__ */ __name(() => {
4256
+ channelWorkerManager?.workerChanged();
4257
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4258
+ }, "onStateChange"),
4259
+ onLog: /* @__PURE__ */ __name(({ stream, line, workspaceCwd }) => {
4260
+ const message = workspaceInputs.length > 1 ? `channel worker [${workspaceCwd}] ${stream}: ${line}` : `channel worker ${stream}: ${line}`;
4261
+ if (stream === "stderr") daemonLog.warn(message);
4262
+ else daemonLog.info(message);
4263
+ }, "onLog")
4264
+ }), "createGroup");
4265
+ channelWorkerManager = workerRuntime.createChannelWorkerManager({
4266
+ resolveGroups: /* @__PURE__ */ __name((selection, operation) => resolveRuntimeChannelGroups(selection, candidateApp, operation), "resolveGroups"),
4267
+ createGroup,
4268
+ reserveLease: reserveChannelServicePidfile,
4269
+ releaseLease: /* @__PURE__ */ __name(() => {
4270
+ removeCurrentServePidfile();
4271
+ if (channelPidfileReserved) {
4272
+ throw new Error("Failed to release the channel service lease.");
4273
+ }
4274
+ }, "releaseLease"),
4275
+ initialLeaseReserved: channelPidfileReserved,
4276
+ onCommittedSelection: /* @__PURE__ */ __name((_selection, groups) => {
4277
+ channelWorkspaceGroups = groups;
4278
+ channelWebhookConfigVersion += 1;
4279
+ refreshChannelWebhookConfigs?.();
4280
+ }, "onCommittedSelection"),
4281
+ onStateChange: /* @__PURE__ */ __name(() => {
4282
+ if (runtimeStartupSettled) writeChannelWorkerPidfile();
4283
+ }, "onStateChange")
4284
+ });
4285
+ return channelWorkerManager;
4286
+ })();
4287
+ channelWorkerManagerStarting = starting;
4288
+ void starting.then(
4289
+ () => {
4290
+ if (channelWorkerManagerStarting === starting) {
4291
+ channelWorkerManagerStarting = void 0;
4292
+ }
4293
+ },
4294
+ () => {
4295
+ if (channelWorkerManagerStarting === starting) {
4296
+ channelWorkerManagerStarting = void 0;
4297
+ }
4298
+ }
4299
+ );
4300
+ return starting;
4301
+ }, "ensureChannelWorkerManager");
4302
+ const completeRuntimeStartup = /* @__PURE__ */ __name(async (candidateApp) => {
3176
4303
  if (runtimeStartupSettled) return;
4304
+ runtimeApp = candidateApp;
4305
+ const acpHandle = candidateApp.locals?.["acpHandle"];
4306
+ acpHandle?.attachServer?.(server);
3177
4307
  if (opts.channelSelection) {
3178
- await channelWorker.start();
4308
+ closeServerAfterChannelWorkerStartupFailure = true;
4309
+ const manager = await ensureChannelWorkerManager();
4310
+ await manager.startInitial(opts.channelSelection);
3179
4311
  if (runtimeStartupSettled) return;
3180
4312
  }
3181
4313
  if (runtimeStartupSettled) return;
@@ -3210,6 +4342,7 @@ async function runQwenServe(optsIn, deps = {}) {
3210
4342
  clearRuntimeStartFallbackTimer();
3211
4343
  runtimeStarting = buildRuntime().then(async (runtime) => {
3212
4344
  if (runtimeStartupSettled) {
4345
+ disposeRuntimeAppResources(runtime.app);
3213
4346
  await shutdownBridgeAfterFailedStartup(runtime.bridge);
3214
4347
  return;
3215
4348
  }
@@ -3222,13 +4355,10 @@ async function runQwenServe(optsIn, deps = {}) {
3222
4355
  );
3223
4356
  return;
3224
4357
  }
3225
- runtimeApp = runtime.app;
3226
- const acpHandle = runtime.app.locals?.["acpHandle"];
3227
- acpHandle?.attachServer?.(server);
3228
4358
  if (shouldPreheat) {
3229
4359
  startBridgePreheat(runtime.bridge);
3230
4360
  }
3231
- await completeRuntimeStartup();
4361
+ await completeRuntimeStartup(runtime.app);
3232
4362
  }).catch((err) => failRuntimeStartup(err));
3233
4363
  }, "startRuntime");
3234
4364
  startRuntimeForRequest = startRuntime;
@@ -3266,11 +4396,10 @@ async function runQwenServe(optsIn, deps = {}) {
3266
4396
  if (shuttingDown) {
3267
4397
  daemonLog.warn(`received ${signal} during drain \u2014 forcing exit`);
3268
4398
  try {
3269
- channelWorker.killAllSync();
4399
+ channelWorkerManager?.killAllSync();
3270
4400
  for (const runtimeBridge of getRuntimeBridgesForCleanup()) {
3271
4401
  runtimeBridge.killAllSync();
3272
4402
  }
3273
- removeCurrentServePidfile();
3274
4403
  } catch (err) {
3275
4404
  daemonLog.error(
3276
4405
  "force-kill error",
@@ -3286,16 +4415,24 @@ async function runQwenServe(optsIn, deps = {}) {
3286
4415
  try {
3287
4416
  await handle.close();
3288
4417
  await daemonLog.flush();
3289
- process.exit(0);
4418
+ process.exit(runtimeStartupError === void 0 ? 0 : 1);
3290
4419
  } catch (err) {
3291
4420
  daemonLog.error("shutdown error", err instanceof Error ? err : null);
3292
4421
  await daemonLog.flush().catch(() => {
3293
4422
  });
4423
+ if (channelWorkerManager?.state().enabled) {
4424
+ daemonLog.error(
4425
+ "refusing to exit while a channel worker or service lease remains; signal again to retry after the child exits (another signal during that retry forces exit)"
4426
+ );
4427
+ await daemonLog.flush().catch(() => {
4428
+ });
4429
+ return;
4430
+ }
3294
4431
  process.exit(1);
3295
4432
  }
3296
4433
  }, "onSignal");
3297
4434
  const onUncaughtExceptionMonitor = /* @__PURE__ */ __name(() => {
3298
- if (process.listenerCount("uncaughtException") === 0) {
4435
+ if (process.listenerCount("uncaughtException") === 0 && !channelWorkerManager?.state().enabled) {
3299
4436
  removeCurrentServePidfile();
3300
4437
  }
3301
4438
  }, "onUncaughtExceptionMonitor");
@@ -3310,17 +4447,24 @@ async function runQwenServe(optsIn, deps = {}) {
3310
4447
  if (closePromise) return closePromise;
3311
4448
  closePromise = new Promise((res, rej) => {
3312
4449
  shuttingDown = true;
3313
- app.locals.stopScheduledTaskKeepalive?.();
4450
+ channelControlDraining = true;
4451
+ const initiallyMountedApp = runtimeApp ?? runtimeAppForCleanup;
4452
+ const initiallyMountedManagement = initiallyMountedApp?.locals?.["workspaceManagementHandle"];
4453
+ const initialManagementWait = initiallyMountedManagement?.sealAndWait?.();
3314
4454
  clearRuntimeStartAfterHealthTimer();
3315
4455
  clearRuntimeStartFallbackTimer();
3316
4456
  cancelDeferredRuntimeStartup();
3317
4457
  let settled = false;
3318
4458
  let bridgeShutdownError;
4459
+ let channelWorkerShutdownError;
3319
4460
  const finish = /* @__PURE__ */ __name((err) => {
3320
4461
  if (settled) return;
3321
4462
  settled = true;
3322
- process.removeListener("SIGINT", onSignal);
3323
- process.removeListener("SIGTERM", onSignal);
4463
+ const preserveSignalHandlers = channelWorkerShutdownError !== void 0 && channelWorkerManager?.state().enabled === true;
4464
+ if (!preserveSignalHandlers) {
4465
+ process.removeListener("SIGINT", onSignal);
4466
+ process.removeListener("SIGTERM", onSignal);
4467
+ }
3324
4468
  process.removeListener(
3325
4469
  "uncaughtExceptionMonitor",
3326
4470
  onUncaughtExceptionMonitor
@@ -3331,9 +4475,17 @@ async function runQwenServe(optsIn, deps = {}) {
3331
4475
  );
3332
4476
  }).finally(() => daemonLog.flush().catch(() => {
3333
4477
  })).finally(() => {
3334
- const finalErr = err ?? bridgeShutdownError;
3335
- if (finalErr) rej(finalErr);
3336
- else res();
4478
+ const finalErr = err ?? bridgeShutdownError ?? channelWorkerShutdownError;
4479
+ if (finalErr) {
4480
+ if (channelWorkerShutdownError && channelWorkerManager?.state().enabled) {
4481
+ closePromise = void 0;
4482
+ shuttingDown = false;
4483
+ channelControlDraining = false;
4484
+ }
4485
+ rej(finalErr);
4486
+ } else {
4487
+ res();
4488
+ }
3337
4489
  });
3338
4490
  }, "finish");
3339
4491
  void (coreRuntimePromise ? coreRuntimePromise.then((core) => core.forceFlushMetrics()) : Promise.resolve()).catch((flushErr) => {
@@ -3347,43 +4499,54 @@ async function runQwenServe(optsIn, deps = {}) {
3347
4499
  daemonLog
3348
4500
  );
3349
4501
  const appForCleanup = runtimeApp ?? runtimeAppForCleanup;
3350
- const deviceFlowRegistry = appForCleanup ? getDeviceFlowRegistry(appForCleanup) : void 0;
3351
- if (deviceFlowRegistry) {
3352
- try {
3353
- deviceFlowRegistry.dispose();
3354
- } catch (err) {
3355
- daemonLog.warn(
3356
- `device-flow registry dispose error: ${err instanceof Error ? err.message : String(err)}`
3357
- );
3358
- }
4502
+ const workspaceManagementHandle = appForCleanup?.locals?.["workspaceManagementHandle"];
4503
+ await initialManagementWait;
4504
+ if (workspaceManagementHandle !== initiallyMountedManagement) {
4505
+ await workspaceManagementHandle?.sealAndWait?.();
3359
4506
  }
3360
- const acpHandle = appForCleanup?.locals?.["acpHandle"];
3361
- if (acpHandle?.dispose) {
3362
- try {
3363
- acpHandle.dispose();
3364
- } catch (err) {
3365
- daemonLog.warn(
3366
- `ACP handle dispose error: ${err instanceof Error ? err.message : String(err)}`
4507
+ disposeRuntimeAppResources(appForCleanup);
4508
+ disposeDaemonEventLoopMonitor();
4509
+ if (channelWorkerManager) {
4510
+ await channelWorkerManager.shutdown().catch((err) => {
4511
+ daemonLog.error(
4512
+ "channel worker stop error",
4513
+ err instanceof Error ? err : null
3367
4514
  );
3368
- }
3369
- }
3370
- const rl = appForCleanup ? getRateLimiter(appForCleanup) : void 0;
3371
- if (rl) {
3372
- rl.setDraining(true);
3373
- rl.dispose();
4515
+ channelWorkerShutdownError = err instanceof Error ? err : new Error(String(err));
4516
+ });
4517
+ } else {
4518
+ removeCurrentServePidfile();
3374
4519
  }
3375
- disposeDaemonEventLoopMonitor();
3376
- await channelWorker.stop().catch((err) => {
3377
- daemonLog.error(
3378
- "channel worker stop error",
3379
- err instanceof Error ? err : null
4520
+ const runtimeRemoval = appForCleanup?.locals?.["workspaceRuntimeRemoval"];
4521
+ const workspaceRegistry = appForCleanup?.locals?.["workspaceRegistry"];
4522
+ const managedRuntimeBridges = /* @__PURE__ */ new Set();
4523
+ if (runtimeRemoval && workspaceRegistry) {
4524
+ const managedRuntimes = workspaceRegistry.listManaged();
4525
+ for (const workspaceRuntime of managedRuntimes) {
4526
+ managedRuntimeBridges.add(workspaceRuntime.bridge);
4527
+ }
4528
+ await Promise.all(
4529
+ managedRuntimes.map(
4530
+ (workspaceRuntime) => runtimeRemoval.disposeRuntime(workspaceRuntime, "daemon_shutdown").catch((err) => {
4531
+ daemonLog.error(
4532
+ "workspace runtime shutdown error",
4533
+ err instanceof Error ? err : null
4534
+ );
4535
+ bridgeShutdownError = err instanceof Error ? err : new Error(String(err));
4536
+ try {
4537
+ workspaceRuntime.bridge.killAllSync();
4538
+ } catch {
4539
+ }
4540
+ })
4541
+ )
3380
4542
  );
3381
- });
3382
- removeCurrentServePidfile();
4543
+ }
3383
4544
  for (const bridgeForShutdown of getRuntimeBridgesForCleanup()) {
4545
+ if (managedRuntimeBridges.has(bridgeForShutdown)) continue;
3384
4546
  if (shutdownBridges.has(bridgeForShutdown)) continue;
3385
4547
  shutdownBridges.add(bridgeForShutdown);
3386
4548
  await bridgeForShutdown.shutdown().catch((err) => {
4549
+ shutdownBridges.delete(bridgeForShutdown);
3387
4550
  daemonLog.error(
3388
4551
  "bridge shutdown error",
3389
4552
  err instanceof Error ? err : null
@@ -3392,6 +4555,12 @@ async function runQwenServe(optsIn, deps = {}) {
3392
4555
  });
3393
4556
  }
3394
4557
  }).finally(() => {
4558
+ if (!server.listening) {
4559
+ void (runtimeFailureListenerClose ?? Promise.resolve()).then(
4560
+ () => finish()
4561
+ );
4562
+ return;
4563
+ }
3395
4564
  const SECONDARY_DEADLINE_MS = 2e3;
3396
4565
  let secondaryTimer;
3397
4566
  const forceTimer = setTimeout(() => {
@@ -3425,17 +4594,19 @@ async function runQwenServe(optsIn, deps = {}) {
3425
4594
  server.on("error", (err) => {
3426
4595
  daemonLog.error("server error", err instanceof Error ? err : null);
3427
4596
  });
3428
- if (runtimeApp && bridgeRef) {
3429
- const acpHandle = runtimeApp.locals?.["acpHandle"];
3430
- acpHandle?.attachServer?.(server);
4597
+ const preparedRuntimeApp = runtimeApp ?? runtimeAppForCleanup;
4598
+ if (preparedRuntimeApp && bridgeRef && deps.bridge) {
3431
4599
  if (shouldPreheat) {
3432
4600
  startBridgePreheat(bridgeRef);
3433
4601
  }
3434
4602
  if (opts.channelSelection && !runtimeStartupSettled) {
3435
4603
  armRuntimeStartupTimer();
3436
- runtimeStarting = completeRuntimeStartup().catch(
4604
+ runtimeStarting = completeRuntimeStartup(preparedRuntimeApp).catch(
3437
4605
  (err) => failRuntimeStartup(err, bridgeRef)
3438
4606
  );
4607
+ } else {
4608
+ const acpHandle = preparedRuntimeApp.locals?.["acpHandle"];
4609
+ acpHandle?.attachServer?.(server);
3439
4610
  }
3440
4611
  } else if (deferRuntimeUntilFirstHealth) {
3441
4612
  scheduleRuntimeStartFallback();
@@ -3448,14 +4619,24 @@ async function runQwenServe(optsIn, deps = {}) {
3448
4619
  void runtimeReady.then(
3449
4620
  () => resolve(handle),
3450
4621
  (err) => {
3451
- void handle.close().catch((closeErr) => {
3452
- daemonLog.error(
3453
- "shutdown after runtime startup error failed",
3454
- closeErr instanceof Error ? closeErr : null
3455
- );
3456
- }).finally(() => {
3457
- reject(err instanceof Error ? err : new Error(String(err)));
3458
- });
4622
+ void handle.close().then(
4623
+ () => {
4624
+ reject(err instanceof Error ? err : new Error(String(err)));
4625
+ },
4626
+ (closeErr) => {
4627
+ daemonLog.error(
4628
+ "shutdown after runtime startup error failed",
4629
+ closeErr instanceof Error ? closeErr : null
4630
+ );
4631
+ if (channelWorkerManager?.state().enabled) {
4632
+ daemonLog.error(
4633
+ "runtime startup failed, but qwen serve remains alive to retain the channel service lease until worker exit is confirmed"
4634
+ );
4635
+ return;
4636
+ }
4637
+ reject(err instanceof Error ? err : new Error(String(err)));
4638
+ }
4639
+ );
3459
4640
  }
3460
4641
  );
3461
4642
  }
@@ -3512,6 +4693,7 @@ async function runQwenServe(optsIn, deps = {}) {
3512
4693
  __name(runQwenServe, "runQwenServe");
3513
4694
  export {
3514
4695
  InvalidPolicyConfigError,
4696
+ createDisabledChannelWorkerSupervisor,
3515
4697
  createLazyBridgeProxy,
3516
4698
  extractContextFilename,
3517
4699
  formatChannelWorkerDaemonUrl,
@@ -3522,11 +4704,11 @@ export {
3522
4704
  };
3523
4705
  /**
3524
4706
  * @license
3525
- * Copyright 2026 Qwen Team
4707
+ * Copyright 2025 Qwen Team
3526
4708
  * SPDX-License-Identifier: Apache-2.0
3527
4709
  */
3528
4710
  /**
3529
4711
  * @license
3530
- * Copyright 2025 Qwen Team
4712
+ * Copyright 2026 Qwen Team
3531
4713
  * SPDX-License-Identifier: Apache-2.0
3532
4714
  */