@qwen-code/qwen-code 0.19.9 → 0.19.10-nightly.20260716.506ce0a1a

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 (323) hide show
  1. package/bundled/qc-helper/docs/configuration/settings.md +14 -6
  2. package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
  3. package/bundled/qc-helper/docs/features/channels/dingtalk.md +33 -0
  4. package/bundled/qc-helper/docs/features/channels/overview.md +64 -20
  5. package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
  6. package/bundled/qc-helper/docs/features/code-review.md +88 -44
  7. package/bundled/qc-helper/docs/features/commands.md +6 -6
  8. package/bundled/qc-helper/docs/features/hooks.md +29 -0
  9. package/bundled/qc-helper/docs/features/sandbox.md +2 -0
  10. package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
  11. package/bundled/qc-helper/docs/qwen-serve.md +49 -20
  12. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
  13. package/bundled/review/DESIGN.md +219 -33
  14. package/bundled/review/SKILL.md +429 -382
  15. package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-WOC3YDWA.js} +31 -32
  16. package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-H5HZCAFD.js} +49 -48
  17. package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-55YDJDNM.js} +922 -550
  18. package/chunks/{agent-HOLHB3RT.js → agent-H6VE5W3L.js} +26 -27
  19. package/chunks/{agent-headless-SXL6H56A.js → agent-headless-T4XJOCRU.js} +26 -27
  20. package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-HBRXJSP4.js} +78 -16
  21. package/chunks/{artifact-tool-U7IRTLIV.js → artifact-tool-MIZLXBLF.js} +2 -2
  22. package/chunks/{askUserQuestion-2DLUUZZG.js → askUserQuestion-XMJVPNWM.js} +2 -2
  23. package/chunks/{bridge-BCJQ7BBB.js → bridge-FTB6ZP3R.js} +31 -34
  24. package/chunks/{ca-UJ6HC4H2.js → ca-CODEN7TD.js} +9 -1
  25. package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
  26. package/chunks/channel-worker-manager-CUDPU4CN.js +418 -0
  27. package/chunks/channel-worker-supervisor-4XTO2ZD3.js +20 -0
  28. package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
  29. package/chunks/{chunk-VA4KQY6V.js → chunk-2JNR4VP2.js} +3 -3
  30. package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
  31. package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
  32. package/chunks/{chunk-CUMMSHH6.js → chunk-3DWIFU7L.js} +1 -1
  33. package/chunks/chunk-3MX7D6QN.js +516 -0
  34. package/chunks/{chunk-SJHDYNHF.js → chunk-4BJVSIS3.js} +3 -3
  35. package/chunks/{chunk-TO6QE22P.js → chunk-5CNYZ7TN.js} +26 -22
  36. package/chunks/{chunk-N3EMS75V.js → chunk-5DEJ4T6C.js} +1333 -1232
  37. package/chunks/chunk-5HBA2Z7V.js +28 -0
  38. package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
  39. package/chunks/{chunk-SCGXUJBT.js → chunk-6LI3L22E.js} +3 -3
  40. package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
  41. package/chunks/{chunk-YAUFFXDS.js → chunk-7GM2RWCR.js} +12 -11
  42. package/chunks/{chunk-OQ4DRIOA.js → chunk-7HWE2W74.js} +2 -2
  43. package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
  44. package/chunks/{chunk-MC23XKFE.js → chunk-A2HWMJVO.js} +37 -3
  45. package/chunks/{chunk-3G7CIHVV.js → chunk-ABNYOMDG.js} +4 -4
  46. package/chunks/{chunk-3AHXV67U.js → chunk-AGZLXLBY.js} +1 -1
  47. package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
  48. package/chunks/{chunk-Q4YQW46J.js → chunk-AMRZVQUY.js} +43 -40
  49. package/chunks/{chunk-W3JHSWRP.js → chunk-AN6C2U46.js} +4 -4
  50. package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
  51. package/chunks/{chunk-5SFOMFG4.js → chunk-AVEOWVOM.js} +36 -2
  52. package/chunks/{chunk-34MW4KTI.js → chunk-BA5JGE5F.js} +2 -2
  53. package/chunks/{chunk-5HOMWMCL.js → chunk-BSJAQUFD.js} +5492 -1336
  54. package/chunks/{chunk-L6P4KPHR.js → chunk-BWJKL5DB.js} +58 -38
  55. package/chunks/{chunk-PVZM22CK.js → chunk-C32JFRGV.js} +5 -5
  56. package/chunks/{chunk-AKIVHSJR.js → chunk-CZIHPO7L.js} +163 -782
  57. package/chunks/chunk-DL7RCO6V.js +493 -0
  58. package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
  59. package/chunks/{chunk-5VXNZWGF.js → chunk-ENUQSKEY.js} +1 -1
  60. package/chunks/{chunk-PDZ7MBDG.js → chunk-EWILX3BM.js} +27 -6
  61. package/chunks/{chunk-BMGVRZN4.js → chunk-EZWX232B.js} +1 -1
  62. package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
  63. package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
  64. package/chunks/chunk-FEOZBUMT.js +77 -0
  65. package/chunks/{chunk-5U27BZ72.js → chunk-FKEGVMPX.js} +269 -83
  66. package/chunks/chunk-FNX3LGAK.js +34 -0
  67. package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
  68. package/chunks/{chunk-PODM4SZ4.js → chunk-G3BIBPI7.js} +5 -5
  69. package/chunks/{chunk-A3XKDTSH.js → chunk-GA65O2TB.js} +4 -4
  70. package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
  71. package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-GXGIM7QP.js} +67 -35
  72. package/chunks/{chunk-6PESIEKJ.js → chunk-GXUWGPYX.js} +68 -6
  73. package/chunks/chunk-GYTKQYDB.js +23 -0
  74. package/chunks/{chunk-GZRTYZ2R.js → chunk-H3XMJV7T.js} +218 -1
  75. package/chunks/{chunk-WQUQVGTF.js → chunk-HGRXW4HQ.js} +467 -106
  76. package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
  77. package/chunks/{chunk-ECNYL4AA.js → chunk-HUEWOHKV.js} +1 -1
  78. package/chunks/chunk-IDS7MSUP.js +74 -0
  79. package/chunks/{chunk-KHUQZZJ6.js → chunk-IHDRJLLR.js} +382 -36
  80. package/chunks/{chunk-CLFKOZEK.js → chunk-J4SEAF4X.js} +114 -4
  81. package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
  82. package/chunks/{chunk-P67PFTUT.js → chunk-KEYEYCHZ.js} +4 -4
  83. package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
  84. package/chunks/{chunk-7PU4FYLG.js → chunk-KOXFAG6P.js} +4 -18
  85. package/chunks/{chunk-EGYZ275M.js → chunk-KWLVWNF5.js} +55 -7
  86. package/chunks/{chunk-XLA62MYB.js → chunk-KXECVZPD.js} +2 -2
  87. package/chunks/{chunk-IAVB3HM3.js → chunk-L4Y55KIS.js} +33 -1
  88. package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
  89. package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
  90. package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
  91. package/chunks/chunk-LXXMOYPL.js +22 -0
  92. package/chunks/{chunk-Q6I5QHMH.js → chunk-MFNKBXYH.js} +1 -1
  93. package/chunks/chunk-MR3PXB6E.js +48 -0
  94. package/chunks/{chunk-JZETEN3Z.js → chunk-N45S36AH.js} +3 -3
  95. package/chunks/{chunk-GWLSNBG4.js → chunk-NA3IG6XG.js} +748 -27
  96. package/chunks/{chunk-D5SKC4YG.js → chunk-O3M25JXE.js} +213 -29
  97. package/chunks/{chunk-EAXLGSFP.js → chunk-O6XGHDS5.js} +11 -11
  98. package/chunks/{chunk-WL4L7EZH.js → chunk-OA4JVLSA.js} +27 -1
  99. package/chunks/{chunk-X4NKFGFJ.js → chunk-OJAMDVF5.js} +0 -15
  100. package/chunks/{chunk-BZIFY5TF.js → chunk-OKAIGAYW.js} +3 -3
  101. package/chunks/{chunk-CNEIYWSA.js → chunk-OVIV236K.js} +5 -5
  102. package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
  103. package/chunks/{chunk-E2IY465S.js → chunk-PWNOAWXB.js} +59 -12
  104. package/chunks/{chunk-B4G2WOFA.js → chunk-Q5MKHNIR.js} +28 -5
  105. package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
  106. package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
  107. package/chunks/{chunk-HKMAENAO.js → chunk-QDTGDM2T.js} +14 -9
  108. package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
  109. package/chunks/{chunk-W2UIXQDL.js → chunk-RTV5TUYB.js} +12 -4
  110. package/chunks/chunk-RW7DUKFO.js +91 -0
  111. package/chunks/{chunk-NVYTCB5Z.js → chunk-SA6QVLWI.js} +17325 -16259
  112. package/chunks/chunk-SJSI7PXU.js +59 -0
  113. package/chunks/{chunk-HVY356M2.js → chunk-SMGBWLNU.js} +3 -3
  114. package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
  115. package/chunks/{chunk-CC2ITGCF.js → chunk-STZQCNN3.js} +49 -6
  116. package/chunks/{chunk-HPDUL5MF.js → chunk-T2ZDAER2.js} +1 -1
  117. package/chunks/{chunk-XUOOWUZS.js → chunk-T3TQ3ACP.js} +1 -1
  118. package/chunks/{chunk-4C5BQ2D2.js → chunk-TIKDHS6V.js} +100 -17
  119. package/chunks/chunk-TV6K2FB4.js +224 -0
  120. package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
  121. package/chunks/{chunk-D2GFWEXB.js → chunk-UCUUH2JV.js} +6 -6
  122. package/chunks/{chunk-BAPGSC7U.js → chunk-UZP7K33Y.js} +23 -9
  123. package/chunks/{chunk-77XJ3SWN.js → chunk-VDAR6UO2.js} +8 -6
  124. package/chunks/{chunk-XYQSMABS.js → chunk-VKLVGA2D.js} +4 -4
  125. package/chunks/{chunk-JSG7ZSBC.js → chunk-VRR65QYW.js} +251 -3
  126. package/chunks/{chunk-U2NNEY4R.js → chunk-VT5AWJN4.js} +1 -1
  127. package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
  128. package/chunks/{chunk-X6TJ3YZV.js → chunk-WKEO3GLZ.js} +160 -60
  129. package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
  130. package/chunks/{chunk-VWPVHAMO.js → chunk-XIWQ5QST.js} +8 -1
  131. package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
  132. package/chunks/{chunk-3VAGG5T5.js → chunk-YYBZUIPL.js} +1015 -100
  133. package/chunks/{chunk-CCDMCZPP.js → chunk-YZ3SBNP7.js} +1 -1
  134. package/chunks/{chunk-ATAKVRIF.js → chunk-Z3XA2TNG.js} +7 -7
  135. package/chunks/{chunk-EMDMPBJ4.js → chunk-Z7SVC7PJ.js} +10 -3
  136. package/chunks/{chunk-AURZZYMD.js → chunk-ZIVSSTUG.js} +4 -4
  137. package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
  138. package/chunks/{chunk-34Z3U5RQ.js → chunk-ZQIYGQCG.js} +765 -168
  139. package/chunks/{computer-use-HM37RX6A.js → computer-use-NADT7ULB.js} +26 -27
  140. package/chunks/{config-utils-NV2SVGPB.js → config-utils-IQQT3GCI.js} +3 -2
  141. package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-U7NEJYJ7.js} +28 -29
  142. package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
  143. package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-SUN33INC.js} +26 -27
  144. package/chunks/{cron-create-AMBKGZX6.js → cron-create-GMVKSXZT.js} +4 -4
  145. package/chunks/{cron-delete-LRU4OJYG.js → cron-delete-VDZKUAVK.js} +4 -4
  146. package/chunks/{cron-list-WVP2JXER.js → cron-list-UG7C7RAR.js} +4 -4
  147. package/chunks/{daemon-ARHTSTXP.js → daemon-SJXEKP3H.js} +773 -126
  148. package/chunks/daemon-status-provider-WIIYLGZJ.js +74 -0
  149. package/chunks/{de-EBJN3OVN.js → de-NOXPCSYN.js} +9 -1
  150. package/chunks/{dist-XKU3ABM5.js → dist-4WCQEZIN.js} +4 -51
  151. package/chunks/{dist-QYCAEZIT.js → dist-DOPL5LSQ.js} +5 -1
  152. package/chunks/{dist-WKPOYU7O.js → dist-GXJVCOS7.js} +1 -1
  153. package/chunks/{dist-R7LN5AZE.js → dist-PX2ERZ6I.js} +2 -2
  154. package/chunks/{dist-PNVLTKTL.js → dist-V2YVLYOW.js} +215 -33
  155. package/chunks/{dist-VHV4EVHG.js → dist-VYWUKURL.js} +1 -1
  156. package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-6FRM6UMU.js} +27 -28
  157. package/chunks/{edit-VNI4NJ73.js → edit-7GOIQTCZ.js} +27 -28
  158. package/chunks/{en-5A6LA7RK.js → en-JFVULHTB.js} +11 -1
  159. package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-476E6WIK.js} +26 -27
  160. package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-IRJM6W3C.js} +42 -28
  161. package/chunks/{environment-5HSSRMJ7.js → environment-ROMULS2X.js} +30 -30
  162. package/chunks/{errors-HMFCJJ7P.js → errors-OUIWPUDY.js} +28 -29
  163. package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-PPSFK753.js} +26 -27
  164. package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-YKQMD4D7.js} +26 -27
  165. package/chunks/{fast-path-FRDMDVHG.js → fast-path-CNK2HHKH.js} +3 -3
  166. package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
  167. package/chunks/{fr-YXRABLYZ.js → fr-HVFNU42H.js} +9 -1
  168. package/chunks/{gemini-QYSEGHAX.js → gemini-WQNFT6TR.js} +216 -90
  169. package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-4QJH2JDP.js} +4 -4
  170. package/chunks/{glob-BRCSGFOT.js → glob-36TVLBWW.js} +28 -28
  171. package/chunks/{grep-EE2DUOSY.js → grep-QTYLNO2M.js} +26 -27
  172. package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-36FQFODK.js} +30 -31
  173. package/chunks/{i18n-BASPENNQ.js → i18n-JUGYPVSP.js} +27 -28
  174. package/chunks/initializer-OBBJUS25.js +72 -0
  175. package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-MCKTPX64.js} +27 -28
  176. package/chunks/{ja-7VQOANVG.js → ja-PY5AF544.js} +10 -2
  177. package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
  178. package/chunks/list-VW5QY4VJ.js +75 -0
  179. package/chunks/loadedSettingsAdapter-IELOOXG6.js +69 -0
  180. package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-QXWZSCYM.js} +5 -5
  181. package/chunks/{ls-ZB2BDP6T.js → ls-2OUTG3IZ.js} +4 -4
  182. package/chunks/{lsp-V5DN4YUJ.js → lsp-4VMNXZW6.js} +2 -2
  183. package/chunks/mcp-Q3EC37ZS.js +69 -0
  184. package/chunks/{monitor-X5Z3H4FY.js → monitor-DCZ27AFR.js} +26 -27
  185. package/chunks/nonInteractiveCli-KXD7PFO4.js +128 -0
  186. package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-YU4XF5LI.js} +27 -28
  187. package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KL5WER2D.js} +13 -13
  188. package/chunks/{pidfile-D4I4FTVA.js → pidfile-WBOD7EJV.js} +27 -28
  189. package/chunks/processUtils-AOV4R34M.js +29 -0
  190. package/chunks/{pt-2C6YCSHL.js → pt-A3PRQXMU.js} +9 -1
  191. package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-YIGBHYE3.js} +28 -29
  192. package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
  193. package/chunks/{read-file-7SZSIZOL.js → read-file-WVL4Y76X.js} +9 -9
  194. package/chunks/{read-mcp-resource-SM5DA4RG.js → read-mcp-resource-JUFHCKSC.js} +2 -2
  195. package/chunks/{record-artifact-4XKZX3UW.js → record-artifact-DWSMBXYY.js} +2 -2
  196. package/chunks/{ripGrep-YNPFVCZP.js → ripGrep-6GSWJERP.js} +26 -27
  197. package/chunks/{ru-6BBHVZZV.js → ru-IBCWUTOC.js} +9 -1
  198. package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-QYUQMEDT.js} +1233 -371
  199. package/chunks/{runtime-57WWRVHN.js → runtime-K2YZCNB3.js} +42 -38
  200. package/chunks/{scheduler-YBLGWSIL.js → scheduler-EQCSN7QV.js} +26 -27
  201. package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
  202. package/chunks/{serve-R63NK3CV.js → serve-DX5UGZD4.js} +36 -35
  203. package/chunks/{server-Z22GCAXP.js → server-T6HJH3DR.js} +5869 -1398
  204. package/chunks/{session-HKAAI7BN.js → session-SNU6ACY6.js} +299 -100
  205. package/chunks/{settings-3EYN66GK.js → settings-AKHZZNEL.js} +34 -33
  206. package/chunks/{shell-6YXINTWJ.js → shell-EY74IEZK.js} +28 -27
  207. package/chunks/{skill-OO57P4X6.js → skill-DPU62O3H.js} +11 -11
  208. package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-RQZRWJ2V.js} +28 -30
  209. package/chunks/{src-G5UPLZSZ.js → src-7FITDSVC.js} +164 -52
  210. package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-XO3RK6DO.js} +28 -29
  211. package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-DVWZRHYQ.js} +728 -382
  212. package/chunks/{syntheticOutput-34H7LGA7.js → syntheticOutput-LELY6HAI.js} +3 -3
  213. package/chunks/{task-create-FRGOEIKY.js → task-create-QY3BIMNM.js} +8 -7
  214. package/chunks/{task-list-OW766BXZ.js → task-list-D2U47WBJ.js} +6 -5
  215. package/chunks/{task-stop-SIR5SNBN.js → task-stop-N6E5IYLH.js} +2 -2
  216. package/chunks/{task-update-YRA532MT.js → task-update-HJCQILLB.js} +8 -7
  217. package/chunks/{team-create-PECAAPXK.js → team-create-FOSRT62K.js} +26 -27
  218. package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
  219. package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-6VUDV27J.js} +26 -27
  220. package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-6UT6IO5T.js} +27 -28
  221. package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
  222. package/chunks/{tool-search-THVIWAPB.js → tool-search-ASSFMMN5.js} +10 -10
  223. package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-YYWUO23H.js} +32 -35
  224. package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
  225. package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-4BWV2IBK.js} +29 -29
  226. package/chunks/types-ML3TRJQ5.js +16 -0
  227. package/chunks/update-relaunch-74DLGH73.js +87 -0
  228. package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-CRFCGFO5.js} +31 -30
  229. package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-BTTEPBGQ.js} +76 -73
  230. package/chunks/{version-3UEA6ZIR.js → version-Y5JE5Q63.js} +1 -1
  231. package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-CFCWTCAP.js} +5 -6
  232. package/chunks/{workflow-QCCCMYP3.js → workflow-6WC7VPQN.js} +27 -28
  233. package/chunks/workspace-providers-status-RVG2C5ZS.js +72 -0
  234. package/chunks/workspace-registration-store-SLEU3D3X.js +27 -0
  235. package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-QMWGVOTF.js} +32 -35
  236. package/chunks/workspace-service-G572JSEU.js +84 -0
  237. package/chunks/workspace-skills-status-VSSMSMNK.js +71 -0
  238. package/chunks/{write-file-I3MUDRIE.js → write-file-5XVDRORP.js} +27 -28
  239. package/chunks/{zh-RQE7I22T.js → zh-PAUNIMHQ.js} +12 -2
  240. package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-GNEUIUFF.js} +12 -2
  241. package/cli-entry.js +92 -8
  242. package/cli.js +11 -11
  243. package/locales/ca.js +16 -0
  244. package/locales/de.js +16 -0
  245. package/locales/en.js +19 -0
  246. package/locales/fr.js +16 -0
  247. package/locales/ja.js +17 -1
  248. package/locales/pt.js +16 -0
  249. package/locales/ru.js +16 -0
  250. package/locales/zh-TW.js +20 -1
  251. package/locales/zh.js +20 -1
  252. package/package.json +3 -3
  253. package/web-shell/assets/{arc-C15hqnJe.js → arc-vx1tRwnX.js} +1 -1
  254. package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-DBi6iUA1.js} +1 -1
  255. package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-Ga9JJ4Ak.js} +1 -1
  256. package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-D8Vi5FYw.js} +1 -1
  257. package/web-shell/assets/channel-B29zQDTL.js +1 -0
  258. package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-CSV6yQpU.js} +1 -1
  259. package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-toYlppdI.js} +1 -1
  260. package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-DbjzuyAr.js} +1 -1
  261. package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-IkkSjSkk.js} +1 -1
  262. package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-D5wUL6Zm.js} +1 -1
  263. package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-C3o2DXG0.js} +1 -1
  264. package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CutIi14T.js} +1 -1
  265. package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-DZ0NRHH-.js} +1 -1
  266. package/web-shell/assets/classDiagram-4FO5ZUOK-BNGI2SvC.js +1 -0
  267. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BNGI2SvC.js +1 -0
  268. package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-B3Dl88UJ.js} +1 -1
  269. package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-DfTxfF6-.js} +1 -1
  270. package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-CJyH98yO.js} +1 -1
  271. package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-EbOiJNmW.js} +1 -1
  272. package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-AYNqpqqA.js} +1 -1
  273. package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BY5VPa4H.js} +1 -1
  274. package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-BhMYAKlk.js} +1 -1
  275. package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-Bp8S_F9l.js} +1 -1
  276. package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-az3TE9PU.js} +1 -1
  277. package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-CfkAEpCe.js} +3 -3
  278. package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-D1QmjMCy.js} +1 -1
  279. package/web-shell/assets/index-C8sDwQUv.js +1130 -0
  280. package/web-shell/assets/index-CaBoc5bb.js +3 -0
  281. package/web-shell/assets/index-Dpg5Wymg.css +5 -0
  282. package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-D3ompLrG.js} +1 -1
  283. package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-D3MRWp9I.js} +1 -1
  284. package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-DVkKCa44.js} +1 -1
  285. package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-BLif81wF.js} +1 -1
  286. package/web-shell/assets/{linear-C8wKCbIC.js → linear-BDU96EGS.js} +1 -1
  287. package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-B-CwC26B.js} +5 -5
  288. package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-CS1WOJ4G.js} +1 -1
  289. package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-BzgtNXVP.js} +1 -1
  290. package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-BRfGC8MA.js} +1 -1
  291. package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-CPBZkC7g.js} +1 -1
  292. package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-nqNvinIk.js} +1 -1
  293. package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-CM_Wdjh3.js} +1 -1
  294. package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-L0y-48VE.js} +1 -1
  295. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BX1DdF8s.js +1 -0
  296. package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-B_n5rb3A.js} +1 -1
  297. package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-C9NmLV5e.js} +1 -1
  298. package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-CrefK9gt.js} +1 -1
  299. package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BUccf-bC.js} +1 -1
  300. package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-DM6ef92l.js} +1 -1
  301. package/web-shell/index.html +2 -2
  302. package/chunks/chunk-524RQP4Q.js +0 -305
  303. package/chunks/chunk-CARU2RR2.js +0 -24
  304. package/chunks/chunk-CU3L64TP.js +0 -93
  305. package/chunks/chunk-OCPBI7J5.js +0 -18
  306. package/chunks/chunk-TEGEBB2I.js +0 -122
  307. package/chunks/chunk-VTU57BWZ.js +0 -30
  308. package/chunks/daemon-status-provider-B2UTZUJ2.js +0 -76
  309. package/chunks/initializer-UTQ7FB7G.js +0 -71
  310. package/chunks/list-DEICDL65.js +0 -74
  311. package/chunks/loadedSettingsAdapter-NOWEGDYJ.js +0 -68
  312. package/chunks/mcp-L5JXEEIA.js +0 -68
  313. package/chunks/nonInteractiveCli-LS2K4X6A.js +0 -124
  314. package/chunks/types-JNKGKUJT.js +0 -12
  315. package/chunks/workspace-providers-status-4KMGETOJ.js +0 -71
  316. package/chunks/workspace-service-RVLBMSMZ.js +0 -80
  317. package/chunks/workspace-skills-status-DS4ZVFTO.js +0 -70
  318. package/web-shell/assets/channel-CLiQD50f.js +0 -1
  319. package/web-shell/assets/classDiagram-4FO5ZUOK-D3sYqow5.js +0 -1
  320. package/web-shell/assets/classDiagram-v2-Q7XG4LA2-D3sYqow5.js +0 -1
  321. package/web-shell/assets/index-D5IWFVk1.css +0 -5
  322. package/web-shell/assets/index-KFJRDhX7.js +0 -783
  323. package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BhQMwgpl.js +0 -1
