@qwen-code/qwen-code 0.19.6-nightly.20260707.bcdb44c5d → 0.19.6-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +17 -9
- package/bundled/qc-helper/docs/features/channels/wecom.md +111 -0
- package/bundled/qc-helper/docs/features/code-review.md +0 -4
- package/bundled/review/DESIGN.md +0 -4
- package/bundled/review/SKILL.md +2 -29
- package/chunks/{MaxSizedBox-EFDCCPYQ.js → MaxSizedBox-2JOX4MMR.js} +11 -9
- package/chunks/{StandaloneSessionPicker-5TQG34MY.js → StandaloneSessionPicker-Z2G37ETA.js} +24 -21
- package/chunks/{acpAgent-KQT52XWB.js → acpAgent-MQJT2H4Y.js} +74 -49
- package/chunks/{agent-RL2YOM2V.js → agent-HEVJ76EO.js} +6 -6
- package/chunks/{agent-headless-SCVFLRZ3.js → agent-headless-UNB5SWYC.js} +6 -6
- package/chunks/{anthropicContentGenerator-PPPLABT5.js → anthropicContentGenerator-AKYPSZIV.js} +3 -3
- package/chunks/{artifact-tool-H2TNPNP5.js → artifact-tool-D233YJFH.js} +25 -6
- package/chunks/{bridge-G3LFYH2D.js → bridge-GX2LGQDS.js} +11 -9
- package/chunks/{channel-worker-supervisor-B7MSMB5K.js → channel-worker-supervisor-CRCVYQIE.js} +1 -1
- package/chunks/{chunk-XUYYEFCM.js → chunk-27QGW3BK.js} +5 -5
- package/chunks/{chunk-HLJMZYTD.js → chunk-2D5Q33PT.js} +3 -3
- package/chunks/{chunk-TNIZ2HCQ.js → chunk-2MDHTI6A.js} +2 -2
- package/chunks/{chunk-VCKMHAEZ.js → chunk-2MJAXDFK.js} +6 -6
- package/chunks/{chunk-WSVZFWN4.js → chunk-2NPS2UDH.js} +305 -97
- package/chunks/{chunk-WAVK7GV6.js → chunk-2X3ZVAAT.js} +2 -2
- package/chunks/chunk-332PWN27.js +19 -0
- package/chunks/{chunk-FVMWEHWU.js → chunk-3B26UVCX.js} +114 -12
- package/chunks/{chunk-XZ2LJL4O.js → chunk-43W4YSO6.js} +1 -12
- package/chunks/{chunk-DLHOIROF.js → chunk-44NROQYV.js} +4 -2
- package/chunks/{chunk-65P5ZXUE.js → chunk-4XV2MRNK.js} +1 -1
- package/chunks/{chunk-DS6NG7SB.js → chunk-5HMMLTUD.js} +11 -11
- package/chunks/{chunk-A2CS67WK.js → chunk-5IGNZP2J.js} +1 -1
- package/chunks/{chunk-N7BUPX4V.js → chunk-6GHEZDDX.js} +1 -1
- package/chunks/{chunk-QU6OLW25.js → chunk-7O6DD2ES.js} +1 -1
- package/chunks/{chunk-RXDYWLOG.js → chunk-7R62CLMI.js} +4 -4
- package/chunks/{chunk-2BJWUJCW.js → chunk-7SAH6M3Y.js} +3 -3
- package/chunks/{chunk-OGAC66WF.js → chunk-7VCI24VZ.js} +4 -107
- package/chunks/chunk-A2X3KLC3.js +3807 -0
- package/chunks/chunk-A3ZQMFO6.js +949 -0
- package/chunks/{chunk-AY7CP32Q.js → chunk-A7UKINBT.js} +7 -7
- package/chunks/{chunk-72DDO73Z.js → chunk-ADO6IDOZ.js} +8 -8
- package/chunks/{chunk-UOGOM4NJ.js → chunk-AJ3CEJRJ.js} +10 -5
- package/chunks/{chunk-NCFY7PWS.js → chunk-CCGOFQV3.js} +51 -2
- package/chunks/{chunk-YFE4YEDW.js → chunk-DB7CZERZ.js} +1 -1
- package/chunks/{chunk-UECJ7AG2.js → chunk-DF74IL3R.js} +4 -4
- package/chunks/{chunk-7YLLBKDB.js → chunk-FCEHOKYP.js} +5 -5
- package/chunks/{chunk-JO6RDLLE.js → chunk-FRR5I3SQ.js} +1 -1
- package/chunks/{chunk-2NL7ED5Q.js → chunk-FV7425LN.js} +22 -1
- package/chunks/{chunk-NCOLCOA6.js → chunk-GPLKAQUX.js} +8 -8
- package/chunks/{chunk-AKGA72ZM.js → chunk-GV2S4F6Q.js} +5 -3
- package/chunks/{chunk-V63Q7BVE.js → chunk-GW67O5SO.js} +1 -1
- package/chunks/{chunk-2A6XOMBQ.js → chunk-HW4N45EE.js} +0 -44
- package/chunks/{chunk-S6PM5JQZ.js → chunk-IFDJAMJW.js} +484 -1222
- package/chunks/{chunk-B2FUQ22Z.js → chunk-ILFQAFWH.js} +1 -1
- package/chunks/chunk-JYFZFWSL.js +167 -0
- package/chunks/{chunk-CA373SPN.js → chunk-K56RTEBN.js} +1 -1
- package/chunks/chunk-LGFAYIKX.js +115 -0
- package/chunks/{chunk-6JESGXWU.js → chunk-LLTFLVFK.js} +4 -4
- package/chunks/{chunk-3A4MUHRP.js → chunk-MZWODTEA.js} +5 -13
- package/chunks/{chunk-IPKM25FZ.js → chunk-N33JAGJ7.js} +505 -62
- package/chunks/{chunk-B2NCNYBK.js → chunk-NVQVIJMO.js} +112 -42
- package/chunks/{chunk-INNPK6XG.js → chunk-O6T7PBUM.js} +30 -6
- package/chunks/{chunk-RN36CE4M.js → chunk-P452E6XF.js} +2 -2
- package/chunks/chunk-PS2NG7KU.js +262 -0
- package/chunks/{chunk-FTEFJT6V.js → chunk-QM4FKX7H.js} +2 -2
- package/chunks/chunk-RODQXLGZ.js +28 -0
- package/chunks/{chunk-KSPVDFE4.js → chunk-SAIILPQ3.js} +0 -3
- package/chunks/{chunk-EKDTGEX4.js → chunk-SJ3QRPN2.js} +14 -8
- package/chunks/{chunk-R57UD732.js → chunk-SKO6VJHG.js} +16 -4
- package/chunks/{chunk-66KNL43D.js → chunk-TBAZMRW3.js} +1 -1
- package/chunks/{chunk-H2UZO2II.js → chunk-TPTG52XG.js} +1 -1
- package/chunks/chunk-UIDXQNMV.js +13 -0
- package/chunks/chunk-VP2FB7OC.js +8223 -0
- package/chunks/{chunk-32KIF557.js → chunk-WKBA74DD.js} +1 -1
- package/chunks/{chunk-IEFMDFCG.js → chunk-WKTLDGD6.js} +1 -1
- package/chunks/{chunk-HT553O4R.js → chunk-WRLMLPWI.js} +3 -3
- package/chunks/{chunk-CYXPEKVN.js → chunk-XXICIIS5.js} +5 -5
- package/chunks/{chunk-5GSUPP7K.js → chunk-Y3QQV7WE.js} +2 -2
- package/chunks/{chunk-CKBRK552.js → chunk-ZKX7IBXU.js} +4 -4
- package/chunks/{chunk-CCPKBMZ4.js → chunk-ZOSL7K3L.js} +203 -38
- package/chunks/{chunk-KD4KV6XW.js → chunk-ZWFS7YCB.js} +4505 -3850
- package/chunks/{computer-use-NKJX6RTG.js → computer-use-IQ46C3YP.js} +6 -6
- package/chunks/{contextCommand-BCABFW4A.js → contextCommand-TTT6AP2W.js} +10 -9
- package/chunks/{cron-create-DDYU4DIR.js → cron-create-JSXEIPVS.js} +1 -1
- package/chunks/{cron-delete-DFKOUZWN.js → cron-delete-OIFVEPGU.js} +1 -1
- package/chunks/{cron-list-ME5QGAR5.js → cron-list-D4ZX4IOE.js} +1 -1
- package/chunks/{daemon-XWG2EGFX.js → daemon-F3I2RXP6.js} +23 -3
- package/chunks/{daemon-status-provider-V7BMA4EH.js → daemon-status-provider-5GAWK65R.js} +13 -12
- package/chunks/dist-573HNSVO.js +3217 -0
- package/chunks/{dist-VHBP2PIG.js → dist-FQ5WRJPL.js} +2 -2
- package/chunks/{dist-LPVU3L2M.js → dist-IMFFBMAT.js} +6 -3792
- package/chunks/{dist-7GU63KI5.js → dist-OT7G2WNM.js} +1 -1
- package/chunks/{dist-H4HHZYCI.js → dist-PKFTNUHO.js} +2 -2
- package/chunks/{dist-3UDX5T4T.js → dist-YTRKAVUB.js} +1 -1
- package/chunks/{earlyInputCapture-TVECMHWI.js → earlyInputCapture-LAGZUGGV.js} +6 -6
- package/chunks/{edit-VKUCEX2N.js → edit-Q5BUQC2S.js} +6 -6
- package/chunks/{en-AXARKOWO.js → en-GA2RMXY5.js} +5 -1
- package/chunks/{enter-worktree-TF6N7GA7.js → enter-worktree-DC4FHMVF.js} +6 -6
- package/chunks/{enterPlanMode-XXQGZP5T.js → enterPlanMode-5BGJBWIY.js} +6 -6
- package/chunks/{errors-LLC2B5D6.js → errors-EGX5DECS.js} +8 -8
- package/chunks/{exit-worktree-YBOMMZLI.js → exit-worktree-2EOSZNZI.js} +6 -6
- package/chunks/{exitPlanMode-74D7EOBH.js → exitPlanMode-JAQ35ELJ.js} +6 -6
- package/chunks/{fast-path-OGY4P74O.js → fast-path-QEWDA6O6.js} +5 -2
- package/chunks/{fr-MBMNQSQ6.js → fr-GWNQG4XH.js} +4 -0
- package/chunks/{gemini-IL6H4VNW.js → gemini-TQ5XANRS.js} +64 -187
- package/chunks/{geminiContentGenerator-O7OCAUQU.js → geminiContentGenerator-DCM2XGDQ.js} +1 -1
- package/chunks/{glob-X5XFJTAC.js → glob-7JLTQ4IQ.js} +6 -6
- package/chunks/{grep-53GLRSNS.js → grep-CAUXEO7Q.js} +6 -6
- package/chunks/handleAutoUpdate-XKXULZQX.js +65 -0
- package/chunks/{initializer-YBUEYP6D.js → initializer-3NRWU5JV.js} +12 -10
- package/chunks/{ja-HFV5QCHR.js → ja-2HOTA47X.js} +4 -0
- package/chunks/{list-2F3FSN46.js → list-NWO6QBDQ.js} +12 -12
- package/chunks/{loadedSettingsAdapter-AJBE627U.js → loadedSettingsAdapter-PJ77LGFS.js} +10 -10
- package/chunks/{loop-wakeup-ZW5P6VPY.js → loop-wakeup-OHWEMFP5.js} +2 -2
- package/chunks/{mcp-SEE2Z7TA.js → mcp-VFEHVF5A.js} +10 -10
- package/chunks/{monitor-YQW2M3DL.js → monitor-FY2ITVSC.js} +14 -9
- package/chunks/{nonInteractiveCli-TGWJDY47.js → nonInteractiveCli-KPCXTVWY.js} +41 -36
- package/chunks/{notebook-edit-O5G3EBYN.js → notebook-edit-BSJMXIWX.js} +6 -6
- package/chunks/{openaiContentGenerator-WAO7PPR6.js → openaiContentGenerator-BA6NWY4S.js} +5 -5
- package/chunks/{pidfile-XMDB2SF7.js → pidfile-WXMRN6QF.js} +6 -6
- package/chunks/{qwenContentGenerator-5NZ5EHRA.js → qwenContentGenerator-U4ZSLGFN.js} +8 -8
- package/chunks/{read-file-KJTMBLFF.js → read-file-VMVHNOMA.js} +2 -2
- package/chunks/{ripGrep-BCDYVQQR.js → ripGrep-NC6MUWXN.js} +6 -6
- package/chunks/{run-qwen-serve-LIWM3CMV.js → run-qwen-serve-NQH6LQTH.js} +124 -31
- package/chunks/{scheduler-VETDW3HX.js → scheduler-35T3E2UQ.js} +6 -6
- package/chunks/{serve-XKFTUZET.js → serve-C36LOB5N.js} +10 -10
- package/chunks/{server-W64GXOEJ.js → server-TDFPIDC3.js} +858 -105
- package/chunks/{session-GXNRZGVF.js → session-STHNQGRJ.js} +42 -37
- package/chunks/{settings-TIQCDHBZ.js → settings-GIE22AYF.js} +9 -9
- package/chunks/{shell-3ZZLLA35.js → shell-JD52AIMU.js} +6 -6
- package/chunks/{skill-TOX5QGBX.js → skill-L4IFKRQ5.js} +14 -4
- package/chunks/{spawnChannel-JBLAIP7L.js → spawnChannel-HGMOEPM7.js} +8 -8
- package/chunks/{src-Q7BIRWUP.js → src-3SNF3G3V.js} +15 -7
- package/chunks/{startInteractiveUI-PP72WI64.js → startInteractiveUI-C7DCDHGF.js} +4981 -13173
- package/chunks/{team-create-S44Z3N62.js → team-create-NYL7KAMA.js} +6 -6
- package/chunks/{team-plan-approval-2YPLSLO5.js → team-plan-approval-LH65JBEH.js} +6 -6
- package/chunks/{theme-manager-4MJVYHPB.js → theme-manager-ANKQO5DR.js} +6 -6
- package/chunks/{tool-search-4LSRQ24Z.js → tool-search-WZEGJFO4.js} +4 -21
- package/chunks/{trustedFolders-XMKLRQDH.js → trustedFolders-HECAG3S3.js} +7 -7
- package/chunks/updateCheck-72BBAE5V.js +65 -0
- package/chunks/{validateNonInterActiveAuth-MMMRF6WS.js → validateNonInterActiveAuth-PDQCPSNA.js} +38 -33
- package/chunks/{version-6HMEMR4K.js → version-VSEUTPNM.js} +2 -1
- package/chunks/{workflow-VYBLLOLC.js → workflow-DPF2CL7U.js} +7 -7
- package/chunks/{workspace-providers-status-5LSCQPWQ.js → workspace-providers-status-TQ23DQ2D.js} +12 -12
- package/chunks/{workspace-service-HBMBWJ4K.js → workspace-service-D34UDMEY.js} +14 -14
- package/chunks/{workspace-skills-status-TLBAQWKQ.js → workspace-skills-status-4DR5UNNC.js} +11 -11
- package/chunks/{write-file-QMAWLWCT.js → write-file-VFNAKGYM.js} +6 -6
- package/chunks/{zh-RS3HZHFH.js → zh-7XVVRTDH.js} +5 -1
- package/chunks/{zh-TW-L5GRQ4S4.js → zh-TW-DPH554OG.js} +5 -1
- package/cli.js +11 -11
- package/locales/en.js +8 -2
- package/locales/fr.js +6 -0
- package/locales/ja.js +6 -0
- package/locales/zh-TW.js +8 -2
- package/locales/zh.js +8 -2
- package/node_modules/@qwen-code/audio-capture/package.json +1 -1
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-arm64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/darwin-x64/@qwen-code+audio-capture.node +0 -0
- package/node_modules/@qwen-code/audio-capture/prebuilds/win32-x64/@qwen-code+audio-capture.node +0 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-CqwzD3ok.js → arc-C7hjaa7g.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-BfA-P0-O.js → architectureDiagram-3BPJPVTR-pm9KtMZY.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-DNTzkXRp.js → blockDiagram-GPEHLZMM-CApElKsU.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-D5axQoXQ.js → c4Diagram-AAUBKEIU-BeDe0-9N.js} +1 -1
- package/web-shell/assets/channel-BNf1dW-j.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-CV0P48eN.js → chunk-2J33WTMH-DJEkmLdl.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-CghJNPCS.js → chunk-4BX2VUAB-DXX8gdpe.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-BrD-776x.js → chunk-55IACEB6-DORmk1kQ.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-DLKkI5Yu.js → chunk-727SXJPM-DWmO4mCZ.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-C0HWhZNK.js → chunk-AQP2D5EJ-C7LRaYw2.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-Cg6PsiNL.js → chunk-FMBD7UC4-CCdXgyC5.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-B1pCuSlf.js → chunk-ND2GUHAM-SyL_xvWc.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-CkE8llI2.js → chunk-QZHKN3VN-BzOuCKxa.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-uOIGlzgi.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-uOIGlzgi.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-Btr-W-vN.js → cose-bilkent-S5V4N54A-BMPWyDKc.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-CAhjVa5L.js → dagre-BM42HDAG-B_GnPWik.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-eUQodUXw.js → diagram-2AECGRRQ-fJqMc3S_.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-BiPKbH6E.js → diagram-5GNKFQAL-ximV3O9D.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-DxuwR-Pu.js → diagram-KO2AKTUF-2vVyjzqw.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-nz9SQ3Az.js → diagram-LMA3HP47-Dckcx1sT.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-UBbYk-Jq.js → diagram-OG6HWLK6-BAVv47ga.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-BLpRQmgi.js → erDiagram-TEJ5UH35-Bn3nf5J0.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-C5Qqg1hx.js → flowDiagram-I6XJVG4X-BIbGF9JT.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BMdf3kjL.js → ganttDiagram-6RSMTGT7-CDbhb3AH.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-D9qG7BKD.js → gitGraphDiagram-PVQCEYII-CbKG1a_w.js} +1 -1
- package/web-shell/assets/index-CnE2ur2L.js +779 -0
- package/web-shell/assets/index-hSKXrlSE.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CtDBPJM8.js → infoDiagram-5YYISTIA-DUFxTy8m.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BQaS7H3_.js → ishikawaDiagram-YF4QCWOH-D69hrBG8.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-CEEujCNX.js → journeyDiagram-JHISSGLW-DsvEw51Y.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-B3QqyyNi.js → kanban-definition-UN3LZRKU-lFFjZEYd.js} +1 -1
- package/web-shell/assets/{linear-DC2Azd_6.js → linear-Bo5bWzvo.js} +1 -1
- package/web-shell/assets/{mermaid.core-DL5PRmh-.js → mermaid.core-C_HKMJx5.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DGlkd_fb.js → mindmap-definition-RKZ34NQL-DlV-NUTs.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Dew4R8DT.js → pieDiagram-4H26LBE5-B2e6FH2a.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-Bk02Tejc.js → quadrantDiagram-W4KKPZXB-D75kSk-b.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BkWJE-6M.js → requirementDiagram-4Y6WPE33-CQ6xakhM.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-BM9bZAuM.js → sankeyDiagram-5OEKKPKP-J_XTKrcY.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-IaE2rOTu.js → sequenceDiagram-3UESZ5HK-D7jTcBtf.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-CQH-ENFJ.js → stateDiagram-AJRCARHV-CrlM_OT3.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-Bs4TK_84.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-DVH5FaeF.js → timeline-definition-PNZ67QCA-5oZi76Ef.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-ChT6J8JT.js → vennDiagram-CIIHVFJN-DO5YptPK.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-D9W5AEjE.js → wardley-L42UT6IY-4t1eJDvM.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-cNYKmuIA.js → wardleyDiagram-YWT4CUSO-DKZc661S.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-BleLm4BJ.js → xychartDiagram-2RQKCTM6-su9hp08G.js} +1 -1
- package/web-shell/index.html +2 -2
- package/web-shell/assets/channel-EyH7BS8F.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CPWvwYMM.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CPWvwYMM.js +0 -1
- package/web-shell/assets/index-CgttHpqB.js +0 -763
- package/web-shell/assets/index-sVELoa_9.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CFqBlFdE.js +0 -1
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
openQwenAsrRealtimeStream,
|
|
12
12
|
openVoiceStream,
|
|
13
13
|
openVoiceStreamWithRetry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-4XV2MRNK.js";
|
|
15
15
|
import {
|
|
16
16
|
SetupGithubError,
|
|
17
17
|
collectSessionData,
|
|
@@ -22,24 +22,25 @@ import {
|
|
|
22
22
|
toJson,
|
|
23
23
|
toJsonl,
|
|
24
24
|
toMarkdown
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-AJ3CEJRJ.js";
|
|
26
|
+
import "./chunk-7VCI24VZ.js";
|
|
27
|
+
import "./chunk-LGFAYIKX.js";
|
|
26
28
|
import "./chunk-54YZOP7P.js";
|
|
27
|
-
import "./chunk-OGAC66WF.js";
|
|
28
29
|
import {
|
|
29
30
|
createDaemonStatusProvider
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import "./chunk-
|
|
31
|
+
} from "./chunk-7SAH6M3Y.js";
|
|
32
|
+
import "./chunk-2D5Q33PT.js";
|
|
32
33
|
import "./chunk-KHDZHZMH.js";
|
|
33
34
|
import {
|
|
34
35
|
createWorkspaceProvidersStatusProvider
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-27QGW3BK.js";
|
|
36
37
|
import {
|
|
37
38
|
getAuthTypeFromEnv,
|
|
38
39
|
resolveCliGenerationConfig
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-QM4FKX7H.js";
|
|
40
41
|
import {
|
|
41
42
|
createWorkspaceSkillsStatusProvider
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-WRLMLPWI.js";
|
|
43
44
|
import "./chunk-6IAWPIQ6.js";
|
|
44
45
|
import {
|
|
45
46
|
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
@@ -51,14 +52,14 @@ import {
|
|
|
51
52
|
transcribeWorkspaceVoiceAudio,
|
|
52
53
|
validateWorkspaceVoiceState,
|
|
53
54
|
voiceSettingsScopeToWire
|
|
54
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-A7UKINBT.js";
|
|
55
56
|
import {
|
|
56
57
|
PermissionRulesValidationError,
|
|
57
58
|
buildPermissionSettings,
|
|
58
59
|
isPermissionRuleType,
|
|
59
60
|
normalizePermissionRules,
|
|
60
61
|
readPermissionRuleSet
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-6GHEZDDX.js";
|
|
62
63
|
import {
|
|
63
64
|
assertVoiceBaseUrlNetworkAllowed,
|
|
64
65
|
isStreamingVoiceModel,
|
|
@@ -66,12 +67,12 @@ import {
|
|
|
66
67
|
resolveVoiceTranscriptionConfig,
|
|
67
68
|
sanitizeVoiceErrorMessage,
|
|
68
69
|
transcribeVoiceAudio
|
|
69
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-WKTLDGD6.js";
|
|
70
71
|
import {
|
|
71
72
|
isVoiceEnabled,
|
|
72
73
|
isVoiceMode,
|
|
73
74
|
readVoiceModel
|
|
74
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-ILFQAFWH.js";
|
|
75
76
|
import "./chunk-E7KNELIZ.js";
|
|
76
77
|
import {
|
|
77
78
|
WorkspacePermissionRulesSessionRequiredError,
|
|
@@ -134,16 +135,16 @@ import {
|
|
|
134
135
|
getSettingDefinition,
|
|
135
136
|
loadSettings,
|
|
136
137
|
validateSettingValue
|
|
137
|
-
} from "./chunk-
|
|
138
|
+
} from "./chunk-O6T7PBUM.js";
|
|
138
139
|
import {
|
|
139
140
|
SUPPORTED_LANGUAGES
|
|
140
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-2MJAXDFK.js";
|
|
141
142
|
import "./chunk-TLRYABYP.js";
|
|
142
143
|
import "./chunk-4RQIB5UZ.js";
|
|
143
144
|
import {
|
|
144
145
|
SessionArtifactValidationError,
|
|
145
146
|
createAcpSessionBridge
|
|
146
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-SKO6VJHG.js";
|
|
147
148
|
import "./chunk-P7M4GA57.js";
|
|
148
149
|
import {
|
|
149
150
|
BranchWhilePromptActiveError,
|
|
@@ -185,18 +186,19 @@ import {
|
|
|
185
186
|
SubscriberLimitExceededError
|
|
186
187
|
} from "./chunk-G7ZG7CA6.js";
|
|
187
188
|
import "./chunk-VRDMOSQS.js";
|
|
188
|
-
import "./chunk-
|
|
189
|
+
import "./chunk-GW67O5SO.js";
|
|
189
190
|
import "./chunk-EXPMGZZV.js";
|
|
190
191
|
import {
|
|
191
192
|
STATUS_SCHEMA_VERSION,
|
|
192
193
|
createIdleWorkspaceMemoryStatus,
|
|
193
194
|
mapDomainErrorToErrorKind
|
|
194
|
-
} from "./chunk-
|
|
195
|
+
} from "./chunk-7O6DD2ES.js";
|
|
195
196
|
import "./chunk-HLKG6CZN.js";
|
|
196
|
-
import "./chunk-
|
|
197
|
+
import "./chunk-RODQXLGZ.js";
|
|
198
|
+
import "./chunk-43W4YSO6.js";
|
|
197
199
|
import {
|
|
198
200
|
getWorkspaceTrustStatus
|
|
199
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-WKBA74DD.js";
|
|
200
202
|
import {
|
|
201
203
|
writeStderrLine
|
|
202
204
|
} from "./chunk-Y6Z2O3WR.js";
|
|
@@ -234,14 +236,16 @@ import {
|
|
|
234
236
|
parseInstallSource,
|
|
235
237
|
redactUrlCredentials,
|
|
236
238
|
shouldShowStep,
|
|
239
|
+
stripTerminalControlSequences,
|
|
237
240
|
writeWorkspaceContextFile
|
|
238
|
-
} from "./chunk-
|
|
241
|
+
} from "./chunk-ZWFS7YCB.js";
|
|
239
242
|
import "./chunk-5P5XGNYH.js";
|
|
240
243
|
import "./chunk-SKAZWEV5.js";
|
|
241
244
|
import "./chunk-K5PGHDBN.js";
|
|
242
245
|
import {
|
|
243
|
-
MAX_JOBS
|
|
244
|
-
|
|
246
|
+
MAX_JOBS,
|
|
247
|
+
nextDurableFireMs
|
|
248
|
+
} from "./chunk-3B26UVCX.js";
|
|
245
249
|
import "./chunk-W7EEOR7D.js";
|
|
246
250
|
import "./chunk-42XGFRJS.js";
|
|
247
251
|
import "./chunk-X2XNQQJI.js";
|
|
@@ -252,11 +256,12 @@ import {
|
|
|
252
256
|
} from "./chunk-2MPVVENX.js";
|
|
253
257
|
import "./chunk-ZTQ26VBE.js";
|
|
254
258
|
import {
|
|
259
|
+
appendCronRun,
|
|
255
260
|
generateCronTaskId,
|
|
261
|
+
getCronFilePath,
|
|
256
262
|
readCronTasks,
|
|
257
|
-
removeCronTasks,
|
|
258
263
|
updateCronTasks
|
|
259
|
-
} from "./chunk-
|
|
264
|
+
} from "./chunk-FV7425LN.js";
|
|
260
265
|
import "./chunk-MLZQVCF3.js";
|
|
261
266
|
import "./chunk-LQ7TMOCE.js";
|
|
262
267
|
import "./chunk-E5A7LHNN.js";
|
|
@@ -283,7 +288,7 @@ import {
|
|
|
283
288
|
recordDaemonHttpRequest,
|
|
284
289
|
recordDaemonHttpResponse,
|
|
285
290
|
withDaemonRequestSpan
|
|
286
|
-
} from "./chunk-
|
|
291
|
+
} from "./chunk-N33JAGJ7.js";
|
|
287
292
|
import "./chunk-E6US47KI.js";
|
|
288
293
|
import "./chunk-UWCTAVOD.js";
|
|
289
294
|
import "./chunk-OFEVLU4C.js";
|
|
@@ -305,8 +310,8 @@ import "./chunk-AHNJGLFV.js";
|
|
|
305
310
|
import "./chunk-22IFUCVR.js";
|
|
306
311
|
import "./chunk-7LTB54MK.js";
|
|
307
312
|
import "./chunk-SIUQ3YYX.js";
|
|
308
|
-
import "./chunk-
|
|
309
|
-
import "./chunk-
|
|
313
|
+
import "./chunk-HW4N45EE.js";
|
|
314
|
+
import "./chunk-CCGOFQV3.js";
|
|
310
315
|
import "./chunk-IRJWHZWU.js";
|
|
311
316
|
import "./chunk-SYCJMSIJ.js";
|
|
312
317
|
import "./chunk-55ZMG67I.js";
|
|
@@ -4893,6 +4898,67 @@ __name(createSessionOrganizationService, "createSessionOrganizationService");
|
|
|
4893
4898
|
|
|
4894
4899
|
// packages/cli/src/serve/server/session-archive.ts
|
|
4895
4900
|
init_esbuild_shims();
|
|
4901
|
+
|
|
4902
|
+
// packages/cli/src/serve/scheduled-task-session-lifecycle.ts
|
|
4903
|
+
init_esbuild_shims();
|
|
4904
|
+
function isBoundTask(task) {
|
|
4905
|
+
return typeof task.sessionId === "string" && task.sessionId.length > 0;
|
|
4906
|
+
}
|
|
4907
|
+
__name(isBoundTask, "isBoundTask");
|
|
4908
|
+
async function disableTasksForSessions(projectRoot, sessionIds) {
|
|
4909
|
+
if (sessionIds.length === 0) return;
|
|
4910
|
+
const targets = new Set(sessionIds);
|
|
4911
|
+
await updateCronTasks(projectRoot, (tasks) => {
|
|
4912
|
+
let changed = false;
|
|
4913
|
+
const next = tasks.map((task) => {
|
|
4914
|
+
if (isBoundTask(task) && targets.has(task.sessionId) && task.enabled !== false) {
|
|
4915
|
+
changed = true;
|
|
4916
|
+
return { ...task, enabled: false, disabledByArchive: true };
|
|
4917
|
+
}
|
|
4918
|
+
return task;
|
|
4919
|
+
});
|
|
4920
|
+
return changed ? next : tasks;
|
|
4921
|
+
});
|
|
4922
|
+
}
|
|
4923
|
+
__name(disableTasksForSessions, "disableTasksForSessions");
|
|
4924
|
+
async function enableTasksForSessions(projectRoot, sessionIds, now = Date.now()) {
|
|
4925
|
+
if (sessionIds.length === 0) return;
|
|
4926
|
+
const targets = new Set(sessionIds);
|
|
4927
|
+
await updateCronTasks(projectRoot, (tasks) => {
|
|
4928
|
+
let changed = false;
|
|
4929
|
+
const next = tasks.map((task) => {
|
|
4930
|
+
if (isBoundTask(task) && targets.has(task.sessionId) && task.enabled === false && task.disabledByArchive === true) {
|
|
4931
|
+
changed = true;
|
|
4932
|
+
const resumed = { ...task, enabled: true };
|
|
4933
|
+
delete resumed.disabledByArchive;
|
|
4934
|
+
const minute = now - now % 6e4;
|
|
4935
|
+
if (resumed.recurring) {
|
|
4936
|
+
resumed.lastFiredAt = minute;
|
|
4937
|
+
} else {
|
|
4938
|
+
resumed.createdAt = now;
|
|
4939
|
+
resumed.lastFiredAt = minute;
|
|
4940
|
+
}
|
|
4941
|
+
return resumed;
|
|
4942
|
+
}
|
|
4943
|
+
return task;
|
|
4944
|
+
});
|
|
4945
|
+
return changed ? next : tasks;
|
|
4946
|
+
});
|
|
4947
|
+
}
|
|
4948
|
+
__name(enableTasksForSessions, "enableTasksForSessions");
|
|
4949
|
+
async function removeTasksForSessions(projectRoot, sessionIds) {
|
|
4950
|
+
if (sessionIds.length === 0) return;
|
|
4951
|
+
const targets = new Set(sessionIds);
|
|
4952
|
+
await updateCronTasks(projectRoot, (tasks) => {
|
|
4953
|
+
const next = tasks.filter(
|
|
4954
|
+
(task) => !isBoundTask(task) || !targets.has(task.sessionId)
|
|
4955
|
+
);
|
|
4956
|
+
return next.length === tasks.length ? tasks : next;
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4959
|
+
__name(removeTasksForSessions, "removeTasksForSessions");
|
|
4960
|
+
|
|
4961
|
+
// packages/cli/src/serve/server/session-archive.ts
|
|
4896
4962
|
var SessionArchiveCoordinator = class {
|
|
4897
4963
|
static {
|
|
4898
4964
|
__name(this, "SessionArchiveCoordinator");
|
|
@@ -4995,6 +5061,13 @@ async function deleteDaemonSessions(params) {
|
|
|
4995
5061
|
}
|
|
4996
5062
|
})
|
|
4997
5063
|
);
|
|
5064
|
+
await removeTasksForSessions(service.getProjectRoot(), removed).catch(
|
|
5065
|
+
(err) => {
|
|
5066
|
+
logSessionArchiveWarning(
|
|
5067
|
+
`removeTasksForSessions failed for [${removed.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
|
|
5068
|
+
);
|
|
5069
|
+
}
|
|
5070
|
+
);
|
|
4998
5071
|
return { removed, notFound, errors: [...closeErrors, ...removeErrors] };
|
|
4999
5072
|
}
|
|
5000
5073
|
__name(deleteDaemonSessions, "deleteDaemonSessions");
|
|
@@ -5151,6 +5224,13 @@ async function archiveDaemonSessions(params) {
|
|
|
5151
5224
|
notFound,
|
|
5152
5225
|
errors
|
|
5153
5226
|
});
|
|
5227
|
+
await disableTasksForSessions(service.getProjectRoot(), archived).catch(
|
|
5228
|
+
(err) => {
|
|
5229
|
+
logSessionArchiveWarning(
|
|
5230
|
+
`disableTasksForSessions failed for [${archived.join(", ")}]: ${err instanceof Error ? err.message : String(err)} \u2014 bound tasks may keep firing until reconciled`
|
|
5231
|
+
);
|
|
5232
|
+
}
|
|
5233
|
+
);
|
|
5154
5234
|
return { archived, alreadyArchived, notFound, errors };
|
|
5155
5235
|
}
|
|
5156
5236
|
__name(archiveDaemonSessions, "archiveDaemonSessions");
|
|
@@ -5197,6 +5277,17 @@ async function unarchiveDaemonSessions(params) {
|
|
|
5197
5277
|
notFound,
|
|
5198
5278
|
errors
|
|
5199
5279
|
});
|
|
5280
|
+
const resumeSessionIds = [.../* @__PURE__ */ new Set([...unarchived, ...alreadyActive])];
|
|
5281
|
+
try {
|
|
5282
|
+
await enableTasksForSessions(service.getProjectRoot(), resumeSessionIds);
|
|
5283
|
+
} catch (err) {
|
|
5284
|
+
logSessionArchiveWarning(
|
|
5285
|
+
`enableTasksForSessions failed for [${resumeSessionIds.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
|
|
5286
|
+
);
|
|
5287
|
+
for (const sessionId of resumeSessionIds) {
|
|
5288
|
+
errors.push({ sessionId, error: err });
|
|
5289
|
+
}
|
|
5290
|
+
}
|
|
5200
5291
|
return { unarchived, alreadyActive, notFound, errors };
|
|
5201
5292
|
}
|
|
5202
5293
|
__name(unarchiveDaemonSessions, "unarchiveDaemonSessions");
|
|
@@ -9798,10 +9889,10 @@ function isCdpInboundFrame(frame) {
|
|
|
9798
9889
|
}
|
|
9799
9890
|
__name(isCdpInboundFrame, "isCdpInboundFrame");
|
|
9800
9891
|
var CdpReverseLink = class {
|
|
9801
|
-
constructor(sendToExtension, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS,
|
|
9892
|
+
constructor(sendToExtension, commandTimeoutMs = DEFAULT_COMMAND_TIMEOUT_MS, log2) {
|
|
9802
9893
|
this.sendToExtension = sendToExtension;
|
|
9803
9894
|
this.commandTimeoutMs = commandTimeoutMs;
|
|
9804
|
-
this.log =
|
|
9895
|
+
this.log = log2;
|
|
9805
9896
|
}
|
|
9806
9897
|
static {
|
|
9807
9898
|
__name(this, "CdpReverseLink");
|
|
@@ -10243,10 +10334,10 @@ var CdpBrowserEmulator = class {
|
|
|
10243
10334
|
var CLOSE_NO_BRIDGE = 1011;
|
|
10244
10335
|
var CLOSE_NORMAL = 1e3;
|
|
10245
10336
|
var CDP_WS_HEARTBEAT_MS = 15e3;
|
|
10246
|
-
function attachCdpClient(ws, registry,
|
|
10337
|
+
function attachCdpClient(ws, registry, log2) {
|
|
10247
10338
|
const bridge = registry.getActive();
|
|
10248
10339
|
if (!bridge) {
|
|
10249
|
-
|
|
10340
|
+
log2("qwen serve: /cdp rejected \u2014 no extension bridge connected");
|
|
10250
10341
|
try {
|
|
10251
10342
|
ws.close(
|
|
10252
10343
|
CLOSE_NO_BRIDGE,
|
|
@@ -10257,7 +10348,7 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10257
10348
|
return;
|
|
10258
10349
|
}
|
|
10259
10350
|
if (bridge.cdpBound) {
|
|
10260
|
-
|
|
10351
|
+
log2("qwen serve: /cdp rejected \u2014 a puppeteer client is already bound");
|
|
10261
10352
|
try {
|
|
10262
10353
|
ws.close(CLOSE_NO_BRIDGE, "A CDP client is already connected");
|
|
10263
10354
|
} catch {
|
|
@@ -10268,19 +10359,19 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10268
10359
|
const link = new CdpReverseLink(
|
|
10269
10360
|
(frame) => bridge.send(frame),
|
|
10270
10361
|
void 0,
|
|
10271
|
-
|
|
10362
|
+
log2
|
|
10272
10363
|
);
|
|
10273
10364
|
const emulator = new CdpBrowserEmulator({
|
|
10274
10365
|
reply: /* @__PURE__ */ __name((frame) => {
|
|
10275
10366
|
safeWsSend(ws, JSON.stringify(frame), "CDP");
|
|
10276
10367
|
}, "reply"),
|
|
10277
10368
|
forwardToTab: link.forwardToTab,
|
|
10278
|
-
log
|
|
10369
|
+
log: log2
|
|
10279
10370
|
});
|
|
10280
10371
|
link.bindEmulator(emulator);
|
|
10281
10372
|
bridge.routeInbound = (frame) => link.handleInbound(frame);
|
|
10282
10373
|
link.onDetach = (reason) => {
|
|
10283
|
-
|
|
10374
|
+
log2(`qwen serve: /cdp tab detached (${reason}); closing puppeteer socket`);
|
|
10284
10375
|
try {
|
|
10285
10376
|
ws.close(CLOSE_NORMAL, `tab detached: ${reason}`);
|
|
10286
10377
|
} catch {
|
|
@@ -10291,7 +10382,7 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10291
10382
|
const heartbeat = setInterval(() => {
|
|
10292
10383
|
if (disposed) return;
|
|
10293
10384
|
if (!heartbeatAlive) {
|
|
10294
|
-
|
|
10385
|
+
log2("qwen serve: /cdp heartbeat missed; closing puppeteer socket");
|
|
10295
10386
|
dispose("puppeteer /cdp heartbeat missed");
|
|
10296
10387
|
try {
|
|
10297
10388
|
ws.close(CLOSE_NORMAL, "cdp heartbeat missed");
|
|
@@ -10303,7 +10394,7 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10303
10394
|
try {
|
|
10304
10395
|
ws.ping();
|
|
10305
10396
|
} catch (err) {
|
|
10306
|
-
|
|
10397
|
+
log2(
|
|
10307
10398
|
`qwen serve: /cdp heartbeat ping failed: ${err instanceof Error ? err.message : String(err)}`
|
|
10308
10399
|
);
|
|
10309
10400
|
dispose("puppeteer /cdp heartbeat ping failed");
|
|
@@ -10321,11 +10412,11 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10321
10412
|
if (notifyExtension && registry.getActive() === bridge) {
|
|
10322
10413
|
try {
|
|
10323
10414
|
bridge.send({ type: CDP_FRAME_TYPES.release });
|
|
10324
|
-
|
|
10415
|
+
log2(
|
|
10325
10416
|
`qwen serve: /cdp sent release to extension (puppeteer disconnected: ${reason})`
|
|
10326
10417
|
);
|
|
10327
10418
|
} catch (err) {
|
|
10328
|
-
|
|
10419
|
+
log2(
|
|
10329
10420
|
`qwen serve: /cdp release send failed: ${err instanceof Error ? err.message : String(err)}`
|
|
10330
10421
|
);
|
|
10331
10422
|
}
|
|
@@ -10338,7 +10429,7 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10338
10429
|
}
|
|
10339
10430
|
}, "dispose");
|
|
10340
10431
|
link.onAttachFailure = (reason) => {
|
|
10341
|
-
|
|
10432
|
+
log2(`qwen serve: /cdp attach failed (${reason}); closing puppeteer socket`);
|
|
10342
10433
|
dispose(`cdp_attach failed: ${reason}`, false);
|
|
10343
10434
|
try {
|
|
10344
10435
|
ws.close(CLOSE_NO_BRIDGE, "cdp attach failed");
|
|
@@ -10349,7 +10440,7 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10349
10440
|
heartbeatAlive = true;
|
|
10350
10441
|
});
|
|
10351
10442
|
bridge.onExtensionGone = () => {
|
|
10352
|
-
|
|
10443
|
+
log2("qwen serve: extension /acp dropped; closing puppeteer /cdp socket");
|
|
10353
10444
|
dispose("extension /acp disconnected", false);
|
|
10354
10445
|
try {
|
|
10355
10446
|
ws.close(CLOSE_NORMAL, "extension disconnected");
|
|
@@ -10365,19 +10456,19 @@ function attachCdpClient(ws, registry, log) {
|
|
|
10365
10456
|
return;
|
|
10366
10457
|
}
|
|
10367
10458
|
void emulator.handleFromClient(frame).catch((err) => {
|
|
10368
|
-
|
|
10459
|
+
log2(
|
|
10369
10460
|
`qwen serve: /cdp emulator error: ${err instanceof Error ? err.message : String(err)}`
|
|
10370
10461
|
);
|
|
10371
10462
|
});
|
|
10372
10463
|
});
|
|
10373
10464
|
ws.on("close", () => dispose("puppeteer /cdp socket closed"));
|
|
10374
10465
|
ws.on("error", (err) => {
|
|
10375
|
-
|
|
10466
|
+
log2(
|
|
10376
10467
|
`qwen serve: /cdp WS error: ${err instanceof Error ? err.message : String(err)}`
|
|
10377
10468
|
);
|
|
10378
10469
|
dispose("puppeteer /cdp socket error");
|
|
10379
10470
|
});
|
|
10380
|
-
|
|
10471
|
+
log2("qwen serve: /cdp puppeteer client bound to extension bridge");
|
|
10381
10472
|
}
|
|
10382
10473
|
__name(attachCdpClient, "attachCdpClient");
|
|
10383
10474
|
|
|
@@ -10516,7 +10607,7 @@ var MAX_INFLIGHT_MCP_DISPATCH = 8;
|
|
|
10516
10607
|
function mountAcpHttp(app, bridge, opts) {
|
|
10517
10608
|
const enabled = opts.enabled ?? process.env["QWEN_SERVE_ACP_HTTP"] !== "0";
|
|
10518
10609
|
if (!enabled) return void 0;
|
|
10519
|
-
const
|
|
10610
|
+
const path14 = opts.path ?? "/acp";
|
|
10520
10611
|
const dispatcherRef = {};
|
|
10521
10612
|
const registry = new ConnectionRegistry(
|
|
10522
10613
|
(req, clientId) => {
|
|
@@ -10653,7 +10744,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
10653
10744
|
opts.archiveCoordinator ?? new SessionArchiveCoordinator()
|
|
10654
10745
|
);
|
|
10655
10746
|
dispatcherRef.current = dispatcher;
|
|
10656
|
-
app.post(
|
|
10747
|
+
app.post(path14, async (req, res) => {
|
|
10657
10748
|
const ct = req.headers["content-type"];
|
|
10658
10749
|
if (!ct || !ct.startsWith("application/json")) {
|
|
10659
10750
|
res.status(415).json({ error: "Content-Type must be application/json" });
|
|
@@ -10757,7 +10848,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
10757
10848
|
);
|
|
10758
10849
|
});
|
|
10759
10850
|
});
|
|
10760
|
-
app.get(
|
|
10851
|
+
app.get(path14, (req, res) => {
|
|
10761
10852
|
const accept = req.headers["accept"] ?? "";
|
|
10762
10853
|
if (!accept.includes("text/event-stream")) {
|
|
10763
10854
|
res.status(406).json({ error: "Accept header must include text/event-stream" });
|
|
@@ -10843,7 +10934,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
10843
10934
|
onPumpSettled();
|
|
10844
10935
|
});
|
|
10845
10936
|
});
|
|
10846
|
-
app.delete(
|
|
10937
|
+
app.delete(path14, (req, res) => {
|
|
10847
10938
|
const connectionId = headerOf(req, ACP_CONNECTION_HEADER);
|
|
10848
10939
|
if (!connectionId) {
|
|
10849
10940
|
res.status(400).json({ error: "Missing Acp-Connection-Id" });
|
|
@@ -10906,7 +10997,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
10906
10997
|
const extraRoute = opts.extraWsRoutes?.find(
|
|
10907
10998
|
(route) => route.path === url.pathname
|
|
10908
10999
|
);
|
|
10909
|
-
if (url.pathname !==
|
|
11000
|
+
if (url.pathname !== path14 && !isCdpPath && !extraRoute) {
|
|
10910
11001
|
logReject(`unknown-path ${url.pathname}`);
|
|
10911
11002
|
socket.destroy();
|
|
10912
11003
|
return;
|
|
@@ -11303,7 +11394,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
11303
11394
|
});
|
|
11304
11395
|
}, "upgradeListener");
|
|
11305
11396
|
httpServer.on("upgrade", upgradeListener);
|
|
11306
|
-
writeStderrLine(`qwen serve: /acp WebSocket transport enabled on ${
|
|
11397
|
+
writeStderrLine(`qwen serve: /acp WebSocket transport enabled on ${path14}`);
|
|
11307
11398
|
}
|
|
11308
11399
|
__name(setupWebSocket, "setupWebSocket");
|
|
11309
11400
|
return {
|
|
@@ -16084,6 +16175,24 @@ var MAX_SCHEDULED_TASKS = MAX_JOBS;
|
|
|
16084
16175
|
var MAX_PROMPT_LENGTH = 1e5;
|
|
16085
16176
|
var MAX_NAME_LENGTH2 = 200;
|
|
16086
16177
|
var MAX_CRON_LENGTH = 200;
|
|
16178
|
+
var MAX_SESSION_NAME_LENGTH = 60;
|
|
16179
|
+
function scheduledTaskSessionName(label) {
|
|
16180
|
+
const cleaned = stripTerminalControlSequences(label).replace(/[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "").trim().replace(/\s+/g, " ");
|
|
16181
|
+
let short = cleaned;
|
|
16182
|
+
if (cleaned.length > MAX_SESSION_NAME_LENGTH) {
|
|
16183
|
+
let cut = MAX_SESSION_NAME_LENGTH - 1;
|
|
16184
|
+
const boundary = cleaned.charCodeAt(cut - 1);
|
|
16185
|
+
if (boundary >= 55296 && boundary <= 56319) cut -= 1;
|
|
16186
|
+
short = `${cleaned.slice(0, cut)}\u2026`;
|
|
16187
|
+
}
|
|
16188
|
+
return `\u23F0 ${short}`;
|
|
16189
|
+
}
|
|
16190
|
+
__name(scheduledTaskSessionName, "scheduledTaskSessionName");
|
|
16191
|
+
function computeNextRunAt(task) {
|
|
16192
|
+
if (task.enabled === false) return null;
|
|
16193
|
+
return nextDurableFireMs(task);
|
|
16194
|
+
}
|
|
16195
|
+
__name(computeNextRunAt, "computeNextRunAt");
|
|
16087
16196
|
function toView(task) {
|
|
16088
16197
|
return {
|
|
16089
16198
|
id: task.id,
|
|
@@ -16094,7 +16203,14 @@ function toView(task) {
|
|
|
16094
16203
|
// Absent enabled defaults to enabled — tool-created tasks never write it.
|
|
16095
16204
|
enabled: task.enabled !== false,
|
|
16096
16205
|
createdAt: task.createdAt,
|
|
16097
|
-
lastFiredAt: task.lastFiredAt
|
|
16206
|
+
lastFiredAt: task.lastFiredAt,
|
|
16207
|
+
nextRunAt: computeNextRunAt(task),
|
|
16208
|
+
// The task's bound session (its run-history transcript), or null for an
|
|
16209
|
+
// unbound tool-created/legacy task.
|
|
16210
|
+
sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
|
|
16211
|
+
// Absent runs (tool-created / never-fired) normalizes to [] so the client
|
|
16212
|
+
// never special-cases undefined.
|
|
16213
|
+
runs: Array.isArray(task.runs) ? task.runs : []
|
|
16098
16214
|
};
|
|
16099
16215
|
}
|
|
16100
16216
|
__name(toView, "toView");
|
|
@@ -16108,8 +16224,26 @@ function validateCron(cron) {
|
|
|
16108
16224
|
}
|
|
16109
16225
|
}
|
|
16110
16226
|
__name(validateCron, "validateCron");
|
|
16227
|
+
function canonicalCron(cron) {
|
|
16228
|
+
try {
|
|
16229
|
+
const f = parseCron(cron);
|
|
16230
|
+
const s = /* @__PURE__ */ __name((set) => [...set].sort((a, b) => a - b).join(","), "s");
|
|
16231
|
+
return [
|
|
16232
|
+
s(f.minute),
|
|
16233
|
+
s(f.hour),
|
|
16234
|
+
s(f.dayOfMonth),
|
|
16235
|
+
s(f.month),
|
|
16236
|
+
s(f.dayOfWeek),
|
|
16237
|
+
f.domIsWild ? "W" : "",
|
|
16238
|
+
f.dowIsWild ? "W" : ""
|
|
16239
|
+
].join("|");
|
|
16240
|
+
} catch {
|
|
16241
|
+
return null;
|
|
16242
|
+
}
|
|
16243
|
+
}
|
|
16244
|
+
__name(canonicalCron, "canonicalCron");
|
|
16111
16245
|
function registerScheduledTasksRoutes(app, deps) {
|
|
16112
|
-
const { boundWorkspace, mutate, safeBody: safeBody2 } = deps;
|
|
16246
|
+
const { boundWorkspace, mutate, safeBody: safeBody2, bridge } = deps;
|
|
16113
16247
|
app.get("/scheduled-tasks", async (_req, res) => {
|
|
16114
16248
|
try {
|
|
16115
16249
|
const tasks = await readCronTasks(boundWorkspace);
|
|
@@ -16182,6 +16316,41 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16182
16316
|
}
|
|
16183
16317
|
const recurring = body["recurring"] !== false;
|
|
16184
16318
|
const enabled = body["enabled"] !== false;
|
|
16319
|
+
let boundSessionId;
|
|
16320
|
+
if (bridge) {
|
|
16321
|
+
try {
|
|
16322
|
+
if ((await readCronTasks(boundWorkspace)).length >= MAX_SCHEDULED_TASKS) {
|
|
16323
|
+
res.status(409).json({
|
|
16324
|
+
error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
|
|
16325
|
+
code: "max_tasks_reached"
|
|
16326
|
+
});
|
|
16327
|
+
return;
|
|
16328
|
+
}
|
|
16329
|
+
} catch {
|
|
16330
|
+
}
|
|
16331
|
+
try {
|
|
16332
|
+
const session = await bridge.spawnOrAttach({
|
|
16333
|
+
workspaceCwd: boundWorkspace,
|
|
16334
|
+
sessionScope: "thread"
|
|
16335
|
+
});
|
|
16336
|
+
boundSessionId = session.sessionId;
|
|
16337
|
+
try {
|
|
16338
|
+
bridge.updateSessionMetadata(boundSessionId, {
|
|
16339
|
+
displayName: scheduledTaskSessionName(nameResult.value ?? prompt)
|
|
16340
|
+
});
|
|
16341
|
+
} catch {
|
|
16342
|
+
}
|
|
16343
|
+
} catch (err) {
|
|
16344
|
+
writeStderrLine(
|
|
16345
|
+
`qwen serve: POST /scheduled-tasks failed to create the task's session: ${err instanceof Error ? err.message : String(err)}`
|
|
16346
|
+
);
|
|
16347
|
+
res.status(500).json({
|
|
16348
|
+
error: "Failed to create the task's session",
|
|
16349
|
+
code: "scheduled_tasks_session_failed"
|
|
16350
|
+
});
|
|
16351
|
+
return;
|
|
16352
|
+
}
|
|
16353
|
+
}
|
|
16185
16354
|
const now = Date.now();
|
|
16186
16355
|
const task = {
|
|
16187
16356
|
id: generateCronTaskId(),
|
|
@@ -16193,8 +16362,17 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16193
16362
|
// minute the task was created — same guard cronScheduler.create uses.
|
|
16194
16363
|
lastFiredAt: now - now % 6e4,
|
|
16195
16364
|
enabled,
|
|
16365
|
+
...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
|
|
16196
16366
|
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
16197
16367
|
};
|
|
16368
|
+
const rollbackSession = /* @__PURE__ */ __name(async () => {
|
|
16369
|
+
if (boundSessionId !== void 0 && bridge) {
|
|
16370
|
+
await bridge.closeSession(boundSessionId).catch(() => {
|
|
16371
|
+
});
|
|
16372
|
+
await new SessionService(boundWorkspace).removeSession(boundSessionId).catch(() => {
|
|
16373
|
+
});
|
|
16374
|
+
}
|
|
16375
|
+
}, "rollbackSession");
|
|
16198
16376
|
let overCap = false;
|
|
16199
16377
|
try {
|
|
16200
16378
|
await updateCronTasks(boundWorkspace, (tasks) => {
|
|
@@ -16205,6 +16383,7 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16205
16383
|
return [...tasks, task];
|
|
16206
16384
|
});
|
|
16207
16385
|
} catch (err) {
|
|
16386
|
+
await rollbackSession();
|
|
16208
16387
|
writeStderrLine(
|
|
16209
16388
|
`qwen serve: POST /scheduled-tasks failed: ${err instanceof Error ? err.message : String(err)}`
|
|
16210
16389
|
);
|
|
@@ -16215,6 +16394,7 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16215
16394
|
return;
|
|
16216
16395
|
}
|
|
16217
16396
|
if (overCap) {
|
|
16397
|
+
await rollbackSession();
|
|
16218
16398
|
res.status(409).json({
|
|
16219
16399
|
error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
|
|
16220
16400
|
code: "max_tasks_reached"
|
|
@@ -16300,17 +16480,32 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16300
16480
|
}
|
|
16301
16481
|
let found = false;
|
|
16302
16482
|
let updated;
|
|
16483
|
+
let blockedByArchive = false;
|
|
16303
16484
|
try {
|
|
16304
16485
|
await updateCronTasks(boundWorkspace, (tasks) => {
|
|
16305
16486
|
const idx = tasks.findIndex((t) => t.id === id);
|
|
16306
16487
|
if (idx === -1) return tasks;
|
|
16307
16488
|
found = true;
|
|
16308
16489
|
const current = tasks[idx];
|
|
16490
|
+
if (patch.enabled === true && current.disabledByArchive === true) {
|
|
16491
|
+
blockedByArchive = true;
|
|
16492
|
+
return tasks;
|
|
16493
|
+
}
|
|
16309
16494
|
const next = { ...current, ...patch };
|
|
16310
16495
|
if (clearName) delete next.name;
|
|
16311
|
-
|
|
16496
|
+
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
16497
|
+
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
16498
|
+
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
16499
|
+
const becameOneShot = patch.recurring === false && current.recurring !== false;
|
|
16500
|
+
{
|
|
16312
16501
|
const now = Date.now();
|
|
16313
|
-
|
|
16502
|
+
const minute = now - now % 6e4;
|
|
16503
|
+
if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
|
|
16504
|
+
next.lastFiredAt = minute;
|
|
16505
|
+
} else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
|
|
16506
|
+
next.createdAt = now;
|
|
16507
|
+
next.lastFiredAt = minute;
|
|
16508
|
+
}
|
|
16314
16509
|
}
|
|
16315
16510
|
updated = next;
|
|
16316
16511
|
return tasks.map((t, i) => i === idx ? next : t);
|
|
@@ -16325,10 +16520,26 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16325
16520
|
});
|
|
16326
16521
|
return;
|
|
16327
16522
|
}
|
|
16523
|
+
if (blockedByArchive) {
|
|
16524
|
+
res.status(409).json({
|
|
16525
|
+
error: "This task was disabled by archiving its session; unarchive the session to re-enable it.",
|
|
16526
|
+
code: "task_session_archived"
|
|
16527
|
+
});
|
|
16528
|
+
return;
|
|
16529
|
+
}
|
|
16328
16530
|
if (!found || !updated) {
|
|
16329
16531
|
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
16330
16532
|
return;
|
|
16331
16533
|
}
|
|
16534
|
+
const effectiveLabelChanged = patch.name !== void 0 || clearName || patch.prompt !== void 0 && updated.name === void 0;
|
|
16535
|
+
if (bridge && updated.sessionId && effectiveLabelChanged) {
|
|
16536
|
+
try {
|
|
16537
|
+
bridge.updateSessionMetadata(updated.sessionId, {
|
|
16538
|
+
displayName: scheduledTaskSessionName(updated.name ?? updated.prompt)
|
|
16539
|
+
});
|
|
16540
|
+
} catch {
|
|
16541
|
+
}
|
|
16542
|
+
}
|
|
16332
16543
|
res.status(200).json(toView(updated));
|
|
16333
16544
|
});
|
|
16334
16545
|
app.delete("/scheduled-tasks/:id", mutate(), async (req, res) => {
|
|
@@ -16337,9 +16548,19 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16337
16548
|
res.status(400).json({ error: "Task id is required", code: "invalid_id" });
|
|
16338
16549
|
return;
|
|
16339
16550
|
}
|
|
16340
|
-
let
|
|
16551
|
+
let boundSessionId;
|
|
16552
|
+
let removed = false;
|
|
16341
16553
|
try {
|
|
16342
|
-
|
|
16554
|
+
await updateCronTasks(boundWorkspace, (tasks) => {
|
|
16555
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
16556
|
+
if (idx === -1) return tasks;
|
|
16557
|
+
const match = tasks[idx].sessionId;
|
|
16558
|
+
if (typeof match === "string" && match.length > 0) {
|
|
16559
|
+
boundSessionId = match;
|
|
16560
|
+
}
|
|
16561
|
+
removed = true;
|
|
16562
|
+
return tasks.filter((_, i) => i !== idx);
|
|
16563
|
+
});
|
|
16343
16564
|
} catch (err) {
|
|
16344
16565
|
writeStderrLine(
|
|
16345
16566
|
`qwen serve: DELETE /scheduled-tasks/${id} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -16350,12 +16571,76 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
16350
16571
|
});
|
|
16351
16572
|
return;
|
|
16352
16573
|
}
|
|
16353
|
-
if (removed
|
|
16574
|
+
if (!removed) {
|
|
16354
16575
|
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
16355
16576
|
return;
|
|
16356
16577
|
}
|
|
16578
|
+
if (boundSessionId && bridge) {
|
|
16579
|
+
await bridge.closeSession(boundSessionId).catch(() => {
|
|
16580
|
+
});
|
|
16581
|
+
}
|
|
16357
16582
|
res.status(200).json({ deleted: true, id });
|
|
16358
16583
|
});
|
|
16584
|
+
app.post("/scheduled-tasks/:id/run", mutate(), async (req, res) => {
|
|
16585
|
+
const id = typeof req.params["id"] === "string" ? req.params["id"] : "";
|
|
16586
|
+
if (id.length === 0) {
|
|
16587
|
+
res.status(400).json({ error: "Task id is required", code: "invalid_id" });
|
|
16588
|
+
return;
|
|
16589
|
+
}
|
|
16590
|
+
const now = Date.now();
|
|
16591
|
+
let found = false;
|
|
16592
|
+
let blockedDisabled = false;
|
|
16593
|
+
let updated;
|
|
16594
|
+
try {
|
|
16595
|
+
await updateCronTasks(boundWorkspace, (tasks) => {
|
|
16596
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
16597
|
+
if (idx === -1) return tasks;
|
|
16598
|
+
found = true;
|
|
16599
|
+
const current = tasks[idx];
|
|
16600
|
+
if (current.enabled === false) {
|
|
16601
|
+
blockedDisabled = true;
|
|
16602
|
+
return tasks;
|
|
16603
|
+
}
|
|
16604
|
+
const next = {
|
|
16605
|
+
...current,
|
|
16606
|
+
lastFiredAt: now,
|
|
16607
|
+
runs: appendCronRun(current.runs, {
|
|
16608
|
+
at: now,
|
|
16609
|
+
kind: "manual",
|
|
16610
|
+
...current.sessionId ? { sessionId: current.sessionId } : {}
|
|
16611
|
+
})
|
|
16612
|
+
};
|
|
16613
|
+
updated = next;
|
|
16614
|
+
if (!current.recurring) {
|
|
16615
|
+
return tasks.filter((_, i) => i !== idx);
|
|
16616
|
+
}
|
|
16617
|
+
return tasks.map((t, i) => i === idx ? next : t);
|
|
16618
|
+
});
|
|
16619
|
+
} catch (err) {
|
|
16620
|
+
writeStderrLine(
|
|
16621
|
+
`qwen serve: POST /scheduled-tasks/${id}/run failed: ${err instanceof Error ? err.message : String(err)}`
|
|
16622
|
+
);
|
|
16623
|
+
res.status(500).json({
|
|
16624
|
+
error: "Failed to record scheduled task run",
|
|
16625
|
+
code: "scheduled_tasks_write_failed"
|
|
16626
|
+
});
|
|
16627
|
+
return;
|
|
16628
|
+
}
|
|
16629
|
+
if (blockedDisabled) {
|
|
16630
|
+
res.status(409).json({
|
|
16631
|
+
error: "Cannot run a disabled task; enable it first (unarchive its session if it was archived).",
|
|
16632
|
+
code: "task_disabled"
|
|
16633
|
+
});
|
|
16634
|
+
return;
|
|
16635
|
+
}
|
|
16636
|
+
if (!found || !updated) {
|
|
16637
|
+
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
16638
|
+
return;
|
|
16639
|
+
}
|
|
16640
|
+
const view = toView(updated);
|
|
16641
|
+
if (!updated.recurring) view.nextRunAt = null;
|
|
16642
|
+
res.status(200).json(view);
|
|
16643
|
+
});
|
|
16359
16644
|
}
|
|
16360
16645
|
__name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
|
|
16361
16646
|
function parseNameField(raw) {
|
|
@@ -16430,6 +16715,320 @@ function registerUsageStatsRoutes(app, deps = {}) {
|
|
|
16430
16715
|
}
|
|
16431
16716
|
__name(registerUsageStatsRoutes, "registerUsageStatsRoutes");
|
|
16432
16717
|
|
|
16718
|
+
// packages/cli/src/serve/scheduled-task-keepalive.ts
|
|
16719
|
+
init_esbuild_shims();
|
|
16720
|
+
import * as fsSync from "node:fs";
|
|
16721
|
+
import * as path11 from "node:path";
|
|
16722
|
+
var log = createDebugLogger("SCHED_KEEPALIVE");
|
|
16723
|
+
function collectBoundSessionIds(tasks) {
|
|
16724
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16725
|
+
const ids = [];
|
|
16726
|
+
for (const task of tasks) {
|
|
16727
|
+
const sessionId = task.sessionId;
|
|
16728
|
+
if (task.enabled === false || // disabled (e.g. archived) — let it be reaped
|
|
16729
|
+
typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) {
|
|
16730
|
+
continue;
|
|
16731
|
+
}
|
|
16732
|
+
seen.add(sessionId);
|
|
16733
|
+
ids.push(sessionId);
|
|
16734
|
+
}
|
|
16735
|
+
return ids;
|
|
16736
|
+
}
|
|
16737
|
+
__name(collectBoundSessionIds, "collectBoundSessionIds");
|
|
16738
|
+
var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
|
|
16739
|
+
var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
|
|
16740
|
+
var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
|
|
16741
|
+
async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding) {
|
|
16742
|
+
const unbound = tasks.filter(
|
|
16743
|
+
(t) => !t.sessionId && t.enabled !== false && !binding.has(t.id)
|
|
16744
|
+
);
|
|
16745
|
+
const needsName = tasks.filter(
|
|
16746
|
+
(t) => t.sessionId && t.enabled !== false && !renamed.has(t.sessionId)
|
|
16747
|
+
);
|
|
16748
|
+
for (const task of unbound) {
|
|
16749
|
+
let spawnedSessionId;
|
|
16750
|
+
try {
|
|
16751
|
+
binding.add(task.id);
|
|
16752
|
+
const rawSpawn = bridge.spawnOrAttach({
|
|
16753
|
+
workspaceCwd: boundWorkspace,
|
|
16754
|
+
sessionScope: "thread"
|
|
16755
|
+
});
|
|
16756
|
+
let timedOut = false;
|
|
16757
|
+
rawSpawn.then(({ sessionId: sessionId2 }) => {
|
|
16758
|
+
if (timedOut) {
|
|
16759
|
+
log.debug(
|
|
16760
|
+
"keepalive: late spawn resolved, cleaning up",
|
|
16761
|
+
task.id,
|
|
16762
|
+
sessionId2
|
|
16763
|
+
);
|
|
16764
|
+
bridge.closeSession(sessionId2).catch(() => {
|
|
16765
|
+
});
|
|
16766
|
+
new SessionService(boundWorkspace).removeSession(sessionId2).catch(() => {
|
|
16767
|
+
});
|
|
16768
|
+
}
|
|
16769
|
+
}).catch(() => {
|
|
16770
|
+
}).finally(() => {
|
|
16771
|
+
binding.delete(task.id);
|
|
16772
|
+
});
|
|
16773
|
+
const { sessionId } = await withTimeout(
|
|
16774
|
+
rawSpawn,
|
|
16775
|
+
spawnTimeoutMs,
|
|
16776
|
+
`spawnOrAttach(${task.id})`
|
|
16777
|
+
).catch((err) => {
|
|
16778
|
+
timedOut = true;
|
|
16779
|
+
throw err;
|
|
16780
|
+
});
|
|
16781
|
+
spawnedSessionId = sessionId;
|
|
16782
|
+
try {
|
|
16783
|
+
bridge.updateSessionMetadata(sessionId, {
|
|
16784
|
+
displayName: scheduledTaskSessionName(task.prompt)
|
|
16785
|
+
});
|
|
16786
|
+
renamed.add(sessionId);
|
|
16787
|
+
} catch {
|
|
16788
|
+
}
|
|
16789
|
+
let matched = false;
|
|
16790
|
+
await updateCronTasks(boundWorkspace, (list) => {
|
|
16791
|
+
if (!list.some(
|
|
16792
|
+
(t) => t.id === task.id && !t.sessionId && t.enabled !== false
|
|
16793
|
+
)) {
|
|
16794
|
+
return list;
|
|
16795
|
+
}
|
|
16796
|
+
const result = list.map(
|
|
16797
|
+
(t) => t.id === task.id && !t.sessionId && t.enabled !== false ? { ...t, sessionId } : t
|
|
16798
|
+
);
|
|
16799
|
+
matched = true;
|
|
16800
|
+
return result;
|
|
16801
|
+
});
|
|
16802
|
+
if (!matched) {
|
|
16803
|
+
throw new Error(`task ${task.id} no longer on disk`);
|
|
16804
|
+
}
|
|
16805
|
+
log.debug(
|
|
16806
|
+
"keepalive: bound task",
|
|
16807
|
+
task.id,
|
|
16808
|
+
"to dedicated session",
|
|
16809
|
+
sessionId
|
|
16810
|
+
);
|
|
16811
|
+
} catch (err) {
|
|
16812
|
+
log.debug("keepalive: failed to bind task", task.id, err);
|
|
16813
|
+
if (spawnedSessionId !== void 0) {
|
|
16814
|
+
await bridge.closeSession(spawnedSessionId).catch(() => {
|
|
16815
|
+
});
|
|
16816
|
+
await new SessionService(boundWorkspace).removeSession(spawnedSessionId).catch(() => {
|
|
16817
|
+
});
|
|
16818
|
+
}
|
|
16819
|
+
}
|
|
16820
|
+
}
|
|
16821
|
+
for (const task of needsName) {
|
|
16822
|
+
const sessionId = task.sessionId;
|
|
16823
|
+
try {
|
|
16824
|
+
bridge.updateSessionMetadata(sessionId, {
|
|
16825
|
+
displayName: scheduledTaskSessionName(task.prompt)
|
|
16826
|
+
});
|
|
16827
|
+
renamed.add(sessionId);
|
|
16828
|
+
} catch (err) {
|
|
16829
|
+
log.debug("keepalive: failed to name session", sessionId, err);
|
|
16830
|
+
}
|
|
16831
|
+
}
|
|
16832
|
+
}
|
|
16833
|
+
__name(bindAndNameSessions, "bindAndNameSessions");
|
|
16834
|
+
function startScheduledTaskKeepalive(opts) {
|
|
16835
|
+
const { bridge, boundWorkspace, intervalMs } = opts;
|
|
16836
|
+
const reviveTimeoutMs = opts.reviveTimeoutMs ?? KEEPALIVE_REVIVE_TIMEOUT_MS;
|
|
16837
|
+
const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
|
|
16838
|
+
const reviveState = /* @__PURE__ */ new Map();
|
|
16839
|
+
const reviving = /* @__PURE__ */ new Set();
|
|
16840
|
+
const binding = /* @__PURE__ */ new Set();
|
|
16841
|
+
const renamed = /* @__PURE__ */ new Set();
|
|
16842
|
+
const tick = /* @__PURE__ */ __name(async () => {
|
|
16843
|
+
let tasks;
|
|
16844
|
+
try {
|
|
16845
|
+
tasks = await readCronTasks(boundWorkspace);
|
|
16846
|
+
} catch (err) {
|
|
16847
|
+
log.debug("keepalive: readCronTasks failed, skipping this pass", err);
|
|
16848
|
+
return;
|
|
16849
|
+
}
|
|
16850
|
+
for (const sessionId of collectBoundSessionIds(tasks)) {
|
|
16851
|
+
try {
|
|
16852
|
+
bridge.recordHeartbeat(sessionId);
|
|
16853
|
+
reviveState.delete(sessionId);
|
|
16854
|
+
} catch (err) {
|
|
16855
|
+
const state = reviveState.get(sessionId);
|
|
16856
|
+
if (reviving.has(sessionId)) {
|
|
16857
|
+
continue;
|
|
16858
|
+
}
|
|
16859
|
+
if (state && Date.now() < state.nextAttemptAt) {
|
|
16860
|
+
continue;
|
|
16861
|
+
}
|
|
16862
|
+
log.debug("keepalive: recordHeartbeat failed for", sessionId, err);
|
|
16863
|
+
const load = bridge.loadSession({
|
|
16864
|
+
sessionId,
|
|
16865
|
+
workspaceCwd: boundWorkspace,
|
|
16866
|
+
historyReplay: "response"
|
|
16867
|
+
});
|
|
16868
|
+
reviving.add(sessionId);
|
|
16869
|
+
void load.catch(() => {
|
|
16870
|
+
}).finally(() => {
|
|
16871
|
+
reviving.delete(sessionId);
|
|
16872
|
+
});
|
|
16873
|
+
try {
|
|
16874
|
+
await withTimeout(load, reviveTimeoutMs, `loadSession(${sessionId})`);
|
|
16875
|
+
log.debug("keepalive: revived non-resident session", sessionId);
|
|
16876
|
+
reviveState.delete(sessionId);
|
|
16877
|
+
} catch (loadErr) {
|
|
16878
|
+
const failures = (state?.failures ?? 0) + 1;
|
|
16879
|
+
const backoff = Math.min(
|
|
16880
|
+
intervalMs * 2 ** Math.min(failures - 1, 6),
|
|
16881
|
+
MAX_REVIVE_BACKOFF_MS
|
|
16882
|
+
);
|
|
16883
|
+
reviveState.set(sessionId, {
|
|
16884
|
+
failures,
|
|
16885
|
+
nextAttemptAt: Date.now() + backoff
|
|
16886
|
+
});
|
|
16887
|
+
log.debug(
|
|
16888
|
+
"keepalive: failed to revive session",
|
|
16889
|
+
sessionId,
|
|
16890
|
+
`(failure ${failures}, next retry in ${backoff}ms)`,
|
|
16891
|
+
loadErr
|
|
16892
|
+
);
|
|
16893
|
+
}
|
|
16894
|
+
}
|
|
16895
|
+
}
|
|
16896
|
+
if (reviveState.size > 0 || renamed.size > 0) {
|
|
16897
|
+
const live = new Set(tasks.map((t) => t.sessionId));
|
|
16898
|
+
for (const id of reviveState.keys()) {
|
|
16899
|
+
if (!live.has(id)) reviveState.delete(id);
|
|
16900
|
+
}
|
|
16901
|
+
for (const id of renamed) {
|
|
16902
|
+
if (!live.has(id)) renamed.delete(id);
|
|
16903
|
+
}
|
|
16904
|
+
}
|
|
16905
|
+
await bindAndNameSessions(
|
|
16906
|
+
bridge,
|
|
16907
|
+
boundWorkspace,
|
|
16908
|
+
tasks,
|
|
16909
|
+
renamed,
|
|
16910
|
+
spawnTimeoutMs,
|
|
16911
|
+
binding
|
|
16912
|
+
);
|
|
16913
|
+
}, "tick");
|
|
16914
|
+
let running = false;
|
|
16915
|
+
const timer = setInterval(() => {
|
|
16916
|
+
if (running) return;
|
|
16917
|
+
running = true;
|
|
16918
|
+
void tick().finally(() => {
|
|
16919
|
+
running = false;
|
|
16920
|
+
});
|
|
16921
|
+
}, intervalMs);
|
|
16922
|
+
timer.unref?.();
|
|
16923
|
+
let bindDebounce;
|
|
16924
|
+
const cronFilePath = getCronFilePath(boundWorkspace);
|
|
16925
|
+
const cronDir = path11.dirname(cronFilePath);
|
|
16926
|
+
const cronFileName = path11.basename(cronFilePath);
|
|
16927
|
+
let fileWatcher;
|
|
16928
|
+
try {
|
|
16929
|
+
fsSync.mkdirSync(cronDir, { recursive: true });
|
|
16930
|
+
fileWatcher = fsSync.watch(
|
|
16931
|
+
cronDir,
|
|
16932
|
+
{ persistent: false },
|
|
16933
|
+
(_event, filename) => {
|
|
16934
|
+
if (filename !== null && filename !== cronFileName) return;
|
|
16935
|
+
if (bindDebounce) clearTimeout(bindDebounce);
|
|
16936
|
+
bindDebounce = setTimeout(() => {
|
|
16937
|
+
if (running) return;
|
|
16938
|
+
running = true;
|
|
16939
|
+
void tick().finally(() => {
|
|
16940
|
+
running = false;
|
|
16941
|
+
});
|
|
16942
|
+
}, 500);
|
|
16943
|
+
bindDebounce.unref?.();
|
|
16944
|
+
}
|
|
16945
|
+
);
|
|
16946
|
+
fileWatcher.on("error", () => {
|
|
16947
|
+
});
|
|
16948
|
+
} catch {
|
|
16949
|
+
}
|
|
16950
|
+
let stopped = false;
|
|
16951
|
+
return {
|
|
16952
|
+
stop: /* @__PURE__ */ __name(() => {
|
|
16953
|
+
if (stopped) return;
|
|
16954
|
+
stopped = true;
|
|
16955
|
+
clearInterval(timer);
|
|
16956
|
+
if (bindDebounce) clearTimeout(bindDebounce);
|
|
16957
|
+
fileWatcher?.close();
|
|
16958
|
+
}, "stop"),
|
|
16959
|
+
tick
|
|
16960
|
+
};
|
|
16961
|
+
}
|
|
16962
|
+
__name(startScheduledTaskKeepalive, "startScheduledTaskKeepalive");
|
|
16963
|
+
var REHYDRATE_LOAD_TIMEOUT_MS = 3e4;
|
|
16964
|
+
var REHYDRATE_MAX_CONCURRENCY = 4;
|
|
16965
|
+
async function rehydrateScheduledTaskSessions(deps) {
|
|
16966
|
+
const { bridge, boundWorkspace } = deps;
|
|
16967
|
+
const timeoutMs = deps.loadTimeoutMs ?? REHYDRATE_LOAD_TIMEOUT_MS;
|
|
16968
|
+
let tasks;
|
|
16969
|
+
try {
|
|
16970
|
+
tasks = await readCronTasks(boundWorkspace);
|
|
16971
|
+
} catch (err) {
|
|
16972
|
+
log.debug("rehydrate: readCronTasks failed", err);
|
|
16973
|
+
return { loaded: [], failed: [] };
|
|
16974
|
+
}
|
|
16975
|
+
const sessionIds = collectBoundSessionIds(tasks);
|
|
16976
|
+
const loaded = [];
|
|
16977
|
+
const failed = [];
|
|
16978
|
+
const loadOne = /* @__PURE__ */ __name(async (sessionId) => {
|
|
16979
|
+
const load = bridge.loadSession({
|
|
16980
|
+
sessionId,
|
|
16981
|
+
workspaceCwd: boundWorkspace,
|
|
16982
|
+
historyReplay: "response"
|
|
16983
|
+
});
|
|
16984
|
+
void load.catch(() => {
|
|
16985
|
+
});
|
|
16986
|
+
try {
|
|
16987
|
+
await withTimeout(load, timeoutMs, `loadSession(${sessionId})`);
|
|
16988
|
+
loaded.push(sessionId);
|
|
16989
|
+
} catch (err) {
|
|
16990
|
+
failed.push(sessionId);
|
|
16991
|
+
try {
|
|
16992
|
+
deps.onError?.(sessionId, err);
|
|
16993
|
+
} catch {
|
|
16994
|
+
}
|
|
16995
|
+
}
|
|
16996
|
+
}, "loadOne");
|
|
16997
|
+
const queue = sessionIds.slice();
|
|
16998
|
+
const worker = /* @__PURE__ */ __name(async () => {
|
|
16999
|
+
for (let sessionId = queue.shift(); sessionId !== void 0; sessionId = queue.shift()) {
|
|
17000
|
+
await loadOne(sessionId);
|
|
17001
|
+
}
|
|
17002
|
+
}, "worker");
|
|
17003
|
+
await Promise.all(
|
|
17004
|
+
Array.from(
|
|
17005
|
+
{ length: Math.min(REHYDRATE_MAX_CONCURRENCY, queue.length) },
|
|
17006
|
+
() => worker()
|
|
17007
|
+
)
|
|
17008
|
+
);
|
|
17009
|
+
return { loaded, failed };
|
|
17010
|
+
}
|
|
17011
|
+
__name(rehydrateScheduledTaskSessions, "rehydrateScheduledTaskSessions");
|
|
17012
|
+
function withTimeout(p, ms, label) {
|
|
17013
|
+
return new Promise((resolve4, reject) => {
|
|
17014
|
+
const timer = setTimeout(() => {
|
|
17015
|
+
reject(new Error(`${label} timed out after ${ms}ms`));
|
|
17016
|
+
}, ms);
|
|
17017
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
17018
|
+
p.then(
|
|
17019
|
+
(v) => {
|
|
17020
|
+
clearTimeout(timer);
|
|
17021
|
+
resolve4(v);
|
|
17022
|
+
},
|
|
17023
|
+
(e) => {
|
|
17024
|
+
clearTimeout(timer);
|
|
17025
|
+
reject(e);
|
|
17026
|
+
}
|
|
17027
|
+
);
|
|
17028
|
+
});
|
|
17029
|
+
}
|
|
17030
|
+
__name(withTimeout, "withTimeout");
|
|
17031
|
+
|
|
16433
17032
|
// packages/cli/src/serve/routes/workspace-status.ts
|
|
16434
17033
|
init_esbuild_shims();
|
|
16435
17034
|
function registerWorkspaceStatusRoutes(app, deps) {
|
|
@@ -17579,7 +18178,7 @@ __name(registerSseEventsRoutes, "registerSseEventsRoutes");
|
|
|
17579
18178
|
// packages/cli/src/serve/routes/a2ui-action.ts
|
|
17580
18179
|
init_esbuild_shims();
|
|
17581
18180
|
import * as fsp4 from "node:fs/promises";
|
|
17582
|
-
import * as
|
|
18181
|
+
import * as path12 from "node:path";
|
|
17583
18182
|
var A2UI_MIME = "application/a2ui+json";
|
|
17584
18183
|
var ACTION_TOOL = "action";
|
|
17585
18184
|
var CALL_TIMEOUT_MS = 15e3;
|
|
@@ -17599,7 +18198,7 @@ __name(usableServerConfig, "usableServerConfig");
|
|
|
17599
18198
|
async function findFromSettingsFile(workspaceCwd) {
|
|
17600
18199
|
try {
|
|
17601
18200
|
const raw = await fsp4.readFile(
|
|
17602
|
-
|
|
18201
|
+
path12.join(workspaceCwd, ".qwen", "settings.json"),
|
|
17603
18202
|
"utf8"
|
|
17604
18203
|
);
|
|
17605
18204
|
const settings = JSON.parse(raw);
|
|
@@ -17724,7 +18323,7 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
|
|
|
17724
18323
|
|
|
17725
18324
|
// packages/cli/src/serve/server/fs-factory.ts
|
|
17726
18325
|
init_esbuild_shims();
|
|
17727
|
-
import * as
|
|
18326
|
+
import * as path13 from "node:path";
|
|
17728
18327
|
var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
|
|
17729
18328
|
function createDefaultFsAuditEmit() {
|
|
17730
18329
|
const WARN_EVERY = 100;
|
|
@@ -17798,14 +18397,14 @@ function parseIdeWorkspacePathEnv(value) {
|
|
|
17798
18397
|
const parsed = JSON.parse(value);
|
|
17799
18398
|
if (Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
|
|
17800
18399
|
return parsed.filter(
|
|
17801
|
-
(workspace) => workspace.length > 0 &&
|
|
18400
|
+
(workspace) => workspace.length > 0 && path13.isAbsolute(workspace)
|
|
17802
18401
|
);
|
|
17803
18402
|
}
|
|
17804
18403
|
throw new Error("IDE workspace path JSON must be a string array");
|
|
17805
18404
|
} catch {
|
|
17806
18405
|
}
|
|
17807
18406
|
}
|
|
17808
|
-
return value.split(
|
|
18407
|
+
return value.split(path13.delimiter).filter((workspace) => workspace.length > 0 && path13.isAbsolute(workspace));
|
|
17809
18408
|
}
|
|
17810
18409
|
__name(parseIdeWorkspacePathEnv, "parseIdeWorkspacePathEnv");
|
|
17811
18410
|
function dropNestedWorkspacesPreservingPrimary(workspaces) {
|
|
@@ -17831,17 +18430,17 @@ __name(dropNestedWorkspacesPreservingPrimary, "dropNestedWorkspacesPreservingPri
|
|
|
17831
18430
|
// packages/cli/src/serve/server/telemetry.ts
|
|
17832
18431
|
init_esbuild_shims();
|
|
17833
18432
|
function resolveDaemonTelemetryRoute(req) {
|
|
17834
|
-
const
|
|
17835
|
-
if (req.method === "POST" &&
|
|
18433
|
+
const path14 = req.path.replace(/\/$/, "") || "/";
|
|
18434
|
+
if (req.method === "POST" && path14 === "/session") {
|
|
17836
18435
|
return { route: "POST /session" };
|
|
17837
18436
|
}
|
|
17838
|
-
if (req.method === "POST" &&
|
|
18437
|
+
if (req.method === "POST" && path14 === "/sessions/delete") {
|
|
17839
18438
|
return { route: "POST /sessions/delete" };
|
|
17840
18439
|
}
|
|
17841
|
-
if (req.method === "GET" &&
|
|
18440
|
+
if (req.method === "GET" && path14 === "/daemon/status") {
|
|
17842
18441
|
return { route: "GET /daemon/status" };
|
|
17843
18442
|
}
|
|
17844
|
-
const sessionAction =
|
|
18443
|
+
const sessionAction = path14.match(
|
|
17845
18444
|
/^\/session\/([^/]+)\/(load|resume|prompt|cancel|recap|btw|mid-turn-message|model|shell|detach|rewind|approval-mode|language|a2ui-action)$/
|
|
17846
18445
|
);
|
|
17847
18446
|
const sessionActionId = sessionAction?.[1];
|
|
@@ -17852,14 +18451,14 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
17852
18451
|
sessionId: sessionActionId
|
|
17853
18452
|
};
|
|
17854
18453
|
}
|
|
17855
|
-
const sessionMetadata =
|
|
18454
|
+
const sessionMetadata = path14.match(/^\/session\/([^/]+)\/metadata$/);
|
|
17856
18455
|
if (sessionMetadata?.[1] && req.method === "PATCH") {
|
|
17857
18456
|
return {
|
|
17858
18457
|
route: "PATCH /session/:id/metadata",
|
|
17859
18458
|
sessionId: sessionMetadata[1]
|
|
17860
18459
|
};
|
|
17861
18460
|
}
|
|
17862
|
-
const sessionArtifacts =
|
|
18461
|
+
const sessionArtifacts = path14.match(/^\/session\/([^/]+)\/artifacts$/);
|
|
17863
18462
|
if (sessionArtifacts?.[1]) {
|
|
17864
18463
|
if (req.method === "GET") {
|
|
17865
18464
|
return {
|
|
@@ -17874,7 +18473,7 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
17874
18473
|
};
|
|
17875
18474
|
}
|
|
17876
18475
|
}
|
|
17877
|
-
const sessionArtifact =
|
|
18476
|
+
const sessionArtifact = path14.match(
|
|
17878
18477
|
/^\/session\/([^/]+)\/artifacts\/([^/]+)$/
|
|
17879
18478
|
);
|
|
17880
18479
|
if (sessionArtifact?.[1] && req.method === "DELETE") {
|
|
@@ -17883,7 +18482,7 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
17883
18482
|
sessionId: sessionArtifact[1]
|
|
17884
18483
|
};
|
|
17885
18484
|
}
|
|
17886
|
-
const sessionPermission =
|
|
18485
|
+
const sessionPermission = path14.match(
|
|
17887
18486
|
/^\/session\/([^/]+)\/permission\/([^/]+)$/
|
|
17888
18487
|
);
|
|
17889
18488
|
if (sessionPermission?.[1] && sessionPermission?.[2] && req.method === "POST") {
|
|
@@ -17894,7 +18493,7 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
17894
18493
|
...rawRequestId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawRequestId) ? { permissionRequestId: rawRequestId } : {}
|
|
17895
18494
|
};
|
|
17896
18495
|
}
|
|
17897
|
-
const globalPermission =
|
|
18496
|
+
const globalPermission = path14.match(/^\/permission\/([^/]+)$/);
|
|
17898
18497
|
if (globalPermission?.[1] && req.method === "POST") {
|
|
17899
18498
|
const rawRequestId = globalPermission[1];
|
|
17900
18499
|
return {
|
|
@@ -17902,66 +18501,66 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
17902
18501
|
...rawRequestId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawRequestId) ? { permissionRequestId: rawRequestId } : {}
|
|
17903
18502
|
};
|
|
17904
18503
|
}
|
|
17905
|
-
const deleteSession =
|
|
18504
|
+
const deleteSession = path14.match(/^\/session\/([^/]+)$/);
|
|
17906
18505
|
const deleteSessionId = deleteSession?.[1];
|
|
17907
18506
|
if (deleteSessionId && req.method === "DELETE") {
|
|
17908
18507
|
return { route: "DELETE /session/:id", sessionId: deleteSessionId };
|
|
17909
18508
|
}
|
|
17910
|
-
if (req.method === "GET" && /^\/workspace\/[^/]+\/sessions$/.test(
|
|
18509
|
+
if (req.method === "GET" && /^\/workspace\/[^/]+\/sessions$/.test(path14)) {
|
|
17911
18510
|
return { route: "GET /workspace/:id/sessions" };
|
|
17912
18511
|
}
|
|
17913
|
-
if (req.method === "POST" &&
|
|
18512
|
+
if (req.method === "POST" && path14 === "/workspace/init") {
|
|
17914
18513
|
return { route: "POST /workspace/init" };
|
|
17915
18514
|
}
|
|
17916
|
-
if (req.method === "POST" &&
|
|
18515
|
+
if (req.method === "POST" && path14 === "/workspace/setup-github") {
|
|
17917
18516
|
return { route: "POST /workspace/setup-github" };
|
|
17918
18517
|
}
|
|
17919
|
-
if (req.method === "POST" &&
|
|
18518
|
+
if (req.method === "POST" && path14 === "/workspace/reload") {
|
|
17920
18519
|
return { route: "POST /workspace/reload" };
|
|
17921
18520
|
}
|
|
17922
|
-
const mcpRestart =
|
|
18521
|
+
const mcpRestart = path14.match(/^\/workspace\/mcp\/([^/]+)\/restart$/);
|
|
17923
18522
|
if (mcpRestart?.[1] && req.method === "POST") {
|
|
17924
18523
|
return { route: "POST /workspace/mcp/:server/restart" };
|
|
17925
18524
|
}
|
|
17926
|
-
if (req.method === "POST" &&
|
|
18525
|
+
if (req.method === "POST" && path14 === "/workspace/mcp/servers") {
|
|
17927
18526
|
return { route: "POST /workspace/mcp/servers" };
|
|
17928
18527
|
}
|
|
17929
|
-
const mcpDelete =
|
|
18528
|
+
const mcpDelete = path14.match(/^\/workspace\/mcp\/servers\/([^/]+)$/);
|
|
17930
18529
|
if (mcpDelete?.[1] && req.method === "DELETE") {
|
|
17931
18530
|
return { route: "DELETE /workspace/mcp/servers/:name" };
|
|
17932
18531
|
}
|
|
17933
|
-
if (req.method === "POST" &&
|
|
18532
|
+
if (req.method === "POST" && path14 === "/workspace/auth/device-flow") {
|
|
17934
18533
|
return { route: "POST /workspace/auth/device-flow" };
|
|
17935
18534
|
}
|
|
17936
|
-
const deviceFlowDelete =
|
|
18535
|
+
const deviceFlowDelete = path14.match(
|
|
17937
18536
|
/^\/workspace\/auth\/device-flow\/([^/]+)$/
|
|
17938
18537
|
);
|
|
17939
18538
|
if (deviceFlowDelete?.[1] && req.method === "DELETE") {
|
|
17940
18539
|
return { route: "DELETE /workspace/auth/device-flow/:id" };
|
|
17941
18540
|
}
|
|
17942
|
-
const toolEnable =
|
|
18541
|
+
const toolEnable = path14.match(/^\/workspace\/tools\/([^/]+)\/enable$/);
|
|
17943
18542
|
if (toolEnable?.[1] && req.method === "POST") {
|
|
17944
18543
|
return { route: "POST /workspace/tools/:name/enable" };
|
|
17945
18544
|
}
|
|
17946
|
-
if (
|
|
18545
|
+
if (path14 === "/workspace/settings") {
|
|
17947
18546
|
if (req.method === "GET") return { route: "GET /workspace/settings" };
|
|
17948
18547
|
if (req.method === "POST") return { route: "POST /workspace/settings" };
|
|
17949
18548
|
}
|
|
17950
|
-
if (
|
|
18549
|
+
if (path14 === "/workspace/permissions") {
|
|
17951
18550
|
if (req.method === "GET") return { route: "GET /workspace/permissions" };
|
|
17952
18551
|
if (req.method === "POST") return { route: "POST /workspace/permissions" };
|
|
17953
18552
|
}
|
|
17954
|
-
if (
|
|
18553
|
+
if (path14 === "/workspace/trust") {
|
|
17955
18554
|
if (req.method === "GET") return { route: "GET /workspace/trust" };
|
|
17956
18555
|
}
|
|
17957
|
-
if (req.method === "POST" &&
|
|
18556
|
+
if (req.method === "POST" && path14 === "/workspace/trust/request") {
|
|
17958
18557
|
return { route: "POST /workspace/trust/request" };
|
|
17959
18558
|
}
|
|
17960
|
-
if (
|
|
18559
|
+
if (path14 === "/workspace/voice") {
|
|
17961
18560
|
if (req.method === "GET") return { route: "GET /workspace/voice" };
|
|
17962
18561
|
if (req.method === "POST") return { route: "POST /workspace/voice" };
|
|
17963
18562
|
}
|
|
17964
|
-
if (req.method === "POST" &&
|
|
18563
|
+
if (req.method === "POST" && path14 === "/workspace/voice/transcribe") {
|
|
17965
18564
|
return { route: "POST /workspace/voice/transcribe" };
|
|
17966
18565
|
}
|
|
17967
18566
|
return void 0;
|
|
@@ -18329,10 +18928,10 @@ function installRateLimiter(app, opts, daemonLog) {
|
|
|
18329
18928
|
{ tier, key: key.slice(0, 64) }
|
|
18330
18929
|
);
|
|
18331
18930
|
} : void 0,
|
|
18332
|
-
onError: daemonLog ? (err,
|
|
18931
|
+
onError: daemonLog ? (err, path14) => {
|
|
18333
18932
|
daemonLog.warn(
|
|
18334
18933
|
`rate limiter error (fail-open): ${err instanceof Error ? err.message : String(err)}`,
|
|
18335
|
-
{ path:
|
|
18934
|
+
{ path: path14 }
|
|
18336
18935
|
);
|
|
18337
18936
|
} : void 0
|
|
18338
18937
|
});
|
|
@@ -18385,14 +18984,69 @@ __name(installSelfOriginStripMiddleware, "installSelfOriginStripMiddleware");
|
|
|
18385
18984
|
|
|
18386
18985
|
// packages/cli/src/serve/workspace-registry.ts
|
|
18387
18986
|
init_esbuild_shims();
|
|
18388
|
-
function
|
|
18389
|
-
|
|
18987
|
+
function createWorkspaceRegistry(inputRuntimes) {
|
|
18988
|
+
if (inputRuntimes.length === 0) {
|
|
18989
|
+
throw new Error(
|
|
18990
|
+
"WorkspaceRegistry requires at least one workspace runtime."
|
|
18991
|
+
);
|
|
18992
|
+
}
|
|
18993
|
+
const primaryRuntimes = inputRuntimes.filter((runtime) => runtime.primary);
|
|
18994
|
+
if (primaryRuntimes.length !== 1) {
|
|
18995
|
+
throw new Error(
|
|
18996
|
+
"WorkspaceRegistry requires exactly one primary workspace runtime."
|
|
18997
|
+
);
|
|
18998
|
+
}
|
|
18999
|
+
const byCwd = /* @__PURE__ */ new Map();
|
|
19000
|
+
const byId = /* @__PURE__ */ new Map();
|
|
19001
|
+
for (const runtime of inputRuntimes) {
|
|
19002
|
+
if (byCwd.has(runtime.workspaceCwd)) {
|
|
19003
|
+
throw new Error(
|
|
19004
|
+
`Duplicate workspace runtime cwd ${JSON.stringify(
|
|
19005
|
+
runtime.workspaceCwd
|
|
19006
|
+
)}.`
|
|
19007
|
+
);
|
|
19008
|
+
}
|
|
19009
|
+
byCwd.set(runtime.workspaceCwd, runtime);
|
|
19010
|
+
if (byId.has(runtime.workspaceId)) {
|
|
19011
|
+
throw new Error(
|
|
19012
|
+
`Duplicate workspace runtime id ${JSON.stringify(
|
|
19013
|
+
runtime.workspaceId
|
|
19014
|
+
)}.`
|
|
19015
|
+
);
|
|
19016
|
+
}
|
|
19017
|
+
byId.set(runtime.workspaceId, runtime);
|
|
19018
|
+
}
|
|
19019
|
+
const runtimes = Object.freeze([...inputRuntimes]);
|
|
19020
|
+
const primary = primaryRuntimes[0];
|
|
18390
19021
|
return {
|
|
18391
|
-
primary
|
|
19022
|
+
primary,
|
|
18392
19023
|
list: /* @__PURE__ */ __name(() => runtimes, "list"),
|
|
18393
|
-
getByWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) =>
|
|
19024
|
+
getByWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) => byCwd.get(workspaceCwd), "getByWorkspaceCwd"),
|
|
19025
|
+
getByWorkspaceId: /* @__PURE__ */ __name((workspaceId) => byId.get(workspaceId), "getByWorkspaceId"),
|
|
19026
|
+
resolveWorkspaceCwd: /* @__PURE__ */ __name((workspaceCwd) => workspaceCwd === void 0 ? primary : byCwd.get(workspaceCwd), "resolveWorkspaceCwd"),
|
|
19027
|
+
resolveLiveSessionOwner: /* @__PURE__ */ __name((sessionId) => {
|
|
19028
|
+
const matches = [];
|
|
19029
|
+
for (const runtime of runtimes) {
|
|
19030
|
+
try {
|
|
19031
|
+
runtime.bridge.getSessionSummary(sessionId);
|
|
19032
|
+
matches.push(runtime);
|
|
19033
|
+
} catch (err) {
|
|
19034
|
+
if (err instanceof SessionNotFoundError) continue;
|
|
19035
|
+
throw err;
|
|
19036
|
+
}
|
|
19037
|
+
}
|
|
19038
|
+
if (matches.length === 0) return { kind: "not_found" };
|
|
19039
|
+
if (matches.length === 1) {
|
|
19040
|
+
return { kind: "found", runtime: matches[0] };
|
|
19041
|
+
}
|
|
19042
|
+
return { kind: "ambiguous", runtimes: matches };
|
|
19043
|
+
}, "resolveLiveSessionOwner")
|
|
18394
19044
|
};
|
|
18395
19045
|
}
|
|
19046
|
+
__name(createWorkspaceRegistry, "createWorkspaceRegistry");
|
|
19047
|
+
function createSingleWorkspaceRegistry(runtime) {
|
|
19048
|
+
return createWorkspaceRegistry([runtime]);
|
|
19049
|
+
}
|
|
18396
19050
|
__name(createSingleWorkspaceRegistry, "createSingleWorkspaceRegistry");
|
|
18397
19051
|
|
|
18398
19052
|
// packages/cli/src/serve/routes/workspace-lifecycle.ts
|
|
@@ -18693,37 +19347,101 @@ __name(registerWorkspaceToolsRoutes, "registerWorkspaceToolsRoutes");
|
|
|
18693
19347
|
|
|
18694
19348
|
// packages/cli/src/serve/server.ts
|
|
18695
19349
|
var warnedDefaultTrust = false;
|
|
19350
|
+
function describeRegistryPrimaryForConflict(registry) {
|
|
19351
|
+
return `registry primary cwd=${JSON.stringify(registry.primary.workspaceCwd)}, workspaceId=${JSON.stringify(registry.primary.workspaceId)}`;
|
|
19352
|
+
}
|
|
19353
|
+
__name(describeRegistryPrimaryForConflict, "describeRegistryPrimaryForConflict");
|
|
19354
|
+
var DEFAULT_SESSION_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
19355
|
+
var KEEPALIVE_MIN_INTERVAL_MS = 3e4;
|
|
19356
|
+
var KEEPALIVE_MAX_INTERVAL_MS = 10 * 6e4;
|
|
19357
|
+
function computeKeepaliveIntervalMs(idleTimeoutMs) {
|
|
19358
|
+
if (idleTimeoutMs <= 0) return KEEPALIVE_MAX_INTERVAL_MS;
|
|
19359
|
+
const target = Math.min(
|
|
19360
|
+
Math.max(KEEPALIVE_MIN_INTERVAL_MS, Math.floor(idleTimeoutMs / 3)),
|
|
19361
|
+
KEEPALIVE_MAX_INTERVAL_MS
|
|
19362
|
+
);
|
|
19363
|
+
return Math.max(1, Math.min(target, Math.floor(idleTimeoutMs / 2)));
|
|
19364
|
+
}
|
|
19365
|
+
__name(computeKeepaliveIntervalMs, "computeKeepaliveIntervalMs");
|
|
18696
19366
|
function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
18697
19367
|
const app = (0, import_express4.default)();
|
|
18698
|
-
const
|
|
18699
|
-
|
|
19368
|
+
const injectedWorkspaceRegistry = deps.workspaceRegistry;
|
|
19369
|
+
const boundWorkspace = injectedWorkspaceRegistry?.primary.workspaceCwd ?? deps.boundWorkspace ?? canonicalizeWorkspace(opts.workspace ?? process.cwd());
|
|
19370
|
+
if (injectedWorkspaceRegistry) {
|
|
19371
|
+
const primary = injectedWorkspaceRegistry.primary;
|
|
19372
|
+
const registryConflictCandidates = [
|
|
19373
|
+
{
|
|
19374
|
+
depName: "deps.boundWorkspace",
|
|
19375
|
+
depValue: deps.boundWorkspace,
|
|
19376
|
+
registryValue: primary.workspaceCwd,
|
|
19377
|
+
detail: `deps.boundWorkspace=${JSON.stringify(deps.boundWorkspace)}`
|
|
19378
|
+
},
|
|
19379
|
+
{
|
|
19380
|
+
depName: "deps.bridge",
|
|
19381
|
+
depValue: deps.bridge,
|
|
19382
|
+
registryValue: primary.bridge,
|
|
19383
|
+
detail: "deps.bridge is a different object"
|
|
19384
|
+
},
|
|
19385
|
+
{
|
|
19386
|
+
depName: "deps.workspace",
|
|
19387
|
+
depValue: deps.workspace,
|
|
19388
|
+
registryValue: primary.workspaceService,
|
|
19389
|
+
detail: "deps.workspace is a different object"
|
|
19390
|
+
},
|
|
19391
|
+
{
|
|
19392
|
+
depName: "deps.fsFactory",
|
|
19393
|
+
depValue: deps.fsFactory,
|
|
19394
|
+
registryValue: primary.routeFileSystemFactory,
|
|
19395
|
+
detail: "deps.fsFactory is a different object"
|
|
19396
|
+
},
|
|
19397
|
+
{
|
|
19398
|
+
depName: "deps.clientMcpSenderRegistry",
|
|
19399
|
+
depValue: deps.clientMcpSenderRegistry,
|
|
19400
|
+
registryValue: primary.clientMcpSenderRegistry,
|
|
19401
|
+
detail: "deps.clientMcpSenderRegistry is a different object"
|
|
19402
|
+
}
|
|
19403
|
+
];
|
|
19404
|
+
for (const candidate of registryConflictCandidates) {
|
|
19405
|
+
if (candidate.depValue === void 0 || candidate.depValue === candidate.registryValue) {
|
|
19406
|
+
continue;
|
|
19407
|
+
}
|
|
19408
|
+
throw new Error(
|
|
19409
|
+
`createServeApp: workspaceRegistry conflicts with ${candidate.depName}: ${describeRegistryPrimaryForConflict(
|
|
19410
|
+
injectedWorkspaceRegistry
|
|
19411
|
+
)}; ${candidate.detail}.`
|
|
19412
|
+
);
|
|
19413
|
+
}
|
|
19414
|
+
}
|
|
19415
|
+
if (!injectedWorkspaceRegistry && !deps.fsFactory && !deps.bridge && !warnedDefaultTrust) {
|
|
18700
19416
|
warnedDefaultTrust = true;
|
|
18701
19417
|
process.stderr.write(
|
|
18702
19418
|
"qwen serve: createServeApp default fsFactory uses trusted=false \u2014 agent ACP writeTextFile calls will reject with untrusted_workspace. Inject deps.fsFactory (with explicit trust) or deps.bridge to override.\n"
|
|
18703
19419
|
);
|
|
18704
19420
|
}
|
|
18705
|
-
const fsFactory = resolveBridgeFsFactory({
|
|
19421
|
+
const fsFactory = injectedWorkspaceRegistry?.primary.routeFileSystemFactory ?? resolveBridgeFsFactory({
|
|
18706
19422
|
boundWorkspaces: [boundWorkspace],
|
|
18707
19423
|
injected: deps.fsFactory,
|
|
18708
19424
|
trusted: false
|
|
18709
19425
|
});
|
|
18710
19426
|
const tokenConfigured = typeof opts.token === "string" && opts.token.length > 0;
|
|
18711
19427
|
const sessionShellCommandEnabled = opts.enableSessionShell === true && tokenConfigured;
|
|
18712
|
-
if (opts.clientMcpOverWs === true && deps.bridge && !deps.clientMcpSenderRegistry) {
|
|
19428
|
+
if (opts.clientMcpOverWs === true && deps.bridge && !injectedWorkspaceRegistry && !deps.clientMcpSenderRegistry) {
|
|
18713
19429
|
throw new Error(
|
|
18714
19430
|
"createServeApp: deps.bridge requires deps.clientMcpSenderRegistry when clientMcpOverWs is enabled (the bridge is already wired to its own sender; a fresh registry here would be an orphan)."
|
|
18715
19431
|
);
|
|
18716
19432
|
}
|
|
18717
|
-
const clientMcpSenderRegistry = deps.clientMcpSenderRegistry ?? new ClientMcpSenderRegistry();
|
|
19433
|
+
const clientMcpSenderRegistry = injectedWorkspaceRegistry?.primary.clientMcpSenderRegistry ?? deps.clientMcpSenderRegistry ?? new ClientMcpSenderRegistry();
|
|
18718
19434
|
const { languageCodes, currentServeFeatures, invalidateServeFeaturesCache } = createServeFeatures({
|
|
18719
19435
|
opts,
|
|
18720
19436
|
boundWorkspace,
|
|
18721
19437
|
persistSettingAvailable: deps.persistSetting !== void 0,
|
|
18722
|
-
|
|
19438
|
+
// Registry injection supplies the primary workspace service through the
|
|
19439
|
+
// runtime, so it has the same reload surface as legacy deps.workspace.
|
|
19440
|
+
reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
|
|
18723
19441
|
sessionShellCommandEnabled
|
|
18724
19442
|
});
|
|
18725
19443
|
const statusProvider = deps.statusProvider ?? createDaemonStatusProvider();
|
|
18726
|
-
const bridge = deps.bridge ?? createAcpSessionBridge({
|
|
19444
|
+
const bridge = injectedWorkspaceRegistry?.primary.bridge ?? deps.bridge ?? createAcpSessionBridge({
|
|
18727
19445
|
maxSessions: opts.maxSessions,
|
|
18728
19446
|
maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
|
|
18729
19447
|
eventRingSize: opts.eventRingSize,
|
|
@@ -18753,7 +19471,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
18753
19471
|
const { daemonLog } = deps;
|
|
18754
19472
|
const sendBridgeError2 = /* @__PURE__ */ __name((res, err, ctx) => sendBridgeError(res, err, ctx, daemonLog), "sendBridgeError");
|
|
18755
19473
|
const sendPermissionVoteError2 = /* @__PURE__ */ __name((res, err, ctx) => sendPermissionVoteError(res, err, ctx, daemonLog), "sendPermissionVoteError");
|
|
18756
|
-
const workspace = deps.workspace ?? createDaemonWorkspaceService({
|
|
19474
|
+
const workspace = injectedWorkspaceRegistry?.primary.workspaceService ?? deps.workspace ?? createDaemonWorkspaceService({
|
|
18757
19475
|
boundWorkspace,
|
|
18758
19476
|
contextFilename: deps.contextFilename ?? "QWEN.md",
|
|
18759
19477
|
statusProvider,
|
|
@@ -18777,8 +19495,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
18777
19495
|
bridge.publishWorkspaceEvent(event);
|
|
18778
19496
|
}, "publishWorkspaceEvent")
|
|
18779
19497
|
});
|
|
18780
|
-
const workspaceRegistry = createSingleWorkspaceRegistry({
|
|
19498
|
+
const workspaceRegistry = injectedWorkspaceRegistry ?? createSingleWorkspaceRegistry({
|
|
19499
|
+
workspaceId: hashDaemonWorkspace(boundWorkspace),
|
|
18781
19500
|
workspaceCwd: boundWorkspace,
|
|
19501
|
+
primary: true,
|
|
19502
|
+
trusted: deps.primaryWorkspaceTrusted ?? false,
|
|
19503
|
+
env: { mode: "parent-process", overlayKeys: [] },
|
|
18782
19504
|
bridge,
|
|
18783
19505
|
workspaceService: workspace,
|
|
18784
19506
|
routeFileSystemFactory: fsFactory,
|
|
@@ -19032,9 +19754,39 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
19032
19754
|
registerScheduledTasksRoutes(app, {
|
|
19033
19755
|
boundWorkspace: primaryBoundWorkspace,
|
|
19034
19756
|
mutate,
|
|
19035
|
-
safeBody
|
|
19757
|
+
safeBody,
|
|
19758
|
+
bridge: deps.manageScheduledTaskSessions ? bridge : void 0
|
|
19036
19759
|
});
|
|
19037
19760
|
registerUsageStatsRoutes(app);
|
|
19761
|
+
if (deps.manageScheduledTaskSessions) {
|
|
19762
|
+
const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
19763
|
+
const keepalive = startScheduledTaskKeepalive({
|
|
19764
|
+
bridge,
|
|
19765
|
+
boundWorkspace,
|
|
19766
|
+
intervalMs: computeKeepaliveIntervalMs(idleTimeoutMs)
|
|
19767
|
+
});
|
|
19768
|
+
app.locals.stopScheduledTaskKeepalive = keepalive.stop;
|
|
19769
|
+
void rehydrateScheduledTaskSessions({
|
|
19770
|
+
bridge,
|
|
19771
|
+
boundWorkspace,
|
|
19772
|
+
onError: /* @__PURE__ */ __name((sessionId, err) => {
|
|
19773
|
+
process.stderr.write(
|
|
19774
|
+
`qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
|
|
19775
|
+
`
|
|
19776
|
+
);
|
|
19777
|
+
}, "onError")
|
|
19778
|
+
// Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
|
|
19779
|
+
// catches readCronTasks failures and per-session load errors internally
|
|
19780
|
+
// (returning { loaded, failed }), so this only guards an unexpected throw
|
|
19781
|
+
// from the function entry itself. Log rather than swallow it — a silent
|
|
19782
|
+
// failure here leaves every bound task dormant with no diagnostic.
|
|
19783
|
+
}).catch((err) => {
|
|
19784
|
+
process.stderr.write(
|
|
19785
|
+
`qwen serve: unexpected scheduled-task rehydration failure: ${err instanceof Error ? err.message : String(err)}
|
|
19786
|
+
`
|
|
19787
|
+
);
|
|
19788
|
+
});
|
|
19789
|
+
}
|
|
19038
19790
|
registerPermissionRoutes(app, {
|
|
19039
19791
|
bridge: primaryBridge,
|
|
19040
19792
|
mutate,
|
|
@@ -19104,6 +19856,7 @@ __name(createServeApp, "createServeApp");
|
|
|
19104
19856
|
export {
|
|
19105
19857
|
InvalidCursorError,
|
|
19106
19858
|
PromptDeadlineExceededError,
|
|
19859
|
+
computeKeepaliveIntervalMs,
|
|
19107
19860
|
createDefaultFsAuditEmit,
|
|
19108
19861
|
createServeApp,
|
|
19109
19862
|
detectFromLoopback,
|