@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.
- package/bundled/qc-helper/docs/configuration/settings.md +14 -6
- package/bundled/qc-helper/docs/features/approval-mode.md +2 -2
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +33 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +64 -20
- package/bundled/qc-helper/docs/features/channels/wecom.md +8 -7
- package/bundled/qc-helper/docs/features/code-review.md +88 -44
- package/bundled/qc-helper/docs/features/commands.md +6 -6
- package/bundled/qc-helper/docs/features/hooks.md +29 -0
- package/bundled/qc-helper/docs/features/sandbox.md +2 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +21 -0
- package/bundled/qc-helper/docs/qwen-serve.md +49 -20
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +219 -33
- package/bundled/review/SKILL.md +429 -382
- package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-WOC3YDWA.js} +31 -32
- package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-H5HZCAFD.js} +49 -48
- package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-55YDJDNM.js} +922 -550
- package/chunks/{agent-HOLHB3RT.js → agent-H6VE5W3L.js} +26 -27
- package/chunks/{agent-headless-SXL6H56A.js → agent-headless-T4XJOCRU.js} +26 -27
- package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-HBRXJSP4.js} +78 -16
- package/chunks/{artifact-tool-U7IRTLIV.js → artifact-tool-MIZLXBLF.js} +2 -2
- package/chunks/{askUserQuestion-2DLUUZZG.js → askUserQuestion-XMJVPNWM.js} +2 -2
- package/chunks/{bridge-BCJQ7BBB.js → bridge-FTB6ZP3R.js} +31 -34
- package/chunks/{ca-UJ6HC4H2.js → ca-CODEN7TD.js} +9 -1
- package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
- package/chunks/channel-worker-manager-CUDPU4CN.js +418 -0
- package/chunks/channel-worker-supervisor-4XTO2ZD3.js +20 -0
- package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
- package/chunks/{chunk-VA4KQY6V.js → chunk-2JNR4VP2.js} +3 -3
- package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
- package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
- package/chunks/{chunk-CUMMSHH6.js → chunk-3DWIFU7L.js} +1 -1
- package/chunks/chunk-3MX7D6QN.js +516 -0
- package/chunks/{chunk-SJHDYNHF.js → chunk-4BJVSIS3.js} +3 -3
- package/chunks/{chunk-TO6QE22P.js → chunk-5CNYZ7TN.js} +26 -22
- package/chunks/{chunk-N3EMS75V.js → chunk-5DEJ4T6C.js} +1333 -1232
- package/chunks/chunk-5HBA2Z7V.js +28 -0
- package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
- package/chunks/{chunk-SCGXUJBT.js → chunk-6LI3L22E.js} +3 -3
- package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
- package/chunks/{chunk-YAUFFXDS.js → chunk-7GM2RWCR.js} +12 -11
- package/chunks/{chunk-OQ4DRIOA.js → chunk-7HWE2W74.js} +2 -2
- package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
- package/chunks/{chunk-MC23XKFE.js → chunk-A2HWMJVO.js} +37 -3
- package/chunks/{chunk-3G7CIHVV.js → chunk-ABNYOMDG.js} +4 -4
- package/chunks/{chunk-3AHXV67U.js → chunk-AGZLXLBY.js} +1 -1
- package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
- package/chunks/{chunk-Q4YQW46J.js → chunk-AMRZVQUY.js} +43 -40
- package/chunks/{chunk-W3JHSWRP.js → chunk-AN6C2U46.js} +4 -4
- package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
- package/chunks/{chunk-5SFOMFG4.js → chunk-AVEOWVOM.js} +36 -2
- package/chunks/{chunk-34MW4KTI.js → chunk-BA5JGE5F.js} +2 -2
- package/chunks/{chunk-5HOMWMCL.js → chunk-BSJAQUFD.js} +5492 -1336
- package/chunks/{chunk-L6P4KPHR.js → chunk-BWJKL5DB.js} +58 -38
- package/chunks/{chunk-PVZM22CK.js → chunk-C32JFRGV.js} +5 -5
- package/chunks/{chunk-AKIVHSJR.js → chunk-CZIHPO7L.js} +163 -782
- package/chunks/chunk-DL7RCO6V.js +493 -0
- package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
- package/chunks/{chunk-5VXNZWGF.js → chunk-ENUQSKEY.js} +1 -1
- package/chunks/{chunk-PDZ7MBDG.js → chunk-EWILX3BM.js} +27 -6
- package/chunks/{chunk-BMGVRZN4.js → chunk-EZWX232B.js} +1 -1
- package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
- package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
- package/chunks/chunk-FEOZBUMT.js +77 -0
- package/chunks/{chunk-5U27BZ72.js → chunk-FKEGVMPX.js} +269 -83
- package/chunks/chunk-FNX3LGAK.js +34 -0
- package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
- package/chunks/{chunk-PODM4SZ4.js → chunk-G3BIBPI7.js} +5 -5
- package/chunks/{chunk-A3XKDTSH.js → chunk-GA65O2TB.js} +4 -4
- package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
- package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-GXGIM7QP.js} +67 -35
- package/chunks/{chunk-6PESIEKJ.js → chunk-GXUWGPYX.js} +68 -6
- package/chunks/chunk-GYTKQYDB.js +23 -0
- package/chunks/{chunk-GZRTYZ2R.js → chunk-H3XMJV7T.js} +218 -1
- package/chunks/{chunk-WQUQVGTF.js → chunk-HGRXW4HQ.js} +467 -106
- package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
- package/chunks/{chunk-ECNYL4AA.js → chunk-HUEWOHKV.js} +1 -1
- package/chunks/chunk-IDS7MSUP.js +74 -0
- package/chunks/{chunk-KHUQZZJ6.js → chunk-IHDRJLLR.js} +382 -36
- package/chunks/{chunk-CLFKOZEK.js → chunk-J4SEAF4X.js} +114 -4
- package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
- package/chunks/{chunk-P67PFTUT.js → chunk-KEYEYCHZ.js} +4 -4
- package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
- package/chunks/{chunk-7PU4FYLG.js → chunk-KOXFAG6P.js} +4 -18
- package/chunks/{chunk-EGYZ275M.js → chunk-KWLVWNF5.js} +55 -7
- package/chunks/{chunk-XLA62MYB.js → chunk-KXECVZPD.js} +2 -2
- package/chunks/{chunk-IAVB3HM3.js → chunk-L4Y55KIS.js} +33 -1
- package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
- package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
- package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
- package/chunks/chunk-LXXMOYPL.js +22 -0
- package/chunks/{chunk-Q6I5QHMH.js → chunk-MFNKBXYH.js} +1 -1
- package/chunks/chunk-MR3PXB6E.js +48 -0
- package/chunks/{chunk-JZETEN3Z.js → chunk-N45S36AH.js} +3 -3
- package/chunks/{chunk-GWLSNBG4.js → chunk-NA3IG6XG.js} +748 -27
- package/chunks/{chunk-D5SKC4YG.js → chunk-O3M25JXE.js} +213 -29
- package/chunks/{chunk-EAXLGSFP.js → chunk-O6XGHDS5.js} +11 -11
- package/chunks/{chunk-WL4L7EZH.js → chunk-OA4JVLSA.js} +27 -1
- package/chunks/{chunk-X4NKFGFJ.js → chunk-OJAMDVF5.js} +0 -15
- package/chunks/{chunk-BZIFY5TF.js → chunk-OKAIGAYW.js} +3 -3
- package/chunks/{chunk-CNEIYWSA.js → chunk-OVIV236K.js} +5 -5
- package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
- package/chunks/{chunk-E2IY465S.js → chunk-PWNOAWXB.js} +59 -12
- package/chunks/{chunk-B4G2WOFA.js → chunk-Q5MKHNIR.js} +28 -5
- package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
- package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
- package/chunks/{chunk-HKMAENAO.js → chunk-QDTGDM2T.js} +14 -9
- package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
- package/chunks/{chunk-W2UIXQDL.js → chunk-RTV5TUYB.js} +12 -4
- package/chunks/chunk-RW7DUKFO.js +91 -0
- package/chunks/{chunk-NVYTCB5Z.js → chunk-SA6QVLWI.js} +17325 -16259
- package/chunks/chunk-SJSI7PXU.js +59 -0
- package/chunks/{chunk-HVY356M2.js → chunk-SMGBWLNU.js} +3 -3
- package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
- package/chunks/{chunk-CC2ITGCF.js → chunk-STZQCNN3.js} +49 -6
- package/chunks/{chunk-HPDUL5MF.js → chunk-T2ZDAER2.js} +1 -1
- package/chunks/{chunk-XUOOWUZS.js → chunk-T3TQ3ACP.js} +1 -1
- package/chunks/{chunk-4C5BQ2D2.js → chunk-TIKDHS6V.js} +100 -17
- package/chunks/chunk-TV6K2FB4.js +224 -0
- package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
- package/chunks/{chunk-D2GFWEXB.js → chunk-UCUUH2JV.js} +6 -6
- package/chunks/{chunk-BAPGSC7U.js → chunk-UZP7K33Y.js} +23 -9
- package/chunks/{chunk-77XJ3SWN.js → chunk-VDAR6UO2.js} +8 -6
- package/chunks/{chunk-XYQSMABS.js → chunk-VKLVGA2D.js} +4 -4
- package/chunks/{chunk-JSG7ZSBC.js → chunk-VRR65QYW.js} +251 -3
- package/chunks/{chunk-U2NNEY4R.js → chunk-VT5AWJN4.js} +1 -1
- package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
- package/chunks/{chunk-X6TJ3YZV.js → chunk-WKEO3GLZ.js} +160 -60
- package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
- package/chunks/{chunk-VWPVHAMO.js → chunk-XIWQ5QST.js} +8 -1
- package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
- package/chunks/{chunk-3VAGG5T5.js → chunk-YYBZUIPL.js} +1015 -100
- package/chunks/{chunk-CCDMCZPP.js → chunk-YZ3SBNP7.js} +1 -1
- package/chunks/{chunk-ATAKVRIF.js → chunk-Z3XA2TNG.js} +7 -7
- package/chunks/{chunk-EMDMPBJ4.js → chunk-Z7SVC7PJ.js} +10 -3
- package/chunks/{chunk-AURZZYMD.js → chunk-ZIVSSTUG.js} +4 -4
- package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
- package/chunks/{chunk-34Z3U5RQ.js → chunk-ZQIYGQCG.js} +765 -168
- package/chunks/{computer-use-HM37RX6A.js → computer-use-NADT7ULB.js} +26 -27
- package/chunks/{config-utils-NV2SVGPB.js → config-utils-IQQT3GCI.js} +3 -2
- package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-U7NEJYJ7.js} +28 -29
- package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
- package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-SUN33INC.js} +26 -27
- package/chunks/{cron-create-AMBKGZX6.js → cron-create-GMVKSXZT.js} +4 -4
- package/chunks/{cron-delete-LRU4OJYG.js → cron-delete-VDZKUAVK.js} +4 -4
- package/chunks/{cron-list-WVP2JXER.js → cron-list-UG7C7RAR.js} +4 -4
- package/chunks/{daemon-ARHTSTXP.js → daemon-SJXEKP3H.js} +773 -126
- package/chunks/daemon-status-provider-WIIYLGZJ.js +74 -0
- package/chunks/{de-EBJN3OVN.js → de-NOXPCSYN.js} +9 -1
- package/chunks/{dist-XKU3ABM5.js → dist-4WCQEZIN.js} +4 -51
- package/chunks/{dist-QYCAEZIT.js → dist-DOPL5LSQ.js} +5 -1
- package/chunks/{dist-WKPOYU7O.js → dist-GXJVCOS7.js} +1 -1
- package/chunks/{dist-R7LN5AZE.js → dist-PX2ERZ6I.js} +2 -2
- package/chunks/{dist-PNVLTKTL.js → dist-V2YVLYOW.js} +215 -33
- package/chunks/{dist-VHV4EVHG.js → dist-VYWUKURL.js} +1 -1
- package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-6FRM6UMU.js} +27 -28
- package/chunks/{edit-VNI4NJ73.js → edit-7GOIQTCZ.js} +27 -28
- package/chunks/{en-5A6LA7RK.js → en-JFVULHTB.js} +11 -1
- package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-476E6WIK.js} +26 -27
- package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-IRJM6W3C.js} +42 -28
- package/chunks/{environment-5HSSRMJ7.js → environment-ROMULS2X.js} +30 -30
- package/chunks/{errors-HMFCJJ7P.js → errors-OUIWPUDY.js} +28 -29
- package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-PPSFK753.js} +26 -27
- package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-YKQMD4D7.js} +26 -27
- package/chunks/{fast-path-FRDMDVHG.js → fast-path-CNK2HHKH.js} +3 -3
- package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
- package/chunks/{fr-YXRABLYZ.js → fr-HVFNU42H.js} +9 -1
- package/chunks/{gemini-QYSEGHAX.js → gemini-WQNFT6TR.js} +216 -90
- package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-4QJH2JDP.js} +4 -4
- package/chunks/{glob-BRCSGFOT.js → glob-36TVLBWW.js} +28 -28
- package/chunks/{grep-EE2DUOSY.js → grep-QTYLNO2M.js} +26 -27
- package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-36FQFODK.js} +30 -31
- package/chunks/{i18n-BASPENNQ.js → i18n-JUGYPVSP.js} +27 -28
- package/chunks/initializer-OBBJUS25.js +72 -0
- package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-MCKTPX64.js} +27 -28
- package/chunks/{ja-7VQOANVG.js → ja-PY5AF544.js} +10 -2
- package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
- package/chunks/list-VW5QY4VJ.js +75 -0
- package/chunks/loadedSettingsAdapter-IELOOXG6.js +69 -0
- package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-QXWZSCYM.js} +5 -5
- package/chunks/{ls-ZB2BDP6T.js → ls-2OUTG3IZ.js} +4 -4
- package/chunks/{lsp-V5DN4YUJ.js → lsp-4VMNXZW6.js} +2 -2
- package/chunks/mcp-Q3EC37ZS.js +69 -0
- package/chunks/{monitor-X5Z3H4FY.js → monitor-DCZ27AFR.js} +26 -27
- package/chunks/nonInteractiveCli-KXD7PFO4.js +128 -0
- package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-YU4XF5LI.js} +27 -28
- package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KL5WER2D.js} +13 -13
- package/chunks/{pidfile-D4I4FTVA.js → pidfile-WBOD7EJV.js} +27 -28
- package/chunks/processUtils-AOV4R34M.js +29 -0
- package/chunks/{pt-2C6YCSHL.js → pt-A3PRQXMU.js} +9 -1
- package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-YIGBHYE3.js} +28 -29
- package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
- package/chunks/{read-file-7SZSIZOL.js → read-file-WVL4Y76X.js} +9 -9
- package/chunks/{read-mcp-resource-SM5DA4RG.js → read-mcp-resource-JUFHCKSC.js} +2 -2
- package/chunks/{record-artifact-4XKZX3UW.js → record-artifact-DWSMBXYY.js} +2 -2
- package/chunks/{ripGrep-YNPFVCZP.js → ripGrep-6GSWJERP.js} +26 -27
- package/chunks/{ru-6BBHVZZV.js → ru-IBCWUTOC.js} +9 -1
- package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-QYUQMEDT.js} +1233 -371
- package/chunks/{runtime-57WWRVHN.js → runtime-K2YZCNB3.js} +42 -38
- package/chunks/{scheduler-YBLGWSIL.js → scheduler-EQCSN7QV.js} +26 -27
- package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
- package/chunks/{serve-R63NK3CV.js → serve-DX5UGZD4.js} +36 -35
- package/chunks/{server-Z22GCAXP.js → server-T6HJH3DR.js} +5869 -1398
- package/chunks/{session-HKAAI7BN.js → session-SNU6ACY6.js} +299 -100
- package/chunks/{settings-3EYN66GK.js → settings-AKHZZNEL.js} +34 -33
- package/chunks/{shell-6YXINTWJ.js → shell-EY74IEZK.js} +28 -27
- package/chunks/{skill-OO57P4X6.js → skill-DPU62O3H.js} +11 -11
- package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-RQZRWJ2V.js} +28 -30
- package/chunks/{src-G5UPLZSZ.js → src-7FITDSVC.js} +164 -52
- package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-XO3RK6DO.js} +28 -29
- package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-DVWZRHYQ.js} +728 -382
- package/chunks/{syntheticOutput-34H7LGA7.js → syntheticOutput-LELY6HAI.js} +3 -3
- package/chunks/{task-create-FRGOEIKY.js → task-create-QY3BIMNM.js} +8 -7
- package/chunks/{task-list-OW766BXZ.js → task-list-D2U47WBJ.js} +6 -5
- package/chunks/{task-stop-SIR5SNBN.js → task-stop-N6E5IYLH.js} +2 -2
- package/chunks/{task-update-YRA532MT.js → task-update-HJCQILLB.js} +8 -7
- package/chunks/{team-create-PECAAPXK.js → team-create-FOSRT62K.js} +26 -27
- package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
- package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-6VUDV27J.js} +26 -27
- package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-6UT6IO5T.js} +27 -28
- package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
- package/chunks/{tool-search-THVIWAPB.js → tool-search-ASSFMMN5.js} +10 -10
- package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-YYWUO23H.js} +32 -35
- package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
- package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-4BWV2IBK.js} +29 -29
- package/chunks/types-ML3TRJQ5.js +16 -0
- package/chunks/update-relaunch-74DLGH73.js +87 -0
- package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-CRFCGFO5.js} +31 -30
- package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-BTTEPBGQ.js} +76 -73
- package/chunks/{version-3UEA6ZIR.js → version-Y5JE5Q63.js} +1 -1
- package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-CFCWTCAP.js} +5 -6
- package/chunks/{workflow-QCCCMYP3.js → workflow-6WC7VPQN.js} +27 -28
- package/chunks/workspace-providers-status-RVG2C5ZS.js +72 -0
- package/chunks/workspace-registration-store-SLEU3D3X.js +27 -0
- package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-QMWGVOTF.js} +32 -35
- package/chunks/workspace-service-G572JSEU.js +84 -0
- package/chunks/workspace-skills-status-VSSMSMNK.js +71 -0
- package/chunks/{write-file-I3MUDRIE.js → write-file-5XVDRORP.js} +27 -28
- package/chunks/{zh-RQE7I22T.js → zh-PAUNIMHQ.js} +12 -2
- package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-GNEUIUFF.js} +12 -2
- package/cli-entry.js +92 -8
- package/cli.js +11 -11
- package/locales/ca.js +16 -0
- package/locales/de.js +16 -0
- package/locales/en.js +19 -0
- package/locales/fr.js +16 -0
- package/locales/ja.js +17 -1
- package/locales/pt.js +16 -0
- package/locales/ru.js +16 -0
- package/locales/zh-TW.js +20 -1
- package/locales/zh.js +20 -1
- package/package.json +3 -3
- package/web-shell/assets/{arc-C15hqnJe.js → arc-vx1tRwnX.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-DBi6iUA1.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-Ga9JJ4Ak.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-D8Vi5FYw.js} +1 -1
- package/web-shell/assets/channel-B29zQDTL.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-CSV6yQpU.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-toYlppdI.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-DbjzuyAr.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-IkkSjSkk.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-D5wUL6Zm.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-C3o2DXG0.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CutIi14T.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-DZ0NRHH-.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BNGI2SvC.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BNGI2SvC.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-B3Dl88UJ.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-DfTxfF6-.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-CJyH98yO.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-EbOiJNmW.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-AYNqpqqA.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BY5VPa4H.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-BhMYAKlk.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-Bp8S_F9l.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-az3TE9PU.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-CfkAEpCe.js} +3 -3
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-D1QmjMCy.js} +1 -1
- package/web-shell/assets/index-C8sDwQUv.js +1130 -0
- package/web-shell/assets/index-CaBoc5bb.js +3 -0
- package/web-shell/assets/index-Dpg5Wymg.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-D3ompLrG.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-D3MRWp9I.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-DVkKCa44.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-BLif81wF.js} +1 -1
- package/web-shell/assets/{linear-C8wKCbIC.js → linear-BDU96EGS.js} +1 -1
- package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-B-CwC26B.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-CS1WOJ4G.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-BzgtNXVP.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-BRfGC8MA.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-CPBZkC7g.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-nqNvinIk.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-CM_Wdjh3.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-L0y-48VE.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BX1DdF8s.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-B_n5rb3A.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-C9NmLV5e.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-CrefK9gt.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BUccf-bC.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-DM6ef92l.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-524RQP4Q.js +0 -305
- package/chunks/chunk-CARU2RR2.js +0 -24
- package/chunks/chunk-CU3L64TP.js +0 -93
- package/chunks/chunk-OCPBI7J5.js +0 -18
- package/chunks/chunk-TEGEBB2I.js +0 -122
- package/chunks/chunk-VTU57BWZ.js +0 -30
- package/chunks/daemon-status-provider-B2UTZUJ2.js +0 -76
- package/chunks/initializer-UTQ7FB7G.js +0 -71
- package/chunks/list-DEICDL65.js +0 -74
- package/chunks/loadedSettingsAdapter-NOWEGDYJ.js +0 -68
- package/chunks/mcp-L5JXEEIA.js +0 -68
- package/chunks/nonInteractiveCli-LS2K4X6A.js +0 -124
- package/chunks/types-JNKGKUJT.js +0 -12
- package/chunks/workspace-providers-status-4KMGETOJ.js +0 -71
- package/chunks/workspace-service-RVLBMSMZ.js +0 -80
- package/chunks/workspace-skills-status-DS4ZVFTO.js +0 -70
- package/web-shell/assets/channel-CLiQD50f.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-D3sYqow5.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-D3sYqow5.js +0 -1
- package/web-shell/assets/index-D5IWFVk1.css +0 -5
- package/web-shell/assets/index-KFJRDhX7.js +0 -783
- 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-
|
|
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-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
} from "./chunk-3SJSQXNS.js";
|
|
46
|
+
resolveChannelCwd
|
|
47
|
+
} from "./chunk-FNX3LGAK.js";
|
|
52
48
|
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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-
|
|
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-
|
|
70
|
+
} from "./chunk-ZQIYGQCG.js";
|
|
67
71
|
import "./chunk-UDXSXLER.js";
|
|
68
72
|
import {
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
loadServeFastPathSettings,
|
|
74
|
+
preResolveServeFastPathHomeEnvOverrides
|
|
75
|
+
} from "./chunk-PEJWA3QQ.js";
|
|
76
|
+
import "./chunk-GOXKNSDZ.js";
|
|
71
77
|
import {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
80
|
-
|
|
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-
|
|
1097
|
-
import("./pidfile-
|
|
1098
|
-
import("./
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
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
|
|
1146
|
-
|
|
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-
|
|
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-
|
|
1210
|
-
import("./environment-
|
|
1211
|
-
import("./loadedSettingsAdapter-
|
|
1212
|
-
import("./trustedFolders-
|
|
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-
|
|
1226
|
-
import("./config-utils-
|
|
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-
|
|
1251
|
-
import("./bridge-
|
|
1252
|
-
import("./spawnChannel-
|
|
1253
|
-
import("./workspace-service-
|
|
1254
|
-
import("./types-
|
|
1255
|
-
import("./daemon-status-provider-
|
|
1256
|
-
import("./workspace-providers-status-
|
|
1257
|
-
import("./workspace-skills-status-
|
|
1258
|
-
import("./total-session-admission-
|
|
1259
|
-
import("./workspace-registry-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
1845
|
-
|
|
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 (!
|
|
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(
|
|
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
|
|
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
|
|
2388
|
+
const eventLoopMonitor = daemonEventLoopMonitor;
|
|
2231
2389
|
daemonEventLoopMonitor = void 0;
|
|
2232
|
-
daemonMetricsSampler
|
|
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
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
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
|
|
2517
|
+
channels,
|
|
2243
2518
|
servePid: process.pid,
|
|
2244
|
-
|
|
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.
|
|
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
|
-
|
|
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-
|
|
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) =>
|
|
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"]?.
|
|
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
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
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
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
workspace
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
const
|
|
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
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
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
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3630
|
-
const
|
|
3631
|
-
|
|
3632
|
-
|
|
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
|
-
|
|
3643
|
-
|
|
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)
|
|
3656
|
-
|
|
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
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
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
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
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
|
-
|
|
3691
|
-
|
|
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
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
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
|
-
|
|
3749
|
-
|
|
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().
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
)
|
|
3776
|
-
|
|
3777
|
-
|
|
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
|
|
4708
|
+
* Copyright 2025 Qwen Team
|
|
3847
4709
|
* SPDX-License-Identifier: Apache-2.0
|
|
3848
4710
|
*/
|
|
3849
4711
|
/**
|
|
3850
4712
|
* @license
|
|
3851
|
-
* Copyright
|
|
4713
|
+
* Copyright 2026 Qwen Team
|
|
3852
4714
|
* SPDX-License-Identifier: Apache-2.0
|
|
3853
4715
|
*/
|