@@ -3,15 +3,13 @@
3
3
  import {
4
4
  DaemonMetricsRing,
5
5
  computeCpuPercent
6
- } from "./chunk-YVEDCAUE.js";
7
- import {
8
- RUNTIME_STARTUP_CANCELLED_MESSAGE
9
- } from "./chunk-QUPXZXLV.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,
@@ -29,56 +27,73 @@ import {
29
27
  positiveFiniteOrNull,
30
28
  require_express,
31
29
  resolveWebShellDir
32
- } from "./chunk-KHUQZZJ6.js";
30
+ } from "./chunk-IHDRJLLR.js";
33
31
  import {
34
32
  isLoopbackBind
35
33
  } from "./chunk-RXFQM6FQ.js";
34
+ import {
35
+ RUNTIME_STARTUP_CANCELLED_MESSAGE
36
+ } from "./chunk-QUPXZXLV.js";
36
37
  import {
37
38
  LOAD_REPLAY_META_KEY
38
39
  } from "./chunk-PZL23GTM.js";
39
- import {
40
- canonicalizeWorkspace
41
- } from "./chunk-W7FJ3N32.js";
42
40
  import {
43
41
  DEFAULT_COMPACTED_REPLAY_MAX_BYTES,
44
42
  normalizeCompactedReplayMaxBytes
45
43
  } from "./chunk-COH43MRJ.js";
46
44
  import "./chunk-WBL3FJEU.js";
47
- import "./chunk-T2NCM2ET.js";
48
45
  import {
49
- loadServeFastPathSettings,
50
- preResolveServeFastPathHomeEnvOverrides
51
- } from "./chunk-3SJSQXNS.js";
46
+ resolveChannelCwd
47
+ } from "./chunk-FNX3LGAK.js";
52
48
  import {
53
- getGlobalQwenDirLite,
54
- resolveConfigPathLite
55
- } from "./chunk-3BTRNWWD.js";
56
- import "./chunk-QRUIS3DN.js";
49
+ MAX_REGISTERED_WORKSPACES,
50
+ resolveWorkspaceInputs,
51
+ workspaceRegistrationId
52
+ } from "./chunk-DL7RCO6V.js";
53
+ import {
54
+ canonicalizeWorkspace
55
+ } from "./chunk-W7FJ3N32.js";
56
+ import "./chunk-3MX7D6QN.js";
57
57
  import {
58
- ChannelWebhookEnqueueError,
59
58
  QWEN_SERVER_TOKEN_ENV
60
- } from "./chunk-X4NKFGFJ.js";
59
+ } from "./chunk-GYTKQYDB.js";
61
60
  import {
62
61
  channelSelectionNames
63
62
  } from "./chunk-TJTKSVIV.js";
63
+ import "./chunk-5HBA2Z7V.js";
64
+ import {
65
+ ChannelWebhookEnqueueError
66
+ } from "./chunk-OJAMDVF5.js";
67
+ import "./chunk-T2NCM2ET.js";
64
68
  import {
65
69
  sanitizeLogText
66
- } from "./chunk-34Z3U5RQ.js";
70
+ } from "./chunk-ZQIYGQCG.js";
67
71
  import "./chunk-UDXSXLER.js";
68
72
  import {
69
- isWithinRoot
70
- } from "./chunk-RDJSGHZE.js";
73
+ loadServeFastPathSettings,
74
+ preResolveServeFastPathHomeEnvOverrides
75
+ } from "./chunk-PEJWA3QQ.js";
76
+ import "./chunk-GOXKNSDZ.js";
71
77
  import {
72
- getCliVersion
73
- } from "./chunk-3AHXV67U.js";
74
- import "./chunk-VJNBRRZG.js";
78
+ getGlobalQwenDirLite,
79
+ resolveConfigPathLite
80
+ } from "./chunk-IDS7MSUP.js";
81
+ import "./chunk-QRUIS3DN.js";
82
+ import "./chunk-ALGGS7UH.js";
83
+ import {
84
+ isWithinRoot
85
+ } from "./chunk-MR3PXB6E.js";
75
86
  import {
76
87
  writeStderrLine,
77
88
  writeStdoutLine
78
89
  } from "./chunk-YUZI3WAC.js";
79
- import "./chunk-CU3L64TP.js";
80
- import "./chunk-ZJE7NSL3.js";
90
+ import {
91
+ getCliVersion
92
+ } from "./chunk-AGZLXLBY.js";
93
+ import "./chunk-VJNBRRZG.js";
81
94
  import "./chunk-H6XPXXMH.js";
95
+ import "./chunk-5M6IDOMF.js";
96
+ import "./chunk-E2UVIFI2.js";
82
97
  import "./chunk-CR3C7WXL.js";
83
98
  import "./chunk-XWRJCPHC.js";
