@qwen-code/qwen-code 0.19.9 → 0.19.10-nightly.20260715.c538bd70d
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 +8 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +3 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +11 -3
- 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/sub-agents.md +21 -0
- package/bundled/qc-helper/docs/qwen-serve.md +46 -20
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +1 -1
- package/bundled/review/DESIGN.md +219 -33
- package/bundled/review/SKILL.md +449 -153
- package/chunks/{MaxSizedBox-6HYJ3ZPJ.js → MaxSizedBox-LOOBDOTZ.js} +31 -31
- package/chunks/{StandaloneSessionPicker-WS4GXYOG.js → StandaloneSessionPicker-76CLZSH2.js} +51 -49
- package/chunks/{acpAgent-5FWSOZL5.js → acpAgent-DFJOK7EB.js} +567 -482
- package/chunks/{agent-HOLHB3RT.js → agent-OJQWXNHP.js} +26 -26
- package/chunks/{agent-headless-SXL6H56A.js → agent-headless-ND7GOORY.js} +26 -26
- package/chunks/{anthropicContentGenerator-L73TO3DB.js → anthropicContentGenerator-56U3YCP2.js} +5 -5
- 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-SNJK2JLK.js} +32 -32
- package/chunks/{ca-UJ6HC4H2.js → ca-C2JTT2N5.js} +4 -1
- package/chunks/channel-worker-group-K7QKH6IG.js +13 -0
- package/chunks/channel-worker-manager-YSFB4HUU.js +418 -0
- package/chunks/channel-worker-supervisor-QCKIOYZD.js +20 -0
- package/chunks/{chunk-CCDMCZPP.js → chunk-26UABK2C.js} +1 -1
- package/chunks/{chunk-LXNEJD34.js → chunk-2FO5GFKZ.js} +1 -1
- package/chunks/{chunk-L36P3NBD.js → chunk-2W3OOD4W.js} +2 -0
- package/chunks/{chunk-7R3CZA3Q.js → chunk-2Z5UX4KI.js} +1 -1
- package/chunks/chunk-3MX7D6QN.js +516 -0
- package/chunks/{chunk-CLFKOZEK.js → chunk-3XULHBC7.js} +1 -1
- package/chunks/chunk-4QZADKJS.js +34 -0
- package/chunks/{chunk-E2IY465S.js → chunk-4UDHAJFV.js} +10 -10
- package/chunks/{chunk-5U27BZ72.js → chunk-55SAYASQ.js} +190 -77
- package/chunks/chunk-5HBA2Z7V.js +28 -0
- package/chunks/{chunk-ZJE7NSL3.js → chunk-5M6IDOMF.js} +34 -97
- package/chunks/{chunk-HVY356M2.js → chunk-5SQ55XJZ.js} +3 -3
- package/chunks/{chunk-EAXLGSFP.js → chunk-6GRAQNTY.js} +8 -8
- package/chunks/{chunk-K434OPES.js → chunk-6WPJRYLZ.js} +3 -3
- package/chunks/{chunk-VWPVHAMO.js → chunk-7DXHIMXL.js} +5 -1
- package/chunks/{chunk-J4TSQ5EQ.js → chunk-7NFB7LBQ.js} +8 -1
- package/chunks/{chunk-5SFOMFG4.js → chunk-7R4DPSRA.js} +36 -2
- package/chunks/{chunk-W2UIXQDL.js → chunk-7STBROEV.js} +1 -1
- package/chunks/{chunk-BMGVRZN4.js → chunk-AETEZU4U.js} +1 -1
- package/chunks/{chunk-HPDUL5MF.js → chunk-AGZWN4WV.js} +1 -1
- package/chunks/{chunk-RDJSGHZE.js → chunk-ALGGS7UH.js} +1 -38
- package/chunks/{chunk-GWHYEOV2.js → chunk-ARKANCNX.js} +2 -1
- package/chunks/{chunk-34Z3U5RQ.js → chunk-AU4R7ACM.js} +518 -114
- package/chunks/{channel-worker-supervisor-WSOAAYUO.js → chunk-B7MFJBKE.js} +67 -35
- package/chunks/{chunk-524RQP4Q.js → chunk-B7NUUEXC.js} +10 -4
- package/chunks/{chunk-MC23XKFE.js → chunk-BLPMRN4B.js} +3 -3
- package/chunks/{chunk-A3XKDTSH.js → chunk-BRRKAUGR.js} +4 -4
- package/chunks/{chunk-W3JHSWRP.js → chunk-BUPLOPUA.js} +4 -4
- package/chunks/{chunk-3VAGG5T5.js → chunk-BYOOK22F.js} +121 -16
- package/chunks/{chunk-EMDMPBJ4.js → chunk-C47ENMZJ.js} +3 -3
- package/chunks/{chunk-3AHXV67U.js → chunk-C5TVXLJZ.js} +1 -1
- package/chunks/{chunk-X6TJ3YZV.js → chunk-CGT5TQIZ.js} +159 -57
- package/chunks/{chunk-4C5BQ2D2.js → chunk-CQQD7MDG.js} +82 -12
- package/chunks/{chunk-KKNMOEZH.js → chunk-E2UVIFI2.js} +185 -398
- package/chunks/{chunk-P67PFTUT.js → chunk-EPY4ZEU6.js} +4 -4
- package/chunks/{chunk-6PESIEKJ.js → chunk-EZSRHWGS.js} +68 -6
- package/chunks/{chunk-4GORAUCN.js → chunk-F333XEAU.js} +1 -1
- package/chunks/{chunk-YLV3XXFB.js → chunk-FBU7WRZI.js} +17 -1
- package/chunks/{chunk-Q6I5QHMH.js → chunk-FGTCZJOD.js} +1 -1
- package/chunks/{chunk-LK7KUE55.js → chunk-FSA7ERJ2.js} +1 -1
- package/chunks/{chunk-B4G2WOFA.js → chunk-FTU55ZZ7.js} +3 -3
- package/chunks/{chunk-EGYZ275M.js → chunk-GCD7PEDZ.js} +4 -4
- package/chunks/{chunk-SJHDYNHF.js → chunk-GDQQRV43.js} +3 -3
- package/chunks/{chunk-3BTRNWWD.js → chunk-GOXKNSDZ.js} +1 -64
- package/chunks/{chunk-GZRTYZ2R.js → chunk-GQKWT45X.js} +154 -1
- package/chunks/chunk-GYTKQYDB.js +23 -0
- package/chunks/{chunk-YVEDCAUE.js → chunk-HGT6JR3U.js} +19 -0
- package/chunks/{chunk-N3EMS75V.js → chunk-HKM2TEF7.js} +1268 -1233
- package/chunks/chunk-IDS7MSUP.js +74 -0
- package/chunks/{chunk-PVZM22CK.js → chunk-INKAZNYC.js} +5 -5
- package/chunks/{chunk-3G7CIHVV.js → chunk-IOQ75R4R.js} +4 -4
- package/chunks/{chunk-AURZZYMD.js → chunk-IQOOJSPR.js} +4 -4
- package/chunks/{chunk-AKIVHSJR.js → chunk-J4UQXGVL.js} +111 -93
- package/chunks/{chunk-VTU57BWZ.js → chunk-JEKOCLRN.js} +1 -1
- package/chunks/{chunk-B5ORX3FG.js → chunk-JGUT3LWZ.js} +6 -1
- package/chunks/{chunk-PDZ7MBDG.js → chunk-JIQHT2O6.js} +27 -6
- package/chunks/{chunk-XUOOWUZS.js → chunk-JPAH76WA.js} +1 -1
- package/chunks/{chunk-BAPGSC7U.js → chunk-K4LG6TVJ.js} +23 -9
- package/chunks/chunk-KET3M4K4.js +493 -0
- package/chunks/{chunk-ORBGV7NJ.js → chunk-KKRTYONM.js} +6 -4
- package/chunks/{chunk-SCGXUJBT.js → chunk-KPA5QGN2.js} +3 -3
- package/chunks/{chunk-IAVB3HM3.js → chunk-KSO42X3Z.js} +13 -0
- package/chunks/{chunk-4QLQE5WJ.js → chunk-L5U3ELZX.js} +1 -1
- package/chunks/{chunk-77XJ3SWN.js → chunk-LIUEXYPL.js} +5 -5
- package/chunks/{chunk-4ZVWQHEQ.js → chunk-LQIDP6K5.js} +1 -1
- package/chunks/{chunk-34MW4KTI.js → chunk-LT5CRUA5.js} +2 -2
- package/chunks/{chunk-DC5Z3DU6.js → chunk-LXLTBIDP.js} +43 -6
- package/chunks/{chunk-VA4KQY6V.js → chunk-MEK7CQJR.js} +3 -3
- package/chunks/{chunk-KHUQZZJ6.js → chunk-MO7O5722.js} +370 -36
- package/chunks/chunk-MR3PXB6E.js +48 -0
- package/chunks/{chunk-PODM4SZ4.js → chunk-MV52C5MA.js} +5 -5
- 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-ECNYL4AA.js → chunk-OPNPGO6D.js} +1 -1
- package/chunks/{chunk-3SJSQXNS.js → chunk-PEJWA3QQ.js} +12 -8
- package/chunks/{chunk-MXL5UP4X.js → chunk-Q6TUALBE.js} +1 -1
- package/chunks/{chunk-QYMQSECS.js → chunk-QAW7PIHT.js} +2 -2
- package/chunks/{chunk-5HOMWMCL.js → chunk-QEDYXCLG.js} +4167 -1338
- package/chunks/chunk-QNNTA7IX.js +91 -0
- package/chunks/{chunk-D2GFWEXB.js → chunk-QNT5T4Q2.js} +6 -6
- package/chunks/{chunk-CUMMSHH6.js → chunk-R5XLNDE2.js} +1 -1
- package/chunks/{chunk-LUODI7WD.js → chunk-RCEEXIOO.js} +6 -4
- package/chunks/{chunk-WQUQVGTF.js → chunk-RQWDLG6Z.js} +183 -96
- package/chunks/{chunk-XYQSMABS.js → chunk-SLCVZX6F.js} +4 -4
- package/chunks/{chunk-CEA3E3JB.js → chunk-SPJQO2CE.js} +2 -2
- package/chunks/{chunk-JSG7ZSBC.js → chunk-TQBODCFD.js} +1 -1
- package/chunks/chunk-TV6K2FB4.js +224 -0
- package/chunks/{chunk-5XUCZNSY.js → chunk-TYLOFD2U.js} +1 -1
- package/chunks/{chunk-CNEIYWSA.js → chunk-UKWAQ7AV.js} +5 -5
- package/chunks/{chunk-7PU4FYLG.js → chunk-US4YQT62.js} +4 -4
- package/chunks/{chunk-Q4YQW46J.js → chunk-UYPPCIJQ.js} +36 -18
- package/chunks/{chunk-YAUFFXDS.js → chunk-UZKG7HFG.js} +12 -11
- package/chunks/{chunk-GWLSNBG4.js → chunk-VQLRHJKL.js} +30 -26
- package/chunks/{chunk-L6P4KPHR.js → chunk-VRUHAVZS.js} +59 -39
- package/chunks/{chunk-HKMAENAO.js → chunk-W2U4RJJU.js} +8 -6
- package/chunks/{chunk-ATAKVRIF.js → chunk-WDSCTLAB.js} +7 -7
- package/chunks/{chunk-ZLXQN2QS.js → chunk-WIEO4CWB.js} +1 -1
- package/chunks/{chunk-OQ4DRIOA.js → chunk-WJOC24IW.js} +2 -2
- package/chunks/{chunk-J3JA76CF.js → chunk-WTNZ6DXB.js} +1 -1
- package/chunks/{chunk-NVYTCB5Z.js → chunk-XCR44EEA.js} +14589 -13980
- package/chunks/{chunk-TDEXZKMT.js → chunk-Y66VOBRP.js} +2 -2
- package/chunks/{chunk-CC2ITGCF.js → chunk-YHN5SUIJ.js} +49 -6
- package/chunks/{chunk-D5SKC4YG.js → chunk-ZBAROUR6.js} +41 -13
- package/chunks/{chunk-U2NNEY4R.js → chunk-ZEEVKDO7.js} +1 -1
- package/chunks/{chunk-5VXNZWGF.js → chunk-ZLOHB76C.js} +1 -1
- package/chunks/{chunk-JZETEN3Z.js → chunk-ZNCLTRNU.js} +3 -3
- package/chunks/{chunk-TO6QE22P.js → chunk-ZP4ZZJJG.js} +26 -22
- package/chunks/{chunk-UOZWKTQG.js → chunk-ZPAHLFZU.js} +2 -2
- package/chunks/{chunk-XLA62MYB.js → chunk-ZTXZ7FM4.js} +2 -2
- package/chunks/{computer-use-HM37RX6A.js → computer-use-DRETHEQF.js} +26 -26
- package/chunks/{config-utils-NV2SVGPB.js → config-utils-XSHOMMK4.js} +3 -2
- package/chunks/{contextCommand-OF5SFGH2.js → contextCommand-7YJUW23J.js} +28 -28
- package/chunks/{create-sub-session-INX7TXJI.js → create-sub-session-EAB2U5XW.js} +2 -2
- package/chunks/{create-sub-session-KPRT7ECJ.js → create-sub-session-L5HOZAEL.js} +26 -26
- 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-MI5HF26N.js} +603 -62
- package/chunks/{daemon-status-provider-B2UTZUJ2.js → daemon-status-provider-2D47GOJT.js} +36 -36
- package/chunks/{de-EBJN3OVN.js → de-2VCDRDGU.js} +4 -1
- package/chunks/{dist-WKPOYU7O.js → dist-IEXZC5ZR.js} +1 -1
- package/chunks/{dist-XKU3ABM5.js → dist-PQK4GCKA.js} +1 -1
- package/chunks/{dist-VHV4EVHG.js → dist-U75JK3PF.js} +1 -1
- package/chunks/{dist-R7LN5AZE.js → dist-VXO7QBON.js} +2 -2
- package/chunks/{dist-PNVLTKTL.js → dist-WH4TZSH3.js} +158 -4
- package/chunks/{dist-QYCAEZIT.js → dist-X2ABIW5R.js} +5 -1
- package/chunks/{earlyInputCapture-3VTHRC4C.js → earlyInputCapture-OJQPGCSX.js} +27 -27
- package/chunks/{edit-VNI4NJ73.js → edit-LZOAFLT2.js} +27 -27
- package/chunks/{en-5A6LA7RK.js → en-NJCA3TAA.js} +5 -1
- package/chunks/{enter-worktree-IYYBKPZT.js → enter-worktree-VL2TCGI5.js} +26 -26
- package/chunks/{enterPlanMode-GMC5FD5A.js → enterPlanMode-QGHBHZWI.js} +42 -27
- package/chunks/{environment-5HSSRMJ7.js → environment-2G5IC2EU.js} +30 -29
- package/chunks/{errors-HMFCJJ7P.js → errors-7QNQDNI2.js} +28 -28
- package/chunks/{exit-worktree-6BHCMP5G.js → exit-worktree-5V3X2MRH.js} +26 -26
- package/chunks/{exitPlanMode-CJW7G74W.js → exitPlanMode-XDPNQB4H.js} +26 -26
- package/chunks/{fast-path-FRDMDVHG.js → fast-path-NNSD4BVZ.js} +3 -3
- package/chunks/{fast-path-settings-5QZE64HR.js → fast-path-settings-DAOVFADC.js} +6 -4
- package/chunks/{fr-YXRABLYZ.js → fr-5F3E7WKD.js} +4 -1
- package/chunks/{gemini-QYSEGHAX.js → gemini-RKDUWGXJ.js} +139 -76
- package/chunks/{geminiContentGenerator-J7YNZDYP.js → geminiContentGenerator-V7QGHXVF.js} +4 -4
- package/chunks/{glob-BRCSGFOT.js → glob-ZNQUUOTS.js} +28 -27
- package/chunks/{grep-EE2DUOSY.js → grep-NYIGLM7R.js} +26 -26
- package/chunks/{handleAutoUpdate-5NWTLR67.js → handleAutoUpdate-UBQ4IQXY.js} +30 -30
- package/chunks/{i18n-BASPENNQ.js → i18n-5T3S6SGP.js} +27 -27
- package/chunks/initializer-TJED246Q.js +73 -0
- package/chunks/{installationInfo-W6V4DT7W.js → installationInfo-OTEU7FKR.js} +27 -27
- package/chunks/{ja-7VQOANVG.js → ja-66J6B53L.js} +5 -2
- package/chunks/{keychain-token-storage-VKUBNCP4.js → keychain-token-storage-AU22CQI6.js} +2 -2
- package/chunks/list-6OHS7MFJ.js +76 -0
- package/chunks/loadedSettingsAdapter-5456XIYG.js +70 -0
- package/chunks/{loop-wakeup-WX7BLWWP.js → loop-wakeup-C4EXLYVA.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-NOWRPFKY.js +70 -0
- package/chunks/{monitor-X5Z3H4FY.js → monitor-CVDZO3IZ.js} +26 -26
- package/chunks/nonInteractiveCli-UGI7Y43E.js +129 -0
- package/chunks/{notebook-edit-TRM2QIJK.js → notebook-edit-NWIA5TEJ.js} +27 -27
- package/chunks/{openaiContentGenerator-AAYONPMF.js → openaiContentGenerator-KJONBBJO.js} +12 -12
- package/chunks/{pidfile-D4I4FTVA.js → pidfile-L3TGXMTF.js} +27 -27
- package/chunks/{pt-2C6YCSHL.js → pt-TFZO5Y6T.js} +4 -1
- package/chunks/{qwenContentGenerator-K3HZ2H76.js → qwenContentGenerator-GXUZB5SJ.js} +28 -28
- package/chunks/{qwenOAuth2-PJQ27GSO.js → qwenOAuth2-LEYOU7RU.js} +5 -5
- package/chunks/{read-file-7SZSIZOL.js → read-file-I4OUZXTA.js} +8 -8
- 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-XLCXANIO.js} +26 -26
- package/chunks/{ru-6BBHVZZV.js → ru-4L4LFHIT.js} +4 -1
- package/chunks/{run-qwen-serve-DMWV5N6L.js → run-qwen-serve-R6SBP6YS.js} +1232 -371
- package/chunks/{runtime-57WWRVHN.js → runtime-U3S33YUQ.js} +42 -37
- package/chunks/{scheduler-YBLGWSIL.js → scheduler-65QCIELP.js} +26 -26
- package/chunks/{send-message-F36YD6KQ.js → send-message-JZ752NWD.js} +3 -3
- package/chunks/{serve-R63NK3CV.js → serve-PSPOFCOD.js} +36 -34
- package/chunks/{server-Z22GCAXP.js → server-6P5ZB56O.js} +5561 -1377
- package/chunks/{session-HKAAI7BN.js → session-ILLOYW75.js} +298 -98
- package/chunks/{settings-3EYN66GK.js → settings-RMUJGYIK.js} +34 -32
- package/chunks/{shell-6YXINTWJ.js → shell-65GTAN5Q.js} +28 -26
- package/chunks/{skill-OO57P4X6.js → skill-L76U3YCX.js} +10 -10
- package/chunks/{spawnChannel-JD7G4VU6.js → spawnChannel-LXIGZ4EM.js} +28 -28
- package/chunks/{src-G5UPLZSZ.js → src-DWZT2X3Z.js} +87 -27
- package/chunks/{standalone-update-OB7F4JPZ.js → standalone-update-F6SRKPSD.js} +28 -28
- package/chunks/{startInteractiveUI-73EGLIIH.js → startInteractiveUI-UEJQP7S3.js} +730 -397
- 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-4QBZVOGN.js} +26 -26
- package/chunks/{team-delete-6OSECUZC.js → team-delete-RCWYDRF4.js} +6 -5
- package/chunks/{team-plan-approval-L6F434RY.js → team-plan-approval-BK4CIOFV.js} +26 -26
- package/chunks/{theme-manager-ZG4RY6GU.js → theme-manager-5F2IGW6E.js} +27 -27
- package/chunks/{todoWrite-YDMFEV4G.js → todoWrite-FKCGATPJ.js} +4 -4
- package/chunks/{tool-search-THVIWAPB.js → tool-search-J2ESO33H.js} +9 -9
- package/chunks/{total-session-admission-JOKNRIIA.js → total-session-admission-U4LZ5QTQ.js} +33 -33
- package/chunks/tree-sitter-YJVE2ZUK.js +2980 -0
- package/chunks/{trustedFolders-EOGT3UVS.js → trustedFolders-TIDOXCJA.js} +29 -28
- package/chunks/types-ML3TRJQ5.js +16 -0
- package/chunks/{updateCheck-2KYEYVSB.js → updateCheck-VRVR26FI.js} +29 -29
- package/chunks/{validateNonInterActiveAuth-EN6ZQSR2.js → validateNonInterActiveAuth-UGKYAVLG.js} +75 -71
- package/chunks/{version-3UEA6ZIR.js → version-7HR6VZAT.js} +1 -1
- package/chunks/{web-fetch-PAAEQKBW.js → web-fetch-QGODBB6S.js} +5 -5
- package/chunks/{workflow-QCCCMYP3.js → workflow-EDQAITEW.js} +27 -27
- package/chunks/workspace-providers-status-27UGAK77.js +73 -0
- package/chunks/workspace-registration-store-5H7577YQ.js +27 -0
- package/chunks/{workspace-registry-24QFLQYH.js → workspace-registry-F3THGAXC.js} +33 -33
- package/chunks/workspace-service-4JSAQAHP.js +86 -0
- package/chunks/workspace-skills-status-5JTWZHZU.js +72 -0
- package/chunks/{write-file-I3MUDRIE.js → write-file-UY6XCZZM.js} +27 -27
- package/chunks/{zh-RQE7I22T.js → zh-FSAH32JB.js} +6 -2
- package/chunks/{zh-TW-TBPQGHKH.js → zh-TW-D2YIE2LO.js} +6 -2
- package/cli.js +11 -11
- package/locales/ca.js +6 -0
- package/locales/de.js +6 -0
- package/locales/en.js +8 -0
- package/locales/fr.js +6 -0
- package/locales/ja.js +7 -1
- package/locales/pt.js +6 -0
- package/locales/ru.js +6 -0
- package/locales/zh-TW.js +9 -1
- package/locales/zh.js +9 -1
- package/package.json +3 -3
- package/web-shell/assets/{arc-C15hqnJe.js → arc-CObt_TK9.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-B-At37J_.js → architectureDiagram-3BPJPVTR-B7aiJ6CK.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-B51wjcU7.js → blockDiagram-GPEHLZMM-BSK2CrID.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-xBK7BAwN.js → c4Diagram-AAUBKEIU-Bhx2p7T_.js} +1 -1
- package/web-shell/assets/channel-BBaLq8MV.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-xKmLg7Yr.js → chunk-2J33WTMH-c3Hzv0Ni.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BfkdKZCM.js → chunk-4BX2VUAB-DNXaK7ZF.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DT713sZf.js → chunk-55IACEB6-BXjvDj_i.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-CYEeAamv.js → chunk-727SXJPM-B6CaKFp-.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DBN-5CFd.js → chunk-AQP2D5EJ-tij6Mz9B.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CGZKk4PH.js → chunk-FMBD7UC4-DdlsGk2h.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-qQbC2O-y.js → chunk-ND2GUHAM-CdgGZSHE.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-B3zeXwsX.js → chunk-QZHKN3VN-D8oJn1C0.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-B2ZK6sWE.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B2ZK6sWE.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-BKsl1Wvy.js → cose-bilkent-S5V4N54A-BUVmNp1Y.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CuuuLiBK.js → dagre-BM42HDAG-CO4q310O.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CG4_eKiV.js → diagram-2AECGRRQ-C6gFvWkg.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-DSFTmZB1.js → diagram-5GNKFQAL-NG2I_c0h.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-BxwlEHn8.js → diagram-KO2AKTUF-DFKMS6I9.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-BUAg-jMG.js → diagram-LMA3HP47-BiElfsfP.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BFM2jlO5.js → diagram-OG6HWLK6-zLWDYUqu.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-CerbFPa2.js → erDiagram-TEJ5UH35-DoVaazhK.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BNeZz5Zz.js → flowDiagram-I6XJVG4X-0RLz-mXg.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-CTOogLaM.js → ganttDiagram-6RSMTGT7-C-eX1A39.js} +3 -3
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-yxSFkXPj.js → gitGraphDiagram-PVQCEYII-BauQu1Bu.js} +1 -1
- package/web-shell/assets/index-3uAT3ehO.css +5 -0
- package/web-shell/assets/index-CVHa2QH7.js +3 -0
- package/web-shell/assets/index-D1KigWat.js +1128 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DYdAUevm.js → infoDiagram-5YYISTIA-C800cFvZ.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CNuijZ90.js → ishikawaDiagram-YF4QCWOH-CFK1Jk6e.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-BTyiuonf.js → journeyDiagram-JHISSGLW-Cjx0WAC4.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-DPJo0Uow.js → kanban-definition-UN3LZRKU-DWMDHbiv.js} +1 -1
- package/web-shell/assets/{linear-C8wKCbIC.js → linear-vpW4FrZs.js} +1 -1
- package/web-shell/assets/{mermaid.core-BV5o7nW5.js → mermaid.core-DsHRUnDd.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BtLcBmSt.js → mindmap-definition-RKZ34NQL-D3Eb1cAK.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-C22J7A9Q.js → pieDiagram-4H26LBE5-Cr2-6sWt.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-DSL10wiL.js → quadrantDiagram-W4KKPZXB-Yd7yUgVp.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-feqh0UpX.js → requirementDiagram-4Y6WPE33-BE6SprL8.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Z4OVaWaZ.js → sankeyDiagram-5OEKKPKP-DzkuMK8d.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DIluIcb1.js → sequenceDiagram-3UESZ5HK-wD9A3Dhi.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-hlhnuoYH.js → stateDiagram-AJRCARHV-BOp5q1Nm.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-BDsWUmPG.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-Dqf_CqgL.js → timeline-definition-PNZ67QCA-Btc08sUA.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-DD2QhaTX.js → vennDiagram-CIIHVFJN-Bv6upsOA.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B2uI85U_.js → wardley-L42UT6IY-D-XamnCK.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-U1aJX71g.js → wardleyDiagram-YWT4CUSO-BbP_5Wfp.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-C0ODHUee.js → xychartDiagram-2RQKCTM6-CO5Hh28b.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-CU3L64TP.js +0 -93
- 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-MO7O5722.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-4QZADKJS.js";
|
|
52
48
|
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
MAX_REGISTERED_WORKSPACES,
|
|
50
|
+
resolveWorkspaceInputs,
|
|
51
|
+
workspaceRegistrationId
|
|
52
|
+
} from "./chunk-KET3M4K4.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-AU4R7ACM.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-C5TVXLJZ.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-QCKIOYZD.js"),
|
|
1140
|
+
import("./pidfile-L3TGXMTF.js"),
|
|
1141
|
+
import("./runtime-U3S33YUQ.js"),
|
|
1142
|
+
import("./cli-entry-path-4VJ3Y6T2.js"),
|
|
1143
|
+
import("./channel-worker-group-K7QKH6IG.js"),
|
|
1144
|
+
import("./channel-worker-manager-YSFB4HUU.js")
|
|
1145
|
+
]).then(
|
|
1146
|
+
([
|
|
1147
|
+
supervisor,
|
|
1148
|
+
pidfile,
|
|
1149
|
+
channelRuntime,
|
|
1150
|
+
cliEntryPath,
|
|
1151
|
+
workerGroup,
|
|
1152
|
+
workerManager
|
|
1153
|
+
]) => ({
|
|
1154
|
+
createChannelWorkerSupervisor: supervisor.createChannelWorkerSupervisor,
|
|
1155
|
+
channelServicePidfile: pidfile,
|
|
1156
|
+
loadChannelsConfig: channelRuntime.loadChannelsConfig,
|
|
1157
|
+
createChannelWorkerGroup: workerGroup.createChannelWorkerGroup,
|
|
1158
|
+
createChannelWorkerManager: workerManager.createChannelWorkerManager,
|
|
1159
|
+
findCliEntryPath: cliEntryPath.findCliEntryPath
|
|
1160
|
+
})
|
|
1161
|
+
).catch((err) => {
|
|
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-DWZT2X3Z.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-RMUJGYIK.js"),
|
|
1280
|
+
import("./environment-2G5IC2EU.js"),
|
|
1281
|
+
import("./loadedSettingsAdapter-5456XIYG.js"),
|
|
1282
|
+
import("./trustedFolders-TIDOXCJA.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-U3S33YUQ.js"),
|
|
1296
|
+
import("./config-utils-XSHOMMK4.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-6P5ZB56O.js"),
|
|
1321
|
+
import("./bridge-SNJK2JLK.js"),
|
|
1322
|
+
import("./spawnChannel-LXIGZ4EM.js"),
|
|
1323
|
+
import("./workspace-service-4JSAQAHP.js"),
|
|
1324
|
+
import("./types-ML3TRJQ5.js"),
|
|
1325
|
+
import("./daemon-status-provider-2D47GOJT.js"),
|
|
1326
|
+
import("./workspace-providers-status-27UGAK77.js"),
|
|
1327
|
+
import("./workspace-skills-status-5JTWZHZU.js"),
|
|
1328
|
+
import("./total-session-admission-U4LZ5QTQ.js"),
|
|
1329
|
+
import("./workspace-registry-F3THGAXC.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,
|
|
@@ -1309,6 +1380,9 @@ function currentServeFeaturesForRunQwenServe(opts, sessionShellCommandEnabled, s
|
|
|
1309
1380
|
rateLimit: opts.rateLimit === true,
|
|
1310
1381
|
reloadAvailable: true,
|
|
1311
1382
|
channelReloadAvailable: opts.channelSelection !== void 0,
|
|
1383
|
+
channelControlAvailable: true,
|
|
1384
|
+
persistentWorkspaceRegistrationAvailable: true,
|
|
1385
|
+
workspaceRuntimeRemovalAvailable: true,
|
|
1312
1386
|
// Advertise the same WS feature flags as the runtime path (serve-features.ts)
|
|
1313
1387
|
// so the bootstrap `/capabilities` window doesn't briefly under-report them.
|
|
1314
1388
|
clientMcpOverWsEnabled: opts.clientMcpOverWs === true,
|
|
@@ -1477,6 +1551,7 @@ function createBootstrapServeApp(input) {
|
|
|
1477
1551
|
multiWorkspaceCapabilitiesRequireRuntime,
|
|
1478
1552
|
getRuntimeError,
|
|
1479
1553
|
getChannelWorkerSnapshot,
|
|
1554
|
+
getChannelWorkerSnapshots,
|
|
1480
1555
|
onHealthServed
|
|
1481
1556
|
} = input;
|
|
1482
1557
|
const app = (0, import_express.default)();
|
|
@@ -1545,6 +1620,7 @@ function createBootstrapServeApp(input) {
|
|
|
1545
1620
|
}
|
|
1546
1621
|
const runtimeError = getRuntimeError();
|
|
1547
1622
|
const channelWorker = getChannelWorkerSnapshot();
|
|
1623
|
+
const channelWorkers = getChannelWorkerSnapshots();
|
|
1548
1624
|
const runtimeFailed = runtimeError !== void 0;
|
|
1549
1625
|
const issue = runtimeError ? {
|
|
1550
1626
|
code: "daemon_runtime_failed",
|
|
@@ -1616,6 +1692,7 @@ function createBootstrapServeApp(input) {
|
|
|
1616
1692
|
},
|
|
1617
1693
|
channel: { live: false },
|
|
1618
1694
|
channelWorker,
|
|
1695
|
+
...channelWorkers.length > 0 ? { channelWorkers } : {},
|
|
1619
1696
|
transport: {
|
|
1620
1697
|
restSseActive: 0,
|
|
1621
1698
|
acp: {
|
|
@@ -1706,7 +1783,7 @@ function isChannelWebhookRequest(req) {
|
|
|
1706
1783
|
return req.method === "POST" && /^\/channels\/[^/]+\/webhooks\/[^/]+\/?$/u.test(req.path);
|
|
1707
1784
|
}
|
|
1708
1785
|
__name(isChannelWebhookRequest, "isChannelWebhookRequest");
|
|
1709
|
-
function createDeferredChannelWebhookAuth(
|
|
1786
|
+
function createDeferredChannelWebhookAuth(resolveSource, runtime, daemonLog) {
|
|
1710
1787
|
return (req, res, next) => {
|
|
1711
1788
|
const match = /^\/channels\/([^/]+)\/webhooks\/([^/]+)\/?$/u.exec(req.path);
|
|
1712
1789
|
const channelName = decodeDeferredWebhookPathSegment(match?.[1]);
|
|
@@ -1720,11 +1797,13 @@ function createDeferredChannelWebhookAuth(workspace, runtime, daemonLog) {
|
|
|
1720
1797
|
res.status(401).json({ error: "Invalid webhook secret" });
|
|
1721
1798
|
return;
|
|
1722
1799
|
}
|
|
1800
|
+
const configSource = resolveSource(channelName);
|
|
1723
1801
|
const secret = readDeferredWebhookSecret(
|
|
1724
1802
|
runtime,
|
|
1725
|
-
|
|
1803
|
+
configSource.workspaceCwd,
|
|
1726
1804
|
channelName,
|
|
1727
|
-
source
|
|
1805
|
+
source,
|
|
1806
|
+
configSource.env
|
|
1728
1807
|
);
|
|
1729
1808
|
if (!matchesWebhookSecret(req.get("x-qwen-webhook-secret"), secret)) {
|
|
1730
1809
|
daemonLog.warn("deferred webhook auth failed", {
|
|
@@ -1748,7 +1827,7 @@ function decodeDeferredWebhookPathSegment(segment) {
|
|
|
1748
1827
|
}
|
|
1749
1828
|
}
|
|
1750
1829
|
__name(decodeDeferredWebhookPathSegment, "decodeDeferredWebhookPathSegment");
|
|
1751
|
-
function readDeferredWebhookSecret(runtime, workspace, channelName, source) {
|
|
1830
|
+
function readDeferredWebhookSecret(runtime, workspace, channelName, source, env) {
|
|
1752
1831
|
try {
|
|
1753
1832
|
const rawConfig = runtime.loadChannelsConfig(workspace)[channelName];
|
|
1754
1833
|
if (typeof rawConfig !== "object" || rawConfig === null) {
|
|
@@ -1756,7 +1835,8 @@ function readDeferredWebhookSecret(runtime, workspace, channelName, source) {
|
|
|
1756
1835
|
}
|
|
1757
1836
|
return runtime.parseChannelWebhookConfig(
|
|
1758
1837
|
channelName,
|
|
1759
|
-
rawConfig
|
|
1838
|
+
rawConfig,
|
|
1839
|
+
env
|
|
1760
1840
|
)?.sources[source]?.secret;
|
|
1761
1841
|
} catch (err) {
|
|
1762
1842
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -1841,30 +1921,42 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
1841
1921
|
clientMcpOverWs: optsIn.clientMcpOverWs ?? (!envFlagDisabled(clientMcpOverWsEnv) && clientMcpOverWsEnv !== void 0),
|
|
1842
1922
|
cdpTunnelOverWs: optsIn.cdpTunnelOverWs ?? (!envFlagDisabled(cdpTunnelOverWsEnv) && (cdpTunnelOverWsEnv !== void 0 || chromeExtensionOriginAllowed))
|
|
1843
1923
|
};
|
|
1844
|
-
|
|
1845
|
-
|
|
1924
|
+
let channelRuntime = opts.channelSelection ? await loadChannelWorkerRuntime() : void 0;
|
|
1925
|
+
let channelServicePidfile = deps.channelServicePidfile ?? channelRuntime?.channelServicePidfile;
|
|
1926
|
+
const ensureChannelRuntime = /* @__PURE__ */ __name(async () => {
|
|
1927
|
+
channelRuntime ??= await loadChannelWorkerRuntime();
|
|
1928
|
+
channelServicePidfile ??= channelRuntime.channelServicePidfile;
|
|
1929
|
+
return channelRuntime;
|
|
1930
|
+
}, "ensureChannelRuntime");
|
|
1846
1931
|
let channelPidfileReserved = false;
|
|
1847
1932
|
const removeCurrentServePidfile = /* @__PURE__ */ __name(() => {
|
|
1848
|
-
if (!
|
|
1933
|
+
if (!channelServicePidfile) return;
|
|
1849
1934
|
if (!channelPidfileReserved) return;
|
|
1850
1935
|
if (channelServicePidfile.removeServeServiceInfo) {
|
|
1851
1936
|
if (channelServicePidfile.removeServeServiceInfo(process.pid)) {
|
|
1852
1937
|
channelPidfileReserved = false;
|
|
1938
|
+
} else {
|
|
1939
|
+
const info2 = channelServicePidfile.readServiceInfo();
|
|
1940
|
+
if (!info2 || info2.owner !== "serve" || info2.pid !== process.pid || info2.servePid !== process.pid) {
|
|
1941
|
+
channelPidfileReserved = false;
|
|
1942
|
+
}
|
|
1853
1943
|
}
|
|
1854
1944
|
return;
|
|
1855
1945
|
}
|
|
1856
1946
|
const info = channelServicePidfile.readServiceInfo();
|
|
1857
1947
|
if (info?.owner === "serve" && info.pid === process.pid && info.servePid === process.pid) {
|
|
1858
1948
|
channelServicePidfile.removeServiceInfo();
|
|
1949
|
+
const remaining = channelServicePidfile.readServiceInfo();
|
|
1950
|
+
channelPidfileReserved = remaining?.owner === "serve" && remaining.pid === process.pid && remaining.servePid === process.pid;
|
|
1951
|
+
} else {
|
|
1859
1952
|
channelPidfileReserved = false;
|
|
1860
1953
|
}
|
|
1861
1954
|
}, "removeCurrentServePidfile");
|
|
1862
|
-
const reserveChannelServicePidfile = /* @__PURE__ */ __name(() => {
|
|
1863
|
-
if (!opts.channelSelection) return;
|
|
1955
|
+
const reserveChannelServicePidfile = /* @__PURE__ */ __name((selection) => {
|
|
1864
1956
|
if (!channelServicePidfile) {
|
|
1865
1957
|
throw new Error("Channel service pidfile runtime is not available.");
|
|
1866
1958
|
}
|
|
1867
|
-
const channelPidfileNames = channelSelectionNames(
|
|
1959
|
+
const channelPidfileNames = channelSelectionNames(selection);
|
|
1868
1960
|
const existingChannelService = channelServicePidfile.readServiceInfo();
|
|
1869
1961
|
if (existingChannelService) {
|
|
1870
1962
|
throw channelServicePidfileConflictError(existingChannelService);
|
|
@@ -1889,9 +1981,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
1889
1981
|
return;
|
|
1890
1982
|
} catch (retryErr) {
|
|
1891
1983
|
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
|
-
);
|
|
1984
|
+
throw channelServiceStartingConflictError();
|
|
1895
1985
|
}
|
|
1896
1986
|
throw retryErr;
|
|
1897
1987
|
}
|
|
@@ -2010,7 +2100,9 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2010
2100
|
}, "validateAndCanonicalizeWorkspace");
|
|
2011
2101
|
const workspaceInputs = rawWorkspaces.map((workspace) => ({
|
|
2012
2102
|
raw: workspace,
|
|
2013
|
-
cwd: validateAndCanonicalizeWorkspace(workspace)
|
|
2103
|
+
cwd: validateAndCanonicalizeWorkspace(workspace),
|
|
2104
|
+
removable: false,
|
|
2105
|
+
registrationIds: []
|
|
2014
2106
|
}));
|
|
2015
2107
|
const boundWorkspace = workspaceInputs[0].cwd;
|
|
2016
2108
|
const seenCanonicalWorkspaces = /* @__PURE__ */ new Set();
|
|
@@ -2042,6 +2134,71 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2042
2134
|
}
|
|
2043
2135
|
}
|
|
2044
2136
|
}
|
|
2137
|
+
if (workspaceInputs.length > MAX_REGISTERED_WORKSPACES) {
|
|
2138
|
+
throw new Error(
|
|
2139
|
+
`At most ${MAX_REGISTERED_WORKSPACES} --workspace values may be registered.`
|
|
2140
|
+
);
|
|
2141
|
+
}
|
|
2142
|
+
let workspaceRegistrationStore = deps.workspaceRegistrationStore;
|
|
2143
|
+
if (workspaceRegistrationStore === void 0 && process.env["QWEN_SERVE_NO_PERSISTENT_REGISTRATION"] !== "1") {
|
|
2144
|
+
const { WorkspaceRegistrationStore } = await import("./workspace-registration-store-5H7577YQ.js");
|
|
2145
|
+
workspaceRegistrationStore = new WorkspaceRegistrationStore(boundWorkspace);
|
|
2146
|
+
}
|
|
2147
|
+
if (workspaceRegistrationStore) {
|
|
2148
|
+
try {
|
|
2149
|
+
const stored = await workspaceRegistrationStore.read();
|
|
2150
|
+
for (const storedWorkspace of stored.workspaces) {
|
|
2151
|
+
const registrationId = workspaceRegistrationId(storedWorkspace);
|
|
2152
|
+
let cwd;
|
|
2153
|
+
try {
|
|
2154
|
+
cwd = validateAndCanonicalizeWorkspace(storedWorkspace);
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
writeStderrLine(
|
|
2157
|
+
`qwen serve: skipping persisted workspace registration ${JSON.stringify(
|
|
2158
|
+
storedWorkspace
|
|
2159
|
+
)}: ${err instanceof Error ? err.message : String(err)}`
|
|
2160
|
+
);
|
|
2161
|
+
continue;
|
|
2162
|
+
}
|
|
2163
|
+
const existingInput = workspaceInputs.find(
|
|
2164
|
+
(workspace) => workspace.cwd === cwd
|
|
2165
|
+
);
|
|
2166
|
+
if (existingInput) {
|
|
2167
|
+
existingInput.registrationIds.push(registrationId);
|
|
2168
|
+
continue;
|
|
2169
|
+
}
|
|
2170
|
+
const nested = workspaceInputs.some(
|
|
2171
|
+
(workspace) => isWithinRoot(cwd, workspace.cwd) || isWithinRoot(workspace.cwd, cwd)
|
|
2172
|
+
);
|
|
2173
|
+
if (nested) {
|
|
2174
|
+
writeStderrLine(
|
|
2175
|
+
`qwen serve: skipping persisted workspace registration ${JSON.stringify(
|
|
2176
|
+
storedWorkspace
|
|
2177
|
+
)}: path nests with an explicit or earlier restored workspace`
|
|
2178
|
+
);
|
|
2179
|
+
continue;
|
|
2180
|
+
}
|
|
2181
|
+
if (workspaceInputs.length >= MAX_REGISTERED_WORKSPACES) {
|
|
2182
|
+
writeStderrLine(
|
|
2183
|
+
`qwen serve: skipping persisted workspace registration ${JSON.stringify(
|
|
2184
|
+
storedWorkspace
|
|
2185
|
+
)}: workspace limit reached`
|
|
2186
|
+
);
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
workspaceInputs.push({
|
|
2190
|
+
raw: storedWorkspace,
|
|
2191
|
+
cwd,
|
|
2192
|
+
removable: true,
|
|
2193
|
+
registrationIds: [registrationId]
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
} catch (err) {
|
|
2197
|
+
writeStderrLine(
|
|
2198
|
+
`qwen serve: failed to read persisted workspace registrations: ${err instanceof Error ? err.message : String(err)}; continuing with explicit workspaces only`
|
|
2199
|
+
);
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2045
2202
|
if (workspaceInputs.length > 1 && deps.bridge) {
|
|
2046
2203
|
throw new Error(
|
|
2047
2204
|
"Injected bridge dependencies are only supported with a single workspace; multiple --workspace values require runQwenServe to construct one bridge per workspace."
|
|
@@ -2227,21 +2384,139 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2227
2384
|
void runtimeReady.catch(() => {
|
|
2228
2385
|
});
|
|
2229
2386
|
const disposeDaemonEventLoopMonitor = /* @__PURE__ */ __name(() => {
|
|
2230
|
-
daemonEventLoopMonitor
|
|
2387
|
+
const eventLoopMonitor = daemonEventLoopMonitor;
|
|
2231
2388
|
daemonEventLoopMonitor = void 0;
|
|
2232
|
-
daemonMetricsSampler
|
|
2389
|
+
const metricsSampler = daemonMetricsSampler;
|
|
2233
2390
|
daemonMetricsSampler = void 0;
|
|
2391
|
+
try {
|
|
2392
|
+
eventLoopMonitor?.dispose();
|
|
2393
|
+
} catch (err) {
|
|
2394
|
+
daemonLog.warn(
|
|
2395
|
+
`event loop monitor dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
try {
|
|
2399
|
+
metricsSampler?.dispose();
|
|
2400
|
+
} catch (err) {
|
|
2401
|
+
daemonLog.warn(
|
|
2402
|
+
`metrics sampler dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2403
|
+
);
|
|
2404
|
+
}
|
|
2234
2405
|
}, "disposeDaemonEventLoopMonitor");
|
|
2235
|
-
let
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2406
|
+
let channelWorkerManager;
|
|
2407
|
+
let channelWorkerManagerStarting;
|
|
2408
|
+
let channelControlDraining = false;
|
|
2409
|
+
let channelWorkspaceGroups;
|
|
2410
|
+
const channelWebhookEnvByWorkspace = /* @__PURE__ */ new Map();
|
|
2411
|
+
let channelWebhookConfigVersion = 0;
|
|
2412
|
+
let refreshChannelWebhookConfigs;
|
|
2413
|
+
let ensureChannelWorkerManager;
|
|
2414
|
+
const getChannelWebhookConfigSources = /* @__PURE__ */ __name(() => {
|
|
2415
|
+
const app2 = runtimeApp ?? runtimeAppForCleanup;
|
|
2416
|
+
const registry = app2?.locals?.["workspaceRegistry"];
|
|
2417
|
+
return (channelWorkspaceGroups ?? []).map((group) => {
|
|
2418
|
+
const env = registry?.getByWorkspaceCwd(group.workspaceCwd)?.env.effectiveEnv ?? channelWebhookEnvByWorkspace.get(group.workspaceCwd);
|
|
2419
|
+
return {
|
|
2420
|
+
workspaceCwd: group.workspaceCwd,
|
|
2421
|
+
...group.selection.mode === "names" ? { channelNames: group.selection.names } : {},
|
|
2422
|
+
...env ? { env } : {}
|
|
2423
|
+
};
|
|
2424
|
+
});
|
|
2425
|
+
}, "getChannelWebhookConfigSources");
|
|
2426
|
+
const resolveChannelWebhookConfigSource = /* @__PURE__ */ __name((channelName) => {
|
|
2427
|
+
const source = getChannelWebhookConfigSources().find(
|
|
2428
|
+
(source2) => !source2.channelNames || source2.channelNames.includes(channelName)
|
|
2429
|
+
);
|
|
2430
|
+
if (source) return source;
|
|
2431
|
+
const env = channelWebhookEnvByWorkspace.get(boundWorkspace);
|
|
2432
|
+
return {
|
|
2433
|
+
workspaceCwd: boundWorkspace,
|
|
2434
|
+
...env ? { env } : {}
|
|
2435
|
+
};
|
|
2436
|
+
}, "resolveChannelWebhookConfigSource");
|
|
2437
|
+
let closeServerAfterChannelWorkerStartupFailure = false;
|
|
2438
|
+
let runtimeFailureListenerClose;
|
|
2439
|
+
const getChannelWorkerSnapshot = /* @__PURE__ */ __name(() => channelWorkerManager?.primarySnapshot() ?? {
|
|
2440
|
+
enabled: false,
|
|
2441
|
+
state: "disabled",
|
|
2442
|
+
channels: []
|
|
2443
|
+
}, "getChannelWorkerSnapshot");
|
|
2444
|
+
const getChannelWorkerSnapshots = /* @__PURE__ */ __name(() => channelWorkerManager?.snapshots() ?? [], "getChannelWorkerSnapshots");
|
|
2445
|
+
const getChannelWorkerControl = /* @__PURE__ */ __name(() => channelWorkerManager?.state() ?? {
|
|
2446
|
+
enabled: false,
|
|
2447
|
+
selection: null,
|
|
2448
|
+
transition: "idle",
|
|
2449
|
+
workers: []
|
|
2450
|
+
}, "getChannelWorkerControl");
|
|
2451
|
+
const daemonDrainingError = /* @__PURE__ */ __name(() => Object.assign(new Error("Daemon is shutting down."), {
|
|
2452
|
+
code: "daemon_draining"
|
|
2453
|
+
}), "daemonDrainingError");
|
|
2454
|
+
const setChannelWorkerSelection = /* @__PURE__ */ __name(async (selection) => {
|
|
2455
|
+
if (channelControlDraining) throw daemonDrainingError();
|
|
2456
|
+
const manager = await ensureChannelWorkerManager?.();
|
|
2457
|
+
if (!manager) throw new Error("Channel worker manager is unavailable.");
|
|
2458
|
+
if (channelControlDraining) {
|
|
2459
|
+
await manager.shutdown().catch(() => void 0);
|
|
2460
|
+
throw daemonDrainingError();
|
|
2461
|
+
}
|
|
2462
|
+
return manager.setSelection(selection);
|
|
2463
|
+
}, "setChannelWorkerSelection");
|
|
2464
|
+
const stopChannelWorker = /* @__PURE__ */ __name(async () => {
|
|
2465
|
+
if (channelControlDraining) throw daemonDrainingError();
|
|
2466
|
+
const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
|
|
2467
|
+
if (channelControlDraining) {
|
|
2468
|
+
await manager?.shutdown().catch(() => void 0);
|
|
2469
|
+
throw daemonDrainingError();
|
|
2470
|
+
}
|
|
2471
|
+
if (!manager) {
|
|
2472
|
+
return { changed: false, state: getChannelWorkerControl() };
|
|
2473
|
+
}
|
|
2474
|
+
return manager.stopSelection();
|
|
2475
|
+
}, "stopChannelWorker");
|
|
2476
|
+
const reloadChannelWorker = /* @__PURE__ */ __name(async () => {
|
|
2477
|
+
if (channelControlDraining) throw daemonDrainingError();
|
|
2478
|
+
const manager = channelWorkerManager ?? await channelWorkerManagerStarting;
|
|
2479
|
+
if (channelControlDraining) {
|
|
2480
|
+
await manager?.shutdown().catch(() => void 0);
|
|
2481
|
+
throw daemonDrainingError();
|
|
2482
|
+
}
|
|
2483
|
+
if (!manager) {
|
|
2484
|
+
return { enabled: false, state: "disabled", channels: [] };
|
|
2485
|
+
}
|
|
2486
|
+
try {
|
|
2487
|
+
return await manager.reload();
|
|
2488
|
+
} finally {
|
|
2489
|
+
writeChannelWorkerPidfile();
|
|
2490
|
+
}
|
|
2491
|
+
}, "reloadChannelWorker");
|
|
2492
|
+
const isLiveWorker = /* @__PURE__ */ __name((snapshot) => snapshot.state === "running" || snapshot.state === "starting", "isLiveWorker");
|
|
2493
|
+
let channelWorkerPidfileUsesWorkers = workspaceInputs.length > 1;
|
|
2494
|
+
const writeChannelWorkerPidfile = /* @__PURE__ */ __name(() => {
|
|
2495
|
+
if (runtimeStartupError !== void 0) return;
|
|
2496
|
+
if (!channelPidfileReserved || !channelServicePidfile) return;
|
|
2497
|
+
const snapshots = getChannelWorkerSnapshots();
|
|
2498
|
+
const workers = snapshots.map((snapshot) => ({
|
|
2499
|
+
workspaceId: snapshot.workspaceId,
|
|
2500
|
+
workspaceCwd: snapshot.workspaceCwd,
|
|
2501
|
+
channels: snapshot.channels,
|
|
2502
|
+
// Drop a stale pid (worker exited/failed/stopped) so readers never signal
|
|
2503
|
+
// a dead process — mirrors the pre-4b clear-on-exit behavior.
|
|
2504
|
+
...isLiveWorker(snapshot) && snapshot.pid !== void 0 ? { workerPid: snapshot.pid } : {}
|
|
2505
|
+
}));
|
|
2506
|
+
const channels = [
|
|
2507
|
+
...new Set(snapshots.flatMap((snapshot) => snapshot.channels))
|
|
2508
|
+
];
|
|
2509
|
+
const primary = snapshots.find((snapshot) => snapshot.primary);
|
|
2510
|
+
if (workers.length > 1 || snapshots.some((snapshot) => !snapshot.primary)) {
|
|
2511
|
+
channelWorkerPidfileUsesWorkers = true;
|
|
2512
|
+
}
|
|
2513
|
+
const includeWorkers = channelWorkerPidfileUsesWorkers && workers.length > 0;
|
|
2240
2514
|
try {
|
|
2241
2515
|
channelServicePidfile.writeServeServiceInfo({
|
|
2242
|
-
channels
|
|
2516
|
+
channels,
|
|
2243
2517
|
servePid: process.pid,
|
|
2244
|
-
|
|
2518
|
+
...primary && isLiveWorker(primary) && primary.pid !== void 0 ? { workerPid: primary.pid } : {},
|
|
2519
|
+
...includeWorkers ? { workers } : {}
|
|
2245
2520
|
});
|
|
2246
2521
|
} catch (err) {
|
|
2247
2522
|
daemonLog.warn(
|
|
@@ -2254,11 +2529,83 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2254
2529
|
() => runtimeStartupError
|
|
2255
2530
|
);
|
|
2256
2531
|
const shutdownBridges = /* @__PURE__ */ new WeakSet();
|
|
2532
|
+
const disposedRuntimeApps = /* @__PURE__ */ new WeakSet();
|
|
2533
|
+
const stoppedRuntimeAppProducers = /* @__PURE__ */ new WeakSet();
|
|
2534
|
+
const stoppedExtensionReconcilers = /* @__PURE__ */ new WeakSet();
|
|
2535
|
+
const stopExtensionReconciler = /* @__PURE__ */ __name((app2) => {
|
|
2536
|
+
if (!app2 || stoppedExtensionReconcilers.has(app2)) return;
|
|
2537
|
+
stoppedExtensionReconcilers.add(app2);
|
|
2538
|
+
const stopExtensionGenerationReconciler = app2.locals?.["stopExtensionGenerationReconciler"];
|
|
2539
|
+
try {
|
|
2540
|
+
stopExtensionGenerationReconciler?.();
|
|
2541
|
+
} catch (err) {
|
|
2542
|
+
daemonLog.warn(
|
|
2543
|
+
`extension generation reconciler dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
}, "stopExtensionReconciler");
|
|
2547
|
+
const stopRuntimeAppProducers = /* @__PURE__ */ __name((app2) => {
|
|
2548
|
+
if (!app2 || stoppedRuntimeAppProducers.has(app2)) return;
|
|
2549
|
+
stoppedRuntimeAppProducers.add(app2);
|
|
2550
|
+
const locals = app2.locals;
|
|
2551
|
+
const stopSafely = /* @__PURE__ */ __name((name, stop) => {
|
|
2552
|
+
try {
|
|
2553
|
+
stop?.();
|
|
2554
|
+
} catch (err) {
|
|
2555
|
+
daemonLog.warn(
|
|
2556
|
+
`${name} dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
}, "stopSafely");
|
|
2560
|
+
stopSafely("scheduled-task keepalive", locals.stopScheduledTaskKeepalive);
|
|
2561
|
+
stopSafely("workspace git state", locals.stopWorkspaceGitState);
|
|
2562
|
+
for (const stop of locals.subSessionStoppers ?? []) {
|
|
2563
|
+
stopSafely("sub-session launcher", stop);
|
|
2564
|
+
}
|
|
2565
|
+
stopExtensionReconciler(app2);
|
|
2566
|
+
}, "stopRuntimeAppProducers");
|
|
2567
|
+
const disposeRuntimeAppResources = /* @__PURE__ */ __name((app2) => {
|
|
2568
|
+
if (!app2 || disposedRuntimeApps.has(app2)) return;
|
|
2569
|
+
disposedRuntimeApps.add(app2);
|
|
2570
|
+
stopRuntimeAppProducers(app2);
|
|
2571
|
+
const deviceFlowRegistry = getDeviceFlowRegistry(app2);
|
|
2572
|
+
if (deviceFlowRegistry) {
|
|
2573
|
+
try {
|
|
2574
|
+
deviceFlowRegistry.dispose();
|
|
2575
|
+
} catch (err) {
|
|
2576
|
+
daemonLog.warn(
|
|
2577
|
+
`device-flow registry dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
const acpHandle = app2.locals?.["acpHandle"];
|
|
2582
|
+
if (acpHandle?.dispose) {
|
|
2583
|
+
try {
|
|
2584
|
+
acpHandle.dispose();
|
|
2585
|
+
} catch (err) {
|
|
2586
|
+
daemonLog.warn(
|
|
2587
|
+
`ACP handle dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
const rateLimiter = getRateLimiter(app2);
|
|
2592
|
+
if (rateLimiter) {
|
|
2593
|
+
try {
|
|
2594
|
+
rateLimiter.setDraining(true);
|
|
2595
|
+
rateLimiter.dispose();
|
|
2596
|
+
} catch (err) {
|
|
2597
|
+
daemonLog.warn(
|
|
2598
|
+
`rate limiter dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
disposeDaemonEventLoopMonitor();
|
|
2603
|
+
}, "disposeRuntimeAppResources");
|
|
2257
2604
|
const getRuntimeBridgesForCleanup = /* @__PURE__ */ __name(() => {
|
|
2258
2605
|
const appForCleanup = runtimeApp ?? runtimeAppForCleanup;
|
|
2259
2606
|
const registry = appForCleanup?.locals?.["workspaceRegistry"];
|
|
2260
2607
|
const bridges = [
|
|
2261
|
-
...registry ? registry.
|
|
2608
|
+
...registry ? registry.listManaged().map((runtime) => runtime.bridge) : [],
|
|
2262
2609
|
...bridgeRef ? [bridgeRef] : [],
|
|
2263
2610
|
...internalRuntimeBridgesForCleanup
|
|
2264
2611
|
];
|
|
@@ -2440,12 +2787,15 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2440
2787
|
// `agent_message_chunk._meta` (`usage` + `durationMs`) at the bridge's
|
|
2441
2788
|
// single session/update fan-in. Increments (not cumulative), so the ring
|
|
2442
2789
|
// sums tokens per window (token-burn chart) and pools the round-trip times
|
|
2443
|
-
// for the LLM-latency percentiles.
|
|
2444
|
-
|
|
2790
|
+
// for the LLM-latency percentiles. `apiErrors` / `apiRetries` ride the
|
|
2791
|
+
// same frame (per-round increments, 0 when none) and window into the
|
|
2792
|
+
// model-API-health chart.
|
|
2793
|
+
tokenUsage(inputTokens, outputTokens, durationMs, apiErrors, apiRetries) {
|
|
2445
2794
|
metricsRing.recordTokens(inputTokens, outputTokens);
|
|
2446
2795
|
if (typeof durationMs === "number") {
|
|
2447
2796
|
metricsRing.recordLlmDuration(durationMs);
|
|
2448
2797
|
}
|
|
2798
|
+
metricsRing.recordApiActivity(apiErrors ?? 0, apiRetries ?? 0);
|
|
2449
2799
|
}
|
|
2450
2800
|
};
|
|
2451
2801
|
return telemetry;
|
|
@@ -2550,6 +2900,63 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2550
2900
|
[...next].sort()
|
|
2551
2901
|
);
|
|
2552
2902
|
}), "persistDisabledToolsFn");
|
|
2903
|
+
const persistDisabledSkillsFn = /* @__PURE__ */ __name((workspace, skillName, enabled) => withSettingsLock(workspace, async () => {
|
|
2904
|
+
const fresh = settingsRuntime.settings.loadSettings(workspace);
|
|
2905
|
+
const normalizedName = skillName.trim().toLowerCase();
|
|
2906
|
+
const disabledNames = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.filter(
|
|
2907
|
+
(entry) => typeof entry === "string"
|
|
2908
|
+
) : [], "disabledNames");
|
|
2909
|
+
const lockedScopes = [
|
|
2910
|
+
["system", fresh.system.settings.skills?.disabled],
|
|
2911
|
+
["user", fresh.user.settings.skills?.disabled],
|
|
2912
|
+
["systemDefaults", fresh.systemDefaults.settings.skills?.disabled]
|
|
2913
|
+
];
|
|
2914
|
+
for (const [scope, names] of lockedScopes) {
|
|
2915
|
+
if (disabledNames(names).some(
|
|
2916
|
+
(name) => name.trim().toLowerCase() === normalizedName
|
|
2917
|
+
)) {
|
|
2918
|
+
throw new runtime.WorkspaceSkillNotToggleableError(
|
|
2919
|
+
skillName,
|
|
2920
|
+
"locked",
|
|
2921
|
+
scope
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
const workspaceDisabled = disabledNames(
|
|
2926
|
+
fresh.workspace.settings.skills?.disabled
|
|
2927
|
+
);
|
|
2928
|
+
const next = [];
|
|
2929
|
+
let found = false;
|
|
2930
|
+
let changed = false;
|
|
2931
|
+
for (const name of workspaceDisabled) {
|
|
2932
|
+
if (name.trim().toLowerCase() !== normalizedName) {
|
|
2933
|
+
next.push(name);
|
|
2934
|
+
continue;
|
|
2935
|
+
}
|
|
2936
|
+
if (enabled) {
|
|
2937
|
+
changed = true;
|
|
2938
|
+
continue;
|
|
2939
|
+
}
|
|
2940
|
+
if (!found) {
|
|
2941
|
+
next.push(skillName);
|
|
2942
|
+
found = true;
|
|
2943
|
+
if (name !== skillName) changed = true;
|
|
2944
|
+
} else {
|
|
2945
|
+
changed = true;
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
if (!enabled && !found) {
|
|
2949
|
+
next.push(skillName);
|
|
2950
|
+
changed = true;
|
|
2951
|
+
}
|
|
2952
|
+
if (!changed) return { changed: false, disabled: workspaceDisabled };
|
|
2953
|
+
fresh.setValue(
|
|
2954
|
+
WORKSPACE_SETTING_SCOPE,
|
|
2955
|
+
"skills.disabled",
|
|
2956
|
+
next.length > 0 ? next : void 0
|
|
2957
|
+
);
|
|
2958
|
+
return { changed: true, disabled: next };
|
|
2959
|
+
}), "persistDisabledSkillsFn");
|
|
2553
2960
|
const persistSettingFn = /* @__PURE__ */ __name((workspace, scope, key, value) => withSettingsLock(workspace, async () => {
|
|
2554
2961
|
const fresh = settingsRuntime.settings.loadSettings(workspace);
|
|
2555
2962
|
fresh.setValue(scope, key, value);
|
|
@@ -2582,7 +2989,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2582
2989
|
);
|
|
2583
2990
|
}
|
|
2584
2991
|
}), "persistSettingsFn");
|
|
2585
|
-
const { createSubSessionLauncher } = await import("./create-sub-session-
|
|
2992
|
+
const { createSubSessionLauncher } = await import("./create-sub-session-L5HOZAEL.js");
|
|
2586
2993
|
const subSessionLauncher = createSubSessionLauncher({
|
|
2587
2994
|
getBridge: /* @__PURE__ */ __name(() => bridgeRef, "getBridge"),
|
|
2588
2995
|
boundWorkspace
|
|
@@ -2623,14 +3030,18 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2623
3030
|
internalRuntimeBridgesForCleanup.push(bridge);
|
|
2624
3031
|
}
|
|
2625
3032
|
runtimeBridges.push(bridge);
|
|
3033
|
+
let invalidatePrimaryServeFeaturesCache = /* @__PURE__ */ __name(() => {
|
|
3034
|
+
}, "invalidatePrimaryServeFeaturesCache");
|
|
2626
3035
|
const workspaceService = runtime.createDaemonWorkspaceService({
|
|
2627
3036
|
boundWorkspace,
|
|
2628
3037
|
contextFilename: contextFilenameForInit ?? "QWEN.md",
|
|
2629
3038
|
statusProvider,
|
|
2630
3039
|
workspaceProvidersStatusProvider,
|
|
2631
3040
|
workspaceSkillsStatusProvider,
|
|
3041
|
+
voiceEnv: runtimeEffectiveEnv,
|
|
2632
3042
|
isChannelLive: /* @__PURE__ */ __name(() => bridge.isChannelLive(), "isChannelLive"),
|
|
2633
3043
|
persistDisabledTools: persistDisabledToolsFn,
|
|
3044
|
+
persistDisabledSkills: persistDisabledSkillsFn,
|
|
2634
3045
|
persistSetting: persistSettingFn,
|
|
2635
3046
|
persistSettings: persistSettingsFn,
|
|
2636
3047
|
preheatAcpChild: /* @__PURE__ */ __name(() => bridge.preheat(), "preheatAcpChild"),
|
|
@@ -2696,7 +3107,12 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2696
3107
|
queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => bridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
|
|
2697
3108
|
invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => bridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
|
|
2698
3109
|
refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => bridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
|
|
2699
|
-
publishWorkspaceEvent: /* @__PURE__ */ __name((event) =>
|
|
3110
|
+
publishWorkspaceEvent: /* @__PURE__ */ __name((event) => {
|
|
3111
|
+
if (event.type === "settings_changed" || event.type === "settings_reloaded") {
|
|
3112
|
+
invalidatePrimaryServeFeaturesCache();
|
|
3113
|
+
}
|
|
3114
|
+
bridge.publishWorkspaceEvent(event);
|
|
3115
|
+
}, "publishWorkspaceEvent")
|
|
2700
3116
|
});
|
|
2701
3117
|
const workspaceRuntimes = [
|
|
2702
3118
|
{
|
|
@@ -2704,6 +3120,8 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2704
3120
|
workspaceCwd: boundWorkspace,
|
|
2705
3121
|
primary: true,
|
|
2706
3122
|
trusted: trustedWorkspace,
|
|
3123
|
+
removable: false,
|
|
3124
|
+
registrationIds: workspaceInputs[0]?.registrationIds ?? [],
|
|
2707
3125
|
env: primaryRuntimeEnv,
|
|
2708
3126
|
bridge,
|
|
2709
3127
|
workspaceService,
|
|
@@ -2745,6 +3163,12 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2745
3163
|
};
|
|
2746
3164
|
}, "createRuntimeEnvMetadata");
|
|
2747
3165
|
const subSessionStoppers = [];
|
|
3166
|
+
const subSessionStoppersByWorkspace = /* @__PURE__ */ new Map();
|
|
3167
|
+
const runtimeCleanupPromises = /* @__PURE__ */ new WeakMap();
|
|
3168
|
+
const removeArrayValue = /* @__PURE__ */ __name((values, value) => {
|
|
3169
|
+
const index = values.indexOf(value);
|
|
3170
|
+
if (index >= 0) values.splice(index, 1);
|
|
3171
|
+
}, "removeArrayValue");
|
|
2748
3172
|
for (const workspaceInput of workspaceInputs.slice(1)) {
|
|
2749
3173
|
let secondarySettings;
|
|
2750
3174
|
try {
|
|
@@ -2838,6 +3262,10 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2838
3262
|
runtimeBridges.push(secondaryBridge);
|
|
2839
3263
|
internalRuntimeBridgesForCleanup.push(secondaryBridge);
|
|
2840
3264
|
subSessionStoppers.push(secondarySubSessionLauncher.stop);
|
|
3265
|
+
subSessionStoppersByWorkspace.set(
|
|
3266
|
+
workspaceInput.cwd,
|
|
3267
|
+
secondarySubSessionLauncher.stop
|
|
3268
|
+
);
|
|
2841
3269
|
const secondaryWorkspaceService = runtime.createDaemonWorkspaceService({
|
|
2842
3270
|
boundWorkspace: workspaceInput.cwd,
|
|
2843
3271
|
contextFilename: contextFilenameForInit ?? "QWEN.md",
|
|
@@ -2846,9 +3274,12 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2846
3274
|
env: secondaryEnv.effectiveEnv
|
|
2847
3275
|
}),
|
|
2848
3276
|
workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
|
|
3277
|
+
voiceEnv: secondaryEnv.effectiveEnv,
|
|
3278
|
+
voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
|
|
2849
3279
|
isChannelLive: /* @__PURE__ */ __name(() => secondaryBridge.isChannelLive(), "isChannelLive"),
|
|
2850
3280
|
preheatAcpChild: /* @__PURE__ */ __name(() => secondaryBridge.preheat(), "preheatAcpChild"),
|
|
2851
3281
|
persistDisabledTools: persistDisabledToolsFn,
|
|
3282
|
+
persistDisabledSkills: persistDisabledSkillsFn,
|
|
2852
3283
|
persistSetting: persistSettingFn,
|
|
2853
3284
|
persistSettings: persistSettingsFn,
|
|
2854
3285
|
reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
|
|
@@ -2906,6 +3337,8 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2906
3337
|
workspaceCwd: workspaceInput.cwd,
|
|
2907
3338
|
primary: false,
|
|
2908
3339
|
trusted: secondaryTrusted,
|
|
3340
|
+
removable: workspaceInput.removable,
|
|
3341
|
+
registrationIds: workspaceInput.registrationIds,
|
|
2909
3342
|
env: secondaryEnv.metadata,
|
|
2910
3343
|
bridge: secondaryBridge,
|
|
2911
3344
|
workspaceService: secondaryWorkspaceService,
|
|
@@ -2916,6 +3349,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2916
3349
|
const workspaceRegistry = runtime.createWorkspaceRegistry(workspaceRuntimes, {
|
|
2917
3350
|
sessionOwnerIndex
|
|
2918
3351
|
});
|
|
3352
|
+
const workspaceVoiceCoordinator = new WorkspaceVoiceCoordinator();
|
|
2919
3353
|
core.registerDaemonGaugeCallbacks({
|
|
2920
3354
|
sessionCount: /* @__PURE__ */ __name(() => workspaceRegistry.list().reduce((sum, item) => sum + item.bridge.sessionCount, 0), "sessionCount"),
|
|
2921
3355
|
sseCount: /* @__PURE__ */ __name(() => runtime.getActiveSseCount(), "sseCount"),
|
|
@@ -2944,7 +3378,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
2944
3378
|
prevCpu = cpu;
|
|
2945
3379
|
prevCpuAt = nowMs;
|
|
2946
3380
|
}
|
|
2947
|
-
const acp = app2.locals?.["acpHandle"]?.
|
|
3381
|
+
const acp = app2.locals?.["acpHandle"]?.getSnapshot();
|
|
2948
3382
|
const hits = getRateLimiter(app2)?.getHitCounts();
|
|
2949
3383
|
const rejectedTotal = hits ? hits.prompt + hits.mutation + hits.read : 0;
|
|
2950
3384
|
const rateLimitRejected = prevRateRejected === void 0 ? 0 : Math.max(0, rejectedTotal - prevRateRejected);
|
|
@@ -3049,111 +3483,139 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3049
3483
|
getBridge: /* @__PURE__ */ __name(() => wsBridgeRef, "getBridge"),
|
|
3050
3484
|
boundWorkspace: cwd
|
|
3051
3485
|
});
|
|
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
|
-
|
|
3486
|
+
let wsBridge;
|
|
3487
|
+
try {
|
|
3488
|
+
wsBridge = runtime.createAcpSessionBridge({
|
|
3489
|
+
clientMcpSender: wsClientMcpRegistry.lookup,
|
|
3490
|
+
onCreateSubSession: wsSubSessionLauncher.launch,
|
|
3491
|
+
maxSessions: opts.maxSessions,
|
|
3492
|
+
freshSessionAdmission: totalSessionAdmission.admit,
|
|
3493
|
+
sessionLifecycle: sessionOwnerIndex.handleBridgeSessionLifecycle,
|
|
3494
|
+
...opts.maxPendingPromptsPerSession !== void 0 ? { maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession } : {},
|
|
3495
|
+
...opts.eventRingSize !== void 0 ? { eventRingSize: opts.eventRingSize } : {},
|
|
3496
|
+
...opts.compactedReplayMaxBytes !== void 0 ? { compactedReplayMaxBytes: opts.compactedReplayMaxBytes } : {},
|
|
3497
|
+
...opts.channelIdleTimeoutMs !== void 0 ? { channelIdleTimeoutMs: opts.channelIdleTimeoutMs } : {},
|
|
3498
|
+
...opts.sessionReapIntervalMs !== void 0 ? { sessionReapIntervalMs: opts.sessionReapIntervalMs } : {},
|
|
3499
|
+
...opts.sessionIdleTimeoutMs !== void 0 ? { sessionIdleTimeoutMs: opts.sessionIdleTimeoutMs } : {},
|
|
3500
|
+
...opts.permissionResponseTimeoutMs !== void 0 ? { permissionResponseTimeoutMs: opts.permissionResponseTimeoutMs } : {},
|
|
3501
|
+
boundWorkspace: cwd,
|
|
3502
|
+
sessionShellCommandEnabled,
|
|
3503
|
+
childEnvOverrides,
|
|
3504
|
+
channelFactory: wsChannelFactory,
|
|
3505
|
+
onDiagnosticLine: diagnosticSink,
|
|
3506
|
+
telemetry: createRuntimeBridgeTelemetry(wsHash),
|
|
3507
|
+
...permissionPolicy !== void 0 ? { permissionPolicy } : {},
|
|
3508
|
+
...permissionConsensusQuorum !== void 0 ? { permissionConsensusQuorum } : {},
|
|
3509
|
+
permissionAudit: permissionAuditPublisher,
|
|
3510
|
+
statusProvider: runtime.createDaemonStatusProvider({
|
|
3511
|
+
env: wsEnv.effectiveEnv
|
|
3512
|
+
}),
|
|
3513
|
+
fileSystem: createBridgeFileSystemAdapter(wsFsFactory),
|
|
3514
|
+
persistApprovalMode: /* @__PURE__ */ __name((workspace, mode) => withSettingsLock(workspace, async () => {
|
|
3515
|
+
const fresh = settingsRuntime.settings.loadSettings(workspace);
|
|
3516
|
+
fresh.setValue(
|
|
3517
|
+
WORKSPACE_SETTING_SCOPE,
|
|
3518
|
+
"tools.approvalMode",
|
|
3519
|
+
mode
|
|
3520
|
+
);
|
|
3521
|
+
}), "persistApprovalMode")
|
|
3522
|
+
});
|
|
3523
|
+
} catch (err) {
|
|
3524
|
+
wsSubSessionLauncher.stop();
|
|
3525
|
+
throw err;
|
|
3526
|
+
}
|
|
3083
3527
|
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
|
|
3528
|
+
let wsService;
|
|
3529
|
+
try {
|
|
3530
|
+
wsService = runtime.createDaemonWorkspaceService({
|
|
3531
|
+
boundWorkspace: cwd,
|
|
3532
|
+
contextFilename: contextFilenameForInit ?? "QWEN.md",
|
|
3533
|
+
statusProvider: runtime.createDaemonStatusProvider({
|
|
3534
|
+
env: wsEnv.effectiveEnv
|
|
3535
|
+
}),
|
|
3536
|
+
workspaceProvidersStatusProvider: runtime.createWorkspaceProvidersStatusProvider({
|
|
3537
|
+
env: wsEnv.effectiveEnv
|
|
3538
|
+
}),
|
|
3539
|
+
workspaceSkillsStatusProvider: runtime.createWorkspaceSkillsStatusProvider(),
|
|
3540
|
+
voiceEnv: wsEnv.effectiveEnv,
|
|
3541
|
+
voiceSettingsScope: WORKSPACE_SETTING_SCOPE,
|
|
3542
|
+
isChannelLive: /* @__PURE__ */ __name(() => wsBridge.isChannelLive(), "isChannelLive"),
|
|
3543
|
+
preheatAcpChild: /* @__PURE__ */ __name(() => wsBridge.preheat(), "preheatAcpChild"),
|
|
3544
|
+
persistDisabledTools: persistDisabledToolsFn,
|
|
3545
|
+
persistDisabledSkills: persistDisabledSkillsFn,
|
|
3546
|
+
persistSetting: persistSettingFn,
|
|
3547
|
+
persistSettings: persistSettingsFn,
|
|
3548
|
+
reloadDaemonEnv: /* @__PURE__ */ __name((workspace) => withSettingsLock(workspace, async () => {
|
|
3549
|
+
const fresh = settingsRuntime.settings.loadSettings(workspace, {
|
|
3550
|
+
skipLoadEnvironment: true
|
|
3551
|
+
});
|
|
3552
|
+
const result = settingsRuntime.settings.reloadEnvironment(
|
|
3109
3553
|
fresh.merged,
|
|
3110
|
-
workspace
|
|
3111
|
-
daemonRuntimeBaseEnv
|
|
3554
|
+
workspace
|
|
3112
3555
|
);
|
|
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
|
-
{
|
|
3556
|
+
try {
|
|
3557
|
+
const refreshedRuntimeEnv = settingsRuntime.environment.buildRuntimeEnvironment(
|
|
3558
|
+
fresh.merged,
|
|
3137
3559
|
workspace,
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3560
|
+
daemonRuntimeBaseEnv
|
|
3561
|
+
);
|
|
3562
|
+
logRuntimeEnvFileReadFailures(workspace, refreshedRuntimeEnv);
|
|
3563
|
+
wsEnv.replace(refreshedRuntimeEnv.effectiveEnv);
|
|
3564
|
+
wsEnv.metadata.envFileReadFailed = refreshedRuntimeEnv.envFileReadFailed;
|
|
3565
|
+
wsEnv.metadata.envFileReadFailures.splice(
|
|
3566
|
+
0,
|
|
3567
|
+
wsEnv.metadata.envFileReadFailures.length,
|
|
3568
|
+
...refreshedRuntimeEnv.envFileReadFailures
|
|
3569
|
+
);
|
|
3570
|
+
wsEnv.metadata.overlayKeys.splice(
|
|
3571
|
+
0,
|
|
3572
|
+
wsEnv.metadata.overlayKeys.length,
|
|
3573
|
+
...refreshedRuntimeEnv.overlayKeys
|
|
3574
|
+
);
|
|
3575
|
+
wsEnv.metadata.envFilePaths.splice(
|
|
3576
|
+
0,
|
|
3577
|
+
wsEnv.metadata.envFilePaths.length,
|
|
3578
|
+
...refreshedRuntimeEnv.envFilePaths
|
|
3579
|
+
);
|
|
3580
|
+
delete wsEnv.metadata.fallbackReason;
|
|
3581
|
+
} catch (err) {
|
|
3582
|
+
wsEnv.metadata.fallbackReason = err instanceof Error ? err.message : String(err);
|
|
3583
|
+
daemonLog.warn(
|
|
3584
|
+
"failed to rebuild dynamic runtime env snapshot after daemon env reload; preserving previous runtime env",
|
|
3585
|
+
{
|
|
3586
|
+
workspace,
|
|
3587
|
+
error: wsEnv.metadata.fallbackReason
|
|
3588
|
+
}
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
return result;
|
|
3592
|
+
}), "reloadDaemonEnv"),
|
|
3593
|
+
queryWorkspaceStatus: /* @__PURE__ */ __name((method, idle) => wsBridge.queryWorkspaceStatus(method, idle), "queryWorkspaceStatus"),
|
|
3594
|
+
invokeWorkspaceCommand: /* @__PURE__ */ __name((method, params, invokeOpts) => wsBridge.invokeWorkspaceCommand(method, params, invokeOpts), "invokeWorkspaceCommand"),
|
|
3595
|
+
refreshExtensionsForAllSessions: /* @__PURE__ */ __name(() => wsBridge.refreshExtensionsForAllSessions(), "refreshExtensionsForAllSessions"),
|
|
3596
|
+
publishWorkspaceEvent: /* @__PURE__ */ __name((event) => wsBridge.publishWorkspaceEvent(event), "publishWorkspaceEvent")
|
|
3597
|
+
});
|
|
3598
|
+
} catch (err) {
|
|
3599
|
+
wsSubSessionLauncher.stop();
|
|
3600
|
+
await wsBridge.shutdown().catch(() => {
|
|
3601
|
+
try {
|
|
3602
|
+
wsBridge.killAllSync();
|
|
3603
|
+
} catch {
|
|
3141
3604
|
}
|
|
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
|
-
});
|
|
3605
|
+
});
|
|
3606
|
+
throw err;
|
|
3607
|
+
}
|
|
3149
3608
|
runtimeBridges.push(wsBridge);
|
|
3150
3609
|
internalRuntimeBridgesForCleanup.push(wsBridge);
|
|
3151
3610
|
subSessionStoppers.push(wsSubSessionLauncher.stop);
|
|
3611
|
+
subSessionStoppersByWorkspace.set(cwd, wsSubSessionLauncher.stop);
|
|
3152
3612
|
return {
|
|
3153
3613
|
workspaceId: wsHash,
|
|
3154
3614
|
workspaceCwd: cwd,
|
|
3155
3615
|
primary: false,
|
|
3156
3616
|
trusted,
|
|
3617
|
+
removable: true,
|
|
3618
|
+
registrationIds: [],
|
|
3157
3619
|
env: wsEnv.metadata,
|
|
3158
3620
|
bridge: wsBridge,
|
|
3159
3621
|
workspaceService: wsService,
|
|
@@ -3161,9 +3623,135 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3161
3623
|
clientMcpSenderRegistry: wsClientMcpRegistry
|
|
3162
3624
|
};
|
|
3163
3625
|
}, "createDynamicWorkspaceRuntime");
|
|
3626
|
+
const workspaceRuntimeRemoval = {
|
|
3627
|
+
async runtimeAdded(runtimeAdded) {
|
|
3628
|
+
const app3 = runtimeApp ?? runtimeAppForCleanup;
|
|
3629
|
+
const startScheduledTaskKeepaliveForWorkspace = app3?.locals?.["startScheduledTaskKeepaliveForWorkspace"];
|
|
3630
|
+
startScheduledTaskKeepaliveForWorkspace?.(runtimeAdded);
|
|
3631
|
+
if (!channelWorkerManager) return;
|
|
3632
|
+
try {
|
|
3633
|
+
await channelWorkerManager.restoreWorkspace(
|
|
3634
|
+
runtimeAdded.workspaceCwd
|
|
3635
|
+
);
|
|
3636
|
+
await channelWorkerManager.refreshWorkspaces();
|
|
3637
|
+
} catch (err) {
|
|
3638
|
+
daemonLog.error(
|
|
3639
|
+
"workspace channel worker startup error",
|
|
3640
|
+
err instanceof Error ? err : null
|
|
3641
|
+
);
|
|
3642
|
+
} finally {
|
|
3643
|
+
writeChannelWorkerPidfile();
|
|
3644
|
+
}
|
|
3645
|
+
},
|
|
3646
|
+
beginDrain(runtimeToDrain) {
|
|
3647
|
+
totalSessionAdmission.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
|
|
3648
|
+
channelWorkerManager?.beginWorkspaceDrain(runtimeToDrain.workspaceCwd);
|
|
3649
|
+
workspaceVoiceCoordinator.beginWorkspaceDrain(runtimeToDrain);
|
|
3650
|
+
},
|
|
3651
|
+
cancelDrain(runtimeToDrain) {
|
|
3652
|
+
channelWorkerManager?.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
|
|
3653
|
+
totalSessionAdmission.cancelWorkspaceDrain(runtimeToDrain.workspaceCwd);
|
|
3654
|
+
workspaceVoiceCoordinator.cancelWorkspaceDrain(runtimeToDrain);
|
|
3655
|
+
},
|
|
3656
|
+
completeDrain(runtimeToDrain) {
|
|
3657
|
+
totalSessionAdmission.completeWorkspaceDrain(
|
|
3658
|
+
runtimeToDrain.workspaceCwd
|
|
3659
|
+
);
|
|
3660
|
+
workspaceVoiceCoordinator.completeWorkspaceDrain(runtimeToDrain);
|
|
3661
|
+
},
|
|
3662
|
+
getActivity(runtimeToDrain) {
|
|
3663
|
+
return {
|
|
3664
|
+
pendingSessionStarts: totalSessionAdmission.snapshotForWorkspace(
|
|
3665
|
+
runtimeToDrain.workspaceCwd
|
|
3666
|
+
).inFlight,
|
|
3667
|
+
channelWorkers: channelWorkerManager?.workspaceActivity(
|
|
3668
|
+
runtimeToDrain.workspaceCwd
|
|
3669
|
+
) ?? 0,
|
|
3670
|
+
voiceSessions: workspaceVoiceCoordinator.getWorkspaceActivity(runtimeToDrain)
|
|
3671
|
+
};
|
|
3672
|
+
},
|
|
3673
|
+
disposeRuntime(runtimeToDrain, reason = "workspace_removed") {
|
|
3674
|
+
const existing = runtimeCleanupPromises.get(runtimeToDrain);
|
|
3675
|
+
if (existing) return existing;
|
|
3676
|
+
const cleanup = (async () => {
|
|
3677
|
+
await workspaceVoiceCoordinator.disposeRuntime(
|
|
3678
|
+
runtimeToDrain,
|
|
3679
|
+
reason
|
|
3680
|
+
);
|
|
3681
|
+
const stopSubSessions = subSessionStoppersByWorkspace.get(
|
|
3682
|
+
runtimeToDrain.workspaceCwd
|
|
3683
|
+
);
|
|
3684
|
+
try {
|
|
3685
|
+
stopSubSessions?.();
|
|
3686
|
+
} catch {
|
|
3687
|
+
}
|
|
3688
|
+
if (reason === "workspace_removed" && channelWorkerManager) {
|
|
3689
|
+
await channelWorkerManager.removeWorkspace(runtimeToDrain.workspaceCwd).catch((err) => {
|
|
3690
|
+
daemonLog.error(
|
|
3691
|
+
"workspace channel worker cleanup error",
|
|
3692
|
+
err instanceof Error ? err : null
|
|
3693
|
+
);
|
|
3694
|
+
});
|
|
3695
|
+
try {
|
|
3696
|
+
await channelWorkerManager.refreshWorkspaces();
|
|
3697
|
+
} catch (err) {
|
|
3698
|
+
channelWorkspaceGroups = (channelWorkspaceGroups ?? []).filter(
|
|
3699
|
+
(group) => group.workspaceCwd !== runtimeToDrain.workspaceCwd
|
|
3700
|
+
);
|
|
3701
|
+
channelWebhookConfigVersion += 1;
|
|
3702
|
+
refreshChannelWebhookConfigs?.();
|
|
3703
|
+
daemonLog.error(
|
|
3704
|
+
"workspace channel worker topology refresh error",
|
|
3705
|
+
err instanceof Error ? err : null
|
|
3706
|
+
);
|
|
3707
|
+
}
|
|
3708
|
+
writeChannelWorkerPidfile();
|
|
3709
|
+
}
|
|
3710
|
+
if (reason === "workspace_removed") {
|
|
3711
|
+
const app3 = runtimeApp ?? runtimeAppForCleanup;
|
|
3712
|
+
const stopWorkspaceGitStateForWorkspace = app3?.locals?.["stopWorkspaceGitStateForWorkspace"];
|
|
3713
|
+
const stopScheduledTaskKeepaliveForWorkspace = app3?.locals?.["stopScheduledTaskKeepaliveForWorkspace"];
|
|
3714
|
+
stopWorkspaceGitStateForWorkspace?.(runtimeToDrain.workspaceCwd);
|
|
3715
|
+
stopScheduledTaskKeepaliveForWorkspace?.(
|
|
3716
|
+
runtimeToDrain.workspaceCwd
|
|
3717
|
+
);
|
|
3718
|
+
}
|
|
3719
|
+
let bridgeStopped = false;
|
|
3720
|
+
try {
|
|
3721
|
+
if (!shutdownBridges.has(runtimeToDrain.bridge)) {
|
|
3722
|
+
await runtimeToDrain.bridge.shutdown({ reason });
|
|
3723
|
+
}
|
|
3724
|
+
bridgeStopped = true;
|
|
3725
|
+
} finally {
|
|
3726
|
+
if (bridgeStopped || reason === "workspace_removed") {
|
|
3727
|
+
subSessionStoppersByWorkspace.delete(runtimeToDrain.workspaceCwd);
|
|
3728
|
+
if (stopSubSessions) {
|
|
3729
|
+
removeArrayValue(subSessionStoppers, stopSubSessions);
|
|
3730
|
+
}
|
|
3731
|
+
removeArrayValue(runtimeBridges, runtimeToDrain.bridge);
|
|
3732
|
+
removeArrayValue(
|
|
3733
|
+
internalRuntimeBridgesForCleanup,
|
|
3734
|
+
runtimeToDrain.bridge
|
|
3735
|
+
);
|
|
3736
|
+
shutdownBridges.add(runtimeToDrain.bridge);
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
})();
|
|
3740
|
+
runtimeCleanupPromises.set(runtimeToDrain, cleanup);
|
|
3741
|
+
void cleanup.catch(() => {
|
|
3742
|
+
if (reason === "daemon_shutdown" && runtimeCleanupPromises.get(runtimeToDrain) === cleanup) {
|
|
3743
|
+
runtimeCleanupPromises.delete(runtimeToDrain);
|
|
3744
|
+
}
|
|
3745
|
+
});
|
|
3746
|
+
return cleanup;
|
|
3747
|
+
}
|
|
3748
|
+
};
|
|
3164
3749
|
const app2 = runtime.createServeApp(opts, () => actualPort, {
|
|
3165
3750
|
workspaceRegistry,
|
|
3166
3751
|
createWorkspaceRuntime: createDynamicWorkspaceRuntime,
|
|
3752
|
+
workspaceRegistrationStore,
|
|
3753
|
+
workspaceRuntimeRemoval,
|
|
3754
|
+
voiceCoordinator: workspaceVoiceCoordinator,
|
|
3167
3755
|
bridge,
|
|
3168
3756
|
webShellDir,
|
|
3169
3757
|
boundWorkspace,
|
|
@@ -3178,11 +3766,27 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3178
3766
|
primaryRuntimeEnv,
|
|
3179
3767
|
daemonLog,
|
|
3180
3768
|
getChannelWorkerSnapshot,
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3769
|
+
getChannelWorkerSnapshots,
|
|
3770
|
+
getChannelWorkerControl,
|
|
3771
|
+
isChannelControlDraining: /* @__PURE__ */ __name(() => channelControlDraining, "isChannelControlDraining"),
|
|
3772
|
+
isChannelControlInitializing: /* @__PURE__ */ __name(() => channelWorkerManagerStarting !== void 0, "isChannelControlInitializing"),
|
|
3773
|
+
setChannelWorkerSelection,
|
|
3774
|
+
stopChannelWorker,
|
|
3775
|
+
getChannelWebhookConfigSources,
|
|
3776
|
+
getChannelWebhookConfigVersion: /* @__PURE__ */ __name(() => channelWebhookConfigVersion, "getChannelWebhookConfigVersion"),
|
|
3777
|
+
registerChannelWebhookConfigRefresh: /* @__PURE__ */ __name((refresh) => {
|
|
3778
|
+
refreshChannelWebhookConfigs = refresh;
|
|
3779
|
+
}, "registerChannelWebhookConfigRefresh"),
|
|
3780
|
+
enqueueChannelWebhookTask: /* @__PURE__ */ __name(async (task) => {
|
|
3781
|
+
if (!channelWorkerManager) {
|
|
3782
|
+
throw new ChannelWebhookEnqueueError(
|
|
3783
|
+
"channel_worker_unavailable",
|
|
3784
|
+
"Channel worker is not running."
|
|
3785
|
+
);
|
|
3786
|
+
}
|
|
3787
|
+
return channelWorkerManager.enqueueWebhookTask(task);
|
|
3788
|
+
}, "enqueueChannelWebhookTask"),
|
|
3789
|
+
reloadChannelWorker,
|
|
3186
3790
|
getPerfSnapshot: /* @__PURE__ */ __name(() => ({
|
|
3187
3791
|
eventLoop: currentDaemonEventLoopMonitor.snapshot(),
|
|
3188
3792
|
promptQueueWait: {
|
|
@@ -3204,6 +3808,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3204
3808
|
// so the WS provider and the child-answering bridge share one sender map.
|
|
3205
3809
|
clientMcpSenderRegistry,
|
|
3206
3810
|
persistDisabledTools: persistDisabledToolsFn,
|
|
3811
|
+
persistDisabledSkills: persistDisabledSkillsFn,
|
|
3207
3812
|
persistSetting: persistSettingFn,
|
|
3208
3813
|
persistSettings: persistSettingsFn,
|
|
3209
3814
|
sessionArtifactsPersistenceAvailable: sessionArtifactsPersistenceAvailableFromSettings(
|
|
@@ -3247,16 +3852,18 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3247
3852
|
}
|
|
3248
3853
|
), "installAuthProvider")
|
|
3249
3854
|
});
|
|
3855
|
+
invalidatePrimaryServeFeaturesCache = app2.locals.invalidateServeFeaturesCache ?? invalidatePrimaryServeFeaturesCache;
|
|
3250
3856
|
app2.locals.subSessionStoppers = subSessionStoppers;
|
|
3251
3857
|
subSessionStoppers.push(subSessionLauncher.stop);
|
|
3858
|
+
subSessionStoppersByWorkspace.set(boundWorkspace, subSessionLauncher.stop);
|
|
3252
3859
|
return { app: app2, bridge };
|
|
3253
3860
|
}, "buildRuntime");
|
|
3254
3861
|
if (deps.bridge) {
|
|
3255
3862
|
const runtime = await buildRuntime();
|
|
3256
3863
|
runtimeAppForCleanup = runtime.app;
|
|
3257
|
-
runtimeApp = runtime.app;
|
|
3258
3864
|
bridgeRef = runtime.bridge;
|
|
3259
3865
|
if (!opts.channelSelection) {
|
|
3866
|
+
runtimeApp = runtime.app;
|
|
3260
3867
|
runtimeStartupSettled = true;
|
|
3261
3868
|
markRuntimeReady();
|
|
3262
3869
|
}
|
|
@@ -3275,10 +3882,11 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3275
3882
|
multiWorkspaceCapabilitiesRequireRuntime: workspaceInputs.length > 1,
|
|
3276
3883
|
getRuntimeError: /* @__PURE__ */ __name(() => runtimeStartupError, "getRuntimeError"),
|
|
3277
3884
|
getChannelWorkerSnapshot,
|
|
3885
|
+
getChannelWorkerSnapshots,
|
|
3278
3886
|
onHealthServed: deferRuntimeUntilFirstHealth ? () => startRuntimeAfterHealth?.() : void 0
|
|
3279
3887
|
});
|
|
3280
3888
|
const deferredChannelWebhookAuth = deferRuntimeUntilFirstHealth ? createDeferredChannelWebhookAuth(
|
|
3281
|
-
|
|
3889
|
+
resolveChannelWebhookConfigSource,
|
|
3282
3890
|
await loadChannelWebhookConfigRuntime(),
|
|
3283
3891
|
daemonLog
|
|
3284
3892
|
) : void 0;
|
|
@@ -3304,7 +3912,70 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3304
3912
|
`Invalid maxConnections: ${opts.maxConnections}. Must be >= 0 (0 / Infinity = unlimited).`
|
|
3305
3913
|
);
|
|
3306
3914
|
}
|
|
3307
|
-
|
|
3915
|
+
const channelValidationSettingsRuntime = opts.channelSelection ? await loadSettingsRuntimeModules() : void 0;
|
|
3916
|
+
const resolveChannelWorkspaceGroupsAtListen = /* @__PURE__ */ __name(() => {
|
|
3917
|
+
if (!opts.channelSelection || !channelValidationSettingsRuntime || !channelRuntime) {
|
|
3918
|
+
return void 0;
|
|
3919
|
+
}
|
|
3920
|
+
const settingsByWorkspace = /* @__PURE__ */ new Map();
|
|
3921
|
+
if (workspaceInputs.length === 1) {
|
|
3922
|
+
const workspace = workspaceInputs[0];
|
|
3923
|
+
const settings = channelValidationSettingsRuntime.settings.loadSettings(
|
|
3924
|
+
workspace.cwd
|
|
3925
|
+
);
|
|
3926
|
+
channelWebhookEnvByWorkspace.set(
|
|
3927
|
+
workspace.cwd,
|
|
3928
|
+
channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
|
|
3929
|
+
settings.merged,
|
|
3930
|
+
workspace.cwd,
|
|
3931
|
+
daemonRuntimeBaseEnv
|
|
3932
|
+
).effectiveEnv
|
|
3933
|
+
);
|
|
3934
|
+
return void 0;
|
|
3935
|
+
}
|
|
3936
|
+
const workspaces = workspaceInputs.map((workspace, index) => {
|
|
3937
|
+
const settings = channelValidationSettingsRuntime.settings.loadSettings(
|
|
3938
|
+
workspace.cwd
|
|
3939
|
+
);
|
|
3940
|
+
settingsByWorkspace.set(workspace.cwd, settings);
|
|
3941
|
+
channelWebhookEnvByWorkspace.set(
|
|
3942
|
+
workspace.cwd,
|
|
3943
|
+
channelValidationSettingsRuntime.environment.buildRuntimeEnvironment(
|
|
3944
|
+
settings.merged,
|
|
3945
|
+
workspace.cwd,
|
|
3946
|
+
daemonRuntimeBaseEnv
|
|
3947
|
+
).effectiveEnv
|
|
3948
|
+
);
|
|
3949
|
+
const trusted = index === 0 && deps.trustedWorkspace !== void 0 ? deps.trustedWorkspace : channelValidationSettingsRuntime.trustedFolders.getWorkspaceTrustStatus(
|
|
3950
|
+
settings.merged,
|
|
3951
|
+
workspace.cwd
|
|
3952
|
+
).effective.state === "trusted";
|
|
3953
|
+
return {
|
|
3954
|
+
workspaceCwd: workspace.cwd,
|
|
3955
|
+
primary: index === 0,
|
|
3956
|
+
trusted
|
|
3957
|
+
};
|
|
3958
|
+
});
|
|
3959
|
+
const grouping = resolveChannelWorkspaceGroups({
|
|
3960
|
+
workspaces,
|
|
3961
|
+
selection: opts.channelSelection,
|
|
3962
|
+
loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
|
|
3963
|
+
const settings = settingsByWorkspace.get(cwd);
|
|
3964
|
+
if (!settings) return {};
|
|
3965
|
+
return channelRuntime.loadChannelsConfig(cwd, settings);
|
|
3966
|
+
}, "loadChannelsConfig")
|
|
3967
|
+
});
|
|
3968
|
+
if (!grouping.ok) {
|
|
3969
|
+
throw Object.assign(new Error(grouping.error.message), {
|
|
3970
|
+
code: grouping.error.code,
|
|
3971
|
+
...grouping.error.channel ? { channel: grouping.error.channel } : {}
|
|
3972
|
+
});
|
|
3973
|
+
}
|
|
3974
|
+
return grouping.groups;
|
|
3975
|
+
}, "resolveChannelWorkspaceGroupsAtListen");
|
|
3976
|
+
if (opts.channelSelection) {
|
|
3977
|
+
reserveChannelServicePidfile(opts.channelSelection);
|
|
3978
|
+
}
|
|
3308
3979
|
return await new Promise((resolve, reject) => {
|
|
3309
3980
|
const onListening = /* @__PURE__ */ __name(() => {
|
|
3310
3981
|
startup.listenerReadyAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3323,46 +3994,14 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3323
3994
|
const scheme = tlsOptions ? "https" : "http";
|
|
3324
3995
|
const url = `${scheme}://${formatHostForUrl(opts.hostname)}:${actualPort}`;
|
|
3325
3996
|
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
|
-
}
|
|
3997
|
+
channelWorkspaceGroups = resolveChannelWorkspaceGroupsAtListen();
|
|
3359
3998
|
} catch (err) {
|
|
3360
3999
|
removeCurrentServePidfile();
|
|
3361
4000
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
3362
4001
|
server.close((closeErr) => {
|
|
3363
4002
|
if (closeErr) {
|
|
3364
4003
|
daemonLog.error(
|
|
3365
|
-
"server close after channel worker
|
|
4004
|
+
"server close after channel worker validation error failed",
|
|
3366
4005
|
closeErr
|
|
3367
4006
|
);
|
|
3368
4007
|
}
|
|
@@ -3370,6 +4009,19 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3370
4009
|
});
|
|
3371
4010
|
return;
|
|
3372
4011
|
}
|
|
4012
|
+
if (channelWorkspaceGroups) {
|
|
4013
|
+
for (const group of channelWorkspaceGroups) {
|
|
4014
|
+
daemonLog.info("channel worker group assigned", {
|
|
4015
|
+
workspace: group.workspaceCwd,
|
|
4016
|
+
channels: group.selection.mode === "all" ? ["all"] : group.selection.names
|
|
4017
|
+
});
|
|
4018
|
+
}
|
|
4019
|
+
if (opts.channelSelection?.mode === "all") {
|
|
4020
|
+
writeStderrLine(
|
|
4021
|
+
"qwen serve: --channel all is primary-workspace only; non-primary workspace channels are not hosted."
|
|
4022
|
+
);
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
3373
4025
|
writeStdoutLine(
|
|
3374
4026
|
`qwen serve listening on ${url} (mode=${opts.mode}, workspace=${boundWorkspace})`
|
|
3375
4027
|
);
|
|
@@ -3445,20 +4097,28 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3445
4097
|
}
|
|
3446
4098
|
}, "shutdownBridgeAfterFailedStartup");
|
|
3447
4099
|
const stopChannelWorkerAfterFailedStartup = /* @__PURE__ */ __name(async () => {
|
|
3448
|
-
|
|
4100
|
+
if (!channelWorkerManager) return true;
|
|
4101
|
+
try {
|
|
4102
|
+
await channelWorkerManager.shutdown();
|
|
4103
|
+
return true;
|
|
4104
|
+
} catch (stopErr) {
|
|
3449
4105
|
daemonLog.error(
|
|
3450
4106
|
"channel worker stop after runtime startup error failed",
|
|
3451
4107
|
stopErr instanceof Error ? stopErr : null
|
|
3452
4108
|
);
|
|
3453
|
-
|
|
4109
|
+
return false;
|
|
4110
|
+
}
|
|
3454
4111
|
}, "stopChannelWorkerAfterFailedStartup");
|
|
3455
4112
|
const failRuntimeStartup = /* @__PURE__ */ __name(async (err, bridgeForCleanup) => {
|
|
3456
4113
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
3457
4114
|
if (runtimeStartupSettled) {
|
|
4115
|
+
disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
|
|
3458
4116
|
await shutdownBridgeAfterFailedStartup(bridgeForCleanup);
|
|
3459
4117
|
return;
|
|
3460
4118
|
}
|
|
3461
4119
|
runtimeStartupSettled = true;
|
|
4120
|
+
disposeRuntimeAppResources(runtimeApp ?? runtimeAppForCleanup);
|
|
4121
|
+
runtimeApp = void 0;
|
|
3462
4122
|
clearRuntimeStartupTimer();
|
|
3463
4123
|
const message = error.message;
|
|
3464
4124
|
runtimeStartupError = message;
|
|
@@ -3468,14 +4128,28 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3468
4128
|
}
|
|
3469
4129
|
writeStderrLine(`qwen serve: runtime startup failed: ${message}`);
|
|
3470
4130
|
daemonLog.error("runtime startup failed", error);
|
|
3471
|
-
|
|
4131
|
+
markRuntimeFailed(error);
|
|
4132
|
+
if (closeServerAfterChannelWorkerStartupFailure && server.listening) {
|
|
4133
|
+
runtimeFailureListenerClose = new Promise((resolve2) => {
|
|
4134
|
+
server.close((closeErr) => {
|
|
4135
|
+
if (closeErr) {
|
|
4136
|
+
daemonLog.error(
|
|
4137
|
+
"server close after runtime startup error failed",
|
|
4138
|
+
closeErr
|
|
4139
|
+
);
|
|
4140
|
+
}
|
|
4141
|
+
resolve2();
|
|
4142
|
+
});
|
|
4143
|
+
});
|
|
4144
|
+
server.closeAllConnections();
|
|
4145
|
+
}
|
|
4146
|
+
const channelWorkerStopped = await stopChannelWorkerAfterFailedStartup();
|
|
3472
4147
|
disposeDaemonEventLoopMonitor();
|
|
3473
|
-
removeCurrentServePidfile();
|
|
4148
|
+
if (channelWorkerStopped) removeCurrentServePidfile();
|
|
3474
4149
|
const bridgesForCleanup = bridgeForCleanup ? [bridgeForCleanup, ...getRuntimeBridgesForCleanup()] : getRuntimeBridgesForCleanup();
|
|
3475
4150
|
for (const bridge of [...new Set(bridgesForCleanup)]) {
|
|
3476
4151
|
await shutdownBridgeAfterFailedStartup(bridge);
|
|
3477
4152
|
}
|
|
3478
|
-
markRuntimeFailed(error);
|
|
3479
4153
|
}, "failRuntimeStartup");
|
|
3480
4154
|
const armRuntimeStartupTimer = /* @__PURE__ */ __name(() => {
|
|
3481
4155
|
if (runtimeStartupTimeoutMs <= 0 || runtimeStartupTimer) return;
|
|
@@ -3488,10 +4162,152 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3488
4162
|
}, runtimeStartupTimeoutMs);
|
|
3489
4163
|
runtimeStartupTimer.unref();
|
|
3490
4164
|
}, "armRuntimeStartupTimer");
|
|
3491
|
-
const
|
|
4165
|
+
const resolveRuntimeChannelGroups = /* @__PURE__ */ __name(async (channelSelection, candidateApp, operation) => {
|
|
4166
|
+
const registry = candidateApp.locals?.["workspaceRegistry"];
|
|
4167
|
+
if (!registry) {
|
|
4168
|
+
throw new Error(
|
|
4169
|
+
"Workspace registry is not available for channel workers."
|
|
4170
|
+
);
|
|
4171
|
+
}
|
|
4172
|
+
const runtimes = registry.list();
|
|
4173
|
+
if (runtimes.length <= 1 && operation === "initial") {
|
|
4174
|
+
return [
|
|
4175
|
+
{
|
|
4176
|
+
workspaceCwd: registry.primary.workspaceCwd,
|
|
4177
|
+
selection: channelSelection
|
|
4178
|
+
}
|
|
4179
|
+
];
|
|
4180
|
+
}
|
|
4181
|
+
const workerRuntime = await ensureChannelRuntime();
|
|
4182
|
+
const settingsRuntime = await loadSettingsRuntimeModules();
|
|
4183
|
+
const settingsByWorkspace = /* @__PURE__ */ new Map();
|
|
4184
|
+
const grouping = resolveChannelWorkspaceGroups({
|
|
4185
|
+
workspaces: runtimes.map((runtime) => {
|
|
4186
|
+
const settings = settingsRuntime.settings.loadSettings(
|
|
4187
|
+
runtime.workspaceCwd
|
|
4188
|
+
);
|
|
4189
|
+
settingsByWorkspace.set(runtime.workspaceCwd, settings);
|
|
4190
|
+
return {
|
|
4191
|
+
workspaceCwd: runtime.workspaceCwd,
|
|
4192
|
+
primary: runtime.primary,
|
|
4193
|
+
trusted: runtime.trusted
|
|
4194
|
+
};
|
|
4195
|
+
}),
|
|
4196
|
+
selection: channelSelection,
|
|
4197
|
+
loadChannelsConfig: /* @__PURE__ */ __name((cwd) => {
|
|
4198
|
+
const settings = settingsByWorkspace.get(cwd);
|
|
4199
|
+
return settings ? workerRuntime.loadChannelsConfig(cwd, settings) : {};
|
|
4200
|
+
}, "loadChannelsConfig")
|
|
4201
|
+
});
|
|
4202
|
+
if (!grouping.ok) {
|
|
4203
|
+
throw Object.assign(new Error(grouping.error.message), {
|
|
4204
|
+
code: grouping.error.code,
|
|
4205
|
+
...grouping.error.channel ? { channel: grouping.error.channel } : {}
|
|
4206
|
+
});
|
|
4207
|
+
}
|
|
4208
|
+
return grouping.groups;
|
|
4209
|
+
}, "resolveRuntimeChannelGroups");
|
|
4210
|
+
ensureChannelWorkerManager = /* @__PURE__ */ __name(() => {
|
|
4211
|
+
if (channelWorkerManager) return Promise.resolve(channelWorkerManager);
|
|
4212
|
+
if (channelWorkerManagerStarting) return channelWorkerManagerStarting;
|
|
4213
|
+
const starting = (async () => {
|
|
4214
|
+
const candidateApp = runtimeApp ?? runtimeAppForCleanup;
|
|
4215
|
+
const registry = candidateApp?.locals?.["workspaceRegistry"];
|
|
4216
|
+
if (!candidateApp || !registry) {
|
|
4217
|
+
throw new Error(
|
|
4218
|
+
"Workspace registry is not available for channels."
|
|
4219
|
+
);
|
|
4220
|
+
}
|
|
4221
|
+
const workerRuntime = await ensureChannelRuntime();
|
|
4222
|
+
const createSupervisor = deps.channelWorkerSupervisorFactory ?? workerRuntime.createChannelWorkerSupervisor;
|
|
4223
|
+
const createGroup = /* @__PURE__ */ __name((groups) => workerRuntime.createChannelWorkerGroup({
|
|
4224
|
+
groups,
|
|
4225
|
+
registry,
|
|
4226
|
+
createSupervisor,
|
|
4227
|
+
shared: {
|
|
4228
|
+
cliEntryPath: workerRuntime.findCliEntryPath(),
|
|
4229
|
+
daemonUrl: formatChannelWorkerDaemonUrl(
|
|
4230
|
+
opts.hostname,
|
|
4231
|
+
actualPort
|
|
4232
|
+
),
|
|
4233
|
+
...token ? { daemonToken: token } : {}
|
|
4234
|
+
},
|
|
4235
|
+
onReady: /* @__PURE__ */ __name((snapshot) => {
|
|
4236
|
+
if (runtimeStartupError !== void 0) return;
|
|
4237
|
+
if (workspaceInputs.length > 1) {
|
|
4238
|
+
daemonLog.info("channel worker ready", {
|
|
4239
|
+
workspace: snapshot.workspaceCwd,
|
|
4240
|
+
pid: snapshot.pid,
|
|
4241
|
+
channels: snapshot.channels
|
|
4242
|
+
});
|
|
4243
|
+
}
|
|
4244
|
+
channelWorkerManager?.workerChanged();
|
|
4245
|
+
if (!runtimeStartupSettled) writeChannelWorkerPidfile();
|
|
4246
|
+
}, "onReady"),
|
|
4247
|
+
onExit: /* @__PURE__ */ __name((snapshot) => {
|
|
4248
|
+
const workspacePrefix = workspaceInputs.length > 1 ? `workspace=${snapshot.workspaceCwd}, ` : "";
|
|
4249
|
+
daemonLog.warn(
|
|
4250
|
+
`channel worker exited (${workspacePrefix}state=${snapshot.state}, pid=${snapshot.pid ?? "unknown"}, code=${snapshot.exitCode ?? "null"}, signal=${snapshot.signal ?? "null"}, error=${snapshot.error ?? "none"}, restartCount=${snapshot.restartCount ?? 0}, nextRestartAt=${snapshot.nextRestartAt ?? "none"}, staleHeartbeatAt=${snapshot.staleHeartbeatAt ?? "none"})`
|
|
4251
|
+
);
|
|
4252
|
+
channelWorkerManager?.workerChanged();
|
|
4253
|
+
if (!runtimeStartupSettled) writeChannelWorkerPidfile();
|
|
4254
|
+
}, "onExit"),
|
|
4255
|
+
onStateChange: /* @__PURE__ */ __name(() => {
|
|
4256
|
+
channelWorkerManager?.workerChanged();
|
|
4257
|
+
if (!runtimeStartupSettled) writeChannelWorkerPidfile();
|
|
4258
|
+
}, "onStateChange"),
|
|
4259
|
+
onLog: /* @__PURE__ */ __name(({ stream, line, workspaceCwd }) => {
|
|
4260
|
+
const message = workspaceInputs.length > 1 ? `channel worker [${workspaceCwd}] ${stream}: ${line}` : `channel worker ${stream}: ${line}`;
|
|
4261
|
+
if (stream === "stderr") daemonLog.warn(message);
|
|
4262
|
+
else daemonLog.info(message);
|
|
4263
|
+
}, "onLog")
|
|
4264
|
+
}), "createGroup");
|
|
4265
|
+
channelWorkerManager = workerRuntime.createChannelWorkerManager({
|
|
4266
|
+
resolveGroups: /* @__PURE__ */ __name((selection, operation) => resolveRuntimeChannelGroups(selection, candidateApp, operation), "resolveGroups"),
|
|
4267
|
+
createGroup,
|
|
4268
|
+
reserveLease: reserveChannelServicePidfile,
|
|
4269
|
+
releaseLease: /* @__PURE__ */ __name(() => {
|
|
4270
|
+
removeCurrentServePidfile();
|
|
4271
|
+
if (channelPidfileReserved) {
|
|
4272
|
+
throw new Error("Failed to release the channel service lease.");
|
|
4273
|
+
}
|
|
4274
|
+
}, "releaseLease"),
|
|
4275
|
+
initialLeaseReserved: channelPidfileReserved,
|
|
4276
|
+
onCommittedSelection: /* @__PURE__ */ __name((_selection, groups) => {
|
|
4277
|
+
channelWorkspaceGroups = groups;
|
|
4278
|
+
channelWebhookConfigVersion += 1;
|
|
4279
|
+
refreshChannelWebhookConfigs?.();
|
|
4280
|
+
}, "onCommittedSelection"),
|
|
4281
|
+
onStateChange: /* @__PURE__ */ __name(() => {
|
|
4282
|
+
if (runtimeStartupSettled) writeChannelWorkerPidfile();
|
|
4283
|
+
}, "onStateChange")
|
|
4284
|
+
});
|
|
4285
|
+
return channelWorkerManager;
|
|
4286
|
+
})();
|
|
4287
|
+
channelWorkerManagerStarting = starting;
|
|
4288
|
+
void starting.then(
|
|
4289
|
+
() => {
|
|
4290
|
+
if (channelWorkerManagerStarting === starting) {
|
|
4291
|
+
channelWorkerManagerStarting = void 0;
|
|
4292
|
+
}
|
|
4293
|
+
},
|
|
4294
|
+
() => {
|
|
4295
|
+
if (channelWorkerManagerStarting === starting) {
|
|
4296
|
+
channelWorkerManagerStarting = void 0;
|
|
4297
|
+
}
|
|
4298
|
+
}
|
|
4299
|
+
);
|
|
4300
|
+
return starting;
|
|
4301
|
+
}, "ensureChannelWorkerManager");
|
|
4302
|
+
const completeRuntimeStartup = /* @__PURE__ */ __name(async (candidateApp) => {
|
|
3492
4303
|
if (runtimeStartupSettled) return;
|
|
4304
|
+
runtimeApp = candidateApp;
|
|
4305
|
+
const acpHandle = candidateApp.locals?.["acpHandle"];
|
|
4306
|
+
acpHandle?.attachServer?.(server);
|
|
3493
4307
|
if (opts.channelSelection) {
|
|
3494
|
-
|
|
4308
|
+
closeServerAfterChannelWorkerStartupFailure = true;
|
|
4309
|
+
const manager = await ensureChannelWorkerManager();
|
|
4310
|
+
await manager.startInitial(opts.channelSelection);
|
|
3495
4311
|
if (runtimeStartupSettled) return;
|
|
3496
4312
|
}
|
|
3497
4313
|
if (runtimeStartupSettled) return;
|
|
@@ -3526,6 +4342,7 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3526
4342
|
clearRuntimeStartFallbackTimer();
|
|
3527
4343
|
runtimeStarting = buildRuntime().then(async (runtime) => {
|
|
3528
4344
|
if (runtimeStartupSettled) {
|
|
4345
|
+
disposeRuntimeAppResources(runtime.app);
|
|
3529
4346
|
await shutdownBridgeAfterFailedStartup(runtime.bridge);
|
|
3530
4347
|
return;
|
|
3531
4348
|
}
|
|
@@ -3538,13 +4355,10 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3538
4355
|
);
|
|
3539
4356
|
return;
|
|
3540
4357
|
}
|
|
3541
|
-
runtimeApp = runtime.app;
|
|
3542
|
-
const acpHandle = runtime.app.locals?.["acpHandle"];
|
|
3543
|
-
acpHandle?.attachServer?.(server);
|
|
3544
4358
|
if (shouldPreheat) {
|
|
3545
4359
|
startBridgePreheat(runtime.bridge);
|
|
3546
4360
|
}
|
|
3547
|
-
await completeRuntimeStartup();
|
|
4361
|
+
await completeRuntimeStartup(runtime.app);
|
|
3548
4362
|
}).catch((err) => failRuntimeStartup(err));
|
|
3549
4363
|
}, "startRuntime");
|
|
3550
4364
|
startRuntimeForRequest = startRuntime;
|
|
@@ -3582,11 +4396,10 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3582
4396
|
if (shuttingDown) {
|
|
3583
4397
|
daemonLog.warn(`received ${signal} during drain \u2014 forcing exit`);
|
|
3584
4398
|
try {
|
|
3585
|
-
|
|
4399
|
+
channelWorkerManager?.killAllSync();
|
|
3586
4400
|
for (const runtimeBridge of getRuntimeBridgesForCleanup()) {
|
|
3587
4401
|
runtimeBridge.killAllSync();
|
|
3588
4402
|
}
|
|
3589
|
-
removeCurrentServePidfile();
|
|
3590
4403
|
} catch (err) {
|
|
3591
4404
|
daemonLog.error(
|
|
3592
4405
|
"force-kill error",
|
|
@@ -3602,16 +4415,24 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3602
4415
|
try {
|
|
3603
4416
|
await handle.close();
|
|
3604
4417
|
await daemonLog.flush();
|
|
3605
|
-
process.exit(0);
|
|
4418
|
+
process.exit(runtimeStartupError === void 0 ? 0 : 1);
|
|
3606
4419
|
} catch (err) {
|
|
3607
4420
|
daemonLog.error("shutdown error", err instanceof Error ? err : null);
|
|
3608
4421
|
await daemonLog.flush().catch(() => {
|
|
3609
4422
|
});
|
|
4423
|
+
if (channelWorkerManager?.state().enabled) {
|
|
4424
|
+
daemonLog.error(
|
|
4425
|
+
"refusing to exit while a channel worker or service lease remains; signal again to retry after the child exits (another signal during that retry forces exit)"
|
|
4426
|
+
);
|
|
4427
|
+
await daemonLog.flush().catch(() => {
|
|
4428
|
+
});
|
|
4429
|
+
return;
|
|
4430
|
+
}
|
|
3610
4431
|
process.exit(1);
|
|
3611
4432
|
}
|
|
3612
4433
|
}, "onSignal");
|
|
3613
4434
|
const onUncaughtExceptionMonitor = /* @__PURE__ */ __name(() => {
|
|
3614
|
-
if (process.listenerCount("uncaughtException") === 0) {
|
|
4435
|
+
if (process.listenerCount("uncaughtException") === 0 && !channelWorkerManager?.state().enabled) {
|
|
3615
4436
|
removeCurrentServePidfile();
|
|
3616
4437
|
}
|
|
3617
4438
|
}, "onUncaughtExceptionMonitor");
|
|
@@ -3626,21 +4447,24 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3626
4447
|
if (closePromise) return closePromise;
|
|
3627
4448
|
closePromise = new Promise((res, rej) => {
|
|
3628
4449
|
shuttingDown = true;
|
|
3629
|
-
|
|
3630
|
-
const
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
}
|
|
4450
|
+
channelControlDraining = true;
|
|
4451
|
+
const initiallyMountedApp = runtimeApp ?? runtimeAppForCleanup;
|
|
4452
|
+
const initiallyMountedManagement = initiallyMountedApp?.locals?.["workspaceManagementHandle"];
|
|
4453
|
+
const initialManagementWait = initiallyMountedManagement?.sealAndWait?.();
|
|
3634
4454
|
clearRuntimeStartAfterHealthTimer();
|
|
3635
4455
|
clearRuntimeStartFallbackTimer();
|
|
3636
4456
|
cancelDeferredRuntimeStartup();
|
|
3637
4457
|
let settled = false;
|
|
3638
4458
|
let bridgeShutdownError;
|
|
4459
|
+
let channelWorkerShutdownError;
|
|
3639
4460
|
const finish = /* @__PURE__ */ __name((err) => {
|
|
3640
4461
|
if (settled) return;
|
|
3641
4462
|
settled = true;
|
|
3642
|
-
|
|
3643
|
-
|
|
4463
|
+
const preserveSignalHandlers = channelWorkerShutdownError !== void 0 && channelWorkerManager?.state().enabled === true;
|
|
4464
|
+
if (!preserveSignalHandlers) {
|
|
4465
|
+
process.removeListener("SIGINT", onSignal);
|
|
4466
|
+
process.removeListener("SIGTERM", onSignal);
|
|
4467
|
+
}
|
|
3644
4468
|
process.removeListener(
|
|
3645
4469
|
"uncaughtExceptionMonitor",
|
|
3646
4470
|
onUncaughtExceptionMonitor
|
|
@@ -3651,9 +4475,17 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3651
4475
|
);
|
|
3652
4476
|
}).finally(() => daemonLog.flush().catch(() => {
|
|
3653
4477
|
})).finally(() => {
|
|
3654
|
-
const finalErr = err ?? bridgeShutdownError;
|
|
3655
|
-
if (finalErr)
|
|
3656
|
-
|
|
4478
|
+
const finalErr = err ?? bridgeShutdownError ?? channelWorkerShutdownError;
|
|
4479
|
+
if (finalErr) {
|
|
4480
|
+
if (channelWorkerShutdownError && channelWorkerManager?.state().enabled) {
|
|
4481
|
+
closePromise = void 0;
|
|
4482
|
+
shuttingDown = false;
|
|
4483
|
+
channelControlDraining = false;
|
|
4484
|
+
}
|
|
4485
|
+
rej(finalErr);
|
|
4486
|
+
} else {
|
|
4487
|
+
res();
|
|
4488
|
+
}
|
|
3657
4489
|
});
|
|
3658
4490
|
}, "finish");
|
|
3659
4491
|
void (coreRuntimePromise ? coreRuntimePromise.then((core) => core.forceFlushMetrics()) : Promise.resolve()).catch((flushErr) => {
|
|
@@ -3667,43 +4499,54 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3667
4499
|
daemonLog
|
|
3668
4500
|
);
|
|
3669
4501
|
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
|
-
}
|
|
4502
|
+
const workspaceManagementHandle = appForCleanup?.locals?.["workspaceManagementHandle"];
|
|
4503
|
+
await initialManagementWait;
|
|
4504
|
+
if (workspaceManagementHandle !== initiallyMountedManagement) {
|
|
4505
|
+
await workspaceManagementHandle?.sealAndWait?.();
|
|
3679
4506
|
}
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
4507
|
+
disposeRuntimeAppResources(appForCleanup);
|
|
4508
|
+
disposeDaemonEventLoopMonitor();
|
|
4509
|
+
if (channelWorkerManager) {
|
|
4510
|
+
await channelWorkerManager.shutdown().catch((err) => {
|
|
4511
|
+
daemonLog.error(
|
|
4512
|
+
"channel worker stop error",
|
|
4513
|
+
err instanceof Error ? err : null
|
|
3687
4514
|
);
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
rl.setDraining(true);
|
|
3693
|
-
rl.dispose();
|
|
4515
|
+
channelWorkerShutdownError = err instanceof Error ? err : new Error(String(err));
|
|
4516
|
+
});
|
|
4517
|
+
} else {
|
|
4518
|
+
removeCurrentServePidfile();
|
|
3694
4519
|
}
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
4520
|
+
const runtimeRemoval = appForCleanup?.locals?.["workspaceRuntimeRemoval"];
|
|
4521
|
+
const workspaceRegistry = appForCleanup?.locals?.["workspaceRegistry"];
|
|
4522
|
+
const managedRuntimeBridges = /* @__PURE__ */ new Set();
|
|
4523
|
+
if (runtimeRemoval && workspaceRegistry) {
|
|
4524
|
+
const managedRuntimes = workspaceRegistry.listManaged();
|
|
4525
|
+
for (const workspaceRuntime of managedRuntimes) {
|
|
4526
|
+
managedRuntimeBridges.add(workspaceRuntime.bridge);
|
|
4527
|
+
}
|
|
4528
|
+
await Promise.all(
|
|
4529
|
+
managedRuntimes.map(
|
|
4530
|
+
(workspaceRuntime) => runtimeRemoval.disposeRuntime(workspaceRuntime, "daemon_shutdown").catch((err) => {
|
|
4531
|
+
daemonLog.error(
|
|
4532
|
+
"workspace runtime shutdown error",
|
|
4533
|
+
err instanceof Error ? err : null
|
|
4534
|
+
);
|
|
4535
|
+
bridgeShutdownError = err instanceof Error ? err : new Error(String(err));
|
|
4536
|
+
try {
|
|
4537
|
+
workspaceRuntime.bridge.killAllSync();
|
|
4538
|
+
} catch {
|
|
4539
|
+
}
|
|
4540
|
+
})
|
|
4541
|
+
)
|
|
3700
4542
|
);
|
|
3701
|
-
}
|
|
3702
|
-
removeCurrentServePidfile();
|
|
4543
|
+
}
|
|
3703
4544
|
for (const bridgeForShutdown of getRuntimeBridgesForCleanup()) {
|
|
4545
|
+
if (managedRuntimeBridges.has(bridgeForShutdown)) continue;
|
|
3704
4546
|
if (shutdownBridges.has(bridgeForShutdown)) continue;
|
|
3705
4547
|
shutdownBridges.add(bridgeForShutdown);
|
|
3706
4548
|
await bridgeForShutdown.shutdown().catch((err) => {
|
|
4549
|
+
shutdownBridges.delete(bridgeForShutdown);
|
|
3707
4550
|
daemonLog.error(
|
|
3708
4551
|
"bridge shutdown error",
|
|
3709
4552
|
err instanceof Error ? err : null
|
|
@@ -3712,6 +4555,12 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3712
4555
|
});
|
|
3713
4556
|
}
|
|
3714
4557
|
}).finally(() => {
|
|
4558
|
+
if (!server.listening) {
|
|
4559
|
+
void (runtimeFailureListenerClose ?? Promise.resolve()).then(
|
|
4560
|
+
() => finish()
|
|
4561
|
+
);
|
|
4562
|
+
return;
|
|
4563
|
+
}
|
|
3715
4564
|
const SECONDARY_DEADLINE_MS = 2e3;
|
|
3716
4565
|
let secondaryTimer;
|
|
3717
4566
|
const forceTimer = setTimeout(() => {
|
|
@@ -3745,17 +4594,19 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3745
4594
|
server.on("error", (err) => {
|
|
3746
4595
|
daemonLog.error("server error", err instanceof Error ? err : null);
|
|
3747
4596
|
});
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
acpHandle?.attachServer?.(server);
|
|
4597
|
+
const preparedRuntimeApp = runtimeApp ?? runtimeAppForCleanup;
|
|
4598
|
+
if (preparedRuntimeApp && bridgeRef && deps.bridge) {
|
|
3751
4599
|
if (shouldPreheat) {
|
|
3752
4600
|
startBridgePreheat(bridgeRef);
|
|
3753
4601
|
}
|
|
3754
4602
|
if (opts.channelSelection && !runtimeStartupSettled) {
|
|
3755
4603
|
armRuntimeStartupTimer();
|
|
3756
|
-
runtimeStarting = completeRuntimeStartup().catch(
|
|
4604
|
+
runtimeStarting = completeRuntimeStartup(preparedRuntimeApp).catch(
|
|
3757
4605
|
(err) => failRuntimeStartup(err, bridgeRef)
|
|
3758
4606
|
);
|
|
4607
|
+
} else {
|
|
4608
|
+
const acpHandle = preparedRuntimeApp.locals?.["acpHandle"];
|
|
4609
|
+
acpHandle?.attachServer?.(server);
|
|
3759
4610
|
}
|
|
3760
4611
|
} else if (deferRuntimeUntilFirstHealth) {
|
|
3761
4612
|
scheduleRuntimeStartFallback();
|
|
@@ -3768,14 +4619,24 @@ async function runQwenServe(optsIn, deps = {}) {
|
|
|
3768
4619
|
void runtimeReady.then(
|
|
3769
4620
|
() => resolve(handle),
|
|
3770
4621
|
(err) => {
|
|
3771
|
-
void handle.close().
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
)
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
4622
|
+
void handle.close().then(
|
|
4623
|
+
() => {
|
|
4624
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4625
|
+
},
|
|
4626
|
+
(closeErr) => {
|
|
4627
|
+
daemonLog.error(
|
|
4628
|
+
"shutdown after runtime startup error failed",
|
|
4629
|
+
closeErr instanceof Error ? closeErr : null
|
|
4630
|
+
);
|
|
4631
|
+
if (channelWorkerManager?.state().enabled) {
|
|
4632
|
+
daemonLog.error(
|
|
4633
|
+
"runtime startup failed, but qwen serve remains alive to retain the channel service lease until worker exit is confirmed"
|
|
4634
|
+
);
|
|
4635
|
+
return;
|
|
4636
|
+
}
|
|
4637
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4638
|
+
}
|
|
4639
|
+
);
|
|
3779
4640
|
}
|
|
3780
4641
|
);
|
|
3781
4642
|
}
|
|
@@ -3843,11 +4704,11 @@ export {
|
|
|
3843
4704
|
};
|
|
3844
4705
|
/**
|
|
3845
4706
|
* @license
|
|
3846
|
-
* Copyright
|
|
4707
|
+
* Copyright 2025 Qwen Team
|
|
3847
4708
|
* SPDX-License-Identifier: Apache-2.0
|
|
3848
4709
|
*/
|
|
3849
4710
|
/**
|
|
3850
4711
|
* @license
|
|
3851
|
-
* Copyright
|
|
4712
|
+
* Copyright 2026 Qwen Team
|
|
3852
4713
|
* SPDX-License-Identifier: Apache-2.0
|
|
3853
4714
|
*/
|