@qwen-code/qwen-code 0.21.7 → 0.21.8-nightly.20260810.55e20db328
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/README.md +2 -0
- package/bundled/qc-helper/docs/configuration/settings.md +73 -59
- package/bundled/qc-helper/docs/extension/introduction.md +15 -1
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +40 -2
- package/bundled/qc-helper/docs/features/channels/feishu.md +13 -2
- package/bundled/qc-helper/docs/features/channels/github.md +13 -11
- package/bundled/qc-helper/docs/features/channels/gitlab.md +13 -11
- package/bundled/qc-helper/docs/features/channels/overview.md +49 -31
- package/bundled/qc-helper/docs/features/channels/plugins.md +2 -2
- package/bundled/qc-helper/docs/features/channels/qqbot.md +4 -2
- package/bundled/qc-helper/docs/features/channels/telegram.md +4 -2
- package/bundled/qc-helper/docs/features/channels/wecom.md +1 -1
- package/bundled/qc-helper/docs/features/code-review.md +4 -0
- package/bundled/qc-helper/docs/features/commands.md +1 -1
- package/bundled/qc-helper/docs/features/hooks.md +52 -0
- package/bundled/qc-helper/docs/integration-jetbrains.md +1 -0
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +10 -5
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +50 -36
- package/bundled/review/SKILL.md +32 -5
- package/chunks/{MaxSizedBox-ANWZBPTS.js → MaxSizedBox-A52T4GEU.js} +29 -25
- package/chunks/{StandaloneSessionPicker-XKS3VU3A.js → StandaloneSessionPicker-4J654SOB.js} +48 -44
- package/chunks/{acp-startup-profiler-ORIQ2CCQ.js → acp-startup-profiler-B5BYAMYQ.js} +2 -2
- package/chunks/{acpAgent-KUAZ3GCZ.js → acpAgent-65AM4AOR.js} +1833 -843
- package/chunks/{agent-T6PTGX5R.js → agent-SVQ7U7NJ.js} +28 -24
- package/chunks/{agent-headless-PR7YCB7S.js → agent-headless-XXGY2SQO.js} +28 -24
- package/chunks/{artifact-tool-U4VOZIK5.js → artifact-tool-N652YE4L.js} +1 -1
- package/chunks/{askUserQuestion-XOBQLPFA.js → askUserQuestion-ONW74PKJ.js} +1 -1
- package/chunks/{bridge-NU6YEEHK.js → bridge-Y32B5S3G.js} +34 -30
- package/chunks/{ca-NYKNH222.js → ca-ZLKAB4K3.js} +6 -0
- package/chunks/{channel-management-service-FSQ7SHYI.js → channel-management-service-PHELKOW2.js} +19 -10
- package/chunks/{channel-settings-store-35VQVUVV.js → channel-settings-store-OW43U6VB.js} +36 -32
- package/chunks/{channel-worker-group-JWQK224X.js → channel-worker-group-MSHT6CWR.js} +7 -7
- package/chunks/{channel-worker-manager-77E3OXRQ.js → channel-worker-manager-XXD3GDSK.js} +7 -7
- package/chunks/{channel-worker-supervisor-62YWUGP2.js → channel-worker-supervisor-IVSDIMI4.js} +4 -4
- package/chunks/{chunk-HYRDKNUY.js → chunk-2545EHZR.js} +1 -1
- package/chunks/{chunk-SPMY6CX6.js → chunk-2ASQDZSJ.js} +3 -3
- package/chunks/{chunk-CJXIIILK.js → chunk-2FRY5CRX.js} +1 -1
- package/chunks/{chunk-CNIID3TV.js → chunk-2UUMVNYT.js} +1 -1
- package/chunks/{chunk-KXSDEOFU.js → chunk-3KJQZEN3.js} +1 -1
- package/chunks/{chunk-22NBYCPD.js → chunk-3P2LV43B.js} +1 -1
- package/chunks/{chunk-Y7E5LNLO.js → chunk-47ZUMGGY.js} +2634 -2114
- package/chunks/{chunk-LA7YLSR6.js → chunk-4EOURKA4.js} +839 -153
- package/chunks/chunk-4JRM2BSM.js +48 -0
- package/chunks/{chunk-BGG4MBYD.js → chunk-4PYCZH2V.js} +4 -187
- package/chunks/{chunk-L4N6TIP7.js → chunk-4TRQPFDP.js} +4 -2
- package/chunks/{chunk-6XJMFJ4D.js → chunk-5WZL724W.js} +177 -120
- package/chunks/{chunk-23RZCH76.js → chunk-5ZTS3OQ3.js} +3 -3
- package/chunks/{chunk-VWOVHOTT.js → chunk-67EWJE77.js} +1 -1
- package/chunks/{chunk-3K7FH2KQ.js → chunk-67N6HB5H.js} +1310 -171
- package/chunks/{chunk-CXE7E23H.js → chunk-6Q5ABMTU.js} +45 -17
- package/chunks/{chunk-NG2R4N5O.js → chunk-6ZRFAKXK.js} +1 -1
- package/chunks/{chunk-RERATVSK.js → chunk-7XX5IBXL.js} +145 -10
- package/chunks/{chunk-S7CV4KO6.js → chunk-AKJQSWV4.js} +4 -4
- package/chunks/{chunk-5KH532V7.js → chunk-AUWN7BAG.js} +1 -1
- package/chunks/{chunk-DBOFL3LQ.js → chunk-BL65MO72.js} +10 -10
- package/chunks/{chunk-AKA24BGO.js → chunk-BT6GQIEJ.js} +1 -1
- package/chunks/{chunk-W7U4ESW2.js → chunk-CG3WBKJK.js} +1 -1
- package/chunks/{chunk-2M5N3DHY.js → chunk-CMOBWHWW.js} +1 -1
- package/chunks/chunk-COBO5EBO.js +135 -0
- package/chunks/chunk-CPG6P4GG.js +82 -0
- package/chunks/{chunk-3NB7TSE2.js → chunk-D2D7J3EW.js} +1 -1
- package/chunks/{chunk-NLREQJFK.js → chunk-DA4HRSBW.js} +15 -0
- package/chunks/{chunk-RNVQB725.js → chunk-DPMJLKUP.js} +2 -2
- package/chunks/{chunk-DIEFUBV6.js → chunk-DX3RGJMS.js} +218 -37
- package/chunks/{chunk-33ACCIIY.js → chunk-DZUO626D.js} +1 -1
- package/chunks/chunk-E2FPSSKP.js +244 -0
- package/chunks/{chunk-72LNFGUY.js → chunk-E2N554HK.js} +3 -3
- package/chunks/{chunk-6EOI4HOK.js → chunk-E2T7FLDU.js} +12 -17
- package/chunks/{chunk-EUQTXRKZ.js → chunk-EISUQQPS.js} +6 -6
- package/chunks/{chunk-H2UQ2M5Z.js → chunk-EUVOKP6Y.js} +96 -22
- package/chunks/{chunk-RMH5OWLD.js → chunk-F3II4BTZ.js} +1 -1
- package/chunks/{chunk-P3LEG54R.js → chunk-F6TUUA2U.js} +3 -3
- package/chunks/chunk-F6WFNA7U.js +22 -0
- package/chunks/{chunk-RZHU3ILK.js → chunk-FAD7OC7V.js} +4 -4
- package/chunks/{chunk-OMKQH5C5.js → chunk-FWWQIFDT.js} +6 -23
- package/chunks/{chunk-TLV2IMHR.js → chunk-FYB4GIDW.js} +3 -3
- package/chunks/{chunk-ZJ3VGYHK.js → chunk-GY24H6IA.js} +40 -22
- package/chunks/{chunk-P2AJ7FTI.js → chunk-H4JC7LZX.js} +1 -1
- package/chunks/{chunk-55LYDVPU.js → chunk-HDYQYYWB.js} +1 -1
- package/chunks/{chunk-PQBHU2IA.js → chunk-HKI3KHAO.js} +11 -11
- package/chunks/{chunk-Y4NGLFGJ.js → chunk-HUWENAHO.js} +1 -1
- package/chunks/{chunk-3ULCB3NE.js → chunk-HV76SFIA.js} +1 -1
- package/chunks/{chunk-CSZEXZBE.js → chunk-HWXGX534.js} +3 -3
- package/chunks/{chunk-E33LOKRA.js → chunk-I5VM3SKY.js} +22 -5
- package/chunks/{chunk-LZC3B5N2.js → chunk-IA7TGCN2.js} +2 -2
- package/chunks/{chunk-RGSBTHSU.js → chunk-KMS57JDD.js} +137 -7
- package/chunks/{chunk-VOARQPTA.js → chunk-KP25NJNM.js} +65 -21
- package/chunks/{chunk-6M26GBKX.js → chunk-L2AFWWJE.js} +42 -3
- package/chunks/{chunk-ZXU5UHMI.js → chunk-LHEC5V6G.js} +2 -2
- package/chunks/{chunk-J26HHFI5.js → chunk-LP2QGNSP.js} +32 -2
- package/chunks/{chunk-R574ATRM.js → chunk-M2PNLYGY.js} +41 -0
- package/chunks/{chunk-MKVZE4ZJ.js → chunk-MFDYOYZZ.js} +3 -2
- package/chunks/{chunk-ALGGS7UH.js → chunk-NPQ5ZKRP.js} +82 -1
- package/chunks/{chunk-YHEEE624.js → chunk-NV3F44FL.js} +7 -3
- package/chunks/{chunk-6GONZVLS.js → chunk-NZMXUSKS.js} +1 -1
- package/chunks/{chunk-HQB2KUAN.js → chunk-O277O7U6.js} +1 -1
- package/chunks/{chunk-Y4EWSQF7.js → chunk-OBP6QWD5.js} +2 -2
- package/chunks/{chunk-CYR3HI5X.js → chunk-OQTXYMKW.js} +2 -2
- package/chunks/{chunk-TYKC75AX.js → chunk-OR6R3IUW.js} +2 -2
- package/chunks/{chunk-TRLYP7OF.js → chunk-OSVH4SMN.js} +16 -141
- package/chunks/{chunk-FPM27XN4.js → chunk-OW2BWT2P.js} +4 -4
- package/chunks/{chunk-TDXGKHDN.js → chunk-P5ULXPK5.js} +2 -2
- package/chunks/{chunk-24ER7UV4.js → chunk-PBRVUF5B.js} +1 -1
- package/chunks/{chunk-LKRMNRSN.js → chunk-PDPFQ2FO.js} +2 -0
- package/chunks/{chunk-2VSTGY6M.js → chunk-PJRW65JO.js} +1 -1
- package/chunks/{chunk-6HVUFDS2.js → chunk-PNVPFARW.js} +22 -13
- package/chunks/{chunk-IC4Z6LX6.js → chunk-PYQADEFD.js} +5 -0
- package/chunks/chunk-R4ZA6GBK.js +208 -0
- package/chunks/{chunk-KR4ZSC7K.js → chunk-RMPLEWF3.js} +3 -3
- package/chunks/{chunk-EORNAQDT.js → chunk-RQ6U2JJQ.js} +1 -1
- package/chunks/{chunk-AE77C5ZU.js → chunk-RYQMJCUO.js} +1 -1
- package/chunks/{chunk-6UWFTUQL.js → chunk-S5CULOHB.js} +75 -31
- package/chunks/{chunk-7UFKAV7Y.js → chunk-S6HYI3MF.js} +2 -2
- package/chunks/chunk-SAH4BD2J.js +92 -0
- package/chunks/chunk-SR7RZ4MS.js +202 -0
- package/chunks/{chunk-QETYKPMG.js → chunk-T2O6NIOY.js} +1 -1
- package/chunks/chunk-TQOF5KBL.js +71 -0
- package/chunks/{chunk-OHJLEW5J.js → chunk-TWFFY5BP.js} +4 -4
- package/chunks/{chunk-SCI7K3GM.js → chunk-TXO5BMR2.js} +19 -10
- package/chunks/{chunk-YJQCUTT2.js → chunk-UAB6J2IE.js} +4 -4
- package/chunks/{chunk-OFI7IGST.js → chunk-UGUKH3SU.js} +10 -10
- package/chunks/{chunk-SHZYHGQH.js → chunk-V2226RFW.js} +1 -1
- package/chunks/{chunk-KKJJB5X6.js → chunk-V47QNK5W.js} +1526 -833
- package/chunks/{chunk-W4B7UBUS.js → chunk-VHXPSL57.js} +6 -6
- package/chunks/{chunk-WUC6ZFXO.js → chunk-VKJ4KTPJ.js} +1 -1
- package/chunks/{chunk-MAJS7AT4.js → chunk-VNNWAZSI.js} +2 -2
- package/chunks/{chunk-BVWVWGLE.js → chunk-WAUGQKUU.js} +4 -64
- package/chunks/{chunk-OH2VKQXH.js → chunk-WH6QMLUW.js} +37 -30
- package/chunks/{chunk-PJOBIWUG.js → chunk-WQYWK4DG.js} +1 -1
- package/chunks/{chunk-LEMXGVEP.js → chunk-YFRFZCIP.js} +3 -3
- package/chunks/{chunk-2U3WZGZG.js → chunk-YGT2AUJ7.js} +103 -135
- package/chunks/{chunk-6XU3PH66.js → chunk-YR7ZQ4RD.js} +22 -69
- package/chunks/{chunk-OA4JVLSA.js → chunk-Z7VOMGDC.js} +22 -1
- package/chunks/{chunk-RUL4S3K3.js → chunk-ZCJBCKL5.js} +175 -60
- package/chunks/{chunk-GSS34377.js → chunk-ZI5IH2HP.js} +2 -2
- package/chunks/{chunk-CB2464BK.js → chunk-ZIKTCMQF.js} +117 -10
- package/chunks/chunk-ZLBIFIMV.js +1099 -0
- package/chunks/{chunk-D3UEZIQH.js → chunk-ZSNBQXMZ.js} +48 -55
- package/chunks/{chunk-FZBZSYKU.js → chunk-ZV7LTLFE.js} +1 -1
- package/chunks/{computer-use-KEAPATUY.js → computer-use-SLN7DV2E.js} +28 -24
- package/chunks/{config-utils-K7SCOWHD.js → config-utils-ULCSRMWD.js} +4 -4
- package/chunks/{contextCommand-ZJA6A5K5.js → contextCommand-EHFYX6FW.js} +30 -26
- package/chunks/{core-runtime-QMJPWHCI.js → core-runtime-FBSP5IIG.js} +33 -29
- package/chunks/{create-sub-session-E4PBYXV5.js → create-sub-session-QIDZUOPU.js} +1 -1
- package/chunks/{create-sub-session-DJE6XICH.js → create-sub-session-WC7YGVSL.js} +29 -25
- package/chunks/{cron-create-GRBWYMIJ.js → cron-create-VONA5JYY.js} +1 -1
- package/chunks/{cron-delete-4CMKBR2M.js → cron-delete-5JXSP2MI.js} +1 -1
- package/chunks/{cron-list-W7K4ASOA.js → cron-list-KE4F2CIR.js} +1 -1
- package/chunks/{daemon-SCTQMM7Z.js → daemon-VSX3FHTY.js} +119 -4
- package/chunks/{daemon-status-provider-FSWDPE2G.js → daemon-status-provider-WW2AD2T7.js} +39 -35
- package/chunks/{daemon-trust-policy-P5L5VFAY.js → daemon-trust-policy-E4MAYWPI.js} +35 -31
- package/chunks/{daemon-trust-policy-monitor-73JYN6ET.js → daemon-trust-policy-monitor-XVIDV6T4.js} +35 -31
- package/chunks/{de-VL76CPLV.js → de-LIW4XVLN.js} +5 -0
- package/chunks/{deferred-core-runtime-BWRCCFTE.js → deferred-core-runtime-5SVUC6UC.js} +28 -24
- package/chunks/{display-image-O2XFPQTC.js → display-image-NQRSIBXM.js} +2 -2
- package/chunks/{dist-HVBMEYWK.js → dist-3NTTUAHT.js} +1 -1
- package/chunks/{dist-7JGAAQSC.js → dist-6BMOAE3Z.js} +2 -2
- package/chunks/{dist-3BMEUGTG.js → dist-B2CGTW6T.js} +1 -1
- package/chunks/{dist-C5U4LJKW.js → dist-EWW3J4HQ.js} +5 -4
- package/chunks/{dist-K4WWQBHS.js → dist-EZE3V3Q7.js} +55 -15
- package/chunks/{dist-DPPHJAVL.js → dist-J47AXBZC.js} +918 -142
- package/chunks/{dist-SFQ34F4M.js → dist-OTUO3AS2.js} +8 -1091
- package/chunks/{dist-KS4O2NKE.js → dist-Z3CS4OVP.js} +14 -8
- package/chunks/{earlyInputCapture-L5ST23A6.js → earlyInputCapture-72FYHYRD.js} +28 -24
- package/chunks/{edit-LHHRFNFK.js → edit-SWVVWHXW.js} +28 -24
- package/chunks/{en-IRJ2WN5T.js → en-SY5GTIGX.js} +6 -0
- package/chunks/{enter-worktree-6NXCRZPF.js → enter-worktree-2HF6WQEO.js} +28 -24
- package/chunks/{enterPlanMode-ZVQT4U7D.js → enterPlanMode-OW6S7L4P.js} +28 -24
- package/chunks/{environment-GJ2HWJOS.js → environment-LRTBTDXH.js} +32 -28
- package/chunks/{errors-6RLH3XXC.js → errors-4CO2DME6.js} +30 -26
- package/chunks/{exit-worktree-I2YLUHHY.js → exit-worktree-GHJEIRGL.js} +28 -24
- package/chunks/{exitPlanMode-7CCWKO7I.js → exitPlanMode-JVP4FNNK.js} +28 -24
- package/chunks/{fast-path-DVFD4HQD.js → fast-path-HCCY7GR2.js} +24 -3
- package/chunks/{fast-path-settings-WQJU2LAT.js → fast-path-settings-MN5QQQET.js} +6 -3
- package/chunks/{fr-GK3HQYVB.js → fr-RQFO7U4P.js} +5 -0
- package/chunks/{gemini-7FWGOYD4.js → gemini-V3YVRKXU.js} +85 -72
- package/chunks/{geminiContentGenerator-V2WVLIXU.js → geminiContentGenerator-LVPMQUWX.js} +1 -1
- package/chunks/{glob-3N6GGI75.js → glob-7HRXHYDR.js} +28 -24
- package/chunks/{goal-tools-APOW6UXL.js → goal-tools-PXWN5VK3.js} +4 -2
- package/chunks/{grep-V43ILZVX.js → grep-BITQUON5.js} +28 -24
- package/chunks/{handleAutoUpdate-A5WFVWIA.js → handleAutoUpdate-DKFY454S.js} +32 -28
- package/chunks/{i18n-PLVQ4FBZ.js → i18n-53BQIQSH.js} +29 -25
- package/chunks/{image-gen-7C6IK6DC.js → image-gen-H62FLDFB.js} +7 -5
- package/chunks/{initializer-CVAIKZYL.js → initializer-Q7NUQRSU.js} +35 -31
- package/chunks/{installationInfo-J6QDHNTK.js → installationInfo-BWFHT7WU.js} +29 -25
- package/chunks/{ja-3FA46IKD.js → ja-KOZKHJHZ.js} +5 -0
- package/chunks/{list-ZZ4OUUWV.js → list-OWQKR6JK.js} +38 -34
- package/chunks/{list-agents-KFFIIS2G.js → list-agents-Z4WABFDZ.js} +1 -1
- package/chunks/{loadedSettingsAdapter-QRYRJSWL.js → loadedSettingsAdapter-HNPKQMFA.js} +35 -31
- package/chunks/{loggingContentGenerator-OJCO75HM.js → loggingContentGenerator-A5I3VQUC.js} +10 -8
- package/chunks/{loop-wakeup-TLMJPMMP.js → loop-wakeup-UZ5RL5Y2.js} +2 -2
- package/chunks/{ls-UVVE2XGE.js → ls-TVHDGIES.js} +1 -1
- package/chunks/{lsp-QMEA2VLB.js → lsp-CVN6OQPI.js} +1 -1
- package/chunks/main-PXAUXNF2.js +8 -0
- package/chunks/{managed-npm-update-PCOSCP2N.js → managed-npm-update-CUUJGUTV.js} +29 -25
- package/chunks/{mcp-M3WKKWKY.js → mcp-GJSC7ZPO.js} +35 -31
- package/chunks/{monitor-GN24FH6C.js → monitor-TZ2II7JM.js} +38 -30
- package/chunks/{nonInteractiveCli-KPTU3VSQ.js → nonInteractiveCli-22RS4EVH.js} +72 -66
- package/chunks/{notebook-edit-4YM65BBO.js → notebook-edit-YZC3YPY2.js} +36 -24
- package/chunks/{openaiContentGenerator-EDQT6GTV.js → openaiContentGenerator-OIGO5XNF.js} +21 -11
- package/chunks/{pidfile-JOIIRN2C.js → pidfile-QJQ65RJ2.js} +28 -24
- package/chunks/{process-registry-2CHQBXH5.js → process-registry-PMJOA5CO.js} +15 -0
- package/chunks/{processUtils-5SV4MX3Q.js → processUtils-V5VSDIKS.js} +2 -2
- package/chunks/{pt-3AOBKPIJ.js → pt-U6AOCTMF.js} +5 -0
- package/chunks/{qwenContentGenerator-ODRJSUGR.js → qwenContentGenerator-HXM25BGB.js} +35 -30
- package/chunks/{qwenOAuth2-NESCMZ47.js → qwenOAuth2-7MTMS2Z5.js} +7 -5
- package/chunks/{read-file-HPSODLPK.js → read-file-PMGXB3ZB.js} +8 -6
- package/chunks/{read-mcp-resource-2TNSJTC3.js → read-mcp-resource-PZ4ZF6YL.js} +1 -1
- package/chunks/{record-artifact-RAON52FC.js → record-artifact-P4HFMS7X.js} +2 -2
- package/chunks/{resumeHistoryUtils-TXCOFFMQ.js → resumeHistoryUtils-YUTPLHUH.js} +33 -29
- package/chunks/{ripGrep-ZKQGTQAO.js → ripGrep-XUS66YIV.js} +28 -24
- package/chunks/{ru-VJRAMC4W.js → ru-CMX4UMYP.js} +5 -0
- package/chunks/{run-qwen-serve-ZPKPKECF.js → run-qwen-serve-4NVSU75L.js} +261 -62
- package/chunks/{runtime-2FLNNM36.js → runtime-QLRVP6HM.js} +40 -36
- package/chunks/{scheduler-365PJHNR.js → scheduler-PBB2NSOP.js} +28 -24
- package/chunks/{sdk-exporters-http-KHAB5JSD.js → sdk-exporters-http-XVTZQRCE.js} +2 -2
- package/chunks/{sdk-impl-KD7FSTC3.js → sdk-impl-7W7AKCS4.js} +7 -3
- package/chunks/{send-message-ZM7MRUGP.js → send-message-CAMSLG2L.js} +4 -3
- package/chunks/{serve-QD2RNLKJ.js → serve-BWKTRX72.js} +37 -31
- package/chunks/{server-XLJVLTYM.js → server-E7CH7WPK.js} +1437 -593
- package/chunks/{session-3VTUHH4Q.js → session-QEKSJ6YU.js} +166 -105
- package/chunks/{settings-KULVPCQC.js → settings-BRAOSJIM.js} +34 -30
- package/chunks/{shell-3SWW22MH.js → shell-OF3CK4AT.js} +28 -24
- package/chunks/{skill-KDHWYS7W.js → skill-HLH2NO2H.js} +9 -7
- package/chunks/{skill-settings-NMY4JEJC.js → skill-settings-DRPU7YI5.js} +34 -30
- package/chunks/{spawnChannel-ZKS4Q5OU.js → spawnChannel-4KO7YTFM.js} +31 -27
- package/chunks/{standalone-update-7CXPGAQ4.js → standalone-update-DJN2R3YW.js} +30 -26
- package/chunks/{startInteractiveUI-2QQLEKM6.js → startInteractiveUI-O3WQQ2WC.js} +384 -173
- package/chunks/{syntheticOutput-ZLCUTKO2.js → syntheticOutput-PEBJQYJV.js} +2 -2
- package/chunks/{task-create-CQP5UEA3.js → task-create-5NWCQSJF.js} +5 -4
- package/chunks/{task-list-XLEZOJXP.js → task-list-53265TRZ.js} +1 -1
- package/chunks/{task-stop-7ZQM5CFF.js → task-stop-FPCOIRYX.js} +1 -1
- package/chunks/{task-update-JA75U2SN.js → task-update-5HN577LS.js} +5 -4
- package/chunks/{team-create-2WTNGAOX.js → team-create-2E4ACBJD.js} +28 -24
- package/chunks/{team-delete-MHY3UZGY.js → team-delete-MMQB4OSC.js} +1 -1
- package/chunks/{team-plan-approval-LZTYLEG4.js → team-plan-approval-LWIDXYOA.js} +28 -24
- package/chunks/{terminal-image-renderer-R5HHAFJN.js → terminal-image-renderer-PJM7663W.js} +30 -26
- package/chunks/{theme-manager-PAUCSJFF.js → theme-manager-FDQTM3RP.js} +28 -24
- package/chunks/{todoWrite-UPVOHYGD.js → todoWrite-JGV6VLOX.js} +1 -1
- package/chunks/{tool-search-2BFCGLI6.js → tool-search-TL5ZXBF4.js} +11 -8
- package/chunks/{total-session-admission-MK4SINFK.js → total-session-admission-LS6EY5KT.js} +37 -32
- package/chunks/{trustedFolders-TJ5S26N7.js → trustedFolders-5RWP5OB7.js} +32 -26
- package/chunks/{types-ML3TRJQ5.js → types-WYCFCEHR.js} +5 -3
- package/chunks/{update-relaunch-N7AYLARF.js → update-relaunch-HWQ4USKY.js} +5 -5
- package/chunks/{updateCheck-QRZ3DVT5.js → updateCheck-EZMBTEIR.js} +31 -27
- package/chunks/{useAutoAcceptIndicator-DBJ7Y5AF.js → useAutoAcceptIndicator-JDMI627A.js} +37 -33
- package/chunks/{validateNonInterActiveAuth-6ZQWUDS3.js → validateNonInterActiveAuth-RRUHC5RO.js} +67 -63
- package/chunks/{version-AJQGQWXC.js → version-XS4UTKUX.js} +1 -1
- package/chunks/{web-fetch-QWJYRXFL.js → web-fetch-2JV7H6OM.js} +14 -10
- package/chunks/{web-search-2AOXJGHU.js → web-search-RCTN2GAM.js} +10 -7
- package/chunks/{workflow-ERH3SJG2.js → workflow-6MKLKQ6R.js} +909 -273
- package/chunks/{workspace-providers-status-HZ474RA4.js → workspace-providers-status-YZ2IJ4DK.js} +38 -34
- package/chunks/{workspace-registration-store-6EUP4JXG.js → workspace-registration-store-IYN72LBS.js} +1 -1
- package/chunks/{workspace-registry-R4APRRNC.js → workspace-registry-7LFBZQLT.js} +37 -32
- package/chunks/{workspace-service-HFIFDMU7.js → workspace-service-2EHSPRJB.js} +45 -39
- package/chunks/{workspace-skills-status-HAHEIHGK.js → workspace-skills-status-5VJ2D5HN.js} +36 -32
- package/chunks/{workspace-trust-reconciler-65GTAGDK.js → workspace-trust-reconciler-X2LZ6XCI.js} +44 -39
- package/chunks/{write-file-B34CDELV.js → write-file-CJK6SCCF.js} +28 -24
- package/chunks/{zh-ARWDLDLR.js → zh-AGL2FVBI.js} +6 -0
- package/chunks/{zh-TW-Y4RGI3P7.js → zh-TW-KI66MHQY.js} +6 -0
- package/chunks/{zoom-image-HPRBZHSS.js → zoom-image-BVW4RFYW.js} +8 -6
- package/cli.js +13 -13
- package/locales/ca.js +10 -0
- package/locales/de.js +9 -0
- package/locales/en.js +10 -0
- package/locales/fr.js +9 -0
- package/locales/ja.js +9 -0
- package/locales/pt.js +9 -0
- package/locales/ru.js +9 -0
- package/locales/zh-TW.js +10 -0
- package/locales/zh.js +10 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-Ip-FFDJ0.js → arc-DDtoJrAW.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-CChqgwIb.js → architectureDiagram-3BPJPVTR-BAInIW4O.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-BHN-Tfss.js → blockDiagram-GPEHLZMM-ChPDk7fP.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BhyjzDjN.js → c4Diagram-AAUBKEIU-Cd9BJuUy.js} +1 -1
- package/web-shell/assets/channel-0OQklTfP.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-BB9eyHrx.js → chunk-2J33WTMH-COQkLp56.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BeV7ce_J.js → chunk-4BX2VUAB-GUJshQ_l.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-DO7kXDiV.js → chunk-55IACEB6-Boaa7c10.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-B27MPznD.js → chunk-727SXJPM-CcRXaly2.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-DHIjqjD_.js → chunk-AQP2D5EJ-BY0OARHh.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-DabMqyN2.js → chunk-FMBD7UC4-DLFQfv0S.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-Dw7Nnnxc.js → chunk-ND2GUHAM-C_S0u-D2.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-DdaZew1Q.js → chunk-QZHKN3VN-DP9m64hw.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CZ4-apsu.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CZ4-apsu.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-CgBpCYH5.js → cose-bilkent-S5V4N54A-CGY6zGE1.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-BB4IU8G0.js → dagre-BM42HDAG-yB7whKNn.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BcUTHU37.js → diagram-2AECGRRQ-Bdlc59La.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-B6Lyihyv.js → diagram-5GNKFQAL-BUClP18L.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-CRIJOjpG.js → diagram-KO2AKTUF-aZm08kjn.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DdNiwWWT.js → diagram-LMA3HP47-7DGwEkxC.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-Dz4b32Do.js → diagram-OG6HWLK6-CAGKayxx.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-D-8NGw77.js → erDiagram-TEJ5UH35-CptoHHQi.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-Dun26LyM.js → flowDiagram-I6XJVG4X-CNOH0s7Q.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-F10Hu1Gc.js → ganttDiagram-6RSMTGT7-CCQuCU3y.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-Bf8Ez6-D.js → gitGraphDiagram-PVQCEYII-B7gv9f4E.js} +1 -1
- package/web-shell/assets/{index-BXqw-nGq.js → index-BoUPVvpf.js} +1 -1
- package/web-shell/assets/index-D1YQXYsB.css +5 -0
- package/web-shell/assets/index-J4N7zCmU.js +1768 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DVgTMLvj.js → infoDiagram-5YYISTIA-Bb3KYEbR.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-uT-KepvK.js → ishikawaDiagram-YF4QCWOH-DWEzbAGi.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Vg_XadQf.js → journeyDiagram-JHISSGLW-CmxwEqeb.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-Dyv1ESBE.js → kanban-definition-UN3LZRKU-Ci0gDD8O.js} +1 -1
- package/web-shell/assets/{linear-BMIepYX3.js → linear-BqxZqGhS.js} +1 -1
- package/web-shell/assets/{mermaid.core-zA8pJ9ag.js → mermaid.core-BDAFffHv.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BCW_BZ_5.js → mindmap-definition-RKZ34NQL-Btvx-xvS.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-DseNEGp2.js → pieDiagram-4H26LBE5-CKAg7yG7.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-6Z7wr1Fi.js → quadrantDiagram-W4KKPZXB-DIt8E1mC.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-CVOlCRPf.js → requirementDiagram-4Y6WPE33-BA7mQWQJ.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-CGhgrUJZ.js → sankeyDiagram-5OEKKPKP-D0JppnVU.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-dlqmpLuQ.js → sequenceDiagram-3UESZ5HK-29DIQFjB.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-B9EW10Xb.js → stateDiagram-AJRCARHV-iiXMdK--.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CEGK3l80.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-BBRh0mgZ.js → timeline-definition-PNZ67QCA-CeF7ngSW.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-B8Gs-REP.js → vennDiagram-CIIHVFJN-Beilq8D6.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-D_y80Ur7.js → wardley-L42UT6IY-DOYjY4zO.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-D-CNfHJ-.js → wardleyDiagram-YWT4CUSO-Dtqp8o18.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-DQ5CvELo.js → xychartDiagram-2RQKCTM6-cdAc0Dfv.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/chunk-6PEXNQTX.js +0 -68
- package/chunks/chunk-IUFV6FYU.js +0 -81
- package/chunks/chunk-RXFQM6FQ.js +0 -42
- package/web-shell/assets/channel-Cu8qd6OB.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BI3KrXhq.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BI3KrXhq.js +0 -1
- package/web-shell/assets/index-QQlUCJGg.css +0 -5
- package/web-shell/assets/index-hcgjV7vS.js +0 -1768
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CJTZJJ5X.js +0 -1
- package/chunks/{anthropicContentGenerator-DTMVEL5M.js → anthropicContentGenerator-SSFE2753.js} +9 -9
- /package/chunks/{chunk-VXZBKKQR.js → chunk-NTTBXH7U.js} +0 -0
- /package/chunks/{chunk-GRC5HGPI.js → chunk-OIBUG24X.js} +0 -0
|
@@ -17,17 +17,28 @@ import {
|
|
|
17
17
|
} from "./chunk-OCPBI7J5.js";
|
|
18
18
|
import {
|
|
19
19
|
defaultSpawnChannelFactory
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-I5VM3SKY.js";
|
|
21
21
|
import {
|
|
22
22
|
BridgeChannelClosedError,
|
|
23
23
|
BridgeTimeoutError,
|
|
24
24
|
SERVE_CONTROL_EXT_METHODS,
|
|
25
25
|
SERVE_STATUS_EXT_METHODS,
|
|
26
26
|
STATUS_SCHEMA_VERSION,
|
|
27
|
+
SessionRestoreTimeoutError,
|
|
27
28
|
createIdleWorkspaceExtensionsStatus,
|
|
28
29
|
createIdleWorkspaceHooksStatus
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-DA4HRSBW.js";
|
|
30
31
|
import {
|
|
32
|
+
ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM,
|
|
33
|
+
ACTIVE_WORK_CLOSE_TIMEOUT_MS,
|
|
34
|
+
ACTIVE_WORK_HEARTBEAT_INTERVAL_MS,
|
|
35
|
+
ACTIVE_WORK_HEARTBEAT_META_KEY,
|
|
36
|
+
ACTIVE_WORK_HEARTBEAT_VERSION,
|
|
37
|
+
ACTIVE_WORK_HOLD_CATEGORIES,
|
|
38
|
+
ACTIVE_WORK_MAX_SESSION_HOLDS,
|
|
39
|
+
ACTIVE_WORK_MAX_SNAPSHOT_SESSIONS,
|
|
40
|
+
ACTIVE_WORK_NOTIFICATION_METHOD,
|
|
41
|
+
ACTIVE_WORK_STALE_INTERVALS,
|
|
31
42
|
CHANNEL_STARTUP_PROFILE_META_KEY,
|
|
32
43
|
CHANNEL_STARTUP_PROFILE_VERSION,
|
|
33
44
|
DAEMON_CHANNEL_DELIVERY_META_KEY,
|
|
@@ -44,10 +55,12 @@ import {
|
|
|
44
55
|
TODO_STOP_GUARD_CONTINUATION_CLAIM_METHOD,
|
|
45
56
|
TODO_STOP_GUARD_QUEUE_RELEASE_METHOD,
|
|
46
57
|
WORKTREE_MCP_DEFER_META_KEY,
|
|
58
|
+
clampActiveWorkIntervalMs,
|
|
47
59
|
isValidTrustedModelPrompt
|
|
48
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-M2PNLYGY.js";
|
|
49
61
|
import {
|
|
50
62
|
BranchWhilePromptActiveError,
|
|
63
|
+
BridgeChannelQuarantinedError,
|
|
51
64
|
CancelSentinelCollisionError,
|
|
52
65
|
CdWhilePromptActiveError,
|
|
53
66
|
InvalidClientIdError,
|
|
@@ -66,7 +79,7 @@ import {
|
|
|
66
79
|
SessionShellDisabledError,
|
|
67
80
|
WorkspaceMismatchError,
|
|
68
81
|
isNotCurrentlyGeneratingCancelError
|
|
69
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-LP2QGNSP.js";
|
|
70
83
|
import {
|
|
71
84
|
canonicalizeWorkspace,
|
|
72
85
|
translateAndCheckAbsoluteWorkspacePath
|
|
@@ -100,16 +113,16 @@ import {
|
|
|
100
113
|
metadataBudgetBytes,
|
|
101
114
|
normalizeSnapshotPayload,
|
|
102
115
|
stableSessionArtifactId
|
|
103
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-47ZUMGGY.js";
|
|
104
117
|
import {
|
|
105
118
|
DAEMON_TRACEPARENT_META_KEY,
|
|
106
119
|
DAEMON_TRACESTATE_META_KEY
|
|
107
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-4TRQPFDP.js";
|
|
108
121
|
import {
|
|
109
122
|
INVOCATION_CONTEXT_META_KEY,
|
|
110
123
|
PRIVATE_ACP_CAPABILITY_ENV,
|
|
111
124
|
PRIVATE_PARENT_CAPABILITY_META_KEY
|
|
112
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-YGT2AUJ7.js";
|
|
113
126
|
import {
|
|
114
127
|
init_esbuild_shims
|
|
115
128
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -751,6 +764,46 @@ function mergeTranscriptUpdateMeta(existing, incoming) {
|
|
|
751
764
|
}
|
|
752
765
|
__name(mergeTranscriptUpdateMeta, "mergeTranscriptUpdateMeta");
|
|
753
766
|
|
|
767
|
+
// packages/acp-bridge/src/session-restore-timeout.ts
|
|
768
|
+
init_esbuild_shims();
|
|
769
|
+
var DEFAULT_SESSION_RESTORE_TIMEOUT_MS = 6e4;
|
|
770
|
+
var MAX_SESSION_RESTORE_TIMEOUT_MS = 2147483647;
|
|
771
|
+
var MIN_RESTORE_RETRY_AFTER_SECONDS = 5;
|
|
772
|
+
var MAX_RESTORE_RETRY_AFTER_SECONDS = 120;
|
|
773
|
+
function restoreRetryAfterSeconds(timeoutMs) {
|
|
774
|
+
return Math.min(
|
|
775
|
+
MAX_RESTORE_RETRY_AFTER_SECONDS,
|
|
776
|
+
Math.max(MIN_RESTORE_RETRY_AFTER_SECONDS, Math.ceil(timeoutMs / 1e3))
|
|
777
|
+
);
|
|
778
|
+
}
|
|
779
|
+
__name(restoreRetryAfterSeconds, "restoreRetryAfterSeconds");
|
|
780
|
+
function assertValidTimeoutMs(field, timeoutMs) {
|
|
781
|
+
if (!Number.isFinite(timeoutMs) || !Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_SESSION_RESTORE_TIMEOUT_MS) {
|
|
782
|
+
throw new TypeError(
|
|
783
|
+
`Invalid ${field}: ${timeoutMs}. Must be a positive integer no greater than ${MAX_SESSION_RESTORE_TIMEOUT_MS}.`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
__name(assertValidTimeoutMs, "assertValidTimeoutMs");
|
|
788
|
+
function resolveSessionRestoreTimeoutMs(opts) {
|
|
789
|
+
if (opts.sessionRestoreTimeoutMs !== void 0) {
|
|
790
|
+
assertValidTimeoutMs(
|
|
791
|
+
"sessionRestoreTimeoutMs",
|
|
792
|
+
opts.sessionRestoreTimeoutMs
|
|
793
|
+
);
|
|
794
|
+
return opts.sessionRestoreTimeoutMs;
|
|
795
|
+
}
|
|
796
|
+
if (opts.initializeTimeoutMs !== void 0) {
|
|
797
|
+
assertValidTimeoutMs("initializeTimeoutMs", opts.initializeTimeoutMs);
|
|
798
|
+
return Math.max(
|
|
799
|
+
opts.initializeTimeoutMs,
|
|
800
|
+
DEFAULT_SESSION_RESTORE_TIMEOUT_MS
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
return DEFAULT_SESSION_RESTORE_TIMEOUT_MS;
|
|
804
|
+
}
|
|
805
|
+
__name(resolveSessionRestoreTimeoutMs, "resolveSessionRestoreTimeoutMs");
|
|
806
|
+
|
|
754
807
|
// packages/acp-bridge/src/session-source.ts
|
|
755
808
|
init_esbuild_shims();
|
|
756
809
|
var SESSION_SOURCE_META_KEY = "qwen.session.source";
|
|
@@ -1580,6 +1633,42 @@ var MultiClientPermissionMediator = class {
|
|
|
1580
1633
|
};
|
|
1581
1634
|
|
|
1582
1635
|
// packages/acp-bridge/src/bridgeClient.ts
|
|
1636
|
+
function parseActiveWorkSnapshot(params) {
|
|
1637
|
+
const seq = params["seq"];
|
|
1638
|
+
const sessions = params["sessions"];
|
|
1639
|
+
if (params["v"] !== ACTIVE_WORK_HEARTBEAT_VERSION || typeof seq !== "number" || !Number.isSafeInteger(seq) || seq <= 0 || !Array.isArray(sessions) || sessions.length > ACTIVE_WORK_MAX_SNAPSHOT_SESSIONS) {
|
|
1640
|
+
return void 0;
|
|
1641
|
+
}
|
|
1642
|
+
const parsed = [];
|
|
1643
|
+
for (const raw of sessions) {
|
|
1644
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
1645
|
+
const entry = raw;
|
|
1646
|
+
const sessionId = entry["sessionId"];
|
|
1647
|
+
const holds = entry["holds"];
|
|
1648
|
+
if (typeof sessionId !== "string" || !Array.isArray(holds) || holds.length > ACTIVE_WORK_MAX_SESSION_HOLDS) {
|
|
1649
|
+
return void 0;
|
|
1650
|
+
}
|
|
1651
|
+
const parsedHolds = [];
|
|
1652
|
+
for (const rawHold of holds) {
|
|
1653
|
+
if (typeof rawHold !== "object" || rawHold === null) return void 0;
|
|
1654
|
+
const hold = rawHold;
|
|
1655
|
+
const category = hold["category"];
|
|
1656
|
+
const id = hold["id"];
|
|
1657
|
+
if (typeof id !== "string" || typeof category !== "string" || !ACTIVE_WORK_HOLD_CATEGORIES.includes(
|
|
1658
|
+
category
|
|
1659
|
+
)) {
|
|
1660
|
+
return void 0;
|
|
1661
|
+
}
|
|
1662
|
+
parsedHolds.push({
|
|
1663
|
+
category,
|
|
1664
|
+
id
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
parsed.push({ sessionId, holds: parsedHolds });
|
|
1668
|
+
}
|
|
1669
|
+
return { v: ACTIVE_WORK_HEARTBEAT_VERSION, seq, sessions: parsed };
|
|
1670
|
+
}
|
|
1671
|
+
__name(parseActiveWorkSnapshot, "parseActiveWorkSnapshot");
|
|
1583
1672
|
var PUBLISH_ARTIFACT_TOOL_NAME = "artifact";
|
|
1584
1673
|
var MAX_CHANNEL_DELIVERY_TEXT_CHARS = 1e5;
|
|
1585
1674
|
var MAX_CHANNEL_DELIVERY_FIELD_CHARS = 2048;
|
|
@@ -1840,7 +1929,7 @@ function sliceLineRange(content, startLine, endLine) {
|
|
|
1840
1929
|
}
|
|
1841
1930
|
__name(sliceLineRange, "sliceLineRange");
|
|
1842
1931
|
var BridgeClient = class {
|
|
1843
|
-
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true, onTokenUsage, onCreateSubSession, onGenerationEvent, onWorkspaceGenerationEvent, onChannelDelivery, hasSessionSpawnInFlight = () => false, getLiveScreenContextCaptureHandler = () => void 0, getLiveTaskToolRequestHandler = () => void 0, getLiveSpeakToUserHandler = () => void 0, externalToolGuard) {
|
|
1932
|
+
constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted, clientMcpSender, ownsSession = () => true, onTokenUsage, onCreateSubSession, onGenerationEvent, onWorkspaceGenerationEvent, onChannelDelivery, hasSessionSpawnInFlight = () => false, getLiveScreenContextCaptureHandler = () => void 0, getLiveTaskToolRequestHandler = () => void 0, getLiveSpeakToUserHandler = () => void 0, externalToolGuard, onActiveWork) {
|
|
1844
1933
|
this.resolveEntry = resolveEntry;
|
|
1845
1934
|
this.resolvePendingRestoreEvents = resolvePendingRestoreEvents;
|
|
1846
1935
|
this.mediator = mediator;
|
|
@@ -1861,6 +1950,7 @@ var BridgeClient = class {
|
|
|
1861
1950
|
this.getLiveTaskToolRequestHandler = getLiveTaskToolRequestHandler;
|
|
1862
1951
|
this.getLiveSpeakToUserHandler = getLiveSpeakToUserHandler;
|
|
1863
1952
|
this.externalToolGuard = externalToolGuard;
|
|
1953
|
+
this.onActiveWork = onActiveWork;
|
|
1864
1954
|
}
|
|
1865
1955
|
static {
|
|
1866
1956
|
__name(this, "BridgeClient");
|
|
@@ -1929,6 +2019,9 @@ var BridgeClient = class {
|
|
|
1929
2019
|
}
|
|
1930
2020
|
}
|
|
1931
2021
|
async sessionUpdate(params) {
|
|
2022
|
+
if (this.abandonedRestoreIds.has(params.sessionId)) {
|
|
2023
|
+
return;
|
|
2024
|
+
}
|
|
1932
2025
|
if (!this.ownsSession(params.sessionId) && !this.inFlightRestoreIds.has(params.sessionId)) {
|
|
1933
2026
|
writeStderrLine(
|
|
1934
2027
|
`[demux] session=${params.sessionId} type=session_update action=dropped reason=session_not_owned`
|
|
@@ -2099,22 +2192,19 @@ var BridgeClient = class {
|
|
|
2099
2192
|
* stale frame for that id anywhere in the system.
|
|
2100
2193
|
*/
|
|
2101
2194
|
tombstonedSessionIds = /* @__PURE__ */ new Map();
|
|
2195
|
+
/** Restore ownership for `sessionUpdate` and artifact demultiplexing. */
|
|
2196
|
+
inFlightRestoreIds = /* @__PURE__ */ new Set();
|
|
2102
2197
|
/**
|
|
2103
|
-
*
|
|
2104
|
-
*
|
|
2105
|
-
*
|
|
2106
|
-
* previously-closed id flow through to the future
|
|
2107
|
-
* `createSessionEntry -> drainEarlyEvents` call.
|
|
2108
|
-
*
|
|
2109
|
-
* Without this, the tombstone set before a future `load` can clear
|
|
2110
|
-
* it via `drainEarlyEvents` would silently drop legitimate
|
|
2111
|
-
* restore-time events (e.g. MCP discovery budget events firing
|
|
2112
|
-
* during the ACP call window).
|
|
2113
|
-
*
|
|
2114
|
-
* Bridge factory enters the set before awaiting the ACP restore
|
|
2115
|
-
* call and exits on settle (success or failure).
|
|
2198
|
+
* Registrations allowed to buffer early extended notifications through an
|
|
2199
|
+
* ordinary close tombstone. This includes restores and caller-supplied-id
|
|
2200
|
+
* spawns, and lasts only until their ACP registration attempt settles.
|
|
2116
2201
|
*/
|
|
2117
|
-
|
|
2202
|
+
inFlightSessionRegistrationIds = /* @__PURE__ */ new Set();
|
|
2203
|
+
/**
|
|
2204
|
+
* Restore ids whose caller timed out while the non-cancellable ACP request
|
|
2205
|
+
* continues.
|
|
2206
|
+
*/
|
|
2207
|
+
abandonedRestoreIds = /* @__PURE__ */ new Set();
|
|
2118
2208
|
/**
|
|
2119
2209
|
* Handle child->bridge ACP `extMethod` requests (calls that expect a
|
|
2120
2210
|
* response, unlike `extNotification`). Served methods:
|
|
@@ -2581,6 +2671,23 @@ var BridgeClient = class {
|
|
|
2581
2671
|
* forward-compat.
|
|
2582
2672
|
*/
|
|
2583
2673
|
async extNotification(method, params) {
|
|
2674
|
+
const notificationSessionId = params["sessionId"];
|
|
2675
|
+
if (typeof notificationSessionId === "string" && this.abandonedRestoreIds.has(notificationSessionId)) {
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
if (method === ACTIVE_WORK_NOTIFICATION_METHOD) {
|
|
2679
|
+
const snapshot = parseActiveWorkSnapshot(params);
|
|
2680
|
+
if (snapshot) {
|
|
2681
|
+
this.onActiveWork?.({
|
|
2682
|
+
v: ACTIVE_WORK_HEARTBEAT_VERSION,
|
|
2683
|
+
seq: snapshot.seq,
|
|
2684
|
+
sessions: snapshot.sessions.filter(
|
|
2685
|
+
(session) => this.ownsSession(session.sessionId)
|
|
2686
|
+
)
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
return;
|
|
2690
|
+
}
|
|
2584
2691
|
if (method === "_qwencode/end_turn") {
|
|
2585
2692
|
const sessionId2 = params["sessionId"];
|
|
2586
2693
|
const reason = params["reason"];
|
|
@@ -2846,6 +2953,9 @@ var BridgeClient = class {
|
|
|
2846
2953
|
}
|
|
2847
2954
|
}
|
|
2848
2955
|
publishExtNotification(sessionId, type, data, turnScoped = false) {
|
|
2956
|
+
if (this.abandonedRestoreIds.has(sessionId)) {
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2849
2959
|
const entry = this.resolveEntry(sessionId);
|
|
2850
2960
|
const frame = {
|
|
2851
2961
|
type,
|
|
@@ -2991,9 +3101,12 @@ var BridgeClient = class {
|
|
|
2991
3101
|
* dropped to bound per-session memory.
|
|
2992
3102
|
*/
|
|
2993
3103
|
bufferEarlyEvent(sessionId, frame) {
|
|
3104
|
+
if (this.abandonedRestoreIds.has(sessionId)) {
|
|
3105
|
+
return;
|
|
3106
|
+
}
|
|
2994
3107
|
const now = Date.now();
|
|
2995
3108
|
this.sweepExpiredTombstones(now);
|
|
2996
|
-
if (this.tombstonedSessionIds.has(sessionId) && !this.
|
|
3109
|
+
if (this.tombstonedSessionIds.has(sessionId) && !this.inFlightSessionRegistrationIds.has(sessionId)) {
|
|
2997
3110
|
writeStderrLine(
|
|
2998
3111
|
`qwen serve: dropping early extNotification for tombstoned session ${JSON.stringify(sessionId)} (post-close stale event)`
|
|
2999
3112
|
);
|
|
@@ -3055,8 +3168,31 @@ var BridgeClient = class {
|
|
|
3055
3168
|
* failed restore doesn't leave a dangling allow-list entry.
|
|
3056
3169
|
*/
|
|
3057
3170
|
markRestoreInFlight(sessionId) {
|
|
3171
|
+
this.markSessionRegistrationInFlight(sessionId);
|
|
3058
3172
|
this.inFlightRestoreIds.add(sessionId);
|
|
3059
3173
|
}
|
|
3174
|
+
/**
|
|
3175
|
+
* Transfer an id from closed/abandoned ownership to a new registration
|
|
3176
|
+
* attempt before its ACP call starts. The in-flight allow-list is what lets
|
|
3177
|
+
* legitimate early notifications bypass the ordinary close tombstone until
|
|
3178
|
+
* `createSessionEntry` can drain them.
|
|
3179
|
+
*/
|
|
3180
|
+
markSessionRegistrationInFlight(sessionId) {
|
|
3181
|
+
this.clearAbandonedRestoreFence(sessionId);
|
|
3182
|
+
this.inFlightSessionRegistrationIds.add(sessionId);
|
|
3183
|
+
}
|
|
3184
|
+
/**
|
|
3185
|
+
* Drop the abandoned-restore fence for `sessionId`.
|
|
3186
|
+
*
|
|
3187
|
+
* The fence has no TTL and suppresses session updates, guardrail events,
|
|
3188
|
+
* and child notifications, so it must not outlive the abandoned attempt it
|
|
3189
|
+
* was raised for. The bridge clears it whenever a legitimate owner takes
|
|
3190
|
+
* the id — a new restore, or `createSessionEntry` registering a session
|
|
3191
|
+
* from any other route.
|
|
3192
|
+
*/
|
|
3193
|
+
clearAbandonedRestoreFence(sessionId) {
|
|
3194
|
+
this.abandonedRestoreIds.delete(sessionId);
|
|
3195
|
+
}
|
|
3060
3196
|
/**
|
|
3061
3197
|
* Companion to `markRestoreInFlight`. Bridge factory calls this when
|
|
3062
3198
|
* the restore IIFE settles — after `createSessionEntry` runs
|
|
@@ -3065,6 +3201,16 @@ var BridgeClient = class {
|
|
|
3065
3201
|
*/
|
|
3066
3202
|
clearRestoreInFlight(sessionId) {
|
|
3067
3203
|
this.inFlightRestoreIds.delete(sessionId);
|
|
3204
|
+
this.clearSessionRegistrationInFlight(sessionId);
|
|
3205
|
+
}
|
|
3206
|
+
clearSessionRegistrationInFlight(sessionId) {
|
|
3207
|
+
this.inFlightSessionRegistrationIds.delete(sessionId);
|
|
3208
|
+
}
|
|
3209
|
+
markRestoreAbandoned(sessionId) {
|
|
3210
|
+
this.inFlightRestoreIds.delete(sessionId);
|
|
3211
|
+
this.inFlightSessionRegistrationIds.delete(sessionId);
|
|
3212
|
+
this.abandonedRestoreIds.add(sessionId);
|
|
3213
|
+
this.earlyEvents.delete(sessionId);
|
|
3068
3214
|
}
|
|
3069
3215
|
/**
|
|
3070
3216
|
* Drain any frames buffered for `sessionId` onto `entry.events`.
|
|
@@ -6094,6 +6240,7 @@ function createAcpSessionBridge(opts) {
|
|
|
6094
6240
|
let liveTaskToolRequestHandler;
|
|
6095
6241
|
let liveSpeakToUserHandler;
|
|
6096
6242
|
const defaultSessionScope = opts.sessionScope ?? "single";
|
|
6243
|
+
const delegateReadTextFileToClient = opts.delegateReadTextFileToClient ?? true;
|
|
6097
6244
|
let maxSessions;
|
|
6098
6245
|
if (opts.maxSessions === void 0) {
|
|
6099
6246
|
maxSessions = DEFAULT_MAX_SESSIONS;
|
|
@@ -6110,7 +6257,31 @@ function createAcpSessionBridge(opts) {
|
|
|
6110
6257
|
} else {
|
|
6111
6258
|
maxSessions = opts.maxSessions;
|
|
6112
6259
|
}
|
|
6113
|
-
const
|
|
6260
|
+
const freshSessionBlocker = /* @__PURE__ */ __name(() => {
|
|
6261
|
+
for (const ci of aliveChannels) {
|
|
6262
|
+
if (ci.isDying) continue;
|
|
6263
|
+
if (ci.isQuarantined) {
|
|
6264
|
+
return { channel: ci, reason: "restore_cleanup_failed" };
|
|
6265
|
+
}
|
|
6266
|
+
if (ci.restoreSettlementOverdue) {
|
|
6267
|
+
return { channel: ci, reason: "restore_settlement_overdue" };
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6270
|
+
return void 0;
|
|
6271
|
+
}, "freshSessionBlocker");
|
|
6272
|
+
const assertFreshSessionsAvailable = /* @__PURE__ */ __name(() => {
|
|
6273
|
+
const blocker = freshSessionBlocker();
|
|
6274
|
+
if (blocker) {
|
|
6275
|
+
throw new BridgeChannelQuarantinedError(
|
|
6276
|
+
blocker.reason,
|
|
6277
|
+
abandonedRestoreRetryAfterSeconds
|
|
6278
|
+
);
|
|
6279
|
+
}
|
|
6280
|
+
}, "assertFreshSessionsAvailable");
|
|
6281
|
+
const reserveFreshSession = /* @__PURE__ */ __name((context) => {
|
|
6282
|
+
assertFreshSessionsAvailable();
|
|
6283
|
+
return opts.freshSessionAdmission?.(context);
|
|
6284
|
+
}, "reserveFreshSession");
|
|
6114
6285
|
const releaseFreshSessionReservation = /* @__PURE__ */ __name((reservation) => {
|
|
6115
6286
|
if (!reservation) return;
|
|
6116
6287
|
try {
|
|
@@ -6155,6 +6326,11 @@ function createAcpSessionBridge(opts) {
|
|
|
6155
6326
|
`Invalid initializeTimeoutMs: ${initTimeoutMs}. Must be > 0.`
|
|
6156
6327
|
);
|
|
6157
6328
|
}
|
|
6329
|
+
const sessionRestoreTimeoutMs = resolveSessionRestoreTimeoutMs(opts);
|
|
6330
|
+
const restoreSettlementGraceMs = sessionRestoreTimeoutMs;
|
|
6331
|
+
const abandonedRestoreRetryAfterSeconds = restoreRetryAfterSeconds(
|
|
6332
|
+
sessionRestoreTimeoutMs
|
|
6333
|
+
);
|
|
6158
6334
|
const permissionTimeoutRaw = opts.permissionResponseTimeoutMs ?? DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
6159
6335
|
const permissionTimeoutMs = permissionTimeoutRaw > 0 && Number.isFinite(permissionTimeoutRaw) ? (
|
|
6160
6336
|
// Clamp to 2^31-1: Node treats setTimeout delays larger than
|
|
@@ -6206,6 +6382,153 @@ function createAcpSessionBridge(opts) {
|
|
|
6206
6382
|
lastActivityTimestamp = Date.now();
|
|
6207
6383
|
}
|
|
6208
6384
|
__name(touchActivity, "touchActivity");
|
|
6385
|
+
function entryHasLocalWork(entry) {
|
|
6386
|
+
return entry.pendingPromptCount > 0 || entry.pendingAgentNotificationCount > 0;
|
|
6387
|
+
}
|
|
6388
|
+
__name(entryHasLocalWork, "entryHasLocalWork");
|
|
6389
|
+
function childHoldsAreFresh(entry, capability) {
|
|
6390
|
+
if (entry.childHoldsAt === null) return false;
|
|
6391
|
+
return Date.now() - entry.childHoldsAt <= capability.intervalMs * ACTIVE_WORK_STALE_INTERVALS;
|
|
6392
|
+
}
|
|
6393
|
+
__name(childHoldsAreFresh, "childHoldsAreFresh");
|
|
6394
|
+
function childReportsHeldWork(entry) {
|
|
6395
|
+
const owner = channelInfoForEntry(entry);
|
|
6396
|
+
if (!owner?.activeWork) return false;
|
|
6397
|
+
if (!childHoldsAreFresh(entry, owner.activeWork)) return false;
|
|
6398
|
+
return entry.childHolds !== null && entry.childHolds.size > 0;
|
|
6399
|
+
}
|
|
6400
|
+
__name(childReportsHeldWork, "childReportsHeldWork");
|
|
6401
|
+
function childWorkIsUnknown(entry) {
|
|
6402
|
+
const owner = channelInfoForEntry(entry);
|
|
6403
|
+
if (!owner?.activeWork) return false;
|
|
6404
|
+
return !childHoldsAreFresh(entry, owner.activeWork);
|
|
6405
|
+
}
|
|
6406
|
+
__name(childWorkIsUnknown, "childWorkIsUnknown");
|
|
6407
|
+
function entryHasActiveWork(entry) {
|
|
6408
|
+
return entryHasLocalWork(entry) || childReportsHeldWork(entry) || childWorkIsUnknown(entry);
|
|
6409
|
+
}
|
|
6410
|
+
__name(entryHasActiveWork, "entryHasActiveWork");
|
|
6411
|
+
function entryIsAutoCloseCandidate(entry) {
|
|
6412
|
+
if (byId.get(entry.sessionId) !== entry) return false;
|
|
6413
|
+
if (isClosingOrAuthorizingClose(entry)) return false;
|
|
6414
|
+
if (entry.events.subscriberCount > 0) return false;
|
|
6415
|
+
if (entryHasLocalWork(entry)) return false;
|
|
6416
|
+
const owner = channelInfoForEntry(entry);
|
|
6417
|
+
if (owner?.pendingRestoreIds.has(entry.sessionId)) return false;
|
|
6418
|
+
return !childReportsHeldWork(entry);
|
|
6419
|
+
}
|
|
6420
|
+
__name(entryIsAutoCloseCandidate, "entryIsAutoCloseCandidate");
|
|
6421
|
+
function isClosingOrAuthorizingClose(entry) {
|
|
6422
|
+
return entry.closing || entry.activeWorkCloseInFlight;
|
|
6423
|
+
}
|
|
6424
|
+
__name(isClosingOrAuthorizingClose, "isClosingOrAuthorizingClose");
|
|
6425
|
+
async function maybeCloseIdleSession(entry, reason) {
|
|
6426
|
+
if (!entryIsAutoCloseCandidate(entry)) return;
|
|
6427
|
+
if (entry.spawnOwnerWantedKill && entry.attachCount === 0) {
|
|
6428
|
+
await bridgeApi.killSession(entry.sessionId).catch(() => {
|
|
6429
|
+
});
|
|
6430
|
+
return;
|
|
6431
|
+
}
|
|
6432
|
+
if (entry.clientIds.size > 0) return;
|
|
6433
|
+
await closeIfChildUnheld(entry, {
|
|
6434
|
+
trigger: reason,
|
|
6435
|
+
closeReason: "last_client_detached"
|
|
6436
|
+
});
|
|
6437
|
+
}
|
|
6438
|
+
__name(maybeCloseIdleSession, "maybeCloseIdleSession");
|
|
6439
|
+
async function closeIfChildUnheld(entry, opts2) {
|
|
6440
|
+
entry.activeWorkCloseInFlight = true;
|
|
6441
|
+
try {
|
|
6442
|
+
if (!await confirmChildUnheld(entry)) return;
|
|
6443
|
+
if (byId.get(entry.sessionId) !== entry) return;
|
|
6444
|
+
const condemnedOwner = channelInfoForEntry(entry);
|
|
6445
|
+
const agentCloseTimeoutMs = condemnedOwner?.isQuarantined === true || condemnedOwner?.restoreSettlementOverdue === true ? ACTIVE_WORK_CLOSE_TIMEOUT_MS : void 0;
|
|
6446
|
+
await closeSessionImpl(entry.sessionId, void 0, {
|
|
6447
|
+
reason: opts2.closeReason,
|
|
6448
|
+
...agentCloseTimeoutMs !== void 0 ? { agentCloseTimeoutMs } : {}
|
|
6449
|
+
}).catch((err) => {
|
|
6450
|
+
writeStderrLine(
|
|
6451
|
+
`qwen serve: deferred close (${opts2.trigger}) failed for ${JSON.stringify(entry.sessionId)}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
6452
|
+
);
|
|
6453
|
+
});
|
|
6454
|
+
} finally {
|
|
6455
|
+
entry.activeWorkCloseInFlight = false;
|
|
6456
|
+
}
|
|
6457
|
+
}
|
|
6458
|
+
__name(closeIfChildUnheld, "closeIfChildUnheld");
|
|
6459
|
+
async function confirmChildUnheld(entry) {
|
|
6460
|
+
const info = channelInfoForEntry(entry);
|
|
6461
|
+
if (!info?.activeWork) return true;
|
|
6462
|
+
if (info.isDying) return false;
|
|
6463
|
+
if (info.isQuarantined || info.restoreSettlementOverdue) return true;
|
|
6464
|
+
try {
|
|
6465
|
+
const response = await withTimeout(
|
|
6466
|
+
entry.connection.extMethod(SERVE_CONTROL_EXT_METHODS.sessionClose, {
|
|
6467
|
+
sessionId: entry.sessionId,
|
|
6468
|
+
[ACTIVE_WORK_CLOSE_IF_UNHELD_PARAM]: true
|
|
6469
|
+
}),
|
|
6470
|
+
ACTIVE_WORK_CLOSE_TIMEOUT_MS,
|
|
6471
|
+
SERVE_CONTROL_EXT_METHODS.sessionClose
|
|
6472
|
+
);
|
|
6473
|
+
if (response["closed"] === true) {
|
|
6474
|
+
return true;
|
|
6475
|
+
}
|
|
6476
|
+
const holds = response["holds"];
|
|
6477
|
+
if (Array.isArray(holds)) {
|
|
6478
|
+
const adopted = /* @__PURE__ */ new Map();
|
|
6479
|
+
for (const hold of holds) {
|
|
6480
|
+
if (typeof hold !== "object" || hold === null) continue;
|
|
6481
|
+
const record = hold;
|
|
6482
|
+
const id = record["id"];
|
|
6483
|
+
const category = record["category"];
|
|
6484
|
+
if (typeof id === "string" && typeof category === "string" && ACTIVE_WORK_HOLD_CATEGORIES.includes(
|
|
6485
|
+
category
|
|
6486
|
+
)) {
|
|
6487
|
+
adopted.set(id, category);
|
|
6488
|
+
}
|
|
6489
|
+
}
|
|
6490
|
+
entry.childHolds = adopted;
|
|
6491
|
+
entry.childHoldsAt = Date.now();
|
|
6492
|
+
}
|
|
6493
|
+
return false;
|
|
6494
|
+
} catch (err) {
|
|
6495
|
+
writeStderrLine(
|
|
6496
|
+
`qwen serve: close-if-unheld for session ${JSON.stringify(entry.sessionId)} did not resolve (${err instanceof Error ? err.message : String(err)}); leaving it in place for the next snapshot to settle`
|
|
6497
|
+
);
|
|
6498
|
+
return false;
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
__name(confirmChildUnheld, "confirmChildUnheld");
|
|
6502
|
+
function applyActiveWorkSnapshot(info, snapshot) {
|
|
6503
|
+
if (!info.activeWork || info.isDying) return;
|
|
6504
|
+
if (snapshot.seq <= info.activeWork.seq) return;
|
|
6505
|
+
info.activeWork.seq = snapshot.seq;
|
|
6506
|
+
const now = Date.now();
|
|
6507
|
+
const reported = /* @__PURE__ */ new Map();
|
|
6508
|
+
for (const session of snapshot.sessions) {
|
|
6509
|
+
const holds = /* @__PURE__ */ new Map();
|
|
6510
|
+
for (const hold of session.holds) holds.set(hold.id, hold.category);
|
|
6511
|
+
reported.set(session.sessionId, holds);
|
|
6512
|
+
}
|
|
6513
|
+
for (const sessionId of Array.from(info.sessionIds)) {
|
|
6514
|
+
const entry = byId.get(sessionId);
|
|
6515
|
+
if (!entry || entry.channel !== info.channel) continue;
|
|
6516
|
+
const holds = reported.get(sessionId) ?? /* @__PURE__ */ new Map();
|
|
6517
|
+
const previouslyHeld = entry.childHolds ? entry.childHolds.size > 0 : void 0;
|
|
6518
|
+
entry.childHolds = holds;
|
|
6519
|
+
entry.childHoldsAt = now;
|
|
6520
|
+
if (previouslyHeld !== void 0 && previouslyHeld !== holds.size > 0) {
|
|
6521
|
+
touchActivity();
|
|
6522
|
+
}
|
|
6523
|
+
if (holds.size === 0) {
|
|
6524
|
+
void maybeCloseIdleSession(
|
|
6525
|
+
entry,
|
|
6526
|
+
reported.has(sessionId) ? "child_idle" : "child_dropped"
|
|
6527
|
+
);
|
|
6528
|
+
}
|
|
6529
|
+
}
|
|
6530
|
+
}
|
|
6531
|
+
__name(applyActiveWorkSnapshot, "applyActiveWorkSnapshot");
|
|
6209
6532
|
function settleActivePromptState(entry, promptId) {
|
|
6210
6533
|
if (entry.activePromptId !== promptId) return;
|
|
6211
6534
|
delete entry.activePromptId;
|
|
@@ -6301,8 +6624,35 @@ function createAcpSessionBridge(opts) {
|
|
|
6301
6624
|
workspaceMcpResourcesCache.delete(serverName);
|
|
6302
6625
|
}
|
|
6303
6626
|
__name(invalidateWorkspaceMcpDetailCache, "invalidateWorkspaceMcpDetailCache");
|
|
6627
|
+
function channelShouldReapWhenIdle(ci) {
|
|
6628
|
+
return ci.emptyReapPending || ci.unsettledAbandonedRestores.size > 0 || ci.isQuarantined;
|
|
6629
|
+
}
|
|
6630
|
+
__name(channelShouldReapWhenIdle, "channelShouldReapWhenIdle");
|
|
6631
|
+
function armRestoreSettlementGrace(ci, sessionId, action) {
|
|
6632
|
+
if (ci.restoreSettlementTimers.has(sessionId)) return;
|
|
6633
|
+
const timer = setTimeout(() => {
|
|
6634
|
+
ci.restoreSettlementTimers.delete(sessionId);
|
|
6635
|
+
if (!ci.unsettledAbandonedRestores.has(sessionId)) return;
|
|
6636
|
+
if (ci.isDying || !aliveChannels.has(ci)) return;
|
|
6637
|
+
ci.restoreSettlementOverdue = true;
|
|
6638
|
+
writeStderrLine(
|
|
6639
|
+
`qwen serve: abandoned session/${action} for ${JSON.stringify(sessionId)} has not settled ${restoreSettlementGraceMs}ms after its deadline; refusing fresh sessions on channel ${ci.id} until it drains`
|
|
6640
|
+
);
|
|
6641
|
+
telemetry.event("session.restore.settlement_overdue", {
|
|
6642
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
6643
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
6644
|
+
"qwen-code.daemon.session_restore.settlement_grace_ms": restoreSettlementGraceMs,
|
|
6645
|
+
"qwen-code.daemon.acp_channel.id": ci.id,
|
|
6646
|
+
"session.id": sessionId
|
|
6647
|
+
});
|
|
6648
|
+
void reapPendingEmptyChannel(ci);
|
|
6649
|
+
}, restoreSettlementGraceMs);
|
|
6650
|
+
timer.unref();
|
|
6651
|
+
ci.restoreSettlementTimers.set(sessionId, timer);
|
|
6652
|
+
}
|
|
6653
|
+
__name(armRestoreSettlementGrace, "armRestoreSettlementGrace");
|
|
6304
6654
|
async function reapPendingEmptyChannel(ci) {
|
|
6305
|
-
if (!ci
|
|
6655
|
+
if (!channelShouldReapWhenIdle(ci) || !hasNoChannelWork(ci)) return;
|
|
6306
6656
|
ci.emptyReapPending = false;
|
|
6307
6657
|
ci.isDying = true;
|
|
6308
6658
|
await ci.channel.kill().catch(() => {
|
|
@@ -6334,21 +6684,17 @@ function createAcpSessionBridge(opts) {
|
|
|
6334
6684
|
if (shuttingDown) return;
|
|
6335
6685
|
const now = Date.now();
|
|
6336
6686
|
for (const [id, entry] of byId) {
|
|
6337
|
-
if (entry
|
|
6338
|
-
if (entry.events.subscriberCount > 0) continue;
|
|
6687
|
+
if (!entryIsAutoCloseCandidate(entry)) continue;
|
|
6339
6688
|
const lastActive = entry.sessionLastSeenAt ?? Date.parse(entry.createdAt);
|
|
6340
6689
|
const idle = now - lastActive;
|
|
6341
6690
|
if (idle < sessionIdleTimeoutMs) continue;
|
|
6342
6691
|
writeStderrLine(
|
|
6343
6692
|
`qwen serve: reaping idle session ${JSON.stringify(id)} (idle for ${Math.round(idle / 1e3)}s, threshold ${Math.round(sessionIdleTimeoutMs / 1e3)}s)`
|
|
6344
6693
|
);
|
|
6345
|
-
void
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
);
|
|
6350
|
-
}
|
|
6351
|
-
);
|
|
6694
|
+
void closeIfChildUnheld(entry, {
|
|
6695
|
+
trigger: "idle_timeout",
|
|
6696
|
+
closeReason: "idle_timeout"
|
|
6697
|
+
});
|
|
6352
6698
|
}
|
|
6353
6699
|
}, sessionReapIntervalMs);
|
|
6354
6700
|
sessionReaper.unref();
|
|
@@ -6476,6 +6822,7 @@ function createAcpSessionBridge(opts) {
|
|
|
6476
6822
|
}
|
|
6477
6823
|
}, "teeServeDebugLine");
|
|
6478
6824
|
const inFlightSpawns = /* @__PURE__ */ new Map();
|
|
6825
|
+
const inFlightRequestedSessionSpawns = /* @__PURE__ */ new Map();
|
|
6479
6826
|
const inFlightRestores = /* @__PURE__ */ new Map();
|
|
6480
6827
|
const pendingRestoreEvents = /* @__PURE__ */ new Map();
|
|
6481
6828
|
const createClientId = /* @__PURE__ */ __name(() => `client_${randomUUID2()}`, "createClientId");
|
|
@@ -6522,18 +6869,7 @@ function createAcpSessionBridge(opts) {
|
|
|
6522
6869
|
entry.attachCount - (released + (attachCountDelta - 1))
|
|
6523
6870
|
);
|
|
6524
6871
|
unregisterClient(entry, clientId);
|
|
6525
|
-
|
|
6526
|
-
await bridgeApi.killSession(entry.sessionId).catch(() => {
|
|
6527
|
-
});
|
|
6528
|
-
} else if (entry.clientIds.size === 0 && entry.events.subscriberCount === 0 && entry.pendingPromptCount === 0) {
|
|
6529
|
-
await closeSessionImpl(entry.sessionId, void 0, {
|
|
6530
|
-
reason: "last_client_detached"
|
|
6531
|
-
}).catch((err) => {
|
|
6532
|
-
writeStderrLine(
|
|
6533
|
-
`qwen serve: close-on-attach-rollback failed for ${JSON.stringify(entry.sessionId)}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
6534
|
-
);
|
|
6535
|
-
});
|
|
6536
|
-
}
|
|
6872
|
+
await maybeCloseIdleSession(entry, "attach_rollback");
|
|
6537
6873
|
}, "rollbackAttachRegistration");
|
|
6538
6874
|
const resolveTrustedClientId = /* @__PURE__ */ __name((entry, clientId) => {
|
|
6539
6875
|
if (clientId === void 0) return void 0;
|
|
@@ -6562,6 +6898,7 @@ function createAcpSessionBridge(opts) {
|
|
|
6562
6898
|
})
|
|
6563
6899
|
);
|
|
6564
6900
|
const sessionIds = /* @__PURE__ */ new Set();
|
|
6901
|
+
const infoRef = {};
|
|
6565
6902
|
let client;
|
|
6566
6903
|
let connection;
|
|
6567
6904
|
try {
|
|
@@ -6663,7 +7000,12 @@ function createAcpSessionBridge(opts) {
|
|
|
6663
7000
|
() => liveScreenContextCaptureHandler,
|
|
6664
7001
|
() => liveTaskToolRequestHandler,
|
|
6665
7002
|
() => liveSpeakToUserHandler,
|
|
6666
|
-
opts.externalToolGuard
|
|
7003
|
+
opts.externalToolGuard,
|
|
7004
|
+
(snapshot) => {
|
|
7005
|
+
const currentInfo = infoRef.current;
|
|
7006
|
+
if (!currentInfo) return;
|
|
7007
|
+
applyActiveWorkSnapshot(currentInfo, snapshot);
|
|
7008
|
+
}
|
|
6667
7009
|
);
|
|
6668
7010
|
connection = new ClientSideConnection(() => client, channel.stream);
|
|
6669
7011
|
} catch (error) {
|
|
@@ -6698,9 +7040,14 @@ function createAcpSessionBridge(opts) {
|
|
|
6698
7040
|
workspaceMcpAuthenticationServerNames: /* @__PURE__ */ new Set(),
|
|
6699
7041
|
workspaceMcpAuthenticationTimers: /* @__PURE__ */ new Map(),
|
|
6700
7042
|
emptyReapPending: false,
|
|
7043
|
+
unsettledAbandonedRestores: /* @__PURE__ */ new Set(),
|
|
7044
|
+
restoreSettlementOverdue: false,
|
|
7045
|
+
restoreSettlementTimers: /* @__PURE__ */ new Map(),
|
|
6701
7046
|
isDying: false,
|
|
7047
|
+
isQuarantined: false,
|
|
6702
7048
|
handshakeComplete: false
|
|
6703
7049
|
};
|
|
7050
|
+
infoRef.current = info;
|
|
6704
7051
|
aliveChannels.add(info);
|
|
6705
7052
|
if (aliveChannels.size > 2) {
|
|
6706
7053
|
writeStderrLine(
|
|
@@ -6718,6 +7065,10 @@ function createAcpSessionBridge(opts) {
|
|
|
6718
7065
|
}
|
|
6719
7066
|
info.workspaceMcpAuthenticationTimers.clear();
|
|
6720
7067
|
info.workspaceMcpAuthenticationServerNames.clear();
|
|
7068
|
+
for (const timer of info.restoreSettlementTimers.values()) {
|
|
7069
|
+
clearTimeout(timer);
|
|
7070
|
+
}
|
|
7071
|
+
info.restoreSettlementTimers.clear();
|
|
6721
7072
|
aliveChannels.delete(info);
|
|
6722
7073
|
if (channelInfo === info) channelInfo = void 0;
|
|
6723
7074
|
const sessions = Array.from(info.sessionIds);
|
|
@@ -6788,13 +7139,20 @@ function createAcpSessionBridge(opts) {
|
|
|
6788
7139
|
connection.initialize({
|
|
6789
7140
|
protocolVersion: PROTOCOL_VERSION,
|
|
6790
7141
|
_meta: {
|
|
7142
|
+
[ACTIVE_WORK_HEARTBEAT_META_KEY]: {
|
|
7143
|
+
v: ACTIVE_WORK_HEARTBEAT_VERSION,
|
|
7144
|
+
intervalMs: ACTIVE_WORK_HEARTBEAT_INTERVAL_MS
|
|
7145
|
+
},
|
|
6791
7146
|
[CHANNEL_STARTUP_PROFILE_META_KEY]: {
|
|
6792
7147
|
v: CHANNEL_STARTUP_PROFILE_VERSION
|
|
6793
7148
|
},
|
|
6794
7149
|
[PRIVATE_PARENT_CAPABILITY_META_KEY]: privateParentCapability
|
|
6795
7150
|
},
|
|
6796
7151
|
clientCapabilities: {
|
|
6797
|
-
fs: {
|
|
7152
|
+
fs: {
|
|
7153
|
+
readTextFile: delegateReadTextFileToClient,
|
|
7154
|
+
writeTextFile: true
|
|
7155
|
+
}
|
|
6798
7156
|
},
|
|
6799
7157
|
clientInfo: { name: "qwen-serve-bridge", version: "0" }
|
|
6800
7158
|
}),
|
|
@@ -6809,6 +7167,19 @@ function createAcpSessionBridge(opts) {
|
|
|
6809
7167
|
);
|
|
6810
7168
|
}
|
|
6811
7169
|
}
|
|
7170
|
+
const activeWorkCapability = isRecord3(response._meta) ? response._meta[ACTIVE_WORK_HEARTBEAT_META_KEY] : void 0;
|
|
7171
|
+
if (isRecord3(activeWorkCapability) && activeWorkCapability["v"] === ACTIVE_WORK_HEARTBEAT_VERSION) {
|
|
7172
|
+
const advertised = activeWorkCapability["categories"];
|
|
7173
|
+
info.activeWork = {
|
|
7174
|
+
intervalMs: clampActiveWorkIntervalMs(
|
|
7175
|
+
activeWorkCapability["intervalMs"]
|
|
7176
|
+
),
|
|
7177
|
+
categories: Array.isArray(advertised) ? ACTIVE_WORK_HOLD_CATEGORIES.filter(
|
|
7178
|
+
(category) => advertised.includes(category)
|
|
7179
|
+
) : [],
|
|
7180
|
+
seq: 0
|
|
7181
|
+
};
|
|
7182
|
+
}
|
|
6812
7183
|
try {
|
|
6813
7184
|
const attributes = getChannelStartupProfileAttributes(
|
|
6814
7185
|
response,
|
|
@@ -6859,6 +7230,9 @@ function createAcpSessionBridge(opts) {
|
|
|
6859
7230
|
ensureChannel
|
|
6860
7231
|
);
|
|
6861
7232
|
ci.sessionSpawnsInFlight++;
|
|
7233
|
+
if (requestedSessionId !== void 0) {
|
|
7234
|
+
ci.client.markSessionRegistrationInFlight(requestedSessionId);
|
|
7235
|
+
}
|
|
6862
7236
|
let sessionRegistered = false;
|
|
6863
7237
|
let sessionRemovedDuringInitialization = false;
|
|
6864
7238
|
let initializedSessionId;
|
|
@@ -7043,6 +7417,12 @@ function createAcpSessionBridge(opts) {
|
|
|
7043
7417
|
...entry.branch ? { branch: entry.branch } : {}
|
|
7044
7418
|
};
|
|
7045
7419
|
} finally {
|
|
7420
|
+
if (requestedSessionId !== void 0) {
|
|
7421
|
+
ci.client.clearSessionRegistrationInFlight(requestedSessionId);
|
|
7422
|
+
if (initializedSessionId !== requestedSessionId && !byId.has(requestedSessionId)) {
|
|
7423
|
+
ci.client.markSessionClosed(requestedSessionId);
|
|
7424
|
+
}
|
|
7425
|
+
}
|
|
7046
7426
|
ci.sessionSpawnsInFlight = Math.max(0, ci.sessionSpawnsInFlight - 1);
|
|
7047
7427
|
if (!sessionRegistered) {
|
|
7048
7428
|
await reapPendingEmptyChannel(ci);
|
|
@@ -7457,12 +7837,17 @@ function createAcpSessionBridge(opts) {
|
|
|
7457
7837
|
const getChildResourceSnapshot = /* @__PURE__ */ __name(() => {
|
|
7458
7838
|
const info = liveChannelInfo();
|
|
7459
7839
|
if (!info || info.childResourceAt === void 0) return void 0;
|
|
7460
|
-
|
|
7840
|
+
const ageMs = Date.now() - info.childResourceAt;
|
|
7841
|
+
if (ageMs > STALE_CHILD_RESOURCE_MS) {
|
|
7461
7842
|
return void 0;
|
|
7462
7843
|
}
|
|
7463
7844
|
return {
|
|
7464
7845
|
rssBytes: info.childRssBytes ?? 0,
|
|
7465
|
-
cpuPercent: info.childCpuPercent ?? 0
|
|
7846
|
+
cpuPercent: info.childCpuPercent ?? 0,
|
|
7847
|
+
// Bounded by the guard above, so a caller summing several children's
|
|
7848
|
+
// readings can say how far apart they were taken. Without it a sum of
|
|
7849
|
+
// readings up to `STALE_CHILD_RESOURCE_MS` apart looks instantaneous.
|
|
7850
|
+
ageMs
|
|
7466
7851
|
};
|
|
7467
7852
|
}, "getChildResourceSnapshot");
|
|
7468
7853
|
const requestSessionStatus = /* @__PURE__ */ __name(async (sessionId, method, params = {}, timeoutMs = initTimeoutMs) => {
|
|
@@ -7688,6 +8073,7 @@ function createAcpSessionBridge(opts) {
|
|
|
7688
8073
|
cwdChangeQueue: Promise.resolve(),
|
|
7689
8074
|
promptQueue: Promise.resolve(),
|
|
7690
8075
|
pendingPromptCount: 0,
|
|
8076
|
+
pendingAgentNotificationCount: 0,
|
|
7691
8077
|
pendingPromptList: [],
|
|
7692
8078
|
midTurnMessageQueue: [],
|
|
7693
8079
|
modelChangeQueue: Promise.resolve(),
|
|
@@ -7702,10 +8088,14 @@ function createAcpSessionBridge(opts) {
|
|
|
7702
8088
|
attachRefs: /* @__PURE__ */ new Map(),
|
|
7703
8089
|
spawnOwnerWantedKill: false,
|
|
7704
8090
|
promptActive: false,
|
|
8091
|
+
childHolds: null,
|
|
8092
|
+
childHoldsAt: null,
|
|
8093
|
+
activeWorkCloseInFlight: false,
|
|
7705
8094
|
retryAllowed: false
|
|
7706
8095
|
};
|
|
7707
8096
|
ci.sessionIds.add(entry.sessionId);
|
|
7708
8097
|
byId.set(entry.sessionId, entry);
|
|
8098
|
+
ci.client.clearAbandonedRestoreFence(entry.sessionId);
|
|
7709
8099
|
touchActivity();
|
|
7710
8100
|
telemetry.metrics?.sessionLifecycle("spawn");
|
|
7711
8101
|
emitSessionLifecycle({
|
|
@@ -8012,7 +8402,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8012
8402
|
const hideInheritedHistory = action === "load" && req.hideInheritedHistory === true;
|
|
8013
8403
|
const existing = byId.get(req.sessionId);
|
|
8014
8404
|
if (existing) {
|
|
8015
|
-
if (existing
|
|
8405
|
+
if (isClosingOrAuthorizingClose(existing)) {
|
|
8016
8406
|
throw new SessionNotFoundError(
|
|
8017
8407
|
req.sessionId,
|
|
8018
8408
|
"The session is closing; retry after close completes"
|
|
@@ -8020,7 +8410,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8020
8410
|
}
|
|
8021
8411
|
const replayFields = action === "load" && req.historyPageSize !== void 0 ? await refreshedReplayFieldsFor(existing, req.historyPageSize) : replayFieldsFor(existing, action);
|
|
8022
8412
|
const historyAnchorRecordId = action === "load" ? await resolveHistoryAnchorRecordId(existing, replayFields) : void 0;
|
|
8023
|
-
if (byId.get(req.sessionId) !== existing || existing
|
|
8413
|
+
if (byId.get(req.sessionId) !== existing || isClosingOrAuthorizingClose(existing)) {
|
|
8024
8414
|
throw new SessionNotFoundError(req.sessionId);
|
|
8025
8415
|
}
|
|
8026
8416
|
existing.attachCount++;
|
|
@@ -8046,19 +8436,27 @@ function createAcpSessionBridge(opts) {
|
|
|
8046
8436
|
...historyAnchorRecordId !== void 0 ? { historyAnchorRecordId } : {}
|
|
8047
8437
|
};
|
|
8048
8438
|
}
|
|
8439
|
+
if (inFlightRequestedSessionSpawns.has(req.sessionId)) {
|
|
8440
|
+
throw new RestoreInProgressError(req.sessionId, "spawn", action);
|
|
8441
|
+
}
|
|
8049
8442
|
const inFlight = inFlightRestores.get(req.sessionId);
|
|
8050
8443
|
if (inFlight) {
|
|
8051
|
-
if (action !== inFlight.action || historyReplay !== inFlight.historyReplay || hideInheritedHistory !== inFlight.hideInheritedHistory) {
|
|
8444
|
+
if (inFlight.lifecycle.phase === "abandoned" || action !== inFlight.action || historyReplay !== inFlight.historyReplay || hideInheritedHistory !== inFlight.hideInheritedHistory) {
|
|
8445
|
+
const abandoned = inFlight.lifecycle.phase === "abandoned";
|
|
8052
8446
|
throw new RestoreInProgressError(
|
|
8053
8447
|
req.sessionId,
|
|
8054
8448
|
inFlight.action,
|
|
8055
|
-
action
|
|
8449
|
+
action,
|
|
8450
|
+
abandoned ? {
|
|
8451
|
+
reason: "awaiting_abandoned_cleanup",
|
|
8452
|
+
retryAfterSeconds: abandonedRestoreRetryAfterSeconds
|
|
8453
|
+
} : void 0
|
|
8056
8454
|
);
|
|
8057
8455
|
}
|
|
8058
8456
|
inFlight.coalesceState.count++;
|
|
8059
8457
|
let restored;
|
|
8060
8458
|
try {
|
|
8061
|
-
restored = await inFlight.
|
|
8459
|
+
restored = await inFlight.publicPromise;
|
|
8062
8460
|
} catch (err) {
|
|
8063
8461
|
inFlight.coalesceState.count--;
|
|
8064
8462
|
throw err;
|
|
@@ -8084,6 +8482,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8084
8482
|
hasActivePrompt: entry.promptActive
|
|
8085
8483
|
};
|
|
8086
8484
|
}
|
|
8485
|
+
assertFreshSessionsAvailable();
|
|
8087
8486
|
if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
|
|
8088
8487
|
throw new SessionLimitExceededError(maxSessions);
|
|
8089
8488
|
}
|
|
@@ -8102,12 +8501,145 @@ function createAcpSessionBridge(opts) {
|
|
|
8102
8501
|
admissionReleased = true;
|
|
8103
8502
|
releaseFreshSessionReservation(admission);
|
|
8104
8503
|
}, "releaseAdmissionOnce");
|
|
8504
|
+
let resolveSettlement;
|
|
8505
|
+
const settlementPromise = new Promise((resolve2) => {
|
|
8506
|
+
resolveSettlement = resolve2;
|
|
8507
|
+
});
|
|
8508
|
+
const restoreLifecycle = {
|
|
8509
|
+
phase: "active"
|
|
8510
|
+
};
|
|
8511
|
+
const settleAbandonedRestore = /* @__PURE__ */ __name(async (channel, lateResult) => {
|
|
8512
|
+
telemetry.event("session.restore.late_result", {
|
|
8513
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8514
|
+
"qwen-code.daemon.session_restore.result": lateResult,
|
|
8515
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8516
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8517
|
+
"session.id": req.sessionId
|
|
8518
|
+
});
|
|
8519
|
+
const usurper = byId.get(req.sessionId);
|
|
8520
|
+
if (usurper) {
|
|
8521
|
+
writeStderrLine(
|
|
8522
|
+
`qwen serve: skipping abandoned session/${action} cleanup for ${JSON.stringify(req.sessionId)}: the id is now owned by a live session`
|
|
8523
|
+
);
|
|
8524
|
+
telemetry.event("session.restore.cleanup", {
|
|
8525
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8526
|
+
"qwen-code.daemon.session_restore.cleanup_result": "id_reclaimed",
|
|
8527
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8528
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8529
|
+
"session.id": req.sessionId
|
|
8530
|
+
});
|
|
8531
|
+
channel.unsettledAbandonedRestores.delete(req.sessionId);
|
|
8532
|
+
const reclaimedTimer = channel.restoreSettlementTimers.get(
|
|
8533
|
+
req.sessionId
|
|
8534
|
+
);
|
|
8535
|
+
if (reclaimedTimer !== void 0) {
|
|
8536
|
+
clearTimeout(reclaimedTimer);
|
|
8537
|
+
channel.restoreSettlementTimers.delete(req.sessionId);
|
|
8538
|
+
}
|
|
8539
|
+
if (channel.unsettledAbandonedRestores.size === 0) {
|
|
8540
|
+
channel.restoreSettlementOverdue = false;
|
|
8541
|
+
}
|
|
8542
|
+
releaseAdmissionOnce();
|
|
8543
|
+
resolveSettlement();
|
|
8544
|
+
return;
|
|
8545
|
+
}
|
|
8546
|
+
try {
|
|
8547
|
+
if (channel.isDying || !aliveChannels.has(channel)) {
|
|
8548
|
+
await channel.channel.exited;
|
|
8549
|
+
telemetry.event("session.restore.cleanup", {
|
|
8550
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8551
|
+
"qwen-code.daemon.session_restore.cleanup_result": "transport_closed",
|
|
8552
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8553
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8554
|
+
"session.id": req.sessionId
|
|
8555
|
+
});
|
|
8556
|
+
return;
|
|
8557
|
+
}
|
|
8558
|
+
try {
|
|
8559
|
+
await Promise.race([
|
|
8560
|
+
withTimeout(
|
|
8561
|
+
channel.connection.extMethod(
|
|
8562
|
+
SERVE_CONTROL_EXT_METHODS.sessionClose,
|
|
8563
|
+
{
|
|
8564
|
+
sessionId: req.sessionId,
|
|
8565
|
+
drainTimeoutMs: Math.max(1, Math.floor(initTimeoutMs * 0.8))
|
|
8566
|
+
}
|
|
8567
|
+
),
|
|
8568
|
+
initTimeoutMs,
|
|
8569
|
+
"abandonedRestoreClose"
|
|
8570
|
+
),
|
|
8571
|
+
getChannelClosedReject(channel)
|
|
8572
|
+
]);
|
|
8573
|
+
telemetry.event("session.restore.cleanup", {
|
|
8574
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8575
|
+
"qwen-code.daemon.session_restore.cleanup_result": "closed",
|
|
8576
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8577
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8578
|
+
"session.id": req.sessionId
|
|
8579
|
+
});
|
|
8580
|
+
} catch (error) {
|
|
8581
|
+
if (isAcpSessionResourceNotFound(error, req.sessionId)) {
|
|
8582
|
+
telemetry.event("session.restore.cleanup", {
|
|
8583
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8584
|
+
"qwen-code.daemon.session_restore.cleanup_result": "not_found",
|
|
8585
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8586
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8587
|
+
"session.id": req.sessionId
|
|
8588
|
+
});
|
|
8589
|
+
return;
|
|
8590
|
+
}
|
|
8591
|
+
if (channel.isDying || !aliveChannels.has(channel)) {
|
|
8592
|
+
await channel.channel.exited;
|
|
8593
|
+
telemetry.event("session.restore.cleanup", {
|
|
8594
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8595
|
+
"qwen-code.daemon.session_restore.cleanup_result": "transport_closed",
|
|
8596
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8597
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8598
|
+
"session.id": req.sessionId
|
|
8599
|
+
});
|
|
8600
|
+
return;
|
|
8601
|
+
}
|
|
8602
|
+
channel.isQuarantined = true;
|
|
8603
|
+
writeStderrLine(
|
|
8604
|
+
`qwen serve: quarantining ACP channel after timed-out session/${action} cleanup failed for ${JSON.stringify(req.sessionId)}: ${extractErrorMessage(error)}`
|
|
8605
|
+
);
|
|
8606
|
+
telemetry.event("session.restore.cleanup", {
|
|
8607
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8608
|
+
"qwen-code.daemon.session_restore.cleanup_result": "quarantined",
|
|
8609
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8610
|
+
"qwen-code.daemon.acp_channel.id": channel.id,
|
|
8611
|
+
"session.id": req.sessionId
|
|
8612
|
+
});
|
|
8613
|
+
if (hasNoChannelWork(channel)) {
|
|
8614
|
+
void killChannelWithLog(
|
|
8615
|
+
channel,
|
|
8616
|
+
`abandoned session/${action} cleanup`
|
|
8617
|
+
);
|
|
8618
|
+
}
|
|
8619
|
+
await channel.channel.exited;
|
|
8620
|
+
}
|
|
8621
|
+
} finally {
|
|
8622
|
+
channel.client.markSessionClosed(req.sessionId);
|
|
8623
|
+
channel.unsettledAbandonedRestores.delete(req.sessionId);
|
|
8624
|
+
const graceTimer = channel.restoreSettlementTimers.get(req.sessionId);
|
|
8625
|
+
if (graceTimer !== void 0) {
|
|
8626
|
+
clearTimeout(graceTimer);
|
|
8627
|
+
channel.restoreSettlementTimers.delete(req.sessionId);
|
|
8628
|
+
}
|
|
8629
|
+
if (channel.unsettledAbandonedRestores.size === 0) {
|
|
8630
|
+
channel.restoreSettlementOverdue = false;
|
|
8631
|
+
}
|
|
8632
|
+
releaseAdmissionOnce();
|
|
8633
|
+
resolveSettlement();
|
|
8634
|
+
}
|
|
8635
|
+
}, "settleAbandonedRestore");
|
|
8105
8636
|
const promise = (async () => {
|
|
8106
8637
|
pendingRestoreEvents.set(req.sessionId, restoreEvents);
|
|
8107
|
-
|
|
8108
|
-
ci
|
|
8109
|
-
|
|
8110
|
-
|
|
8638
|
+
const restoreChannel = await ensureChannel();
|
|
8639
|
+
ci = restoreChannel;
|
|
8640
|
+
restoreChannel.pendingRestoreIds.add(req.sessionId);
|
|
8641
|
+
restoreChannel.client.markRestoreInFlight(req.sessionId);
|
|
8642
|
+
const transportClosed = restoreChannel.channel.exited.then(() => {
|
|
8111
8643
|
throw new BridgeChannelClosedError(`during session/${action}`);
|
|
8112
8644
|
});
|
|
8113
8645
|
transportClosed.catch(() => {
|
|
@@ -8118,10 +8650,18 @@ function createAcpSessionBridge(opts) {
|
|
|
8118
8650
|
let replayError;
|
|
8119
8651
|
let replayHasMore;
|
|
8120
8652
|
try {
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8653
|
+
const rawRestore = telemetry.withSpan(
|
|
8654
|
+
"session.restore",
|
|
8655
|
+
{
|
|
8656
|
+
"qwen-code.daemon.bridge.operation": `session.${action}`,
|
|
8657
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8658
|
+
"qwen-code.daemon.acp_channel.id": restoreChannel.id,
|
|
8659
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8660
|
+
"session.id": req.sessionId
|
|
8661
|
+
},
|
|
8662
|
+
async () => {
|
|
8663
|
+
if (action === "load") {
|
|
8664
|
+
const request2 = telemetry.injectPromptContext({
|
|
8125
8665
|
sessionId: req.sessionId,
|
|
8126
8666
|
cwd: workspaceKey,
|
|
8127
8667
|
// Restore path drops per-request `mcpServers` (matches
|
|
@@ -8130,49 +8670,88 @@ function createAcpSessionBridge(opts) {
|
|
|
8130
8670
|
// intentionally has no `mcpServers` field for the
|
|
8131
8671
|
// same reason.
|
|
8132
8672
|
mcpServers: [],
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
...historyReplay === "response" ? {
|
|
8140
|
-
[LOAD_REPLAY_MODE_META_KEY]: LOAD_REPLAY_BULK_MODE,
|
|
8141
|
-
...req.historyPageSize !== void 0 ? {
|
|
8142
|
-
[LOAD_REPLAY_PAGE_SIZE_META_KEY]: req.historyPageSize
|
|
8143
|
-
} : {}
|
|
8144
|
-
} : {},
|
|
8145
|
-
...hideInheritedHistory ? {
|
|
8146
|
-
[LOAD_REPLAY_HIDE_INHERITED_META_KEY]: true
|
|
8673
|
+
_meta: {
|
|
8674
|
+
...sessionSourceRequestMeta(req.sourceType, req.sourceId),
|
|
8675
|
+
...historyReplay === "response" ? {
|
|
8676
|
+
[LOAD_REPLAY_MODE_META_KEY]: LOAD_REPLAY_BULK_MODE,
|
|
8677
|
+
...req.historyPageSize !== void 0 ? {
|
|
8678
|
+
[LOAD_REPLAY_PAGE_SIZE_META_KEY]: req.historyPageSize
|
|
8147
8679
|
} : {}
|
|
8148
|
-
}
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
)
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8680
|
+
} : {},
|
|
8681
|
+
...hideInheritedHistory ? { [LOAD_REPLAY_HIDE_INHERITED_META_KEY]: true } : {}
|
|
8682
|
+
}
|
|
8683
|
+
});
|
|
8684
|
+
return await restoreChannel.connection.loadSession(request2);
|
|
8685
|
+
}
|
|
8686
|
+
const request = telemetry.injectPromptContext({
|
|
8687
|
+
sessionId: req.sessionId,
|
|
8688
|
+
cwd: workspaceKey,
|
|
8689
|
+
mcpServers: [],
|
|
8690
|
+
_meta: sessionSourceRequestMeta(req.sourceType, req.sourceId)
|
|
8691
|
+
});
|
|
8692
|
+
return await restoreChannel.connection.unstable_resumeSession(
|
|
8693
|
+
request
|
|
8694
|
+
);
|
|
8695
|
+
}
|
|
8696
|
+
);
|
|
8697
|
+
const observedRestore = Promise.race([rawRestore, transportClosed]);
|
|
8698
|
+
state = await new Promise((resolve2, reject) => {
|
|
8699
|
+
const timer = setTimeout(() => {
|
|
8700
|
+
if (restoreLifecycle.phase !== "active") return;
|
|
8701
|
+
restoreLifecycle.phase = "abandoned";
|
|
8702
|
+
restoreChannel.pendingRestoreIds.delete(req.sessionId);
|
|
8703
|
+
restoreChannel.client.markRestoreAbandoned(req.sessionId);
|
|
8704
|
+
pendingRestoreEvents.delete(req.sessionId);
|
|
8705
|
+
restoreEvents.close();
|
|
8706
|
+
restoreChannel.unsettledAbandonedRestores.add(req.sessionId);
|
|
8707
|
+
const channelWasEmpty = hasNoChannelWork(restoreChannel);
|
|
8708
|
+
telemetry.event("session.restore.public_result", {
|
|
8709
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8710
|
+
"qwen-code.daemon.session_restore.result": "timeout",
|
|
8711
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8712
|
+
"qwen-code.daemon.acp_channel.id": restoreChannel.id,
|
|
8713
|
+
"qwen-code.daemon.session_restore.channel_was_empty": channelWasEmpty,
|
|
8714
|
+
"session.id": req.sessionId
|
|
8715
|
+
});
|
|
8716
|
+
writeStderrLine(
|
|
8717
|
+
`qwen serve: session/${action} timed out after ${sessionRestoreTimeoutMs}ms for ${JSON.stringify(req.sessionId)} on channel ${restoreChannel.id}; decision=${channelWasEmpty ? "kill_empty" : "fence_shared"}`
|
|
8718
|
+
);
|
|
8719
|
+
if (channelWasEmpty) {
|
|
8720
|
+
void killChannelWithLog(
|
|
8721
|
+
restoreChannel,
|
|
8722
|
+
`timed-out session/${action} on empty channel`
|
|
8723
|
+
);
|
|
8724
|
+
} else {
|
|
8725
|
+
armRestoreSettlementGrace(restoreChannel, req.sessionId, action);
|
|
8726
|
+
}
|
|
8727
|
+
reject(
|
|
8728
|
+
new SessionRestoreTimeoutError(
|
|
8729
|
+
req.sessionId,
|
|
8730
|
+
action,
|
|
8731
|
+
sessionRestoreTimeoutMs
|
|
8732
|
+
)
|
|
8733
|
+
);
|
|
8734
|
+
}, sessionRestoreTimeoutMs);
|
|
8735
|
+
timer.unref();
|
|
8736
|
+
void observedRestore.then(
|
|
8737
|
+
(value) => {
|
|
8738
|
+
if (restoreLifecycle.phase === "active") {
|
|
8739
|
+
clearTimeout(timer);
|
|
8740
|
+
resolve2(value);
|
|
8741
|
+
return;
|
|
8742
|
+
}
|
|
8743
|
+
void settleAbandonedRestore(restoreChannel, "success");
|
|
8744
|
+
},
|
|
8745
|
+
(error) => {
|
|
8746
|
+
if (restoreLifecycle.phase === "active") {
|
|
8747
|
+
clearTimeout(timer);
|
|
8748
|
+
reject(error);
|
|
8749
|
+
return;
|
|
8750
|
+
}
|
|
8751
|
+
void settleAbandonedRestore(restoreChannel, "failure");
|
|
8752
|
+
}
|
|
8753
|
+
);
|
|
8754
|
+
});
|
|
8176
8755
|
if (action === "load" && historyReplay === "response") {
|
|
8177
8756
|
const extracted = extractLoadReplayResponse(state);
|
|
8178
8757
|
state = extracted.state;
|
|
@@ -8182,6 +8761,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8182
8761
|
replayHasMore = extracted.hasMore === true ? true : void 0;
|
|
8183
8762
|
}
|
|
8184
8763
|
} catch (err) {
|
|
8764
|
+
if (err instanceof SessionRestoreTimeoutError) throw err;
|
|
8185
8765
|
restoreEvents.close();
|
|
8186
8766
|
if (isAcpSessionResourceNotFound(err, req.sessionId)) {
|
|
8187
8767
|
throw new SessionNotFoundError(req.sessionId);
|
|
@@ -8207,6 +8787,12 @@ function createAcpSessionBridge(opts) {
|
|
|
8207
8787
|
const racedEntry = byId.get(req.sessionId);
|
|
8208
8788
|
if (racedEntry) {
|
|
8209
8789
|
restoreEvents.close();
|
|
8790
|
+
if (isClosingOrAuthorizingClose(racedEntry)) {
|
|
8791
|
+
throw new SessionNotFoundError(
|
|
8792
|
+
req.sessionId,
|
|
8793
|
+
"The session is closing; retry after close completes"
|
|
8794
|
+
);
|
|
8795
|
+
}
|
|
8210
8796
|
racedEntry.attachCount += 1 + coalesceState.count;
|
|
8211
8797
|
const clientId2 = registerClient(racedEntry, req.clientId);
|
|
8212
8798
|
recordAttachRef(racedEntry, clientId2);
|
|
@@ -8312,6 +8898,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8312
8898
|
...replayFieldsFor(entry, action)
|
|
8313
8899
|
};
|
|
8314
8900
|
})().finally(async () => {
|
|
8901
|
+
if (restoreLifecycle.phase === "abandoned") return;
|
|
8315
8902
|
releaseAdmissionOnce();
|
|
8316
8903
|
ci?.pendingRestoreIds.delete(req.sessionId);
|
|
8317
8904
|
ci?.client.clearRestoreInFlight(req.sessionId);
|
|
@@ -8341,18 +8928,48 @@ function createAcpSessionBridge(opts) {
|
|
|
8341
8928
|
await reapPendingEmptyChannel(ci);
|
|
8342
8929
|
}
|
|
8343
8930
|
});
|
|
8931
|
+
void promise.then(
|
|
8932
|
+
() => {
|
|
8933
|
+
if (restoreLifecycle.phase === "active") {
|
|
8934
|
+
telemetry.event("session.restore.public_result", {
|
|
8935
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8936
|
+
"qwen-code.daemon.session_restore.result": "success",
|
|
8937
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8938
|
+
...ci ? { "qwen-code.daemon.acp_channel.id": ci.id } : {},
|
|
8939
|
+
"session.id": req.sessionId
|
|
8940
|
+
});
|
|
8941
|
+
resolveSettlement();
|
|
8942
|
+
}
|
|
8943
|
+
},
|
|
8944
|
+
() => {
|
|
8945
|
+
if (restoreLifecycle.phase === "active") {
|
|
8946
|
+
telemetry.event("session.restore.public_result", {
|
|
8947
|
+
"qwen-code.daemon.session_restore.action": action,
|
|
8948
|
+
"qwen-code.daemon.session_restore.result": "failure",
|
|
8949
|
+
"qwen-code.daemon.session_restore.timeout_ms": sessionRestoreTimeoutMs,
|
|
8950
|
+
...ci ? { "qwen-code.daemon.acp_channel.id": ci.id } : {},
|
|
8951
|
+
"session.id": req.sessionId
|
|
8952
|
+
});
|
|
8953
|
+
resolveSettlement();
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
);
|
|
8344
8957
|
inFlightRestores.set(req.sessionId, {
|
|
8345
8958
|
action,
|
|
8346
8959
|
historyReplay,
|
|
8347
8960
|
hideInheritedHistory,
|
|
8348
|
-
promise,
|
|
8961
|
+
publicPromise: promise,
|
|
8962
|
+
settlementPromise,
|
|
8963
|
+
lifecycle: restoreLifecycle,
|
|
8349
8964
|
coalesceState
|
|
8350
8965
|
});
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8966
|
+
void settlementPromise.finally(() => {
|
|
8967
|
+
const current = inFlightRestores.get(req.sessionId);
|
|
8968
|
+
if (current?.settlementPromise === settlementPromise) {
|
|
8969
|
+
inFlightRestores.delete(req.sessionId);
|
|
8970
|
+
}
|
|
8971
|
+
});
|
|
8972
|
+
return await promise;
|
|
8356
8973
|
}
|
|
8357
8974
|
__name(restoreSession, "restoreSession");
|
|
8358
8975
|
async function closeSessionImpl(sessionId, context, closeOpts) {
|
|
@@ -8390,7 +9007,8 @@ function createAcpSessionBridge(opts) {
|
|
|
8390
9007
|
entry.pendingInteractions.clear();
|
|
8391
9008
|
await notifyAgentSessionClose(entry, ci, "closeSession", {
|
|
8392
9009
|
throwOnFailure: true,
|
|
8393
|
-
requireFlush: closeOpts?.requireAgentClose === true
|
|
9010
|
+
requireFlush: closeOpts?.requireAgentClose === true,
|
|
9011
|
+
...closeOpts?.agentCloseTimeoutMs !== void 0 ? { timeoutMs: closeOpts.agentCloseTimeoutMs } : {}
|
|
8394
9012
|
});
|
|
8395
9013
|
} catch (error) {
|
|
8396
9014
|
if (isDefinitiveAcpRequestError(error)) {
|
|
@@ -8528,6 +9146,44 @@ function createAcpSessionBridge(opts) {
|
|
|
8528
9146
|
get activePromptCount() {
|
|
8529
9147
|
return activePromptCounter;
|
|
8530
9148
|
},
|
|
9149
|
+
get activeWork() {
|
|
9150
|
+
for (const entry of byId.values()) {
|
|
9151
|
+
if (entryHasActiveWork(entry)) return true;
|
|
9152
|
+
}
|
|
9153
|
+
return false;
|
|
9154
|
+
},
|
|
9155
|
+
/**
|
|
9156
|
+
* Raw coverage counts rather than a pre-collapsed grade.
|
|
9157
|
+
*
|
|
9158
|
+
* The grade has to be computed over the whole daemon, not per runtime and
|
|
9159
|
+
* then combined: a runtime with zero Sessions is vacuously `full`, and
|
|
9160
|
+
* folding that in as evidence made a deployment whose only real Sessions
|
|
9161
|
+
* were unreported aggregate to `partial`. Counts compose; grades do not.
|
|
9162
|
+
*/
|
|
9163
|
+
get activeWorkCoverage() {
|
|
9164
|
+
let covered = 0;
|
|
9165
|
+
let onNegotiatedChannel = 0;
|
|
9166
|
+
let total = 0;
|
|
9167
|
+
let oldestCoveredReportAt = null;
|
|
9168
|
+
for (const entry of byId.values()) {
|
|
9169
|
+
total++;
|
|
9170
|
+
const owner = channelInfoForEntry(entry);
|
|
9171
|
+
const capability = owner?.activeWork;
|
|
9172
|
+
if (!capability) continue;
|
|
9173
|
+
onNegotiatedChannel++;
|
|
9174
|
+
if (ACTIVE_WORK_HOLD_CATEGORIES.some(
|
|
9175
|
+
(category) => !capability.categories.includes(category)
|
|
9176
|
+
)) {
|
|
9177
|
+
continue;
|
|
9178
|
+
}
|
|
9179
|
+
if (!childHoldsAreFresh(entry, capability)) continue;
|
|
9180
|
+
covered++;
|
|
9181
|
+
if (entry.childHoldsAt !== null && (oldestCoveredReportAt === null || entry.childHoldsAt < oldestCoveredReportAt)) {
|
|
9182
|
+
oldestCoveredReportAt = entry.childHoldsAt;
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
9185
|
+
return { total, covered, onNegotiatedChannel, oldestCoveredReportAt };
|
|
9186
|
+
},
|
|
8531
9187
|
get lastActivityAt() {
|
|
8532
9188
|
return lastActivityTimestamp;
|
|
8533
9189
|
},
|
|
@@ -8557,7 +9213,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8557
9213
|
if (req.sessionScope !== void 0 && req.sessionScope !== "single" && req.sessionScope !== "thread") {
|
|
8558
9214
|
throw new InvalidSessionScopeError(req.sessionScope);
|
|
8559
9215
|
}
|
|
8560
|
-
const effectiveScope = req.sessionScope ?? defaultSessionScope;
|
|
9216
|
+
const effectiveScope = req.sessionId !== void 0 ? "thread" : req.sessionScope ?? defaultSessionScope;
|
|
8561
9217
|
const source = parseSessionSource(req.sourceType, req.sourceId);
|
|
8562
9218
|
if ("error" in source) {
|
|
8563
9219
|
throw new InvalidSessionMetadataError("sourceType", source.error);
|
|
@@ -8570,7 +9226,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8570
9226
|
if (effectiveScope === "single") {
|
|
8571
9227
|
const existing = defaultEntry;
|
|
8572
9228
|
if (existing) {
|
|
8573
|
-
if (existing
|
|
9229
|
+
if (isClosingOrAuthorizingClose(existing)) {
|
|
8574
9230
|
throw new SessionNotFoundError(
|
|
8575
9231
|
existing.sessionId,
|
|
8576
9232
|
"The session is closing; retry after close completes"
|
|
@@ -8644,13 +9300,51 @@ function createAcpSessionBridge(opts) {
|
|
|
8644
9300
|
};
|
|
8645
9301
|
}
|
|
8646
9302
|
}
|
|
9303
|
+
if (req.sessionId !== void 0) {
|
|
9304
|
+
const restoreOwner = inFlightRestores.get(req.sessionId);
|
|
9305
|
+
if (restoreOwner) {
|
|
9306
|
+
const abandoned = restoreOwner.lifecycle.phase === "abandoned";
|
|
9307
|
+
throw new RestoreInProgressError(
|
|
9308
|
+
req.sessionId,
|
|
9309
|
+
restoreOwner.action,
|
|
9310
|
+
"spawn",
|
|
9311
|
+
abandoned ? {
|
|
9312
|
+
reason: "awaiting_abandoned_cleanup",
|
|
9313
|
+
retryAfterSeconds: abandonedRestoreRetryAfterSeconds
|
|
9314
|
+
} : void 0
|
|
9315
|
+
);
|
|
9316
|
+
}
|
|
9317
|
+
if (inFlightRequestedSessionSpawns.has(req.sessionId)) {
|
|
9318
|
+
throw new RestoreInProgressError(req.sessionId, "spawn", "spawn");
|
|
9319
|
+
}
|
|
9320
|
+
}
|
|
9321
|
+
assertFreshSessionsAvailable();
|
|
8647
9322
|
if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
|
|
8648
9323
|
throw new SessionLimitExceededError(maxSessions);
|
|
8649
9324
|
}
|
|
8650
|
-
const
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
9325
|
+
const requestedSessionRegistrationOwner = req.sessionId !== void 0 ? Symbol(req.sessionId) : void 0;
|
|
9326
|
+
if (req.sessionId !== void 0 && requestedSessionRegistrationOwner !== void 0) {
|
|
9327
|
+
inFlightRequestedSessionSpawns.set(
|
|
9328
|
+
req.sessionId,
|
|
9329
|
+
requestedSessionRegistrationOwner
|
|
9330
|
+
);
|
|
9331
|
+
}
|
|
9332
|
+
const releaseRequestedSessionRegistration = /* @__PURE__ */ __name(() => {
|
|
9333
|
+
if (req.sessionId !== void 0 && requestedSessionRegistrationOwner !== void 0 && inFlightRequestedSessionSpawns.get(req.sessionId) === requestedSessionRegistrationOwner) {
|
|
9334
|
+
inFlightRequestedSessionSpawns.delete(req.sessionId);
|
|
9335
|
+
}
|
|
9336
|
+
}, "releaseRequestedSessionRegistration");
|
|
9337
|
+
let admission;
|
|
9338
|
+
try {
|
|
9339
|
+
admission = reserveFreshSession({
|
|
9340
|
+
operation: "spawn",
|
|
9341
|
+
workspaceCwd: workspaceKey,
|
|
9342
|
+
...req.sessionId !== void 0 ? { sessionId: req.sessionId } : {}
|
|
9343
|
+
});
|
|
9344
|
+
} catch (error) {
|
|
9345
|
+
releaseRequestedSessionRegistration();
|
|
9346
|
+
throw error;
|
|
9347
|
+
}
|
|
8654
9348
|
let admissionReleased = false;
|
|
8655
9349
|
const releaseAdmissionOnce = /* @__PURE__ */ __name(() => {
|
|
8656
9350
|
if (admissionReleased) return;
|
|
@@ -8677,6 +9371,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8677
9371
|
} finally {
|
|
8678
9372
|
releaseAdmissionOnce();
|
|
8679
9373
|
inFlightSpawns.delete(tracker);
|
|
9374
|
+
releaseRequestedSessionRegistration();
|
|
8680
9375
|
}
|
|
8681
9376
|
},
|
|
8682
9377
|
// Keep this method non-async: admission failures must throw before
|
|
@@ -8690,7 +9385,7 @@ function createAcpSessionBridge(opts) {
|
|
|
8690
9385
|
const queuedAt = Date.now();
|
|
8691
9386
|
const entry = byId.get(sessionId);
|
|
8692
9387
|
if (!entry) return Promise.reject(new SessionNotFoundError(sessionId));
|
|
8693
|
-
if (entry
|
|
9388
|
+
if (isClosingOrAuthorizingClose(entry)) {
|
|
8694
9389
|
return Promise.reject(
|
|
8695
9390
|
new SessionNotFoundError(
|
|
8696
9391
|
sessionId,
|
|
@@ -9067,15 +9762,7 @@ function createAcpSessionBridge(opts) {
|
|
|
9067
9762
|
);
|
|
9068
9763
|
entry.midTurnMessageQueue.length = 0;
|
|
9069
9764
|
}
|
|
9070
|
-
|
|
9071
|
-
void closeSessionImpl(sessionId, void 0, {
|
|
9072
|
-
reason: "last_client_detached"
|
|
9073
|
-
}).catch((err) => {
|
|
9074
|
-
writeStderrLine(
|
|
9075
|
-
`qwen serve: deferred close-on-prompt-complete failed for ${JSON.stringify(sessionId)}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
9076
|
-
);
|
|
9077
|
-
});
|
|
9078
|
-
}
|
|
9765
|
+
void maybeCloseIdleSession(entry, "prompt_settled");
|
|
9079
9766
|
}).catch(() => {
|
|
9080
9767
|
});
|
|
9081
9768
|
return result;
|
|
@@ -9266,6 +9953,7 @@ function createAcpSessionBridge(opts) {
|
|
|
9266
9953
|
if (entry.promptActive && !isSideTask) {
|
|
9267
9954
|
throw new BranchWhilePromptActiveError(sessionId);
|
|
9268
9955
|
}
|
|
9956
|
+
assertFreshSessionsAvailable();
|
|
9269
9957
|
if (byId.size + inFlightSpawns.size + inFlightRestores.size >= maxSessions) {
|
|
9270
9958
|
throw new SessionLimitExceededError(maxSessions);
|
|
9271
9959
|
}
|
|
@@ -10396,18 +11084,27 @@ function createAcpSessionBridge(opts) {
|
|
|
10396
11084
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
10397
11085
|
const info = channelInfoForEntry(entry);
|
|
10398
11086
|
if (!info || info.isDying) throw new SessionNotFoundError(sessionId);
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
11087
|
+
entry.pendingAgentNotificationCount++;
|
|
11088
|
+
try {
|
|
11089
|
+
const response = await Promise.race([
|
|
11090
|
+
withTimeout(
|
|
11091
|
+
entry.connection.extMethod(
|
|
11092
|
+
SERVE_CONTROL_EXT_METHODS.sessionBackgroundNotification,
|
|
11093
|
+
{ sessionId, ...notification }
|
|
11094
|
+
),
|
|
11095
|
+
initTimeoutMs,
|
|
11096
|
+
SERVE_CONTROL_EXT_METHODS.sessionBackgroundNotification
|
|
10404
11097
|
),
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
11098
|
+
getTransportClosedReject(entry)
|
|
11099
|
+
]);
|
|
11100
|
+
return { sessionId, accepted: response["accepted"] === true };
|
|
11101
|
+
} finally {
|
|
11102
|
+
entry.pendingAgentNotificationCount = Math.max(
|
|
11103
|
+
0,
|
|
11104
|
+
entry.pendingAgentNotificationCount - 1
|
|
11105
|
+
);
|
|
11106
|
+
void maybeCloseIdleSession(entry, "agent_notification_settled");
|
|
11107
|
+
}
|
|
10411
11108
|
},
|
|
10412
11109
|
async generateSessionBtw(sessionId, question, signal, _context) {
|
|
10413
11110
|
const entry = byId.get(sessionId);
|
|
@@ -10648,7 +11345,7 @@ function createAcpSessionBridge(opts) {
|
|
|
10648
11345
|
async rewindSession(sessionId, req, context) {
|
|
10649
11346
|
const entry = byId.get(sessionId);
|
|
10650
11347
|
if (!entry) throw new SessionNotFoundError(sessionId);
|
|
10651
|
-
if (entry
|
|
11348
|
+
if (isClosingOrAuthorizingClose(entry)) {
|
|
10652
11349
|
throw new SessionNotFoundError(sessionId, "The session is closing");
|
|
10653
11350
|
}
|
|
10654
11351
|
const info = channelInfoForEntry(entry);
|
|
@@ -11138,18 +11835,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11138
11835
|
if (entry.attachCount > 0) entry.attachCount--;
|
|
11139
11836
|
}
|
|
11140
11837
|
unregisterClient(entry, clientId);
|
|
11141
|
-
|
|
11142
|
-
await this.killSession(sessionId).catch(() => {
|
|
11143
|
-
});
|
|
11144
|
-
} else if (entry.clientIds.size === 0 && entry.events.subscriberCount === 0 && entry.pendingPromptCount === 0) {
|
|
11145
|
-
await closeSessionImpl(sessionId, void 0, {
|
|
11146
|
-
reason: "last_client_detached"
|
|
11147
|
-
}).catch((err) => {
|
|
11148
|
-
writeStderrLine(
|
|
11149
|
-
`qwen serve: close-on-last-detach failed for ${JSON.stringify(sessionId)}: ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
11150
|
-
);
|
|
11151
|
-
});
|
|
11152
|
-
}
|
|
11838
|
+
await maybeCloseIdleSession(entry, "last_client_detached");
|
|
11153
11839
|
},
|
|
11154
11840
|
killAllSync() {
|
|
11155
11841
|
shuttingDown = true;
|
|
@@ -11226,7 +11912,7 @@ function createAcpSessionBridge(opts) {
|
|
|
11226
11912
|
)
|
|
11227
11913
|
);
|
|
11228
11914
|
const inFlightRestoreAwaits = Array.from(inFlightRestores.values()).map(
|
|
11229
|
-
(restore) => restore.
|
|
11915
|
+
(restore) => restore.settlementPromise.then(
|
|
11230
11916
|
() => void 0,
|
|
11231
11917
|
() => void 0
|
|
11232
11918
|
)
|