84
99
  import {
@@ -106,92 +121,6 @@ import * as path from "node:path";
106
121
  import * as os from "node:os";
107
122
  import { monitorEventLoopDelay, performance } from "node:perf_hooks";
108
123
 
109
- // packages/cli/src/serve/workspace-inputs.ts
110
- init_esbuild_shims();
111
- var DuplicateWorkspaceInputError = class extends Error {
112
- static {
113
- __name(this, "DuplicateWorkspaceInputError");
114
- }
115
- constructor(workspace) {
116
- super(
117
- `Duplicate --workspace value resolves to ${JSON.stringify(workspace)}. Pass distinct --workspace values.`
118
- );
119
- this.name = "DuplicateWorkspaceInputError";
120
- }
121
- };
122
- var NestedWorkspaceInputError = class extends Error {
123
- static {
124
- __name(this, "NestedWorkspaceInputError");
125
- }
126
- constructor(parent, child) {
127
- super(
128
- `Nested --workspace values are not supported yet: ${JSON.stringify(child)} is inside ${JSON.stringify(parent)}. Pass non-nested --workspace values.`
129
- );
130
- this.name = "NestedWorkspaceInputError";
131
- }
132
- };
133
- var MissingWorkspaceInputError = class extends Error {
134
- static {
135
- __name(this, "MissingWorkspaceInputError");
136
- }
137
- constructor() {
138
- super("--workspace requires a value.");
139
- this.name = "MissingWorkspaceInputError";
140
- }
141
- };
142
- function normalizeWorkspaceInputs(workspace) {
143
- if (Array.isArray(workspace)) {
144
- if (workspace.length === 0) {
145
- throw new MissingWorkspaceInputError();
146
- }
147
- return workspace.map((value) => String(value));
148
- }
149
- if (workspace === void 0) return [process.cwd()];
150
- return [String(workspace)];
151
- }
152
- __name(normalizeWorkspaceInputs, "normalizeWorkspaceInputs");
153
- function isNestedWorkspace(parent, child) {
154
- return parent !== child && isWithinRoot(child, parent);
155
- }
156
- __name(isNestedWorkspace, "isNestedWorkspace");
157
- function rejectDuplicateOrNestedWorkspaceInputs(workspaces) {
158
- if (workspaces.length <= 1) return;
159
- let canonicalWorkspaces;
160
- try {
161
- canonicalWorkspaces = workspaces.map(
162
- (workspace) => canonicalizeWorkspace(workspace)
163
- );
164
- } catch {
165
- return;
166
- }
167
- const seen = /* @__PURE__ */ new Set();
168
- for (const workspace of canonicalWorkspaces) {
169
- if (seen.has(workspace)) {
170
- throw new DuplicateWorkspaceInputError(workspace);
171
- }
172
- seen.add(workspace);
173
- }
174
- for (let i = 0; i < canonicalWorkspaces.length; i++) {
175
- for (let j = i + 1; j < canonicalWorkspaces.length; j++) {
176
- const first = canonicalWorkspaces[i];
177
- const second = canonicalWorkspaces[j];
178
- if (isNestedWorkspace(first, second)) {
179
- throw new NestedWorkspaceInputError(first, second);
180
- }
181
- if (isNestedWorkspace(second, first)) {
182
- throw new NestedWorkspaceInputError(second, first);
183
- }
184
- }
185
- }
186
- }
187
- __name(rejectDuplicateOrNestedWorkspaceInputs, "rejectDuplicateOrNestedWorkspaceInputs");
188
- function resolveWorkspaceInputs(workspace) {
189
- const workspaces = normalizeWorkspaceInputs(workspace);
190
- rejectDuplicateOrNestedWorkspaceInputs(workspaces);
191
- return workspaces;
192
- }
193
- __name(resolveWorkspaceInputs, "resolveWorkspaceInputs");
194
-
195
124
  // packages/cli/src/serve/permission-audit.ts
196
125
  init_esbuild_shims();
197
126
  var DEFAULT_PERMISSION_AUDIT_RING_SIZE = 512;
@@ -889,6 +818,120 @@ function asRecord(value) {
889
818
  }
890
819
  __name(asRecord, "asRecord");
891
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
+
892
935
  // packages/cli/src/serve/run-qwen-serve.ts
893
936
  var QWEN_SERVE_CLIENT_MCP_OVER_WS_ENV = "QWEN_SERVE_CLIENT_MCP_OVER_WS";
894
937
  var QWEN_SERVE_CDP_TUNNEL_OVER_WS_ENV = "QWEN_SERVE_CDP_TUNNEL_OVER_WS";
@@ -1093,14 +1136,29 @@ __name(withSettingsLock, "withSettingsLock");
1093
1136
  var channelWorkerRuntimePromise;
1094
1137
  async function loadChannelWorkerRuntime() {
1095
1138
  channelWorkerRuntimePromise ??= Promise.all([
1096
- import("./channel-worker-supervisor-WSOAAYUO.js"),
1097
- import("./pidfile-D4I4FTVA.js"),
1098
- import("./cli-entry-path-4VJ3Y6T2.js")
1099
- ]).then(([supervisor, pidfile, cliEntryPath]) => ({
1100
- createChannelWorkerSupervisor: supervisor.createChannelWorkerSupervisor,
1101
- channelServicePidfile: pidfile,
1102
- findCliEntryPath: cliEntryPath.findCliEntryPath
1103
- })).catch((err) => {
1139
+ import("./channel-worker-supervisor-4XTO2ZD3.js"),
1140
+ import("./pidfile-WBOD7EJV.js"),
1141
+ import("./runtime-K2YZCNB3.js"),
1142
+ import("./cli-entry-path-4VJ3Y6T2.js"),
1143
+ import("./channel-worker-group-K7QKH6IG.js"),
1144
+ import("./channel-worker-manager-CUDPU4CN.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) => {
1104
1162
  channelWorkerRuntimePromise = void 0;
1105
1163
  throw err;
1106
1164
  });
@@ -1142,11 +1200,23 @@ function writeServeChannelReservation(channelServicePidfile, channels) {
1142
1200
  __name(writeServeChannelReservation, "writeServeChannelReservation");
1143
1201
  function channelServicePidfileConflictError(info) {
1144
1202
  const owner = info.owner === "serve" ? "qwen serve" : "qwen channel start";
1145
- return new Error(
1146
- `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 }
1147
1208
  );
1148
1209
  }
1149
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");
1150
1220
  function normalizeInstallModelIds(req, provider, getDefaultModelIds) {
1151
1221
  const fromRequest = req.modelIds?.map((id) => id.trim()).filter((id) => id.length > 0);
1152
1222
  const modelIds = fromRequest && fromRequest.length > 0 ? fromRequest : getDefaultModelIds(provider);
@@ -1176,7 +1246,7 @@ function shouldPreheatBridge(deps) {
1176
1246
  __name(shouldPreheatBridge, "shouldPreheatBridge");
1177
1247
  var coreRuntimePromise;
1178
1248
  function loadCoreRuntime() {
1179
- coreRuntimePromise ??= import("./src-G5UPLZSZ.js");
1249
+ coreRuntimePromise ??= import("./src-7FITDSVC.js");
1180
1250
  return coreRuntimePromise;
1181
1251
  }
1182
1252
  __name(loadCoreRuntime, "loadCoreRuntime");
@@ -1206,10 +1276,10 @@ __name(resolveDaemonLogBaseDirForRun, "resolveDaemonLogBaseDirForRun");
1206
1276
  var settingsRuntimePromise;
1207
1277
  function loadSettingsRuntimeModules() {
1208
1278
  settingsRuntimePromise ??= Promise.all([
1209
- import("./settings-3EYN66GK.js"),
1210
- import("./environment-5HSSRMJ7.js"),
1211
- import("./loadedSettingsAdapter-NOWEGDYJ.js"),
1212
- import("./trustedFolders-EOGT3UVS.js")
1279
+ import("./settings-AKHZZNEL.js"),
1280
+ import("./environment-ROMULS2X.js"),
1281
+ import("./loadedSettingsAdapter-IELOOXG6.js"),
1282
+ import("./trustedFolders-4BWV2IBK.js")
1213
1283
  ]).then(([settings, environment, loadedSettingsAdapter, trustedFolders]) => ({
1214
1284
  settings,
1215
1285
  environment,
@@ -1222,8 +1292,8 @@ __name(loadSettingsRuntimeModules, "loadSettingsRuntimeModules");
1222
1292
  var channelWebhookConfigRuntimePromise;
1223
1293
  function loadChannelWebhookConfigRuntime() {
1224
1294
  channelWebhookConfigRuntimePromise ??= Promise.all([
1225
- import("./runtime-57WWRVHN.js"),
1226
- import("./config-utils-NV2SVGPB.js")
1295
+ import("./runtime-K2YZCNB3.js"),
1296
+ import("./config-utils-IQQT3GCI.js")
1227
1297
  ]).then(([channelRuntime, configUtils]) => ({
1228
1298
  loadChannelsConfig: channelRuntime.loadChannelsConfig,
1229
1299
  parseChannelWebhookConfig: configUtils.parseChannelWebhookConfig
@@ -1247,16 +1317,16 @@ async function loadServeRuntimeModules() {
1247
1317
  totalSessionAdmissionModule,
1248
1318
  workspaceRegistryModule
1249
1319
  ] = await Promise.all([
1250
- import("./server-Z22GCAXP.js"),
1251
- import("./bridge-BCJQ7BBB.js"),
1252
- import("./spawnChannel-JD7G4VU6.js"),
1253
- import("./workspace-service-RVLBMSMZ.js"),
1254
- import("./types-JNKGKUJT.js"),
1255
- import("./daemon-status-provider-B2UTZUJ2.js"),
1256
- import("./workspace-providers-status-4KMGETOJ.js"),
1257
- import("./workspace-skills-status-DS4ZVFTO.js"),
1258
- import("./total-session-admission-JOKNRIIA.js"),
1259
- import("./workspace-registry-24QFLQYH.js")
1320
+ import("./server-T6HJH3DR.js"),
1321
+ import("./bridge-FTB6ZP3R.js"),
1322
+ import("./spawnChannel-RQZRWJ2V.js"),
1323
+ import("./workspace-service-G572JSEU.js"),
1324
+ import("./types-ML3TRJQ5.js"),
1325
+ import("./daemon-status-provider-WIIYLGZJ.js"),
1326
+ import("./workspace-providers-status-RVG2C5ZS.js"),
1327
+ import("./workspace-skills-status-VSSMSMNK.js"),
1328
+ import("./total-session-admission-YYWUO23H.js"),
1329
+ import("./workspace-registry-QMWGVOTF.js")
1260
1330
  ]);
1261
1331
  return {
1262
1332
  createServeApp: serverModule.createServeApp,
@@ -1267,6 +1337,7 @@ async function loadServeRuntimeModules() {
1267
1337
  createSpawnChannelFactory: spawnChannelModule.createSpawnChannelFactory,
1268
1338
  createDaemonWorkspaceService: workspaceModule.createDaemonWorkspaceService,
1269
1339
  WorkspaceSettingsPartialPersistError: workspaceTypesModule.WorkspaceSettingsPartialPersistError,
1340
+ WorkspaceSkillNotToggleableError: workspaceTypesModule.WorkspaceSkillNotToggleableError,
1270
1341
  createDaemonStatusProvider: daemonStatusProviderModule.createDaemonStatusProvider,
1271
1342
  createWorkspaceProvidersStatusProvider: workspaceProvidersStatusModule.createWorkspaceProvidersStatusProvider,
1272
1343
  createWorkspaceSkillsStatusProvider: workspaceSkillsStatusModule.createWorkspaceSkillsStatusProvider,
@@ -1306,9 +1377,13 @@ function currentServeFeaturesForRunQwenServe(opts, sessionShellCommandEnabled, s
1306
1377
  persistSettingAvailable: true,
1307
1378
  sessionShellCommandEnabled,
1308
1379
  sessionArtifactsPersistenceAvailable,
1380
+ sessionGenerationAvailable: true,
1309
1381
  rateLimit: opts.rateLimit === true,
1310
1382
  reloadAvailable: true,
1311
1383
  channelReloadAvailable: opts.channelSelection !== void 0,
1384
+ channelControlAvailable: true,
1385
+ persistentWorkspaceRegistrationAvailable: true,
1386
+ workspaceRuntimeRemovalAvailable: true,
1312
1387
  // Advertise the same WS feature flags as the runtime path (serve-features.ts)
1313
1388
  // so the bootstrap `/capabilities` window doesn't briefly under-report them.
1314
1389
  clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
@@ -1477,6 +1552,7 @@ function createBootstrapServeApp(input) {
1477
1552
  multiWorkspaceCapabilitiesRequireRuntime,
1478
1553
  getRuntimeError,
1479
1554
  getChannelWorkerSnapshot,
1555
+ getChannelWorkerSnapshots,
1480
1556
  onHealthServed
1481
1557
  } = input;
1482
1558
  const app = (0, import_express.default)();
@@ -1545,6 +1621,7 @@ function createBootstrapServeApp(input) {
1545
1621
  }
1546
1622
  const runtimeError = getRuntimeError();
1547
1623
  const channelWorker = getChannelWorkerSnapshot();
1624
+ const channelWorkers = getChannelWorkerSnapshots();
1548
1625
  const runtimeFailed = runtimeError !== void 0;
1549
1626
  const issue = runtimeError ? {
1550
1627
  code: "daemon_runtime_failed",
@@ -1616,6 +1693,7 @@ function createBootstrapServeApp(input) {
1616
1693
  },
1617
1694
  channel: { live: false },
1618
1695
  channelWorker,
1696
+ ...channelWorkers.length > 0 ? { channelWorkers } : {},
1619
1697
  transport: {
1620
1698
  restSseActive: 0,
1621
1699
  acp: {
@@ -1706,7 +1784,7 @@ function isChannelWebhookRequest(req) {
1706
1784
  return req.method === "POST" && /^\/channels\/[^/]+\/webhooks\/[^/]+\/?$/u.test(req.path);
1707
1785
  }
1708
1786
  __name(isChannelWebhookRequest, "isChannelWebhookRequest");
1709
- function createDeferredChannelWebhookAuth(workspace, runtime, daemonLog) {
1787
+ function createDeferredChannelWebhookAuth(resolveSource, runtime, daemonLog) {
1710
1788
  return (req, res, next) => {
1711
1789
  const match = /^\/channels\/([^/]+)\/webhooks\/([^/]+)\/?$/u.exec(req.path);
1712
1790
  const channelName = decodeDeferredWebhookPathSegment(match?.[1]);
@@ -1720,11 +1798,13 @@ function createDeferredChannelWebhookAuth(workspace, runtime, daemonLog) {
1720
1798
  res.status(401).json({ error: "Invalid webhook secret" });
1721
1799
  return;
1722
1800
  }
1801
+ const configSource = resolveSource(channelName);
1723
1802
  const secret = readDeferredWebhookSecret(
1724
1803
  runtime,
1725
- workspace,
1804
+ configSource.workspaceCwd,
1726
1805
  channelName,
1727
- source
1806
+ source,
1807
+ configSource.env
1728
1808
  );
1729
1809
  if (!matchesWebhookSecret(req.get("x-qwen-webhook-secret"), secret)) {
1730
1810
  daemonLog.warn("deferred webhook auth failed", {
@@ -1748,7 +1828,7 @@ function decodeDeferredWebhookPathSegment(segment) {
1748
1828
  }
1749
1829
  }
1750
1830
  __name(decodeDeferredWebhookPathSegment, "decodeDeferredWebhookPathSegment");
1751
- function readDeferredWebhookSecret(runtime, workspace, channelName, source) {
1831
+ function readDeferredWebhookSecret(runtime, workspace, channelName, source, env) {
1752
1832
  try {
1753
1833
  const rawConfig = runtime.loadChannelsConfig(workspace)[channelName];
1754
1834
  if (typeof rawConfig !== "object" || rawConfig === null) {
@@ -1756,7 +1836,8 @@ function readDeferredWebhookSecret(runtime, workspace, channelName, source) {
1756
1836
  }
1757
1837
  return runtime.parseChannelWebhookConfig(
1758
1838
  channelName,
1759
- rawConfig
1839
+ rawConfig,
1840
+ env
1760
1841
  )?.sources[source]?.secret;
1761
1842
  } catch (err) {
1762
1843
  const reason = err instanceof Error ? err.message : String(err);
@@ -1841,30 +1922,42 @@ async function runQwenServe(optsIn, deps = {}) {
1841
1922
  clientMcpOverWs: optsIn.clientMcpOverWs ?? (!envFlagDisabled(clientMcpOverWsEnv) && clientMcpOverWsEnv !== void 0),
1842
1923
  cdpTunnelOverWs: optsIn.cdpTunnelOverWs ?? (!envFlagDisabled(cdpTunnelOverWsEnv) && (cdpTunnelOverWsEnv !== void 0 || chromeExtensionOriginAllowed))
1843
1924
  };
1844
- const channelRuntime = opts.channelSelection ? await loadChannelWorkerRuntime() : void 0;
1845
- const channelServicePidfile = deps.channelServicePidfile ?? channelRuntime?.channelServicePidfile;
1925
+ let channelRuntime = opts.channelSelection ? await loadChannelWorkerRuntime() : void 0;
1926
+ let channelServicePidfile = deps.channelServicePidfile ?? channelRuntime?.channelServicePidfile;
1927
+ const ensureChannelRuntime = /* @__PURE__ */ __name(async () => {
1928
+ channelRuntime ??= await loadChannelWorkerRuntime();
1929
+ channelServicePidfile ??= channelRuntime.channelServicePidfile;
1930
+ return channelRuntime;
1931
+ }, "ensureChannelRuntime");
1846
1932
  let channelPidfileReserved = false;
1847
1933
  const removeCurrentServePidfile = /* @__PURE__ */ __name(() => {
1848
- if (!opts.channelSelection || !channelServicePidfile) return;
1934
+ if (!channelServicePidfile) return;
1849
1935
  if (!channelPidfileReserved) return;
1850
1936
  if (channelServicePidfile.removeServeServiceInfo) {
1851
1937
  if (channelServicePidfile.removeServeServiceInfo(process.pid)) {
1852
1938
  channelPidfileReserved = false;
1939
+ } else {
1940
+ const info2 = channelServicePidfile.readServiceInfo();
1941
+ if (!info2 || info2.owner !== "serve" || info2.pid !== process.pid || info2.servePid !== process.pid) {
1942
+ channelPidfileReserved = false;
1943
+ }
1853
1944
  }
1854
1945
  return;
1855
1946
  }
1856
1947
  const info = channelServicePidfile.readServiceInfo();
1857
1948
  if (info?.owner === "serve" && info.pid === process.pid && info.servePid === process.pid) {
1858
1949
  channelServicePidfile.removeServiceInfo();
1950
+ const remaining = channelServicePidfile.readServiceInfo();
1951
+ channelPidfileReserved = remaining?.owner === "serve" && remaining.pid === process.pid && remaining.servePid === process.pid;
1952
+ } else {
1859
1953
  channelPidfileReserved = false;
1860
1954
  }
1861
1955
  }, "removeCurrentServePidfile");
1862
- const reserveChannelServicePidfile = /* @__PURE__ */ __name(() => {
1863
- if (!opts.channelSelection) return;
1956
+ const reserveChannelServicePidfile = /* @__PURE__ */ __name((selection) => {
1864
1957
  if (!channelServicePidfile) {
1865
1958
  throw new Error("Channel service pidfile runtime is not available.");
1866
1959
  }
1867
- const channelPidfileNames = channelSelectionNames(opts.channelSelection);
1960
+ const channelPidfileNames = channelSelectionNames(selection);
1868
1961
  const existingChannelService = channelServicePidfile.readServiceInfo();
1869
1962
  if (existingChannelService) {
1870
1963
  throw channelServicePidfileConflictError(existingChannelService);
@@ -1889,9 +1982,7 @@ async function runQwenServe(optsIn, deps = {}) {
1889
1982
  return;
1890
1983
  } catch (retryErr) {
1891
1984
  if (retryErr && typeof retryErr === "object" && "code" in retryErr && retryErr.code === "EEXIST") {
1892
- throw new Error(
1893
- "Channel service is already starting. Retry after the current startup finishes."
1894
- );
1985
+ throw channelServiceStartingConflictError();
1895
1986
  }
1896
1987
  throw retryErr;
1897
1988
  }
@@ -2010,7 +2101,9 @@ async function runQwenServe(optsIn, deps = {}) {
2010
2101
  }, "validateAndCanonicalizeWorkspace");
2011
2102
  const workspaceInputs = rawWorkspaces.map((workspace) => ({
2012
2103
  raw: workspace,
2013
- cwd: validateAndCanonicalizeWorkspace(workspace)
2104
+ cwd: validateAndCanonicalizeWorkspace(workspace),
2105
+ removable: false,
2106
+ registrationIds: []
2014
2107
  }));
2015
2108
  const boundWorkspace = workspaceInputs[0].cwd;
2016
2109
  const seenCanonicalWorkspaces = /* @__PURE__ */ new Set();
@@ -2042,6 +2135,71 @@ async function runQwenServe(optsIn, deps = {}) {
2042
2135
  }
2043
2136
  }
2044
2137
  }
2138
+ if (workspaceInputs.length > MAX_REGISTERED_WORKSPACES) {
2139
+ throw new Error(
2140
+ `At most ${MAX_REGISTERED_WORKSPACES} --workspace values may be registered.`
2141
+ );
2142
+ }
2143
+ let workspaceRegistrationStore = deps.workspaceRegistrationStore;
2144
+ if (workspaceRegistrationStore === void 0 && process.env["QWEN_SERVE_NO_PERSISTENT_REGISTRATION"] !== "1") {
2145
+ const { WorkspaceRegistrationStore } = await import("./workspace-registration-store-SLEU3D3X.js");
2146
+ workspaceRegistrationStore = new WorkspaceRegistrationStore(boundWorkspace);
2147
+ }
2148
+ if (workspaceRegistrationStore) {
2149
+ try {
2150
+ const stored = await workspaceRegistrationStore.read();
2151
+ for (const storedWorkspace of stored.workspaces) {
2152
+ const registrationId = workspaceRegistrationId(storedWorkspace);
2153
+ let cwd;
2154
+ try {
2155
+ cwd = validateAndCanonicalizeWorkspace(storedWorkspace);
2156
+ } catch (err) {
2157
+ writeStderrLine(
2158
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2159
+ storedWorkspace
2160
+ )}: ${err instanceof Error ? err.message : String(err)}`
2161
+ );
2162
+ continue;
2163
+ }
2164
+ const existingInput = workspaceInputs.find(
2165
+ (workspace) => workspace.cwd === cwd
2166
+ );
2167
+ if (existingInput) {
2168
+ existingInput.registrationIds.push(registrationId);
2169
+ continue;
2170
+ }
2171
+ const nested = workspaceInputs.some(
2172
+ (workspace) => isWithinRoot(cwd, workspace.cwd) || isWithinRoot(workspace.cwd, cwd)
2173
+ );
2174
+ if (nested) {
2175
+ writeStderrLine(
2176
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2177
+ storedWorkspace
2178
+ )}: path nests with an explicit or earlier restored workspace`
2179
+ );
2180
+ continue;
2181
+ }
2182
+ if (workspaceInputs.length >= MAX_REGISTERED_WORKSPACES) {
2183
+ writeStderrLine(
2184
+ `qwen serve: skipping persisted workspace registration ${JSON.stringify(
2185
+ storedWorkspace
2186
+ )}: workspace limit reached`
2187
+ );
2188
+ continue;
2189
+ }
2190
+ workspaceInputs.push({
2191
+ raw: storedWorkspace,
2192
+ cwd,
2193
+ removable: true,
2194
+ registrationIds: [registrationId]
2195
+ });
2196
+ }
2197
+ } catch (err) {
2198
+ writeStderrLine(
2199
+ `qwen serve: failed to read persisted workspace registrations: ${err instanceof Error ? err.message : String(err)}; continuing with explicit workspaces only`
2200
+ );
2201
+ }
2202
+ }
2045
2203
  if (workspaceInputs.length > 1 && deps.bridge) {
2046
2204
  throw new Error(
2047
2205
  "Injected bridge dependencies are only supported with a single workspace; multiple --workspace values require runQwenServe to construct one bridge per workspace."
@@ -2227,21 +2385,139 @@ async function runQwenServe(optsIn, deps = {}) {
2227
2385
  void runtimeReady.catch(() => {
2228
2386
  });
2229
2387
  const disposeDaemonEventLoopMonitor = /* @__PURE__ */ __name(() => {
2230
- daemonEventLoopMonitor?.dispose();
2388
+ const eventLoopMonitor = daemonEventLoopMonitor;
2231
2389
  daemonEventLoopMonitor = void 0;
2232
- daemonMetricsSampler?.dispose();
2390
+ const metricsSampler = daemonMetricsSampler;
2233
2391
  daemonMetricsSampler = void 0;
2392
+ try {
2393
+ eventLoopMonitor?.dispose();
2394
+ } catch (err) {
2395
+ daemonLog.warn(
2396
+ `event loop monitor dispose error: ${err instanceof Error ? err.message : String(err)}`
2397
+ );
2398
+ }
2399
+ try {
2400
+ metricsSampler?.dispose();
2401
+ } catch (err) {
2402
+ daemonLog.warn(
2403
+ `metrics sampler dispose error: ${err instanceof Error ? err.message : String(err)}`
2404
+ );
2405
+ }
2234
2406
  }, "disposeDaemonEventLoopMonitor");
2235
- let channelWorker = createDisabledChannelWorkerSupervisor();
2236
- const getChannelWorkerSnapshot = /* @__PURE__ */ __name(() => channelWorker.snapshot(), "getChannelWorkerSnapshot");
2237
- const reloadChannelWorker = /* @__PURE__ */ __name(() => channelWorker.restart(), "reloadChannelWorker");
2238
- const writeChannelWorkerPidfile = /* @__PURE__ */ __name((snapshot = channelWorker.snapshot(), options = {}) => {
2239
- if (!opts.channelSelection || !channelServicePidfile) return;
2407
+ let channelWorkerManager;
2408
+ let channelWorkerManagerStarting;
2409
+ let channelControlDraining = false;
2410
+ let channelWorkspaceGroups;
2411
+ const channelWebhookEnvByWorkspace = /* @__PURE__ */ new Map();
2412
+ let channelWebhookConfigVersion = 0;
2413
+ let refreshChannelWebhookConfigs;
2414
+ let ensureChannelWorkerManager;
2415
+ const getChannelWebhookConfigSources = /* @__PURE__ */ __name(() => {
2416
+ const app2 = runtimeApp ?? runtimeAppForCleanup;
2417
+ const registry = app2?.locals?.["workspaceRegistry"];
2418
+ return (channelWorkspaceGroups ?? []).map((group) => {
2419
+ const env = registry?.getByWorkspaceCwd(group.workspaceCwd)?.env.effectiveEnv ?? channelWebhookEnvByWorkspace.get(group.workspaceCwd);
2420
+ return {
2421
+ workspaceCwd: group.workspaceCwd,
2422
+ ...group.selection.mode === "names" ? { channelNames: group.selection.names } : {},
2423
+ ...env ? { env } : {}
2424
+ };
2425
+ });
2426
+ }, "getChannelWebhookConfigSources");
2427
+ const resolveChannelWebhookConfigSource = /* @__PURE__ */ __name((channelName) => {
2428
+ const source = getChannelWebhookConfigSources().find(
2429
+ (source2) => !source2.channelNames || source2.channelNames.includes(channelName)
2430
+ );
2431
+ if (source) return source;
2432
+ const env = channelWebhookEnvByWorkspace.get(boundWorkspace);
2433
+ return {
2434
+ workspaceCwd: boundWorkspace,
2435
+ ...env ? { env } : {}
2436
+ };
2437
+ }, "resolveChannelWebhookConfigSource");
2438
+ let closeServerAfterChannelWorkerStartupFailure = false;
2439
+ let runtimeFailureListenerClose;
2440
+ const getChannelWorkerSnapshot = /* @__PURE__ */ __name(() => channelWorkerManager?.primarySnapshot() ?? {
2441
+ enabled: false,
2442
+ state: "disabled",
2443
+ channels: []
2444
+ }, "getChannelWorkerSnapshot");
2445
+ const getChannelWorkerSnapshots = /* @__PURE__ */ __name(() => channelWorkerManager?.snapshots() ?? [], "getChannelWorkerSnapshots");
2446
+ const getChannelWorkerControl = /* @__PURE__ */ __name(() => channelWorkerManager?.state() ?? {
2447
+ enabled: false,
2448
+ selection: null,
2449
+ transition: "idle",
2450
+ workers: []
2451
+ }, "getChannelWorkerControl");
2452
+ const daemonDrainingError = /* @__PURE__ */ __name(() => Object.assign(new Error("Daemon is shutting down."), {
2453
+ code: "daemon_draining"
2454
+ }), "daemonDrainingError");
2455
+ const setChannelWorkerSelection = /* @__PURE__ */ __name(async (selection) => {
2456
+ if (channelControlDraining) throw daemonDrainingError();
2457
+ const manager = await ensureChannelWorkerManager?.();
2458
+ if (!manager) throw new Error("Channel worker manager is unavailable.");
2459
+ if (channelControlDraining) {
2460
+ await manager.shutdown().catch(() => void 0);
2461
+ throw daemonDrainingError();
2462
+ }
2463
+ return manager.setSelection(selection);
2464
+ }, "setChannelWorkerSelection");
2465
+ const stopChannelWorker = /* @__PURE__ */ __name(async () => {
2466
+ if (channelControlDraining) throw daemonDrainingError();
2467
+ const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
2468
+ if (channelControlDraining) {
2469
+ await manager?.shutdown().catch(() => void 0);
2470
+ throw daemonDrainingError();
2471
+ }
2472
+ if (!manager) {
2473
+ return { changed: false, state: getChannelWorkerControl() };
2474
+ }
2475
+ return manager.stopSelection();
2476
+ }, "stopChannelWorker");
2477
+ const reloadChannelWorker = /* @__PURE__ */ __name(async () => {
2478
+ if (channelControlDraining) throw daemonDrainingError();
2479
+ const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
2480
+ if (channelControlDraining) {
2481
+ await manager?.shutdown().catch(() => void 0);
2482
+ throw daemonDrainingError();
2483
+ }
2484
+ if (!manager) {
2485
+ return { enabled: false, state: "disabled", channels: [] };
2486
+ }
2487
+ try {
2488
+ return await manager.reload();
2489
+ } finally {
2490
+ writeChannelWorkerPidfile();
2491
+ }
2492
+ }, "reloadChannelWorker");
2493
+ const isLiveWorker = /* @__PURE__ */ __name((snapshot) => snapshot.state === "running" || snapshot.state === "starting", "isLiveWorker");
2494
+ let channelWorkerPidfileUsesWorkers = workspaceInputs.length > 1;
2495
+ const writeChannelWorkerPidfile = /* @__PURE__ */ __name(() => {
2496
+ if (runtimeStartupError !== void 0) return;
2497
+ if (!channelPidfileReserved || !channelServicePidfile) return;
2498
+ const snapshots = getChannelWorkerSnapshots();
2499
+ const workers = snapshots.map((snapshot) => ({
2500
+ workspaceId: snapshot.workspaceId,
2501
+ workspaceCwd: snapshot.workspaceCwd,
2502
+ channels: snapshot.channels,
2503
+ // Drop a stale pid (worker exited/failed/stopped) so readers never signal
2504
+ // a dead process — mirrors the pre-4b clear-on-exit behavior.
2505
+ ...isLiveWorker(snapshot) && snapshot.pid !== void 0 ? { workerPid: snapshot.pid } : {}
2506
+ }));
2507
+ const channels = [
2508
+ ...new Set(snapshots.flatMap((snapshot) => snapshot.channels))
2509
+ ];
2510
+ const primary = snapshots.find((snapshot) => snapshot.primary);
2511
+ if (workers.length > 1 || snapshots.some((snapshot) => !snapshot.primary)) {
2512
+ channelWorkerPidfileUsesWorkers = true;
2513
+ }
2514
+ const includeWorkers = channelWorkerPidfileUsesWorkers && workers.length > 0;
2240
2515
  try {
2241
2516
  channelServicePidfile.writeServeServiceInfo({
2242
- channels: snapshot.channels,
2517
+ channels,
2243
2518
  servePid: process.pid,
2244
- ...!options.clearWorkerPid && snapshot.pid !== void 0 ? { workerPid: snapshot.pid } : {}
2519
+ ...primary && isLiveWorker(primary) && primary.pid !== void 0 ? { workerPid: primary.pid } : {},
2520
+ ...includeWorkers ? { workers } : {}
2245
2521
  });
2246
2522
  } catch (err) {
2247
2523
  daemonLog.warn(
@@ -2254,11 +2530,83 @@ async function runQwenServe(optsIn, deps = {}) {
2254
2530
  () => runtimeStartupError
2255
2531
  );
2256
2532
  const shutdownBridges = /* @__PURE__ */ new WeakSet();
2533
+ const disposedRuntimeApps = /* @__PURE__ */ new WeakSet();
2534
+ const stoppedRuntimeAppProducers = /* @__PURE__ */ new WeakSet();
2535
+ const stoppedExtensionReconcilers = /* @__PURE__ */ new WeakSet();
2536
+ const stopExtensionReconciler = /* @__PURE__ */ __name((app2) => {
2537
+ if (!app2 || stoppedExtensionReconcilers.has(app2)) return;
2538
+ stoppedExtensionReconcilers.add(app2);
2539
+ const stopExtensionGenerationReconciler = app2.locals?.["stopExtensionGenerationReconciler"];
2540
+ try {
2541
+ stopExtensionGenerationReconciler?.();
2542
+ } catch (err) {
2543
+ daemonLog.warn(
2544
+ `extension generation reconciler dispose error: ${err instanceof Error ? err.message : String(err)}`
2545
+ );
2546
+ }
2547
+ }, "stopExtensionReconciler");
2548
+ const stopRuntimeAppProducers = /* @__PURE__ */ __name((app2) => {
2549
+ if (!app2 || stoppedRuntimeAppProducers.has(app2)) return;
2550
+ stoppedRuntimeAppProducers.add(app2);
2551
+ const locals = app2.locals;
2552
+ const stopSafely = /* @__PURE__ */ __name((name, stop) => {
2553
+ try {
2554
+ stop?.();
2555
+ } catch (err) {
2556
+ daemonLog.warn(
2557
+ `${name} dispose error: ${err instanceof Error ? err.message : String(err)}`
2558
+ );
2559
+ }
2560
+ }, "stopSafely");
2561
+ stopSafely("scheduled-task keepalive", locals.stopScheduledTaskKeepalive);
2562
+ stopSafely("workspace git state", locals.stopWorkspaceGitState);
2563
+ for (const stop of locals.subSessionStoppers ?? []) {
2564
+ stopSafely("sub-session launcher", stop);
2565
+ }
2566
+ stopExtensionReconciler(app2);
2567
+ }, "stopRuntimeAppProducers");
2568
+ const disposeRuntimeAppResources = /* @__PURE__ */ __name((app2) => {
2569
+ if (!app2 || disposedRuntimeApps.has(app2)) return;
2570
+ disposedRuntimeApps.add(app2);
2571
+ stopRuntimeAppProducers(app2);
2572
+ const deviceFlowRegistry = getDeviceFlowRegistry(app2);
2573
+ if (deviceFlowRegistry) {
2574
+ try {
2575
+ deviceFlowRegistry.dispose();
2576
+ } catch (err) {
2577
+ daemonLog.warn(
2578
+ `device-flow registry dispose error: ${err instanceof Error ? err.message : String(err)}`
2579
+ );
2580
+ }
2581
+ }
2582
+ const acpHandle = app2.locals?.["acpHandle"];
2583
+ if (acpHandle?.dispose) {
2584
+ try {
2585
+ acpHandle.dispose();
2586
+ } catch (err) {
2587
+ daemonLog.warn(
2588
+ `ACP handle dispose error: ${err instanceof Error ? err.message : String(err)}`
2589
+ );
2590
+ }
2591
+ }
2592
+ const rateLimiter = getRateLimiter(app2);
2593
+ if (rateLimiter) {
2594
+ try {
2595
+ rateLimiter.setDraining(true);
2596
+ rateLimiter.dispose();
2597
+ } catch (err) {
2598
+ daemonLog.warn(
2599
+ `rate limiter dispose error: ${err instanceof Error ? err.message : String(err)}`
2600
+ );
2601
+ }
2602
+ }
2603
+ disposeDaemonEventLoopMonitor();
2604
+ }, "disposeRuntimeAppResources");
2257
2605
  const getRuntimeBridgesForCleanup = /* @__PURE__ */ __name(() => {
2258
2606
  const appForCleanup = runtimeApp ?? runtimeAppForCleanup;
2259
2607
  const registry = appForCleanup?.locals?.["workspaceRegistry"];
2260
2608
  const bridges = [
2261
- ...registry ? registry.list().map((runtime) => runtime.bridge) : [],
2609
+ ...registry ? registry.listManaged().map((runtime) => runtime.bridge) : [],
2262
2610
  ...bridgeRef ? [bridgeRef] : [],
2263
2611
  ...internalRuntimeBridgesForCleanup
2264
2612
  ];
@@ -2440,12 +2788,15 @@ async function runQwenServe(optsIn, deps = {}) {
2440
2788
  // `agent_message_chunk._meta` (`usage` + `durationMs`) at the bridge's
2441
2789
  // single session/update fan-in. Increments (not cumulative), so the ring
2442
2790
  // sums tokens per window (token-burn chart) and pools the round-trip times
2443
- // for the LLM-latency percentiles.
2444
- tokenUsage(inputTokens, outputTokens, durationMs) {
2791
+ // for the LLM-latency percentiles. `apiErrors` / `apiRetries` ride the
2792
+ // same frame (per-round increments, 0 when none) and window into the
2793
+ // model-API-health chart.
2794
+ tokenUsage(inputTokens, outputTokens, durationMs, apiErrors, apiRetries) {
2445
2795
  metricsRing.recordTokens(inputTokens, outputTokens);
2446
2796
  if (typeof durationMs === "number") {
2447
2797
  metricsRing.recordLlmDuration(durationMs);
2448
2798
  }
2799
+ metricsRing.recordApiActivity(apiErrors ?? 0, apiRetries ?? 0);
2449
2800
  }
2450
2801
  };
2451
2802
  return telemetry;
@@ -2550,6 +2901,63 @@ async function runQwenServe(optsIn, deps = {}) {
2550
2901
  [...next].sort()
2551
2902
  );
2552
2903
  }), "persistDisabledToolsFn");
2904
+ const persistDisabledSkillsFn = /* @__PURE__ */ __name((workspace, skillName, enabled) => withSettingsLock(workspace, async () => {
2905
+ const fresh = settingsRuntime.settings.loadSettings(workspace);
2906
+ const normalizedName = skillName.trim().toLowerCase();
2907
+ const disabledNames = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.filter(
2908
+ (entry) => typeof entry === "string"
2909
+ ) : [], "disabledNames");
2910
+ const lockedScopes = [
2911
+ ["system", fresh.system.settings.skills?.disabled],
2912
+ ["user", fresh.user.settings.skills?.disabled],
2913
+ ["systemDefaults", fresh.systemDefaults.settings.skills?.disabled]
2914
+ ];
2915
+ for (const [scope, names] of lockedScopes) {
2916
+ if (disabledNames(names).some(
2917
+ (name) => name.trim().toLowerCase() === normalizedName
2918
+ )) {
2919
+ throw new runtime.WorkspaceSkillNotToggleableError(
2920
+ skillName,
2921
+ "locked",
2922
+ scope
2923
+ );
2924
+ }
2925
+ }
2926
+ const workspaceDisabled = disabledNames(
2927
+ fresh.workspace.settings.skills?.disabled
2928
+ );
2929
+ const next = [];
2930
+ let found = false;
2931
+ let changed = false;
2932
+ for (const name of workspaceDisabled) {
2933
+ if (name.trim().toLowerCase() !== normalizedName) {
2934
+ next.push(name);
2935
+ continue;
2936
+ }
2937
+ if (enabled) {
2938
+ changed = true;
2939
+ continue;
2940
+ }
2941
+ if (!found) {
2942
+ next.push(skillName);
2943
+ found = true;
2944
+ if (name !== skillName) changed = true;
2945
+ } else {
2946
+ changed = true;
2947
+ }
2948
+ }
2949
+ if (!enabled && !found) {
2950
+ next.push(skillName);
2951
+ changed = true;
2952
+ }
2953
+ if (!changed) return { changed: false, disabled: workspaceDisabled };
2954
+ fresh.setValue(
2955
+ WORKSPACE_SETTING_SCOPE,
2956
+ "skills.disabled",
2957
+ next.length > 0 ? next : void 0
2958
+ );
2959
+ return { changed: true, disabled: next };
2960
+ }), "persistDisabledSkillsFn");
2553
2961
  const persistSettingFn = /* @__PURE__ */ __name((workspace, scope, key, value) => withSettingsLock(workspace, async () => {
2554
2962
  const fresh = settingsRuntime.settings.loadSettings(workspace);
2555
2963
  fresh.setValue(scope, key, value);
@@ -2582,7 +2990,7 @@ async function runQwenServe(optsIn, deps = {}) {
2582
2990
  );
2583
2991
  }
2584
2992
  }), "persistSettingsFn");
2585
- const { createSubSessionLauncher } = await import("./create-sub-session-KPRT7ECJ.js");
2993
+ const { createSubSessionLauncher } = await import("./create-sub-session-SUN33INC.js");
2586
2994
  const subSessionLauncher = createSubSessionLauncher({
2587
2995
  getBridge: /* @__PURE__ */ __name(() => bridgeRef, "getBridge"),
2588
2996
  boundWorkspace
@@ -2623,14 +3031,18 @@ async function runQwenServe(optsIn, deps = {}) {
2623
3031
  internalRuntimeBridgesForCleanup.push(bridge);
2624
3032
  }
2625
3033
  runtimeBridges.push(bridge);
3034
+ let invalidatePrimaryServeFeaturesCache = /* @__PURE__ */ __name(() => {
3035
+ }, "invalidatePrimaryServeFeaturesCache");
2626
3036
  const workspaceService = runtime.createDaemonWorkspaceService({
2627
3037
  boundWorkspace,
2628
3038
  contextFilename: contextFilenameForInit ?? "QWEN.md",
2629
3039
  statusProvider,
2630
3040
  workspaceProvidersStatusProvider,
2631
3041
  workspaceSkillsStatusProvider,
3042
+ voiceEnv: runtimeEffectiveEnv,
2632
3043
  isChannelLive: /* @__PURE__ */ __name(() => bridge.isChannelLive(), "isChannelLive"),
2633
3044
  persistDisabledTools: persistDisabledToolsFn,
3045
+ persistDisabledSkills: persistDisabledSkillsFn,
2634
3046
  persistSetting: persistSettingFn,
2635
3047
  persistSettings: persistSettingsFn,
2636
3048
  preheatAcpChild: /* @__PURE__ */ __name(() => bridge.preheat(), "preheatAcpChild"),
@@ -2696,7 +3108,12 @@ async function runQwenServe(optsIn, deps = {}) {
2696
3108
  queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => bridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
2697
3109
  invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => bridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
2698
3110
  refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => bridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
2699
- publishWorkspaceEvent: /* @__PURE__ */ __name((event) => bridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
3111
+ publishWorkspaceEvent: /* @__PURE__ */ __name((event) => {
3112
+ if (event.type === "settings_changed" || event.type === "settings_reloaded") {
3113
+ invalidatePrimaryServeFeaturesCache();
3114
+ }
3115
+ bridge.publishWorkspaceEvent(event);
3116
+ }, "publishWorkspaceEvent")
2700
3117
  });
2701
3118
  const workspaceRuntimes = [
2702
3119
  {
@@ -2704,6 +3121,8 @@ async function runQwenServe(optsIn, deps = {}) {
2704
3121
  workspaceCwd: boundWorkspace,
2705
3122
  primary: true,
2706
3123
  trusted: trustedWorkspace,
3124
+ removable: false,
3125
+ registrationIds: workspaceInputs[0]?.registrationIds ?? [],
2707
3126
  env: primaryRuntimeEnv,
2708
3127
  bridge,
2709
3128
  workspaceService,
@@ -2745,6 +3164,12 @@ async function runQwenServe(optsIn, deps = {}) {
2745
3164
  };
2746
3165
  }, "createRuntimeEnvMetadata");
2747
3166
  const subSessionStoppers = [];
3167
+ const subSessionStoppersByWorkspace = /* @__PURE__ */ new Map();
3168
+ const runtimeCleanupPromises = /* @__PURE__ */ new WeakMap();
3169
+ const removeArrayValue = /* @__PURE__ */ __name((values, value) => {
3170
+ const index = values.indexOf(value);
3171
+ if (index >= 0) values.splice(index, 1);
3172
+ }, "removeArrayValue");
2748
3173
  for (const workspaceInput of workspaceInputs.slice(1)) {
2749
3174
  let secondarySettings;
2750
3175
  try {
@@ -2838,6 +3263,10 @@ async function runQwenServe(optsIn, deps = {}) {
2838
3263
  runtimeBridges.push(secondaryBridge);
2839
3264
  internalRuntimeBridgesForCleanup.push(secondaryBridge);
2840
3265
  subSessionStoppers.push(secondarySubSessionLauncher.stop);
3266
+ subSessionStoppersByWorkspace.set(
3267
+ workspaceInput.cwd,
3268
+ secondarySubSessionLauncher.stop
3269
+ );
2841
3270
  const secondaryWorkspaceService = runtime.createDaemonWorkspaceService({
2842
3271
  boundWorkspace: workspaceInput.cwd,
2843
3272
  contextFilename: contextFilenameForInit ?? "QWEN.md",
@@ -2846,9 +3275,12 @@ async function runQwenServe(optsIn, deps = {}) {
2846
3275
  env: secondaryEnv.effectiveEnv
2847
3276
  }),
2848
3277
  workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
3278
+ voiceEnv: secondaryEnv.effectiveEnv,
3279
+ voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
2849
3280
  isChannelLive: /* @__PURE__ */ __name(() => secondaryBridge.isChannelLive(), "isChannelLive"),
2850
3281
  preheatAcpChild: /* @__PURE__ */ __name(() => secondaryBridge.preheat(), "preheatAcpChild"),
2851
3282
  persistDisabledTools: persistDisabledToolsFn,
3283
+ persistDisabledSkills: persistDisabledSkillsFn,
2852
3284
  persistSetting: persistSettingFn,
2853
3285
  persistSettings: persistSettingsFn,
2854
3286
  reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
@@ -2906,6 +3338,8 @@ async function runQwenServe(optsIn, deps = {}) {
2906
3338
  workspaceCwd: workspaceInput.cwd,
2907
3339
  primary: false,
2908
3340
  trusted: secondaryTrusted,
3341
+ removable: workspaceInput.removable,
3342
+ registrationIds: workspaceInput.registrationIds,
2909
3343
  env: secondaryEnv.metadata,
2910
3344
  bridge: secondaryBridge,
2911
3345
  workspaceService: secondaryWorkspaceService,
@@ -2916,6 +3350,7 @@ async function runQwenServe(optsIn, deps = {}) {
2916
3350
  const workspaceRegistry = runtime.createWorkspaceRegistry(workspaceRuntimes, {
2917
3351
  sessionOwnerIndex
2918
3352
  });
3353
+ const workspaceVoiceCoordinator = new WorkspaceVoiceCoordinator();
2919
3354
  core.registerDaemonGaugeCallbacks({
2920
3355
  sessionCount: /* @__PURE__ */ __name(() => workspaceRegistry.list().reduce((sum, item) => sum + item.bridge.sessionCount, 0), "sessionCount"),
2921
3356
  sseCount: /* @__PURE__ */ __name(() => runtime.getActiveSseCount(), "sseCount"),
@@ -2944,7 +3379,7 @@ async function runQwenServe(optsIn, deps = {}) {
2944
3379
  prevCpu = cpu;
2945
3380
  prevCpuAt = nowMs;
2946
3381
  }
2947
- const acp = app2.locals?.["acpHandle"]?.registry.getSnapshot();
3382
+ const acp = app2.locals?.["acpHandle"]?.getSnapshot();
2948
3383
  const hits = getRateLimiter(app2)?.getHitCounts();
2949
3384
  const rejectedTotal = hits ? hits.prompt + hits.mutation + hits.read : 0;
2950
3385
  const rateLimitRejected = prevRateRejected === void 0 ? 0 : Math.max(0, rejectedTotal - prevRateRejected);
@@ -3049,111 +3484,139 @@ async function runQwenServe(optsIn, deps = {}) {
3049
3484
  getBridge: /* @__PURE__ */ __name(() => wsBridgeRef, "getBridge"),
3050
3485
  boundWorkspace: cwd
3051
3486
  });
3052
- const wsBridge = runtime.createAcpSessionBridge({
3053
- clientMcpSender: wsClientMcpRegistry.lookup,
3054
- onCreateSubSession: wsSubSessionLauncher.launch,
3055
- maxSessions: opts.maxSessions,
3056
- freshSessionAdmission: totalSessionAdmission.admit,
3057
- sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
3058
- ...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
3059
- ...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
3060
- ...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
3061
- ...opts.channelIdleTimeoutMs !== void 0 ? { channelIdleTimeoutMs: opts.channelIdleTimeoutMs } : {},
3062
- ...opts.sessionReapIntervalMs !== void 0 ? { sessionReapIntervalMs: opts.sessionReapIntervalMs } : {},
3063
- ...opts.sessionIdleTimeoutMs !== void 0 ? { sessionIdleTimeoutMs: opts.sessionIdleTimeoutMs } : {},
3064
- ...opts.permissionResponseTimeoutMs !== void 0 ? { permissionResponseTimeoutMs: opts.permissionResponseTimeoutMs } : {},
3065
- boundWorkspace: cwd,
3066
- sessionShellCommandEnabled,
3067
- childEnvOverrides,
3068
- channelFactory: wsChannelFactory,
3069
- onDiagnosticLine: diagnosticSink,
3070
- telemetry: createRuntimeBridgeTelemetry(wsHash),
3071
- ...permissionPolicy !== void 0 ? { permissionPolicy } : {},
3072
- ...permissionConsensusQuorum !== void 0 ? { permissionConsensusQuorum } : {},
3073
- permissionAudit: permissionAuditPublisher,
3074
- statusProvider: runtime.createDaemonStatusProvider({
3075
- env: wsEnv.effectiveEnv
3076
- }),
3077
- fileSystem: createBridgeFileSystemAdapter(wsFsFactory),
3078
- persistApprovalMode: /* @__PURE__ */ __name((workspace, mode) => withSettingsLock(workspace, async () => {
3079
- const fresh = settingsRuntime.settings.loadSettings(workspace);
3080
- fresh.setValue(WORKSPACE_SETTING_SCOPE, "tools.approvalMode", mode);
3081
- }), "persistApprovalMode")
3082
- });
3487
+ let wsBridge;
3488
+ try {
3489
+ wsBridge = runtime.createAcpSessionBridge({
3490
+ clientMcpSender: wsClientMcpRegistry.lookup,
3491
+ onCreateSubSession: wsSubSessionLauncher.launch,
3492
+ maxSessions: opts.maxSessions,
3493
+ freshSessionAdmission: totalSessionAdmission.admit,
3494
+ sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
3495
+ ...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
3496
+ ...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
3497
+ ...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
3498
+ ...opts.channelIdleTimeoutMs !== void 0 ? { channelIdleTimeoutMs: opts.channelIdleTimeoutMs } : {},
3499
+ ...opts.sessionReapIntervalMs !== void 0 ? { sessionReapIntervalMs: opts.sessionReapIntervalMs } : {},
3500
+ ...opts.sessionIdleTimeoutMs !== void 0 ? { sessionIdleTimeoutMs: opts.sessionIdleTimeoutMs } : {},
3501
+ ...opts.permissionResponseTimeoutMs !== void 0 ? { permissionResponseTimeoutMs: opts.permissionResponseTimeoutMs } : {},
3502
+ boundWorkspace: cwd,
3503
+ sessionShellCommandEnabled,
3504
+ childEnvOverrides,
3505
+ channelFactory: wsChannelFactory,
3506
+ onDiagnosticLine: diagnosticSink,
3507
+ telemetry: createRuntimeBridgeTelemetry(wsHash),
3508
+ ...permissionPolicy !== void 0 ? { permissionPolicy } : {},
3509
+ ...permissionConsensusQuorum !== void 0 ? { permissionConsensusQuorum } : {},
3510
+ permissionAudit: permissionAuditPublisher,
3511
+ statusProvider: runtime.createDaemonStatusProvider({
3512
+ env: wsEnv.effectiveEnv
3513
+ }),
3514
+ fileSystem: createBridgeFileSystemAdapter(wsFsFactory),
3515
+ persistApprovalMode: /* @__PURE__ */ __name((workspace, mode) => withSettingsLock(workspace, async () => {
3516
+ const fresh = settingsRuntime.settings.loadSettings(workspace);
3517
+ fresh.setValue(
3518
+ WORKSPACE_SETTING_SCOPE,
3519
+ "tools.approvalMode",
3520
+ mode
3521
+ );
3522
+ }), "persistApprovalMode")
3523
+ });
3524
+ } catch (err) {
3525
+ wsSubSessionLauncher.stop();
3526
+ throw err;
3527
+ }
3083
3528
  wsBridgeRef = wsBridge;
3084
- const wsService = runtime.createDaemonWorkspaceService({
3085
- boundWorkspace: cwd,
3086
- contextFilename: contextFilenameForInit ?? "QWEN.md",
3087
- statusProvider: runtime.createDaemonStatusProvider({
3088
- env: wsEnv.effectiveEnv
3089
- }),
3090
- workspaceProvidersStatusProvider: runtime.createWorkspaceProvidersStatusProvider({
3091
- env: wsEnv.effectiveEnv
3092
- }),
3093
- workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
3094
- isChannelLive: /* @__PURE__ */ __name(() => wsBridge.isChannelLive(), "isChannelLive"),
3095
- preheatAcpChild: /* @__PURE__ */ __name(() => wsBridge.preheat(), "preheatAcpChild"),
3096
- persistDisabledTools: persistDisabledToolsFn,
3097
- persistSetting: persistSettingFn,
3098
- persistSettings: persistSettingsFn,
3099
- reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
3100
- const fresh = settingsRuntime.settings.loadSettings(workspace, {
3101
- skipLoadEnvironment: true
3102
- });
3103
- const result = settingsRuntime.settings.reloadEnvironment(
3104
- fresh.merged,
3105
- workspace
3106
- );
3107
- try {
3108
- const refreshedRuntimeEnv = settingsRuntime.environment.buildRuntimeEnvironment(
3529
+ let wsService;
3530
+ try {
3531
+ wsService = runtime.createDaemonWorkspaceService({
3532
+ boundWorkspace: cwd,
3533
+ contextFilename: contextFilenameForInit ?? "QWEN.md",
3534
+ statusProvider: runtime.createDaemonStatusProvider({
3535
+ env: wsEnv.effectiveEnv
3536
+ }),
3537
+ workspaceProvidersStatusProvider: runtime.createWorkspaceProvidersStatusProvider({
3538
+ env: wsEnv.effectiveEnv
3539
+ }),
3540
+ workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
3541
+ voiceEnv: wsEnv.effectiveEnv,
3542
+ voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
3543
+ isChannelLive: /* @__PURE__ */ __name(() => wsBridge.isChannelLive(), "isChannelLive"),
3544
+ preheatAcpChild: /* @__PURE__ */ __name(() => wsBridge.preheat(), "preheatAcpChild"),
3545
+ persistDisabledTools: persistDisabledToolsFn,
3546
+ persistDisabledSkills: persistDisabledSkillsFn,
3547
+ persistSetting: persistSettingFn,
3548
+ persistSettings: persistSettingsFn,
3549
+ reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
3550
+ const fresh = settingsRuntime.settings.loadSettings(workspace, {
3551
+ skipLoadEnvironment: true
3552
+ });
3553
+ const result = settingsRuntime.settings.reloadEnvironment(
3109
3554
  fresh.merged,
3110
- workspace,
3111
- daemonRuntimeBaseEnv
3555
+ workspace
3112
3556
  );
3113
- logRuntimeEnvFileReadFailures(workspace, refreshedRuntimeEnv);
3114
- wsEnv.replace(refreshedRuntimeEnv.effectiveEnv);
3115
- wsEnv.metadata.envFileReadFailed = refreshedRuntimeEnv.envFileReadFailed;
3116
- wsEnv.metadata.envFileReadFailures.splice(
3117
- 0,
3118
- wsEnv.metadata.envFileReadFailures.length,
3119
- ...refreshedRuntimeEnv.envFileReadFailures
3120
- );
3121
- wsEnv.metadata.overlayKeys.splice(
3122
- 0,
3123
- wsEnv.metadata.overlayKeys.length,
3124
- ...refreshedRuntimeEnv.overlayKeys
3125
- );
3126
- wsEnv.metadata.envFilePaths.splice(
3127
- 0,
3128
- wsEnv.metadata.envFilePaths.length,
3129
- ...refreshedRuntimeEnv.envFilePaths
3130
- );
3131
- delete wsEnv.metadata.fallbackReason;
3132
- } catch (err) {
3133
- wsEnv.metadata.fallbackReason = err instanceof Error ? err.message : String(err);
3134
- daemonLog.warn(
3135
- "failed to rebuild dynamic runtime env snapshot after daemon env reload; preserving previous runtime env",
3136
- {
3557
+ try {
3558
+ const refreshedRuntimeEnv = settingsRuntime.environment.buildRuntimeEnvironment(
3559
+ fresh.merged,
3137
3560
  workspace,
3138
- error: wsEnv.metadata.fallbackReason
3139
- }
3140
- );
3561
+ daemonRuntimeBaseEnv
3562
+ );
3563
+ logRuntimeEnvFileReadFailures(workspace, refreshedRuntimeEnv);
3564
+ wsEnv.replace(refreshedRuntimeEnv.effectiveEnv);
3565
+ wsEnv.metadata.envFileReadFailed = refreshedRuntimeEnv.envFileReadFailed;
3566
+ wsEnv.metadata.envFileReadFailures.splice(
3567
+ 0,
3568
+ wsEnv.metadata.envFileReadFailures.length,
3569
+ ...refreshedRuntimeEnv.envFileReadFailures
3570
+ );
3571
+ wsEnv.metadata.overlayKeys.splice(
3572
+ 0,
3573
+ wsEnv.metadata.overlayKeys.length,
3574
+ ...refreshedRuntimeEnv.overlayKeys
3575
+ );
3576
+ wsEnv.metadata.envFilePaths.splice(
3577
+ 0,
3578
+ wsEnv.metadata.envFilePaths.length,
3579
+ ...refreshedRuntimeEnv.envFilePaths
3580
+ );
3581
+ delete wsEnv.metadata.fallbackReason;
3582
+ } catch (err) {
3583
+ wsEnv.metadata.fallbackReason = err instanceof Error ? err.message : String(err);
3584
+ daemonLog.warn(
3585
+ "failed to rebuild dynamic runtime env snapshot after daemon env reload; preserving previous runtime env",
3586
+ {
3587
+ workspace,
3588
+ error: wsEnv.metadata.fallbackReason
3589
+ }
3590
+ );
3591
+ }
3592
+ return result;
3593
+ }), "reloadDaemonEnv"),
3594
+ queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => wsBridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
3595
+ invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => wsBridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
3596
+ refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => wsBridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
3597
+ publishWorkspaceEvent: /* @__PURE__ */ __name((event) => wsBridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
3598
+ });
3599
+ } catch (err) {
3600
+ wsSubSessionLauncher.stop();
3601
+ await wsBridge.shutdown().catch(() => {
3602
+ try {
3603
+ wsBridge.killAllSync();
3604
+ } catch {
3141
3605
  }
3142
- return result;
3143
- }), "reloadDaemonEnv"),
3144
- queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => wsBridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
3145
- invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => wsBridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
3146
- refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => wsBridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
3147
- publishWorkspaceEvent: /* @__PURE__ */ __name((event) => wsBridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
3148
- });
3606
+ });
3607
+ throw err;
3608
+ }
3149
3609
  runtimeBridges.push(wsBridge);
3150
3610
  internalRuntimeBridgesForCleanup.push(wsBridge);
3151
3611
  subSessionStoppers.push(wsSubSessionLauncher.stop);
3612
+ subSessionStoppersByWorkspace.set(cwd, wsSubSessionLauncher.stop);
3152
3613
  return {
3153
3614
  workspaceId: wsHash,
3154
3615
  workspaceCwd: cwd,
3155
3616
  primary: false,
3156
3617
  trusted,
3618
+ removable: true,
3619
+ registrationIds: [],
3157
3620
  env: wsEnv.metadata,
3158
3621
  bridge: wsBridge,
3159
3622
  workspaceService: wsService,
@@ -3161,9 +3624,135 @@ async function runQwenServe(optsIn, deps = {}) {
3161
3624
  clientMcpSenderRegistry: wsClientMcpRegistry
3162
3625
  };
3163
3626
  }, "createDynamicWorkspaceRuntime");
3627
+ const workspaceRuntimeRemoval = {
3628
+ async runtimeAdded(runtimeAdded) {
3629
+ const app3 = runtimeApp ?? runtimeAppForCleanup;
3630
+ const startScheduledTaskKeepaliveForWorkspace = app3?.locals?.["startScheduledTaskKeepaliveForWorkspace"];
3631
+ startScheduledTaskKeepaliveForWorkspace?.(runtimeAdded);
3632
+ if (!channelWorkerManager) return;
3633
+ try {
3634
+ await channelWorkerManager.restoreWorkspace(
3635
+ runtimeAdded.workspaceCwd
3636
+ );
3637
+ await channelWorkerManager.refreshWorkspaces();
3638
+ } catch (err) {
3639
+ daemonLog.error(
3640
+ "workspace channel worker startup error",
3641
+ err instanceof Error ? err : null
3642
+ );
3643
+ } finally {
3644
+ writeChannelWorkerPidfile();
3645
+ }
3646
+ },
3647
+ beginDrain(runtimeToDrain) {
3648
+ totalSessionAdmission.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
3649
+ channelWorkerManager?.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
3650
+ workspaceVoiceCoordinator.beginWorkspaceDrain(runtimeToDrain);
3651
+ },
3652
+ cancelDrain(runtimeToDrain) {
3653
+ channelWorkerManager?.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
3654
+ totalSessionAdmission.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
3655
+ workspaceVoiceCoordinator.cancelWorkspaceDrain(runtimeToDrain);
3656
+ },
3657
+ completeDrain(runtimeToDrain) {
3658
+ totalSessionAdmission.completeWorkspaceDrain(
3659
+ runtimeToDrain.workspaceCwd
3660
+ );
3661
+ workspaceVoiceCoordinator.completeWorkspaceDrain(runtimeToDrain);
3662
+ },
3663
+ getActivity(runtimeToDrain) {
3664
+ return {
3665
+ pendingSessionStarts: totalSessionAdmission.snapshotForWorkspace(
3666
+ runtimeToDrain.workspaceCwd
3667
+ ).inFlight,
3668
+ channelWorkers: channelWorkerManager?.workspaceActivity(
3669
+ runtimeToDrain.workspaceCwd
3670
+ ) ?? 0,
3671
+ voiceSessions: workspaceVoiceCoordinator.getWorkspaceActivity(runtimeToDrain)
3672
+ };
3673
+ },
3674
+ disposeRuntime(runtimeToDrain, reason = "workspace_removed") {
3675
+ const existing = runtimeCleanupPromises.get(runtimeToDrain);
3676
+ if (existing) return existing;
3677
+ const cleanup = (async () => {
3678
+ await workspaceVoiceCoordinator.disposeRuntime(
3679
+ runtimeToDrain,
3680
+ reason
3681
+ );
3682
+ const stopSubSessions = subSessionStoppersByWorkspace.get(
3683
+ runtimeToDrain.workspaceCwd
3684
+ );
3685
+ try {
3686
+ stopSubSessions?.();
3687
+ } catch {
3688
+ }
3689
+ if (reason === "workspace_removed" && channelWorkerManager) {
3690
+ await channelWorkerManager.removeWorkspace(runtimeToDrain.workspaceCwd).catch((err) => {
3691
+ daemonLog.error(
3692
+ "workspace channel worker cleanup error",
3693
+ err instanceof Error ? err : null
3694
+ );
3695
+ });
3696
+ try {
3697
+ await channelWorkerManager.refreshWorkspaces();
3698
+ } catch (err) {
3699
+ channelWorkspaceGroups = (channelWorkspaceGroups ?? []).filter(
3700
+ (group) => group.workspaceCwd !== runtimeToDrain.workspaceCwd
3701
+ );
3702
+ channelWebhookConfigVersion += 1;
3703
+ refreshChannelWebhookConfigs?.();
3704
+ daemonLog.error(
3705
+ "workspace channel worker topology refresh error",
3706
+ err instanceof Error ? err : null
3707
+ );
3708
+ }
3709
+ writeChannelWorkerPidfile();
3710
+ }
3711
+ if (reason === "workspace_removed") {
3712
+ const app3 = runtimeApp ?? runtimeAppForCleanup;
3713
+ const stopWorkspaceGitStateForWorkspace = app3?.locals?.["stopWorkspaceGitStateForWorkspace"];
3714
+ const stopScheduledTaskKeepaliveForWorkspace = app3?.locals?.["stopScheduledTaskKeepaliveForWorkspace"];
3715
+ stopWorkspaceGitStateForWorkspace?.(runtimeToDrain.workspaceCwd);
3716
+ stopScheduledTaskKeepaliveForWorkspace?.(
3717
+ runtimeToDrain.workspaceCwd
3718
+ );
3719
+ }
3720
+ let bridgeStopped = false;
3721
+ try {
3722
+ if (!shutdownBridges.has(runtimeToDrain.bridge)) {
3723
+ await runtimeToDrain.bridge.shutdown({ reason });
3724
+ }
3725
+ bridgeStopped = true;
3726
+ } finally {
3727
+ if (bridgeStopped || reason === "workspace_removed") {
3728
+ subSessionStoppersByWorkspace.delete(runtimeToDrain.workspaceCwd);
3729
+ if (stopSubSessions) {
3730
+ removeArrayValue(subSessionStoppers, stopSubSessions);
3731
+ }
3732
+ removeArrayValue(runtimeBridges, runtimeToDrain.bridge);
3733
+ removeArrayValue(
3734
+ internalRuntimeBridgesForCleanup,
3735
+ runtimeToDrain.bridge
3736
+ );
3737
+ shutdownBridges.add(runtimeToDrain.bridge);
3738
+ }
3739
+ }
3740
+ })();
3741
+ runtimeCleanupPromises.set(runtimeToDrain, cleanup);
3742
+ void cleanup.catch(() => {
3743
+ if (reason === "daemon_shutdown" && runtimeCleanupPromises.get(runtimeToDrain) === cleanup) {
3744
+ runtimeCleanupPromises.delete(runtimeToDrain);
3745
+ }
3746
+ });
3747
+ return cleanup;
3748
+ }
3749
+ };
3164
3750
  const app2 = runtime.createServeApp(opts, () => actualPort, {
3165
3751
  workspaceRegistry,
3166
3752
  createWorkspaceRuntime: createDynamicWorkspaceRuntime,
3753
+ workspaceRegistrationStore,
3754
+ workspaceRuntimeRemoval,
3755
+ voiceCoordinator: workspaceVoiceCoordinator,
3167
3756
  bridge,
3168
3757
  webShellDir,
3169
3758
  boundWorkspace,
@@ -3178,11 +3767,27 @@ async function runQwenServe(optsIn, deps = {}) {
3178
3767
  primaryRuntimeEnv,
3179
3768
  daemonLog,
3180
3769
  getChannelWorkerSnapshot,
3181
- enqueueChannelWebhookTask: /* @__PURE__ */ __name((task) => channelWorker.enqueueWebhookTask(task), "enqueueChannelWebhookTask"),
3182
- // Gate both the `channel_reload` capability and the reload route on the
3183
- // presence of this dep, so it is advertised only when a channel worker
3184
- // exists to reload.
3185
- ...opts.channelSelection ? { reloadChannelWorker } : {},
3770
+ getChannelWorkerSnapshots,
3771
+ getChannelWorkerControl,
3772
+ isChannelControlDraining: /* @__PURE__ */ __name(() => channelControlDraining, "isChannelControlDraining"),
3773
+ isChannelControlInitializing: /* @__PURE__ */ __name(() => channelWorkerManagerStarting !== void 0, "isChannelControlInitializing"),
3774
+ setChannelWorkerSelection,
3775
+ stopChannelWorker,
3776
+ getChannelWebhookConfigSources,
3777
+ getChannelWebhookConfigVersion: /* @__PURE__ */ __name(() => channelWebhookConfigVersion, "getChannelWebhookConfigVersion"),
3778
+ registerChannelWebhookConfigRefresh: /* @__PURE__ */ __name((refresh) => {
3779
+ refreshChannelWebhookConfigs = refresh;
3780
+ }, "registerChannelWebhookConfigRefresh"),
3781
+ enqueueChannelWebhookTask: /* @__PURE__ */ __name(async (task) => {
3782
+ if (!channelWorkerManager) {
3783
+ throw new ChannelWebhookEnqueueError(
3784
+ "channel_worker_unavailable",
3785
+ "Channel worker is not running."
3786
+ );
3787
+ }
3788
+ return channelWorkerManager.enqueueWebhookTask(task);
3789
+ }, "enqueueChannelWebhookTask"),
3790
+ reloadChannelWorker,
3186
3791
  getPerfSnapshot: /* @__PURE__ */ __name(() => ({
3187
3792
  eventLoop: currentDaemonEventLoopMonitor.snapshot(),
3188
3793
  promptQueueWait: {
@@ -3204,6 +3809,7 @@ async function runQwenServe(optsIn, deps = {}) {
3204
3809
  // so the WS provider and the child-answering bridge share one sender map.
3205
3810
  clientMcpSenderRegistry,
3206
3811
  persistDisabledTools: persistDisabledToolsFn,
3812
+ persistDisabledSkills: persistDisabledSkillsFn,
3207
3813
  persistSetting: persistSettingFn,
3208
3814
  persistSettings: persistSettingsFn,
3209
3815
  sessionArtifactsPersistenceAvailable: sessionArtifactsPersistenceAvailableFromSettings(
@@ -3247,16 +3853,18 @@ async function runQwenServe(optsIn, deps = {}) {
3247
3853
  }
3248
3854
  ), "installAuthProvider")
3249
3855
  });
3856
+ invalidatePrimaryServeFeaturesCache = app2.locals.invalidateServeFeaturesCache ?? invalidatePrimaryServeFeaturesCache;
3250
3857
  app2.locals.subSessionStoppers = subSessionStoppers;
3251
3858
  subSessionStoppers.push(subSessionLauncher.stop);
3859
+ subSessionStoppersByWorkspace.set(boundWorkspace, subSessionLauncher.stop);
3252
3860
  return { app: app2, bridge };
3253
3861
  }, "buildRuntime");
3254
3862
  if (deps.bridge) {
3255
3863
  const runtime = await buildRuntime();
3256
3864
  runtimeAppForCleanup = runtime.app;
3257
- runtimeApp = runtime.app;
3258
3865
  bridgeRef = runtime.bridge;
3259
3866
  if (!opts.channelSelection) {
3867
+ runtimeApp = runtime.app;
3260
3868
  runtimeStartupSettled = true;
3261
3869
  markRuntimeReady();
3262
3870
  }
@@ -3275,10 +3883,11 @@ async function runQwenServe(optsIn, deps = {}) {
3275
3883
  multiWorkspaceCapabilitiesRequireRuntime: workspaceInputs.length > 1,
3276
3884
  getRuntimeError: /* @__PURE__ */ __name(() => runtimeStartupError, "getRuntimeError"),
3277
3885
  getChannelWorkerSnapshot,
3886
+ getChannelWorkerSnapshots,
3278
3887
  onHealthServed: deferRuntimeUntilFirstHealth ? () => startRuntimeAfterHealth?.() : void 0
3279
3888
  });
3280
3889
  const deferredChannelWebhookAuth = deferRuntimeUntilFirstHealth ? createDeferredChannelWebhookAuth(
3281
- boundWorkspace,
3890
+ resolveChannelWebhookConfigSource,
3282
3891
  await loadChannelWebhookConfigRuntime(),
3283
3892
  daemonLog
3284
3893
  ) : void 0;
@@ -3304,7 +3913,70 @@ async function runQwenServe(optsIn, deps = {}) {
3304
3913
  `Invalid maxConnections: ${opts.maxConnections}. Must be >= 0 (0 / Infinity = unlimited).`
3305
3914
  );
3306
3915
  }
3307
- reserveChannelServicePidfile();
3916
+ const channelValidationSettingsRuntime = opts.channelSelection ? await loadSettingsRuntimeModules() : void 0;
3917
+ const resolveChannelWorkspaceGroupsAtListen = /* @__PURE__ */ __name(() => {
3918
+ if (!opts.channelSelection || !channelValidationSettingsRuntime || !channelRuntime) {
3919
+ return void 0;
3920
+ }
3921
+ const settingsByWorkspace = /* @__PURE__ */ new Map();
3922
+ if (workspaceInputs.length === 1) {
3923
+ const workspace = workspaceInputs[0];
3924
+ const settings = channelValidationSettingsRuntime.settings.loadSettings(
3925
+ workspace.cwd
3926
+ );
3927
+ channelWebhookEnvByWorkspace.set(
3928
+ workspace.cwd,
3929
+ channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
3930
+ settings.merged,
3931
+ workspace.cwd,
3932
+ daemonRuntimeBaseEnv
3933
+ ).effectiveEnv
3934
+ );
3935
+ return void 0;
3936
+ }
3937
+ const workspaces = workspaceInputs.map((workspace, index) => {
3938
+ const settings = channelValidationSettingsRuntime.settings.loadSettings(
3939
+ workspace.cwd
3940
+ );
3941
+ settingsByWorkspace.set(workspace.cwd, settings);
3942
+ channelWebhookEnvByWorkspace.set(
3943
+ workspace.cwd,
3944
+ channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
3945
+ settings.merged,
3946
+ workspace.cwd,
3947
+ daemonRuntimeBaseEnv
3948
+ ).effectiveEnv
3949
+ );
3950
+ const trusted = index === 0 && deps.trustedWorkspace !== void 0 ? deps.trustedWorkspace : channelValidationSettingsRuntime.trustedFolders.getWorkspaceTrustStatus(
3951
+ settings.merged,
3952
+ workspace.cwd
3953
+ ).effective.state === "trusted";
3954
+ return {
3955
+ workspaceCwd: workspace.cwd,
3956
+ primary: index === 0,
3957
+ trusted
3958
+ };
3959
+ });
3960
+ const grouping = resolveChannelWorkspaceGroups({
3961
+ workspaces,
3962
+ selection: opts.channelSelection,
3963
+ loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
3964
+ const settings = settingsByWorkspace.get(cwd);
3965
+ if (!settings) return {};
3966
+ return channelRuntime.loadChannelsConfig(cwd, settings);
3967
+ }, "loadChannelsConfig")
3968
+ });
3969
+ if (!grouping.ok) {
3970
+ throw Object.assign(new Error(grouping.error.message), {
3971
+ code: grouping.error.code,
3972
+ ...grouping.error.channel ? { channel: grouping.error.channel } : {}
3973
+ });
3974
+ }
3975
+ return grouping.groups;
3976
+ }, "resolveChannelWorkspaceGroupsAtListen");
3977
+ if (opts.channelSelection) {
3978
+ reserveChannelServicePidfile(opts.channelSelection);
3979
+ }
3308
3980
  return await new Promise((resolve, reject) => {
3309
3981
  const onListening = /* @__PURE__ */ __name(() => {
3310
3982
  startup.listenerReadyAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -3323,46 +3995,14 @@ async function runQwenServe(optsIn, deps = {}) {
3323
3995
  const scheme = tlsOptions ? "https" : "http";
3324
3996
  const url = `${scheme}://${formatHostForUrl(opts.hostname)}:${actualPort}`;
3325
3997
  try {
3326
- if (opts.channelSelection) {
3327
- const createSupervisor = deps.channelWorkerSupervisorFactory ?? channelRuntime?.createChannelWorkerSupervisor;
3328
- const findCliEntryPath = channelRuntime?.findCliEntryPath;
3329
- if (!createSupervisor || !findCliEntryPath) {
3330
- throw new Error(
3331
- "Channel worker supervisor runtime is not available."
3332
- );
3333
- }
3334
- channelWorker = createSupervisor({
3335
- cliEntryPath: findCliEntryPath(),
3336
- daemonUrl: formatChannelWorkerDaemonUrl(opts.hostname, actualPort),
3337
- ...token ? { daemonToken: token } : {},
3338
- workspace: boundWorkspace,
3339
- selection: opts.channelSelection,
3340
- onReady: /* @__PURE__ */ __name((snapshot) => {
3341
- writeChannelWorkerPidfile(snapshot);
3342
- }, "onReady"),
3343
- onLog: /* @__PURE__ */ __name(({ stream, line }) => {
3344
- const message = `channel worker ${stream}: ${line}`;
3345
- if (stream === "stderr") {
3346
- daemonLog.warn(message);
3347
- } else {
3348
- daemonLog.info(message);
3349
- }
3350
- }, "onLog"),
3351
- onExit: /* @__PURE__ */ __name((snapshot) => {
3352
- daemonLog.warn(
3353
- `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"})`
3354
- );
3355
- writeChannelWorkerPidfile(snapshot, { clearWorkerPid: true });
3356
- }, "onExit")
3357
- });
3358
- }
3998
+ channelWorkspaceGroups = resolveChannelWorkspaceGroupsAtListen();
3359
3999
  } catch (err) {
3360
4000
  removeCurrentServePidfile();
3361
4001
  const error = err instanceof Error ? err : new Error(String(err));
3362
4002
  server.close((closeErr) => {
3363
4003
  if (closeErr) {
3364
4004
  daemonLog.error(
3365
- "server close after channel worker setup error failed",
4005
+ "server close after channel worker validation error failed",
3366
4006
  closeErr
3367
4007
  );
3368
4008
  }
@@ -3370,6 +4010,19 @@ async function runQwenServe(optsIn, deps = {}) {
3370
4010
  });
3371
4011
  return;
3372
4012
  }
4013
+ if (channelWorkspaceGroups) {
4014
+ for (const group of channelWorkspaceGroups) {
4015
+ daemonLog.info("channel worker group assigned", {
4016
+ workspace: group.workspaceCwd,
4017
+ channels: group.selection.mode === "all" ? ["all"] : group.selection.names
4018
+ });
4019
+ }
4020
+ if (opts.channelSelection?.mode === "all") {
4021
+ writeStderrLine(
4022
+ "qwen serve: --channel all is primary-workspace only; non-primary workspace channels are not hosted."
4023
+ );
4024
+ }
4025
+ }
3373
4026
  writeStdoutLine(
3374
4027
  `qwen serve listening on ${url} (mode=${opts.mode}, workspace=${boundWorkspace})`
3375
4028
  );
@@ -3445,20 +4098,28 @@ async function runQwenServe(optsIn, deps = {}) {
3445
4098
  }
3446
4099
  }, "shutdownBridgeAfterFailedStartup");
3447
4100
  const stopChannelWorkerAfterFailedStartup = /* @__PURE__ */ __name(async () => {
3448
- await channelWorker.stop().catch((stopErr) => {
4101
+ if (!channelWorkerManager) return true;
4102
+ try {
4103
+ await channelWorkerManager.shutdown();
4104
+ return true;
4105
+ } catch (stopErr) {
3449
4106
  daemonLog.error(
3450
4107
  "channel worker stop after runtime startup error failed",
3451
4108
  stopErr instanceof Error ? stopErr : null
3452
4109
  );
3453
- });
4110
+ return false;
4111
+ }
3454
4112
  }, "stopChannelWorkerAfterFailedStartup");
3455
4113
  const failRuntimeStartup = /* @__PURE__ */ __name(async (err, bridgeForCleanup) => {
3456
4114
  const error = err instanceof Error ? err : new Error(String(err));
3457
4115
  if (runtimeStartupSettled) {
4116
+ disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
3458
4117
  await shutdownBridgeAfterFailedStartup(bridgeForCleanup);
3459
4118
  return;
3460
4119
  }
3461
4120
  runtimeStartupSettled = true;
4121
+ disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
4122
+ runtimeApp = void 0;
3462
4123
  clearRuntimeStartupTimer();
3463
4124
  const message = error.message;
3464
4125
  runtimeStartupError = message;
@@ -3468,14 +4129,28 @@ async function runQwenServe(optsIn, deps = {}) {
3468
4129
  }
3469
4130
  writeStderrLine(`qwen serve: runtime startup failed: ${message}`);
3470
4131
  daemonLog.error("runtime startup failed", error);
3471
- await stopChannelWorkerAfterFailedStartup();
4132
+ markRuntimeFailed(error);
4133
+ if (closeServerAfterChannelWorkerStartupFailure && server.listening) {
4134
+ runtimeFailureListenerClose = new Promise((resolve2) => {
4135
+ server.close((closeErr) => {
4136
+ if (closeErr) {
4137
+ daemonLog.error(
4138
+ "server close after runtime startup error failed",
4139
+ closeErr
4140
+ );
4141
+ }
4142
+ resolve2();
4143
+ });
4144
+ });
4145
+ server.closeAllConnections();
4146
+ }
4147
+ const channelWorkerStopped = await stopChannelWorkerAfterFailedStartup();
3472
4148
  disposeDaemonEventLoopMonitor();
3473
- removeCurrentServePidfile();
4149
+ if (channelWorkerStopped) removeCurrentServePidfile();
3474
4150
  const bridgesForCleanup = bridgeForCleanup ? [bridgeForCleanup, ...getRuntimeBridgesForCleanup()] : getRuntimeBridgesForCleanup();
3475
4151
  for (const bridge of [...new Set(bridgesForCleanup)]) {
3476
4152
  await shutdownBridgeAfterFailedStartup(bridge);
3477
4153
  }
3478
- markRuntimeFailed(error);
3479
4154
  }, "failRuntimeStartup");
3480
4155
  const armRuntimeStartupTimer = /* @__PURE__ */ __name(() => {
3481
4156
  if (runtimeStartupTimeoutMs <= 0 || runtimeStartupTimer) return;
@@ -3488,10 +4163,152 @@ async function runQwenServe(optsIn, deps = {}) {
3488
4163
  }, runtimeStartupTimeoutMs);
3489
4164
  runtimeStartupTimer.unref();
3490
4165
  }, "armRuntimeStartupTimer");
3491
- const completeRuntimeStartup = /* @__PURE__ */ __name(async () => {
4166
+ const resolveRuntimeChannelGroups = /* @__PURE__ */ __name(async (channelSelection, candidateApp, operation) => {
4167
+ const registry = candidateApp.locals?.["workspaceRegistry"];
4168
+ if (!registry) {
4169
+ throw new Error(
4170
+ "Workspace registry is not available for channel workers."
4171
+ );
4172
+ }
4173
+ const runtimes = registry.list();
4174
+ if (runtimes.length <= 1 && operation === "initial") {
4175
+ return [
4176
+ {
4177
+ workspaceCwd: registry.primary.workspaceCwd,
4178
+ selection: channelSelection
4179
+ }
4180
+ ];
4181
+ }
4182
+ const workerRuntime = await ensureChannelRuntime();
4183
+ const settingsRuntime = await loadSettingsRuntimeModules();
4184
+ const settingsByWorkspace = /* @__PURE__ */ new Map();
4185
+ const grouping = resolveChannelWorkspaceGroups({
4186
+ workspaces: runtimes.map((runtime) => {
4187
+ const settings = settingsRuntime.settings.loadSettings(
4188
+ runtime.workspaceCwd
4189
+ );
4190
+ settingsByWorkspace.set(runtime.workspaceCwd, settings);
4191
+ return {
4192
+ workspaceCwd: runtime.workspaceCwd,
4193
+ primary: runtime.primary,
4194
+ trusted: runtime.trusted
4195
+ };
4196
+ }),
4197
+ selection: channelSelection,
4198
+ loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
4199
+ const settings = settingsByWorkspace.get(cwd);
4200
+ return settings ? workerRuntime.loadChannelsConfig(cwd, settings) : {};
4201
+ }, "loadChannelsConfig")
4202
+ });
4203
+ if (!grouping.ok) {
4204
+ throw Object.assign(new Error(grouping.error.message), {
4205
+ code: grouping.error.code,
4206
+ ...grouping.error.channel ? { channel: grouping.error.channel } : {}
4207
+ });
4208
+ }
4209
+ return grouping.groups;
4210
+ }, "resolveRuntimeChannelGroups");
4211
+ ensureChannelWorkerManager = /* @__PURE__ */ __name(() => {
4212
+ if (channelWorkerManager) return Promise.resolve(channelWorkerManager);
4213
+ if (channelWorkerManagerStarting) return channelWorkerManagerStarting;
4214
+ const starting = (async () => {
4215
+ const candidateApp = runtimeApp ?? runtimeAppForCleanup;
4216
+ const registry = candidateApp?.locals?.["workspaceRegistry"];
4217
+ if (!candidateApp || !registry) {
4218
+ throw new Error(
4219
+ "Workspace registry is not available for channels."
4220
+ );
4221
+ }
4222
+ const workerRuntime = await ensureChannelRuntime();
4223
+ const createSupervisor = deps.channelWorkerSupervisorFactory ?? workerRuntime.createChannelWorkerSupervisor;
4224
+ const createGroup = /* @__PURE__ */ __name((groups) => workerRuntime.createChannelWorkerGroup({
4225
+ groups,
4226
+ registry,
4227
+ createSupervisor,
4228
+ shared: {
4229
+ cliEntryPath: workerRuntime.findCliEntryPath(),
4230
+ daemonUrl: formatChannelWorkerDaemonUrl(
4231
+ opts.hostname,
4232
+ actualPort
4233
+ ),
4234
+ ...token ? { daemonToken: token } : {}
4235
+ },
4236
+ onReady: /* @__PURE__ */ __name((snapshot) => {
4237
+ if (runtimeStartupError !== void 0) return;
4238
+ if (workspaceInputs.length > 1) {
4239
+ daemonLog.info("channel worker ready", {
4240
+ workspace: snapshot.workspaceCwd,
4241
+ pid: snapshot.pid,
4242
+ channels: snapshot.channels
4243
+ });
4244
+ }
4245
+ channelWorkerManager?.workerChanged();
4246
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4247
+ }, "onReady"),
4248
+ onExit: /* @__PURE__ */ __name((snapshot) => {
4249
+ const workspacePrefix = workspaceInputs.length > 1 ? `workspace=${snapshot.workspaceCwd}, ` : "";
4250
+ daemonLog.warn(
4251
+ `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"})`
4252
+ );
4253
+ channelWorkerManager?.workerChanged();
4254
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4255
+ }, "onExit"),
4256
+ onStateChange: /* @__PURE__ */ __name(() => {
4257
+ channelWorkerManager?.workerChanged();
4258
+ if (!runtimeStartupSettled) writeChannelWorkerPidfile();
4259
+ }, "onStateChange"),
4260
+ onLog: /* @__PURE__ */ __name(({ stream, line, workspaceCwd }) => {
4261
+ const message = workspaceInputs.length > 1 ? `channel worker [${workspaceCwd}] ${stream}: ${line}` : `channel worker ${stream}: ${line}`;
4262
+ if (stream === "stderr") daemonLog.warn(message);
4263
+ else daemonLog.info(message);
4264
+ }, "onLog")
4265
+ }), "createGroup");
4266
+ channelWorkerManager = workerRuntime.createChannelWorkerManager({
4267
+ resolveGroups: /* @__PURE__ */ __name((selection, operation) => resolveRuntimeChannelGroups(selection, candidateApp, operation), "resolveGroups"),
4268
+ createGroup,
4269
+ reserveLease: reserveChannelServicePidfile,
4270
+ releaseLease: /* @__PURE__ */ __name(() => {
4271
+ removeCurrentServePidfile();
4272
+ if (channelPidfileReserved) {
4273
+ throw new Error("Failed to release the channel service lease.");
4274
+ }
4275
+ }, "releaseLease"),
4276
+ initialLeaseReserved: channelPidfileReserved,
4277
+ onCommittedSelection: /* @__PURE__ */ __name((_selection, groups) => {
4278
+ channelWorkspaceGroups = groups;
4279
+ channelWebhookConfigVersion += 1;
4280
+ refreshChannelWebhookConfigs?.();
4281
+ }, "onCommittedSelection"),
4282
+ onStateChange: /* @__PURE__ */ __name(() => {
4283
+ if (runtimeStartupSettled) writeChannelWorkerPidfile();
4284
+ }, "onStateChange")
4285
+ });
4286
+ return channelWorkerManager;
4287
+ })();
4288
+ channelWorkerManagerStarting = starting;
4289
+ void starting.then(
4290
+ () => {
4291
+ if (channelWorkerManagerStarting === starting) {
4292
+ channelWorkerManagerStarting = void 0;
4293
+ }
4294
+ },
4295
+ () => {
4296
+ if (channelWorkerManagerStarting === starting) {
4297
+ channelWorkerManagerStarting = void 0;
4298
+ }
4299
+ }
4300
+ );
4301
+ return starting;
4302
+ }, "ensureChannelWorkerManager");
4303
+ const completeRuntimeStartup = /* @__PURE__ */ __name(async (candidateApp) => {
3492
4304
  if (runtimeStartupSettled) return;
4305
+ runtimeApp = candidateApp;
4306
+ const acpHandle = candidateApp.locals?.["acpHandle"];
4307
+ acpHandle?.attachServer?.(server);
3493
4308
  if (opts.channelSelection) {
3494
- await channelWorker.start();
4309
+ closeServerAfterChannelWorkerStartupFailure = true;
4310
+ const manager = await ensureChannelWorkerManager();
4311
+ await manager.startInitial(opts.channelSelection);
3495
4312
  if (runtimeStartupSettled) return;
3496
4313
  }
3497
4314
  if (runtimeStartupSettled) return;
@@ -3526,6 +4343,7 @@ async function runQwenServe(optsIn, deps = {}) {
3526
4343
  clearRuntimeStartFallbackTimer();
3527
4344
  runtimeStarting = buildRuntime().then(async (runtime) => {
3528
4345
  if (runtimeStartupSettled) {
4346
+ disposeRuntimeAppResources(runtime.app);
3529
4347
  await shutdownBridgeAfterFailedStartup(runtime.bridge);
3530
4348
  return;
3531
4349
  }
@@ -3538,13 +4356,10 @@ async function runQwenServe(optsIn, deps = {}) {
3538
4356
  );
3539
4357
  return;
3540
4358
  }
3541
- runtimeApp = runtime.app;
3542
- const acpHandle = runtime.app.locals?.["acpHandle"];
3543
- acpHandle?.attachServer?.(server);
3544
4359
  if (shouldPreheat) {
3545
4360
  startBridgePreheat(runtime.bridge);
3546
4361
  }
3547
- await completeRuntimeStartup();
4362
+ await completeRuntimeStartup(runtime.app);
3548
4363
  }).catch((err) => failRuntimeStartup(err));
3549
4364
  }, "startRuntime");
3550
4365
  startRuntimeForRequest = startRuntime;
@@ -3582,11 +4397,10 @@ async function runQwenServe(optsIn, deps = {}) {
3582
4397
  if (shuttingDown) {
3583
4398
  daemonLog.warn(`received ${signal} during drain \u2014 forcing exit`);
3584
4399
  try {
3585
- channelWorker.killAllSync();
4400
+ channelWorkerManager?.killAllSync();
3586
4401
  for (const runtimeBridge of getRuntimeBridgesForCleanup()) {
3587
4402
  runtimeBridge.killAllSync();
3588
4403
  }
3589
- removeCurrentServePidfile();
3590
4404
  } catch (err) {
3591
4405
  daemonLog.error(
3592
4406
  "force-kill error",
@@ -3602,16 +4416,24 @@ async function runQwenServe(optsIn, deps = {}) {
3602
4416
  try {
3603
4417
  await handle.close();
3604
4418
  await daemonLog.flush();
3605
- process.exit(0);
4419
+ process.exit(runtimeStartupError === void 0 ? 0 : 1);
3606
4420
  } catch (err) {
3607
4421
  daemonLog.error("shutdown error", err instanceof Error ? err : null);
3608
4422
  await daemonLog.flush().catch(() => {
3609
4423
  });
4424
+ if (channelWorkerManager?.state().enabled) {
4425
+ daemonLog.error(
4426
+ "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)"
4427
+ );
4428
+ await daemonLog.flush().catch(() => {
4429
+ });
4430
+ return;
4431
+ }
3610
4432
  process.exit(1);
3611
4433
  }
3612
4434
  }, "onSignal");
3613
4435
  const onUncaughtExceptionMonitor = /* @__PURE__ */ __name(() => {
3614
- if (process.listenerCount("uncaughtException") === 0) {
4436
+ if (process.listenerCount("uncaughtException") === 0 && !channelWorkerManager?.state().enabled) {
3615
4437
  removeCurrentServePidfile();
3616
4438
  }
3617
4439
  }, "onUncaughtExceptionMonitor");
@@ -3626,21 +4448,24 @@ async function runQwenServe(optsIn, deps = {}) {
3626
4448
  if (closePromise) return closePromise;
3627
4449
  closePromise = new Promise((res, rej) => {
3628
4450
  shuttingDown = true;
3629
- app.locals.stopScheduledTaskKeepalive?.();
3630
- const stoppers = app.locals.subSessionStoppers;
3631
- if (stoppers) {
3632
- for (const stop of stoppers) stop();
3633
- }
4451
+ channelControlDraining = true;
4452
+ const initiallyMountedApp = runtimeApp ?? runtimeAppForCleanup;
4453
+ const initiallyMountedManagement = initiallyMountedApp?.locals?.["workspaceManagementHandle"];
4454
+ const initialManagementWait = initiallyMountedManagement?.sealAndWait?.();
3634
4455
  clearRuntimeStartAfterHealthTimer();
3635
4456
  clearRuntimeStartFallbackTimer();
3636
4457
  cancelDeferredRuntimeStartup();
3637
4458
  let settled = false;
3638
4459
  let bridgeShutdownError;
4460
+ let channelWorkerShutdownError;
3639
4461
  const finish = /* @__PURE__ */ __name((err) => {
3640
4462
  if (settled) return;
3641
4463
  settled = true;
3642
- process.removeListener("SIGINT", onSignal);
3643
- process.removeListener("SIGTERM", onSignal);
4464
+ const preserveSignalHandlers = channelWorkerShutdownError !== void 0 && channelWorkerManager?.state().enabled === true;
4465
+ if (!preserveSignalHandlers) {
4466
+ process.removeListener("SIGINT", onSignal);
4467
+ process.removeListener("SIGTERM", onSignal);
4468
+ }
3644
4469
  process.removeListener(
3645
4470
  "uncaughtExceptionMonitor",
3646
4471
  onUncaughtExceptionMonitor
@@ -3651,9 +4476,17 @@ async function runQwenServe(optsIn, deps = {}) {
3651
4476
  );
3652
4477
  }).finally(() => daemonLog.flush().catch(() => {
3653
4478
  })).finally(() => {
3654
- const finalErr = err ?? bridgeShutdownError;
3655
- if (finalErr) rej(finalErr);
3656
- else res();
4479
+ const finalErr = err ?? bridgeShutdownError ?? channelWorkerShutdownError;
4480
+ if (finalErr) {
4481
+ if (channelWorkerShutdownError && channelWorkerManager?.state().enabled) {
4482
+ closePromise = void 0;
4483
+ shuttingDown = false;
4484
+ channelControlDraining = false;
4485
+ }
4486
+ rej(finalErr);
4487
+ } else {
4488
+ res();
4489
+ }
3657
4490
  });
3658
4491
  }, "finish");
3659
4492
  void (coreRuntimePromise ? coreRuntimePromise.then((core) => core.forceFlushMetrics()) : Promise.resolve()).catch((flushErr) => {
@@ -3667,43 +4500,54 @@ async function runQwenServe(optsIn, deps = {}) {
3667
4500
  daemonLog
3668
4501
  );
3669
4502
  const appForCleanup = runtimeApp ?? runtimeAppForCleanup;
3670
- const deviceFlowRegistry = appForCleanup ? getDeviceFlowRegistry(appForCleanup) : void 0;
3671
- if (deviceFlowRegistry) {
3672
- try {
3673
- deviceFlowRegistry.dispose();
3674
- } catch (err) {
3675
- daemonLog.warn(
3676
- `device-flow registry dispose error: ${err instanceof Error ? err.message : String(err)}`
3677
- );
3678
- }
4503
+ const workspaceManagementHandle = appForCleanup?.locals?.["workspaceManagementHandle"];
4504
+ await initialManagementWait;
4505
+ if (workspaceManagementHandle !== initiallyMountedManagement) {
4506
+ await workspaceManagementHandle?.sealAndWait?.();
3679
4507
  }
3680
- const acpHandle = appForCleanup?.locals?.["acpHandle"];
3681
- if (acpHandle?.dispose) {
3682
- try {
3683
- acpHandle.dispose();
3684
- } catch (err) {
3685
- daemonLog.warn(
3686
- `ACP handle dispose error: ${err instanceof Error ? err.message : String(err)}`
4508
+ disposeRuntimeAppResources(appForCleanup);
4509
+ disposeDaemonEventLoopMonitor();
4510
+ if (channelWorkerManager) {
4511
+ await channelWorkerManager.shutdown().catch((err) => {
4512
+ daemonLog.error(
4513
+ "channel worker stop error",
4514
+ err instanceof Error ? err : null
3687
4515
  );
3688
- }
3689
- }
3690
- const rl = appForCleanup ? getRateLimiter(appForCleanup) : void 0;
3691
- if (rl) {
3692
- rl.setDraining(true);
3693
- rl.dispose();
4516
+ channelWorkerShutdownError = err instanceof Error ? err : new Error(String(err));
4517
+ });
4518
+ } else {
4519
+ removeCurrentServePidfile();
3694
4520
  }
3695
- disposeDaemonEventLoopMonitor();
3696
- await channelWorker.stop().catch((err) => {
3697
- daemonLog.error(
3698
- "channel worker stop error",
3699
- err instanceof Error ? err : null
4521
+ const runtimeRemoval = appForCleanup?.locals?.["workspaceRuntimeRemoval"];
4522
+ const workspaceRegistry = appForCleanup?.locals?.["workspaceRegistry"];
4523
+ const managedRuntimeBridges = /* @__PURE__ */ new Set();
4524
+ if (runtimeRemoval && workspaceRegistry) {
4525
+ const managedRuntimes = workspaceRegistry.listManaged();
4526
+ for (const workspaceRuntime of managedRuntimes) {
4527
+ managedRuntimeBridges.add(workspaceRuntime.bridge);
4528
+ }
4529
+ await Promise.all(
4530
+ managedRuntimes.map(
4531
+ (workspaceRuntime) => runtimeRemoval.disposeRuntime(workspaceRuntime, "daemon_shutdown").catch((err) => {
4532
+ daemonLog.error(
4533
+ "workspace runtime shutdown error",
4534
+ err instanceof Error ? err : null
4535
+ );
4536
+ bridgeShutdownError = err instanceof Error ? err : new Error(String(err));
4537
+ try {
4538
+ workspaceRuntime.bridge.killAllSync();
4539
+ } catch {
4540
+ }
4541
+ })
4542
+ )
3700
4543
  );
3701
- });
3702
- removeCurrentServePidfile();
4544
+ }
3703
4545
  for (const bridgeForShutdown of getRuntimeBridgesForCleanup()) {
4546
+ if (managedRuntimeBridges.has(bridgeForShutdown)) continue;
3704
4547
  if (shutdownBridges.has(bridgeForShutdown)) continue;
3705
4548
  shutdownBridges.add(bridgeForShutdown);
3706
4549
  await bridgeForShutdown.shutdown().catch((err) => {
4550
+ shutdownBridges.delete(bridgeForShutdown);
3707
4551
  daemonLog.error(
3708
4552
  "bridge shutdown error",
3709
4553
  err instanceof Error ? err : null
@@ -3712,6 +4556,12 @@ async function runQwenServe(optsIn, deps = {}) {
3712
4556
  });
3713
4557
  }
3714
4558
  }).finally(() => {
4559
+ if (!server.listening) {
4560
+ void (runtimeFailureListenerClose ?? Promise.resolve()).then(
4561
+ () => finish()
4562
+ );
4563
+ return;
4564
+ }
3715
4565
  const SECONDARY_DEADLINE_MS = 2e3;
3716
4566
  let secondaryTimer;
3717
4567
  const forceTimer = setTimeout(() => {
@@ -3745,17 +4595,19 @@ async function runQwenServe(optsIn, deps = {}) {
3745
4595
  server.on("error", (err) => {
3746
4596
  daemonLog.error("server error", err instanceof Error ? err : null);
3747
4597
  });
3748
- if (runtimeApp && bridgeRef) {
3749
- const acpHandle = runtimeApp.locals?.["acpHandle"];
3750
- acpHandle?.attachServer?.(server);
4598
+ const preparedRuntimeApp = runtimeApp ?? runtimeAppForCleanup;
4599
+ if (preparedRuntimeApp && bridgeRef && deps.bridge) {
3751
4600
  if (shouldPreheat) {
3752
4601
  startBridgePreheat(bridgeRef);
3753
4602
  }
3754
4603
  if (opts.channelSelection && !runtimeStartupSettled) {
3755
4604
  armRuntimeStartupTimer();
3756
- runtimeStarting = completeRuntimeStartup().catch(
4605
+ runtimeStarting = completeRuntimeStartup(preparedRuntimeApp).catch(
3757
4606
  (err) => failRuntimeStartup(err, bridgeRef)
3758
4607
  );
4608
+ } else {
4609
+ const acpHandle = preparedRuntimeApp.locals?.["acpHandle"];
4610
+ acpHandle?.attachServer?.(server);
3759
4611
  }
3760
4612
  } else if (deferRuntimeUntilFirstHealth) {
3761
4613
  scheduleRuntimeStartFallback();
@@ -3768,14 +4620,24 @@ async function runQwenServe(optsIn, deps = {}) {
3768
4620
  void runtimeReady.then(
3769
4621
  () => resolve(handle),
3770
4622
  (err) => {
3771
- void handle.close().catch((closeErr) => {
3772
- daemonLog.error(
3773
- "shutdown after runtime startup error failed",
3774
- closeErr instanceof Error ? closeErr : null
3775
- );
3776
- }).finally(() => {
3777
- reject(err instanceof Error ? err : new Error(String(err)));
3778
- });
4623
+ void handle.close().then(
4624
+ () => {
4625
+ reject(err instanceof Error ? err : new Error(String(err)));
4626
+ },
4627
+ (closeErr) => {
4628
+ daemonLog.error(
4629
+ "shutdown after runtime startup error failed",
4630
+ closeErr instanceof Error ? closeErr : null
4631
+ );
4632
+ if (channelWorkerManager?.state().enabled) {
4633
+ daemonLog.error(
4634
+ "runtime startup failed, but qwen serve remains alive to retain the channel service lease until worker exit is confirmed"
4635
+ );
4636
+ return;
4637
+ }
4638
+ reject(err instanceof Error ? err : new Error(String(err)));
4639
+ }
4640
+ );
3779
4641
  }
3780
4642
  );
3781
4643
  }
@@ -3843,11 +4705,11 @@ export {
3843
4705
  };
3844
4706
  /**
3845
4707
  * @license
3846
- * Copyright 2026 Qwen Team
4708
+ * Copyright 2025 Qwen Team
3847
4709
  * SPDX-License-Identifier: Apache-2.0
3848
4710
  */
3849
4711
  /**
3850
4712
  * @license
3851
- * Copyright 2025 Qwen Team
4713
+ * Copyright 2026 Qwen Team
3852
4714
  * SPDX-License-Identifier: Apache-2.0
3853
4715
  */