@qwen-code/qwen-code 0.20.2-jobbench-no-todo-write.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled/qc-helper/docs/configuration/settings.md +5 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +23 -5
- package/bundled/qc-helper/docs/integration-github-action.md +9 -9
- package/bundled/review/SKILL.md +7 -3
- package/chunks/MaxSizedBox-5DPPWPGT.js +85 -0
- package/chunks/{StandaloneSessionPicker-WBRBHD2M.js → StandaloneSessionPicker-BIRMPLRD.js} +66 -58
- package/chunks/{acp-startup-profiler-N3RHHXJ3.js → acp-startup-profiler-RV3IV562.js} +2 -2
- package/chunks/{acpAgent-BBQZ33CA.js → acpAgent-6J2U72PQ.js} +706 -182
- package/chunks/agent-6ODUANDO.js +81 -0
- package/chunks/agent-headless-7BYQTMHW.js +75 -0
- package/chunks/{anthropicContentGenerator-HGWAHO24.js → anthropicContentGenerator-75BKLTSP.js} +117 -43
- package/chunks/{artifact-tool-56T5IMBP.js → artifact-tool-Y5T7GG7F.js} +3 -3
- package/chunks/{askUserQuestion-E25OBIC2.js → askUserQuestion-2H6747FR.js} +3 -3
- package/chunks/bridge-ZUB64FAE.js +90 -0
- package/chunks/{build-SSCNEHZZ.js → build-RV63TIRH.js} +2 -3
- package/chunks/{ca-N6VVUFVB.js → ca-25EDXPFZ.js} +2 -0
- package/chunks/{channel-worker-group-LFBT7K64.js → channel-worker-group-2ZD7TVAT.js} +7 -6
- package/chunks/{channel-worker-manager-3RUPERG2.js → channel-worker-manager-4OA4BCGB.js} +189 -29
- package/chunks/{channel-worker-supervisor-A3KVATD3.js → channel-worker-supervisor-V7KCFJTS.js} +6 -5
- package/chunks/{chunk-TYQMGACW.js → chunk-22C7BQ6D.js} +508 -10967
- package/chunks/chunk-2JZBVYTU.js +452 -0
- package/chunks/{chunk-H2XVO6NE.js → chunk-2MIN6GRR.js} +1 -1
- package/chunks/{chunk-B2HSPMD4.js → chunk-2NH6DYI4.js} +12 -12
- package/chunks/chunk-2SCDWPXI.js +246 -0
- package/chunks/{chunk-JK26TQON.js → chunk-2X55UKQE.js} +3 -3
- package/chunks/{chunk-7VUQQBR7.js → chunk-3QMGYBFN.js} +2 -65
- package/chunks/{chunk-UMCULC5M.js → chunk-3RN6GBKS.js} +1 -1
- package/chunks/{chunk-QR6U5QPP.js → chunk-3SJ43L4W.js} +4 -0
- package/chunks/chunk-46UV252V.js +128 -0
- package/chunks/{chunk-GPMVHZP4.js → chunk-4WIZGAH3.js} +7 -7
- package/chunks/{chunk-CI3GWKGJ.js → chunk-55DJUCI2.js} +87 -29
- package/chunks/{chunk-QNLNLENL.js → chunk-5I2IWRSH.js} +2 -2
- package/chunks/{chunk-D7WXIW7H.js → chunk-5NBDS5S6.js} +145 -5
- package/chunks/{chunk-E4IMU4Y5.js → chunk-63P4EL5V.js} +1 -1
- package/chunks/chunk-6FGBXPWM.js +293 -0
- package/chunks/{chunk-NEEB7UEN.js → chunk-6GMVPFB2.js} +153 -72
- package/chunks/{chunk-KWK7UE6L.js → chunk-6OUGMXDC.js} +6 -6
- package/chunks/{chunk-QRUIS3DN.js → chunk-6PEXNQTX.js} +22 -1
- package/chunks/{chunk-77OZOGPT.js → chunk-7JURR4JT.js} +1 -1
- package/chunks/{chunk-4MWNZNJ4.js → chunk-7MVVZO4N.js} +4 -4
- package/chunks/{chunk-6ZBPS62S.js → chunk-7ZCNENPP.js} +1 -1
- package/chunks/{chunk-6X4GWOPW.js → chunk-A5L3JMUA.js} +1 -1
- package/chunks/{chunk-B3I77W5J.js → chunk-ACY3A37B.js} +3 -3
- package/chunks/chunk-AMDSOFFV.js +10860 -0
- package/chunks/{chunk-RV4C2ZFG.js → chunk-BIQWWWJN.js} +1 -1
- package/chunks/{chunk-ZHERRXZJ.js → chunk-BJX6ZSUK.js} +4 -4
- package/chunks/chunk-BK2UNYWD.js +29 -0
- package/chunks/{chunk-7TLUW4ZE.js → chunk-BKHWX6I2.js} +3 -3
- package/chunks/chunk-BPJSQIJX.js +100 -0
- package/chunks/{chunk-M7WBGLYP.js → chunk-BULDBTYC.js} +2 -0
- package/chunks/{chunk-H4A4A2SY.js → chunk-CIKQ7KKO.js} +4625 -8645
- package/chunks/{chunk-QZJY47IE.js → chunk-D3UEZIQH.js} +7 -5
- package/chunks/chunk-DHHOYAPR.js +1462 -0
- package/chunks/{chunk-LESHKUWF.js → chunk-DLWL3Z7A.js} +5 -3
- package/chunks/{chunk-XHATNRQA.js → chunk-DP3IHZGG.js} +0 -2
- package/chunks/chunk-E5TUC6CA.js +479 -0
- package/chunks/{chunk-6NRFYMKG.js → chunk-EBJQ6AXW.js} +11 -10
- package/chunks/{chunk-HABKX6LY.js → chunk-EPDRMGT4.js} +164 -17
- package/chunks/{chunk-P2BQZ7H7.js → chunk-ETSW4KLJ.js} +2 -2
- package/chunks/{chunk-KHOVYUHX.js → chunk-FNQ6T3CV.js} +20 -3
- package/chunks/{chunk-64EG42HV.js → chunk-FQK6JAFG.js} +72 -23
- package/chunks/{chunk-L6U47G5P.js → chunk-FSITMZJH.js} +8 -8
- package/chunks/{chunk-6RLROE6G.js → chunk-GLWP3FDB.js} +80 -15
- package/chunks/{chunk-CXIOPXRR.js → chunk-GSN55ZRI.js} +5 -5
- package/chunks/{chunk-LVA5OHQO.js → chunk-H4SBPHSA.js} +3 -3
- package/chunks/chunk-H5FFA6TH.js +902 -0
- package/chunks/{chunk-TDKQP3M6.js → chunk-HIJQF5B5.js} +1 -1
- package/chunks/{chunk-NXE6SQIV.js → chunk-IJTOWOD7.js} +14 -3
- package/chunks/chunk-IKCX4CCL.js +469 -0
- package/chunks/{chunk-7SSWNGEJ.js → chunk-IKYJHJNF.js} +3 -3
- package/chunks/{chunk-64XKYOXK.js → chunk-IO3IX5Q4.js} +1 -1
- package/chunks/{chunk-RS7MT2QG.js → chunk-IPUUTYMV.js} +2 -4
- package/chunks/{chunk-XU457J4V.js → chunk-IRH27ZC2.js} +2 -2
- package/chunks/{chunk-SVIMKSEI.js → chunk-J24WCGIN.js} +4 -4
- package/chunks/{chunk-4LVZNIDO.js → chunk-J56UI34H.js} +4 -13
- package/chunks/{chunk-TJTKSVIV.js → chunk-JLU636DO.js} +5 -1
- package/chunks/{chunk-7PIL2BYF.js → chunk-JVPM2ULZ.js} +6 -6
- package/chunks/{chunk-KBB5O3JO.js → chunk-JXJFVC6E.js} +37 -18
- package/chunks/chunk-JZA3JUDJ.js +82 -0
- package/chunks/{chunk-45PO6ZIS.js → chunk-K36B6G2O.js} +5 -5
- package/chunks/{chunk-GPSKDNEE.js → chunk-K4XWPEWB.js} +4 -4
- package/chunks/{chunk-K7EUPLIP.js → chunk-KIM5GUMA.js} +654 -117
- package/chunks/{chunk-42W5BDEY.js → chunk-KMQ33DO4.js} +7 -5
- package/chunks/{chunk-E2UVIFI2.js → chunk-KRXPRVGL.js} +0 -1
- package/chunks/{chunk-WHGVTP7Q.js → chunk-L26JL52R.js} +3 -3
- package/chunks/{chunk-7Z6JQEL6.js → chunk-L5UHQJTJ.js} +1 -1
- package/chunks/{chunk-26CBI4DC.js → chunk-LB6DUZ26.js} +259 -67
- package/chunks/chunk-LEH5C7FV.js +232 -0
- package/chunks/{chunk-UTGFTJ2H.js → chunk-LH2BYDQ5.js} +6 -4
- package/chunks/{chunk-QKTHJXCS.js → chunk-LK7CHLVP.js} +79 -2
- package/chunks/{chunk-V7WNRZL7.js → chunk-LKEJ26GS.js} +11 -11
- package/chunks/{chunk-6VPLV3L3.js → chunk-LQIW3YFY.js} +227 -41
- package/chunks/chunk-LS77BEZP.js +405 -0
- package/chunks/{chunk-5WDRI7US.js → chunk-M4FMGVY4.js} +3 -3
- package/chunks/{chunk-57FIIFJN.js → chunk-M5JM7OSF.js} +1 -1
- package/chunks/{chunk-7362QS5B.js → chunk-MB4MZHMJ.js} +80 -37
- package/chunks/{chunk-4K56OJFJ.js → chunk-MUP3T3AD.js} +1 -1
- package/chunks/{chunk-CJQ3FZ2G.js → chunk-MVSUYZDT.js} +4 -4
- package/chunks/{chunk-6FZYKBKV.js → chunk-MZAXJAUM.js} +1 -1
- package/chunks/{chunk-32L4D2O2.js → chunk-NH6KE4JX.js} +3 -3
- package/chunks/chunk-NIBLUX3Y.js +934 -0
- package/chunks/{chunk-OQB4EXO4.js → chunk-NL7LTRLR.js} +1 -1
- package/chunks/{chunk-6S5HSCOI.js → chunk-OFDOK3VM.js} +5 -5
- package/chunks/{chunk-LIZRAKPB.js → chunk-OHNBB4XR.js} +1 -1
- package/chunks/{chunk-MDZTPSXO.js → chunk-OKY7HXPG.js} +2 -2
- package/chunks/{chunk-NHDKSOEY.js → chunk-P3QQPMQA.js} +5 -5
- package/chunks/{chunk-4SCOLXTD.js → chunk-PC6JANNU.js} +5 -5
- package/chunks/{chunk-IWALV67J.js → chunk-PHOF65IG.js} +4300 -1284
- package/chunks/{chunk-OQ5SYCPE.js → chunk-PJIZUQVC.js} +2 -2
- package/chunks/{chunk-5DTTYNB7.js → chunk-PQNHRFJC.js} +16 -3
- package/chunks/{chunk-YM3SZTH4.js → chunk-PR75REBZ.js} +18 -1
- package/chunks/{chunk-5XORMWA2.js → chunk-PSOO6YXD.js} +18 -15
- package/chunks/{chunk-X6N25LXS.js → chunk-PWTZEM3C.js} +2 -2
- package/chunks/{chunk-GSX6P2JW.js → chunk-PWVFN2LF.js} +1 -1
- package/chunks/{chunk-AHX6AKPD.js → chunk-Q4M4MDQ4.js} +2 -2
- package/chunks/{chunk-3EHJ44GG.js → chunk-QAF7NMK7.js} +1 -1
- package/chunks/{chunk-WSYKDFYR.js → chunk-R5AFZNQW.js} +5 -5
- package/chunks/{chunk-63DJBU32.js → chunk-RF3EXIHJ.js} +39 -18
- package/chunks/{chunk-4K7VDKAD.js → chunk-RHLZR4E5.js} +1 -1
- package/chunks/{chunk-SXPSOMQ4.js → chunk-RIBKPMRP.js} +220 -141
- package/chunks/{chunk-RVLZCXEE.js → chunk-RWTEFFPU.js} +82 -3
- package/chunks/{chunk-ZUTM4LHM.js → chunk-RZIX2G32.js} +1 -1
- package/chunks/{chunk-ZKBNRL6O.js → chunk-SQCQ4KO2.js} +336 -404
- package/chunks/{chunk-THJNPLI4.js → chunk-TARRHLLG.js} +1 -0
- package/chunks/{chunk-RHYFF54J.js → chunk-TEHGS6UP.js} +50 -21
- package/chunks/{chunk-ACQJPDDS.js → chunk-TGILQ3YH.js} +8 -8
- package/chunks/{chunk-Q2YKNMLS.js → chunk-TOFQCPDC.js} +43 -10
- package/chunks/{chunk-ACZIBDYD.js → chunk-TPRQ7RZH.js} +587 -176
- package/chunks/{chunk-T4TZQJ7W.js → chunk-TWPJO254.js} +5 -16
- package/chunks/{chunk-7MWABCXU.js → chunk-U7M2DMGW.js} +3 -3
- package/chunks/{chunk-KQQ757OQ.js → chunk-UDX5OBWR.js} +41 -9
- package/chunks/{chunk-SRPZG4ER.js → chunk-USTWD7QV.js} +6 -4
- package/chunks/{chunk-NPQDJGKU.js → chunk-UUUTRMI2.js} +1 -1
- package/chunks/chunk-UW5EOVUN.js +249 -0
- package/chunks/{chunk-6IL7KRLE.js → chunk-VAK25FTU.js} +1 -1
- package/chunks/{chunk-TDDFEPBX.js → chunk-VIA5XA4U.js} +5 -2
- package/chunks/{chunk-3BJDQVE6.js → chunk-VRYUBFMC.js} +1 -1
- package/chunks/{chunk-PLQODS7F.js → chunk-VULLI6WQ.js} +172 -6
- package/chunks/{chunk-GN45XAAU.js → chunk-WCXCRJYB.js} +1 -1
- package/chunks/{chunk-2LI23QA6.js → chunk-X5XDDSSH.js} +1 -1
- package/chunks/{chunk-O32RMIMO.js → chunk-Y34KJKDC.js} +1 -1
- package/chunks/{chunk-7ZD5EKXE.js → chunk-YBL3QUDD.js} +2 -2
- package/chunks/{chunk-H4AR2JQF.js → chunk-YH6G52F2.js} +3 -3
- package/chunks/{chunk-3G3UUMRS.js → chunk-YPE6A4GC.js} +2 -2
- package/chunks/{chunk-3F2JUWCH.js → chunk-YX324OPW.js} +1 -1
- package/chunks/{chunk-CGIDQG6J.js → chunk-Z2BC6UJ5.js} +3 -3
- package/chunks/{chunk-QLJUC7TG.js → chunk-ZD6UTE4A.js} +1 -1
- package/chunks/{chunk-ZPWJZHJ2.js → chunk-ZFDTEDCF.js} +6 -6
- package/chunks/chunk-ZJHVAS7M.js +289 -0
- package/chunks/{chunk-XAGLQITN.js → chunk-ZNAUOR2I.js} +15 -12
- package/chunks/{chunk-T2L47JJK.js → chunk-ZOIFNCKL.js} +4 -4
- package/chunks/{computer-use-RZ3UUWYW.js → computer-use-SOQ4E3VX.js} +43 -34
- package/chunks/{config-utils-SQUBZEQM.js → config-utils-7V7GGIW6.js} +3 -3
- package/chunks/contextCommand-JLHYA34Z.js +80 -0
- package/chunks/{create-sub-session-AZ77LBL3.js → create-sub-session-IWW2IZ2T.js} +3 -3
- package/chunks/{create-sub-session-EQG73FT6.js → create-sub-session-QRJLW5BV.js} +43 -34
- package/chunks/{cron-create-KTWJM7QT.js → cron-create-YIID5XAW.js} +6 -6
- package/chunks/{cron-delete-2P3I5ULL.js → cron-delete-ZVHYCEP2.js} +5 -5
- package/chunks/{cron-list-PXDPGEDQ.js → cron-list-XEGS463Q.js} +5 -5
- package/chunks/{daemon-RAPSDJH7.js → daemon-YO6433NF.js} +350 -53
- package/chunks/daemon-status-provider-2233Q37D.js +89 -0
- package/chunks/{de-4IBXM7CN.js → de-HGRCYDEJ.js} +1 -0
- package/chunks/{dist-UIFWIFRO.js → dist-46NQKLTW.js} +2 -2
- package/chunks/{dist-XRYV6TJP.js → dist-AIKFMUKK.js} +50 -4
- package/chunks/{dist-XBJVSWS2.js → dist-BBLXMS3N.js} +14 -2
- package/chunks/{dist-OMW6WDEO.js → dist-F6IBUDR4.js} +40 -9
- package/chunks/{dist-PJLG2XYX.js → dist-WEAHOXDM.js} +1 -1
- package/chunks/{dist-OAV7LJGJ.js → dist-YFNEUWSE.js} +26 -2
- package/chunks/earlyInputCapture-A7NDU3PF.js +82 -0
- package/chunks/{edit-XRSKQPHQ.js → edit-OBDSQURM.js} +43 -34
- package/chunks/{en-USMCCJAJ.js → en-MTWBNGDO.js} +15 -0
- package/chunks/{enter-worktree-WAHCWE6I.js → enter-worktree-U6MRPQ2P.js} +43 -34
- package/chunks/{enterPlanMode-QIOYLDCF.js → enterPlanMode-BC5QUZZ2.js} +43 -34
- package/chunks/{environment-T3FXCDJI.js → environment-W5UFC2CH.js} +46 -37
- package/chunks/errors-M7CLORXH.js +88 -0
- package/chunks/{exit-worktree-RHVTLX6T.js → exit-worktree-DGNYMECB.js} +43 -34
- package/chunks/{exitPlanMode-UATOE2GQ.js → exitPlanMode-GXTBWQAR.js} +43 -34
- package/chunks/{fast-path-J3RHOYSZ.js → fast-path-JJZFJANL.js} +6 -6
- package/chunks/{fast-path-settings-XB3CPUJT.js → fast-path-settings-WQJU2LAT.js} +2 -2
- package/chunks/{fr-WVHEBDDB.js → fr-45RLL55O.js} +1 -0
- package/chunks/{gemini-P72OGOH6.js → gemini-QS36EBZV.js} +133 -102
- package/chunks/{geminiContentGenerator-F6EG5FXF.js → geminiContentGenerator-AG4KB6CV.js} +14 -8
- package/chunks/{getMachineId-bsd-QFVLPUPT.js → getMachineId-bsd-V7W3GODC.js} +1 -1
- package/chunks/{getMachineId-darwin-DGMQQE2E.js → getMachineId-darwin-TDO75DQP.js} +1 -1
- package/chunks/{getMachineId-linux-R4Z6CSWC.js → getMachineId-linux-TF43WQT2.js} +1 -1
- package/chunks/{getMachineId-unsupported-Z3SBVBUV.js → getMachineId-unsupported-ZGUO3TXT.js} +1 -1
- package/chunks/{getMachineId-win-SCK5UFDT.js → getMachineId-win-ECFYZZFQ.js} +1 -1
- package/chunks/{glob-WHASQZRX.js → glob-V7R3PSK3.js} +43 -34
- package/chunks/{grep-LS7AADJ3.js → grep-QYPSK7OP.js} +43 -34
- package/chunks/handleAutoUpdate-6DBEZYPV.js +81 -0
- package/chunks/{i18n-IMVASWIF.js → i18n-VUJJZIMU.js} +44 -35
- package/chunks/image-gen-Z3VPGKRC.js +240 -0
- package/chunks/initializer-UWAK5U5O.js +86 -0
- package/chunks/installationInfo-6O2YAA52.js +80 -0
- package/chunks/{ja-KY4ROZTE.js → ja-B7DF7DFG.js} +1 -0
- package/chunks/{keychain-token-storage-6ACJDYIB.js → keychain-token-storage-MDTG3WRM.js} +3 -3
- package/chunks/{kittyProtocolDetector-HCNNKJTI.js → kittyProtocolDetector-MBRTDRBK.js} +5 -3
- package/chunks/list-GB4ESM3T.js +89 -0
- package/chunks/list-agents-5KJJHR6I.js +80 -0
- package/chunks/loadedSettingsAdapter-OT6JVQ7U.js +83 -0
- package/chunks/loggingContentGenerator-HS3S5H3Q.js +1077 -0
- package/chunks/{loop-wakeup-RNMRVA66.js → loop-wakeup-FXKNNYSY.js} +7 -7
- package/chunks/{ls-J2ZI5XYK.js → ls-NTK6VOQJ.js} +5 -5
- package/chunks/{lsp-UMS3NUB5.js → lsp-2JI24STP.js} +3 -3
- package/chunks/{managed-npm-update-L6UY7OM7.js → managed-npm-update-JYEMMXA3.js} +94 -37
- package/chunks/mcp-6DBDJPFU.js +83 -0
- package/chunks/{monitor-DXYFB5QD.js → monitor-R3ODH5U6.js} +45 -35
- package/chunks/node-UUDY34IG.js +305 -0
- package/chunks/nonInteractiveCli-MOYCYBBU.js +141 -0
- package/chunks/{notebook-edit-KGD7YJEA.js → notebook-edit-BNOK452R.js} +43 -34
- package/chunks/{openaiContentGenerator-C74A2XAU.js → openaiContentGenerator-WMCU3O2H.js} +27 -17
- package/chunks/pidfile-TFRZZZIO.js +86 -0
- package/chunks/{processUtils-GUT5B4R6.js → processUtils-RT7UNCC2.js} +2 -2
- package/chunks/{pt-OK455PLH.js → pt-22Q3FP73.js} +1 -0
- package/chunks/{qwenContentGenerator-PT46FQPA.js → qwenContentGenerator-HHCRK4SX.js} +56 -41
- package/chunks/{qwenOAuth2-S7DZHUUU.js → qwenOAuth2-OWLB5AKH.js} +14 -27
- package/chunks/read-file-APMO3PSX.js +31 -0
- package/chunks/{read-mcp-resource-F6HYMDUY.js → read-mcp-resource-4DKQWGHD.js} +3 -3
- package/chunks/{record-artifact-7GCFLDD7.js → record-artifact-RQKFYO5B.js} +3 -3
- package/chunks/resumeHistoryUtils-6KRYEAWZ.js +91 -0
- package/chunks/ripGrep-BEJDEDXW.js +73 -0
- package/chunks/{ru-7SPDGMGD.js → ru-FZCNZHDC.js} +1 -0
- package/chunks/{run-qwen-serve-QO4PT5NV.js → run-qwen-serve-FU6HEM4J.js} +276 -62
- package/chunks/{runtime-EOTXBUM6.js → runtime-XXRRTNP6.js} +55 -44
- package/chunks/{scheduler-MAIQ2PHR.js → scheduler-G2ZS2Z7E.js} +43 -34
- package/chunks/{sdk-exporters-grpc-ETLH47EP.js → sdk-exporters-grpc-AK3LGHNO.js} +3 -3
- package/chunks/{sdk-exporters-http-T3POX73F.js → sdk-exporters-http-FYBSUCPD.js} +6 -6
- package/chunks/{sdk-impl-NSLPDH6I.js → sdk-impl-GMVPB7NB.js} +6 -6
- package/chunks/{send-message-PYIJ2PZL.js → send-message-Q6OOR6BR.js} +46 -9
- package/chunks/serve-7BSTXJ4T.js +89 -0
- package/chunks/{server-CBCC3XQC.js → server-4UMH7OIZ.js} +2348 -396
- package/chunks/{session-RQUEFQDL.js → session-K3O3Q2SV.js} +107 -88
- package/chunks/{settings-QHXCJDSR.js → settings-CR2EWTBA.js} +53 -44
- package/chunks/shell-HH3PF3A2.js +83 -0
- package/chunks/{skill-WHSGTGKP.js → skill-I3SDA4MB.js} +17 -15
- package/chunks/spawnChannel-RWNDBXGA.js +82 -0
- package/chunks/{src-F3HKX47D.js → src-GE4TTTML.js} +290 -171
- package/chunks/{standalone-update-BKLONSVI.js → standalone-update-Q6WFRZZQ.js} +45 -36
- package/chunks/{startInteractiveUI-TNJ37X5W.js → startInteractiveUI-SLZGHRPH.js} +736 -298
- package/chunks/{syntheticOutput-H7RTI5KL.js → syntheticOutput-I3757IWH.js} +4 -4
- package/chunks/{task-create-7474AJJD.js → task-create-N7WQSGYA.js} +10 -10
- package/chunks/{task-list-633HGOIB.js → task-list-FOPULZEP.js} +7 -7
- package/chunks/{task-stop-MNUGHPIA.js → task-stop-H6RHXFVQ.js} +4 -4
- package/chunks/{task-update-66GQB5LI.js → task-update-M57TFZJT.js} +10 -10
- package/chunks/{team-create-LUHJ7ZCC.js → team-create-YJALH5D2.js} +44 -35
- package/chunks/{team-delete-BB3CG3QF.js → team-delete-QE2UXJL7.js} +7 -7
- package/chunks/{team-plan-approval-X3DYRL6L.js → team-plan-approval-34QFYKGN.js} +43 -34
- package/chunks/theme-manager-SWRILQHI.js +77 -0
- package/chunks/todoWrite-VQ7FKOHL.js +358 -0
- package/chunks/{tool-search-BAWOETUY.js → tool-search-NF7GB6LE.js} +16 -16
- package/chunks/total-session-admission-DLHHHLD3.js +84 -0
- package/chunks/{tree-sitter-FS4VPMZA.js → tree-sitter-4D7QS7F6.js} +1 -1
- package/chunks/{tree-sitter-bash-6B46JJCV.js → tree-sitter-bash-VEJGF5XF.js} +1 -1
- package/chunks/{trustedFolders-4UEOIKOF.js → trustedFolders-KHXHY6PY.js} +44 -35
- package/chunks/{update-relaunch-WDWABT5P.js → update-relaunch-WBUZJC5O.js} +5 -5
- package/chunks/updateCheck-RKL6M5XN.js +92 -0
- package/chunks/useAutoAcceptIndicator-CFQ5BUJL.js +93 -0
- package/chunks/{validateNonInterActiveAuth-OKUE3JLF.js → validateNonInterActiveAuth-3R223G3R.js} +91 -81
- package/chunks/{version-GMUULLWB.js → version-HS7YSFHV.js} +1 -1
- package/chunks/{web-fetch-JBWTMPFN.js → web-fetch-NKCSG7ZE.js} +18 -16
- package/chunks/{web-search-27COJHJT.js → web-search-S62WAP4S.js} +13 -27
- package/chunks/{workflow-5L37J7YF.js → workflow-QAGU5RU4.js} +44 -35
- package/chunks/workspace-providers-status-QSVZUETE.js +86 -0
- package/chunks/{workspace-registration-store-TYPYXIP6.js → workspace-registration-store-24JMHDGF.js} +2 -2
- package/chunks/workspace-registry-UT4RBNBM.js +88 -0
- package/chunks/workspace-service-JFWRUS4V.js +98 -0
- package/chunks/workspace-skills-status-ZBBKJOI2.js +85 -0
- package/chunks/write-file-VHIXW5M7.js +73 -0
- package/chunks/{zh-WY5DWYZD.js → zh-LUIGBD55.js} +15 -0
- package/chunks/{zh-TW-BM47YBFH.js → zh-TW-F5KG2IYD.js} +15 -0
- package/cli-entry.js +10 -1
- package/cli.js +13 -13
- package/locales/ca.js +2 -0
- package/locales/de.js +1 -0
- package/locales/en.js +25 -0
- package/locales/fr.js +1 -0
- package/locales/ja.js +1 -0
- package/locales/pt.js +1 -0
- package/locales/ru.js +1 -0
- package/locales/zh-TW.js +23 -0
- package/locales/zh.js +23 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-BWFm0SI0.js → arc-DcbWnB9T.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-CZ_yL-DQ.js → architectureDiagram-3BPJPVTR-kMMF5sud.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-B9F9mJvG.js → blockDiagram-GPEHLZMM-Htl9vTJS.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-BUdwJW5f.js → c4Diagram-AAUBKEIU-BnZnm0mQ.js} +1 -1
- package/web-shell/assets/channel-Cq7YKtfC.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-w4cF-qlF.js → chunk-2J33WTMH-DziB7kDG.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-BXwURxHJ.js → chunk-4BX2VUAB-CmkD8daw.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-Gem3LalC.js → chunk-55IACEB6-CHAd9A_U.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-A3ddVojI.js → chunk-727SXJPM-Dqaam3fE.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-CjHZ5L_R.js → chunk-AQP2D5EJ-D_-saBYM.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-CKgdgcpv.js → chunk-FMBD7UC4-B9r_veWD.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-Cn2Dykjb.js → chunk-ND2GUHAM-B3EaCSpL.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN--0SyraC5.js → chunk-QZHKN3VN-CYq8x9mn.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CQ9aC1Tg.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CQ9aC1Tg.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-CphhAity.js → cose-bilkent-S5V4N54A-D0ng4uiB.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-DU--jiKp.js → dagre-BM42HDAG-DCZollQv.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BzvuZw1Y.js → diagram-2AECGRRQ-Dfk2pWS0.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-D84-49Y0.js → diagram-5GNKFQAL-kX38ltWR.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-DQTq-3_3.js → diagram-KO2AKTUF-CJz2vsXh.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-8FTrshzN.js → diagram-LMA3HP47-BvMLZm_7.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-BCjpDBCm.js → diagram-OG6HWLK6-l7kfStkO.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-BtRObkmg.js → erDiagram-TEJ5UH35-BSVa8GGT.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-DTrW6oxy.js → flowDiagram-I6XJVG4X-CoawKIXH.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BgPNSW6j.js → ganttDiagram-6RSMTGT7-DFUDH0zF.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-BTclNgGV.js → gitGraphDiagram-PVQCEYII-Y2pvpT4e.js} +1 -1
- package/web-shell/assets/{index-CxA7AqY6.js → index-D0GX0zZf.js} +1 -1
- package/web-shell/assets/index-D9haPt0X.css +5 -0
- package/web-shell/assets/index-ckX9Pq5k.js +1230 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-DCE4AJt2.js → infoDiagram-5YYISTIA-CU8_zLiX.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-C8iE6q4Y.js → ishikawaDiagram-YF4QCWOH-AVQiV0DU.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-C_dxdyEc.js → journeyDiagram-JHISSGLW-DQ0VSKa3.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-Dw3n1u3w.js → kanban-definition-UN3LZRKU-BqnWqsE_.js} +1 -1
- package/web-shell/assets/{linear-C2BF2zJ9.js → linear-BkoihsaA.js} +1 -1
- package/web-shell/assets/{mermaid.core-CGTQU3MA.js → mermaid.core-5RJs-31j.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BVFZm9ZC.js → mindmap-definition-RKZ34NQL-D33Bxnpd.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-Cc-TNN3n.js → pieDiagram-4H26LBE5-BuEAw3BH.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-CgW3Rzsi.js → quadrantDiagram-W4KKPZXB-Kox_usEq.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-BAaj0Y3B.js → requirementDiagram-4Y6WPE33-CNjeUif0.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-XJWmekxS.js → sankeyDiagram-5OEKKPKP-BCd2OL_U.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-CtRc_0wf.js → sequenceDiagram-3UESZ5HK-CF2ZTsz0.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-WCnvMGy5.js → stateDiagram-AJRCARHV-qenSzHtm.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-B7W4zlCr.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-C9cRx49L.js → timeline-definition-PNZ67QCA-B5DyWdgs.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BvXOCEt-.js → vennDiagram-CIIHVFJN-DqP4I_o_.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-ByafGtzu.js → wardley-L42UT6IY-CJe2e4mg.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-CozAnw8x.js → wardleyDiagram-YWT4CUSO-BMDSw-Rr.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-Camu9Qvq.js → xychartDiagram-2RQKCTM6-BTVZYkxD.js} +1 -1
- package/web-shell/index.html +17 -13
- package/chunks/MaxSizedBox-HNWBEL5H.js +0 -77
- package/chunks/agent-KTMY6SF3.js +0 -72
- package/chunks/agent-headless-HJ56ZZOW.js +0 -66
- package/chunks/bridge-AMC5AD7W.js +0 -80
- package/chunks/chunk-CBOQ3HY7.js +0 -2019
- package/chunks/chunk-UHGNAWHK.js +0 -6928
- package/chunks/contextCommand-PW4GINQU.js +0 -71
- package/chunks/daemon-status-provider-3IWTBWQ3.js +0 -79
- package/chunks/earlyInputCapture-TYNI3B6E.js +0 -73
- package/chunks/errors-QAWTJTAW.js +0 -79
- package/chunks/handleAutoUpdate-V5A3JHOG.js +0 -72
- package/chunks/initializer-JJLF5JCJ.js +0 -77
- package/chunks/installationInfo-LAWMHQAG.js +0 -71
- package/chunks/list-L2ECB6UM.js +0 -80
- package/chunks/loadedSettingsAdapter-RLMZ4Z3E.js +0 -74
- package/chunks/mcp-E4O7Z6FO.js +0 -74
- package/chunks/nonInteractiveCli-GU2UKULE.js +0 -131
- package/chunks/pidfile-IWQWZNZV.js +0 -77
- package/chunks/read-file-ZOCXW4AD.js +0 -31
- package/chunks/resumeHistoryUtils-TJWRDE2L.js +0 -83
- package/chunks/ripGrep-OFKAW2VE.js +0 -64
- package/chunks/serve-UB4CF67Q.js +0 -80
- package/chunks/shell-RPK7EAOC.js +0 -74
- package/chunks/spawnChannel-IUP3ZNMT.js +0 -73
- package/chunks/theme-manager-ALL7F4CJ.js +0 -68
- package/chunks/total-session-admission-PLONPNXI.js +0 -74
- package/chunks/updateCheck-PVROE4GR.js +0 -87
- package/chunks/useAutoAcceptIndicator-6BNLNN5S.js +0 -85
- package/chunks/workspace-providers-status-2U3IF4TX.js +0 -77
- package/chunks/workspace-registry-DLQDDDIF.js +0 -78
- package/chunks/workspace-service-7K3LF4QX.js +0 -89
- package/chunks/workspace-skills-status-4DOZ3DBS.js +0 -76
- package/chunks/write-file-PTPXDKZ3.js +0 -64
- package/web-shell/assets/channel-DiLlxxIf.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-CkylTdM4.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-CkylTdM4.js +0 -1
- package/web-shell/assets/index-CGtQqOIa.css +0 -5
- package/web-shell/assets/index-TtM0hVjU.js +0 -1207
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-D1gzH2Ue.js +0 -1
|
@@ -8,21 +8,24 @@ import {
|
|
|
8
8
|
formatWorkspaceMemoryDreamSummary,
|
|
9
9
|
formatWorkspaceMemoryForgetSummary,
|
|
10
10
|
isValidServerName,
|
|
11
|
+
normalizeChannelDelivery,
|
|
12
|
+
parseChannelDelivery,
|
|
11
13
|
redactMcpServersSetting,
|
|
12
14
|
replayTranscriptRecordPage,
|
|
13
15
|
restoreRedactedMcpServersSetting,
|
|
14
16
|
shouldSuppressRememberErrorDetails,
|
|
15
17
|
workspaceMemoryFailureCode,
|
|
16
18
|
workspaceMemoryFailureDiagnostics
|
|
17
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RIBKPMRP.js";
|
|
18
20
|
import {
|
|
19
21
|
openQwenAsrRealtimeStream,
|
|
20
22
|
openVoiceStream,
|
|
21
23
|
openVoiceStreamWithRetry
|
|
22
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-BJX6ZSUK.js";
|
|
23
25
|
import {
|
|
24
26
|
SetupGithubError,
|
|
25
27
|
collectSessionData,
|
|
28
|
+
createTranscriptMessageUpdate,
|
|
26
29
|
generateExportFilename,
|
|
27
30
|
normalizeSessionData,
|
|
28
31
|
setupGithub,
|
|
@@ -30,17 +33,66 @@ import {
|
|
|
30
33
|
toJson,
|
|
31
34
|
toJsonl,
|
|
32
35
|
toMarkdown
|
|
33
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-EBJQ6AXW.js";
|
|
34
37
|
import {
|
|
35
38
|
OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
|
|
36
39
|
ObservedChannelContactStore
|
|
37
|
-
} from "./chunk-
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
40
|
+
} from "./chunk-RHLZR4E5.js";
|
|
41
|
+
import "./chunk-IPUUTYMV.js";
|
|
42
|
+
import "./chunk-WCXCRJYB.js";
|
|
43
|
+
import "./chunk-2MIN6GRR.js";
|
|
41
44
|
import "./chunk-QHTIBUWB.js";
|
|
42
45
|
import "./chunk-QTERJVPZ.js";
|
|
43
46
|
import "./chunk-3Z43GZUQ.js";
|
|
47
|
+
import {
|
|
48
|
+
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
49
|
+
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
50
|
+
WorkspaceSkillManagementError,
|
|
51
|
+
WorkspaceVoiceError,
|
|
52
|
+
buildWorkspaceVoiceSettingsWrites,
|
|
53
|
+
buildWorkspaceVoiceStatus,
|
|
54
|
+
createDaemonWorkspaceService,
|
|
55
|
+
hasConfiguredBatchVoiceTranscriptionModel,
|
|
56
|
+
transcribeWorkspaceVoiceAudio,
|
|
57
|
+
validateWorkspaceSkillName,
|
|
58
|
+
validateWorkspaceVoiceState,
|
|
59
|
+
voiceSettingsScopeToWire
|
|
60
|
+
} from "./chunk-TGILQ3YH.js";
|
|
61
|
+
import {
|
|
62
|
+
PermissionRulesValidationError,
|
|
63
|
+
buildPermissionSettings,
|
|
64
|
+
isPermissionRuleType,
|
|
65
|
+
normalizePermissionRules,
|
|
66
|
+
readPermissionRuleSet
|
|
67
|
+
} from "./chunk-VRYUBFMC.js";
|
|
68
|
+
import {
|
|
69
|
+
assertVoiceBaseUrlNetworkAllowed,
|
|
70
|
+
isStreamingVoiceModel,
|
|
71
|
+
resolveVoiceStreamConfig,
|
|
72
|
+
resolveVoiceTranscriptionConfig,
|
|
73
|
+
sanitizeVoiceErrorMessage,
|
|
74
|
+
transcribeVoiceAudio
|
|
75
|
+
} from "./chunk-H4SBPHSA.js";
|
|
76
|
+
import {
|
|
77
|
+
isVoiceEnabled,
|
|
78
|
+
isVoiceMode,
|
|
79
|
+
readVoiceModel
|
|
80
|
+
} from "./chunk-YBL3QUDD.js";
|
|
81
|
+
import "./chunk-ZD6UTE4A.js";
|
|
82
|
+
import {
|
|
83
|
+
WorkspacePermissionRulesSessionRequiredError,
|
|
84
|
+
WorkspaceSettingsPartialPersistError,
|
|
85
|
+
WorkspaceSkillNotFoundError,
|
|
86
|
+
WorkspaceSkillNotToggleableError
|
|
87
|
+
} from "./chunk-OA4JVLSA.js";
|
|
88
|
+
import {
|
|
89
|
+
createTotalSessionAdmissionController
|
|
90
|
+
} from "./chunk-VYPFXUCB.js";
|
|
91
|
+
import {
|
|
92
|
+
createSingleWorkspaceRegistry,
|
|
93
|
+
createWorkspaceSessionOwnerIndex
|
|
94
|
+
} from "./chunk-UGYMA4EI.js";
|
|
95
|
+
import "./chunk-GRC5HGPI.js";
|
|
44
96
|
import {
|
|
45
97
|
CAPABILITIES_SCHEMA_VERSION,
|
|
46
98
|
CLIENT_ID_HEADER,
|
|
@@ -98,102 +150,33 @@ import {
|
|
|
98
150
|
setRateLimiter,
|
|
99
151
|
unsafeRevealSecret,
|
|
100
152
|
validateMcpRuntimeServerName
|
|
101
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-IJTOWOD7.js";
|
|
102
154
|
import {
|
|
103
155
|
isLoopbackBind
|
|
104
156
|
} from "./chunk-RXFQM6FQ.js";
|
|
105
|
-
import {
|
|
106
|
-
createDaemonStatusProvider
|
|
107
|
-
} from "./chunk-SVIMKSEI.js";
|
|
108
|
-
import "./chunk-LXXMOYPL.js";
|
|
109
|
-
import "./chunk-CJQ3FZ2G.js";
|
|
110
|
-
import "./chunk-E5Z2AVNV.js";
|
|
111
|
-
import {
|
|
112
|
-
createWorkspaceProvidersStatusProvider
|
|
113
|
-
} from "./chunk-L6U47G5P.js";
|
|
114
|
-
import {
|
|
115
|
-
getAuthTypeFromEnv,
|
|
116
|
-
resolveCliGenerationConfig
|
|
117
|
-
} from "./chunk-42W5BDEY.js";
|
|
118
|
-
import {
|
|
119
|
-
snapshotProcessEnv
|
|
120
|
-
} from "./chunk-P2BQZ7H7.js";
|
|
121
|
-
import {
|
|
122
|
-
createWorkspaceSkillsStatusProvider
|
|
123
|
-
} from "./chunk-B3I77W5J.js";
|
|
124
|
-
import "./chunk-2W3OOD4W.js";
|
|
125
|
-
import {
|
|
126
|
-
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
127
|
-
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
128
|
-
WorkspaceSkillManagementError,
|
|
129
|
-
WorkspaceVoiceError,
|
|
130
|
-
buildWorkspaceVoiceSettingsWrites,
|
|
131
|
-
buildWorkspaceVoiceStatus,
|
|
132
|
-
createDaemonWorkspaceService,
|
|
133
|
-
hasConfiguredBatchVoiceTranscriptionModel,
|
|
134
|
-
transcribeWorkspaceVoiceAudio,
|
|
135
|
-
validateWorkspaceSkillName,
|
|
136
|
-
validateWorkspaceVoiceState,
|
|
137
|
-
voiceSettingsScopeToWire
|
|
138
|
-
} from "./chunk-ACQJPDDS.js";
|
|
139
|
-
import {
|
|
140
|
-
PermissionRulesValidationError,
|
|
141
|
-
buildPermissionSettings,
|
|
142
|
-
isPermissionRuleType,
|
|
143
|
-
normalizePermissionRules,
|
|
144
|
-
readPermissionRuleSet
|
|
145
|
-
} from "./chunk-3BJDQVE6.js";
|
|
146
|
-
import {
|
|
147
|
-
assertVoiceBaseUrlNetworkAllowed,
|
|
148
|
-
isStreamingVoiceModel,
|
|
149
|
-
resolveVoiceStreamConfig,
|
|
150
|
-
resolveVoiceTranscriptionConfig,
|
|
151
|
-
sanitizeVoiceErrorMessage,
|
|
152
|
-
transcribeVoiceAudio
|
|
153
|
-
} from "./chunk-LVA5OHQO.js";
|
|
154
|
-
import {
|
|
155
|
-
isVoiceEnabled,
|
|
156
|
-
isVoiceMode,
|
|
157
|
-
readVoiceModel
|
|
158
|
-
} from "./chunk-7ZD5EKXE.js";
|
|
159
|
-
import "./chunk-QLJUC7TG.js";
|
|
160
|
-
import {
|
|
161
|
-
WorkspacePermissionRulesSessionRequiredError,
|
|
162
|
-
WorkspaceSettingsPartialPersistError,
|
|
163
|
-
WorkspaceSkillNotFoundError,
|
|
164
|
-
WorkspaceSkillNotToggleableError
|
|
165
|
-
} from "./chunk-OA4JVLSA.js";
|
|
166
|
-
import {
|
|
167
|
-
createTotalSessionAdmissionController
|
|
168
|
-
} from "./chunk-VYPFXUCB.js";
|
|
169
|
-
import {
|
|
170
|
-
createSingleWorkspaceRegistry,
|
|
171
|
-
createWorkspaceSessionOwnerIndex
|
|
172
|
-
} from "./chunk-UGYMA4EI.js";
|
|
173
|
-
import "./chunk-GRC5HGPI.js";
|
|
174
157
|
import {
|
|
175
158
|
daemonObservedContactsPath,
|
|
176
159
|
loadChannelsConfig
|
|
177
|
-
} from "./chunk-
|
|
178
|
-
import "./chunk-
|
|
160
|
+
} from "./chunk-PSOO6YXD.js";
|
|
161
|
+
import "./chunk-PC6JANNU.js";
|
|
179
162
|
import "./chunk-57OAHC2Y.js";
|
|
180
163
|
import {
|
|
181
|
-
|
|
182
|
-
} from "./chunk-
|
|
183
|
-
import "./chunk-
|
|
184
|
-
import "./chunk-
|
|
164
|
+
createDaemonStatusProvider
|
|
165
|
+
} from "./chunk-J24WCGIN.js";
|
|
166
|
+
import "./chunk-LXXMOYPL.js";
|
|
167
|
+
import "./chunk-MVSUYZDT.js";
|
|
168
|
+
import "./chunk-E5Z2AVNV.js";
|
|
185
169
|
import {
|
|
186
170
|
SessionArtifactAuthorizationError,
|
|
187
171
|
SessionArtifactValidationError,
|
|
188
172
|
createAcpSessionBridge,
|
|
189
173
|
parseSessionSource
|
|
190
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-KIM5GUMA.js";
|
|
191
175
|
import {
|
|
192
176
|
EVENT_SCHEMA_VERSION,
|
|
177
|
+
EventBus,
|
|
193
178
|
SubscriberLimitExceededError
|
|
194
|
-
} from "./chunk-
|
|
195
|
-
import "./chunk-COH43MRJ.js";
|
|
196
|
-
import "./chunk-QR6U5QPP.js";
|
|
179
|
+
} from "./chunk-GLWP3FDB.js";
|
|
197
180
|
import {
|
|
198
181
|
BranchWhilePromptActiveError,
|
|
199
182
|
CancelSentinelCollisionError,
|
|
@@ -227,33 +210,72 @@ import {
|
|
|
227
210
|
WorkspaceInitSymlinkError,
|
|
228
211
|
WorkspaceMismatchError
|
|
229
212
|
} from "./chunk-UH3WSE5L.js";
|
|
230
|
-
import "./chunk-
|
|
213
|
+
import "./chunk-COH43MRJ.js";
|
|
214
|
+
import "./chunk-3SJ43L4W.js";
|
|
215
|
+
import "./chunk-7JURR4JT.js";
|
|
216
|
+
import {
|
|
217
|
+
createWorkspaceProvidersStatusProvider
|
|
218
|
+
} from "./chunk-FSITMZJH.js";
|
|
219
|
+
import {
|
|
220
|
+
getAuthTypeFromEnv,
|
|
221
|
+
resolveCliGenerationConfig
|
|
222
|
+
} from "./chunk-KMQ33DO4.js";
|
|
223
|
+
import {
|
|
224
|
+
snapshotProcessEnv
|
|
225
|
+
} from "./chunk-ETSW4KLJ.js";
|
|
226
|
+
import {
|
|
227
|
+
createWorkspaceSkillsStatusProvider
|
|
228
|
+
} from "./chunk-ACY3A37B.js";
|
|
229
|
+
import "./chunk-2W3OOD4W.js";
|
|
231
230
|
import {
|
|
232
231
|
STATUS_SCHEMA_VERSION,
|
|
233
232
|
createIdleWorkspaceMemoryStatus,
|
|
234
233
|
mapDomainErrorToErrorKind
|
|
235
|
-
} from "./chunk-
|
|
234
|
+
} from "./chunk-VIA5XA4U.js";
|
|
235
|
+
import "./chunk-WBL3FJEU.js";
|
|
236
|
+
import "./chunk-T2NCM2ET.js";
|
|
237
|
+
import {
|
|
238
|
+
parseChannelWebhookConfigLenient
|
|
239
|
+
} from "./chunk-4WIZGAH3.js";
|
|
240
|
+
import "./chunk-7ZCNENPP.js";
|
|
241
|
+
import "./chunk-V6WHFGST.js";
|
|
242
|
+
import {
|
|
243
|
+
MAX_REGISTERED_WORKSPACES,
|
|
244
|
+
WorkspaceDisplayNameValidationError,
|
|
245
|
+
WorkspaceRegistrationStoreCommittedError,
|
|
246
|
+
WorkspaceRegistrationStoreLimitError,
|
|
247
|
+
normalizeWorkspaceDisplayName,
|
|
248
|
+
workspaceRegistrationId
|
|
249
|
+
} from "./chunk-Q4M4MDQ4.js";
|
|
250
|
+
import {
|
|
251
|
+
MAX_WORKSPACE_PATH_LENGTH,
|
|
252
|
+
canonicalizeWorkspace,
|
|
253
|
+
canonicalizeWorkspaces,
|
|
254
|
+
translateAndCheckAbsoluteWorkspacePath
|
|
255
|
+
} from "./chunk-2RFKHEXL.js";
|
|
236
256
|
import {
|
|
257
|
+
ChannelDeliveryError,
|
|
237
258
|
MAX_CHANNEL_STARTUP_FAILURES,
|
|
238
259
|
MAX_CHANNEL_STARTUP_FAILURE_CHANNEL_LENGTH,
|
|
239
260
|
MAX_CHANNEL_STARTUP_FAILURE_CODE_LENGTH,
|
|
240
261
|
MAX_CHANNEL_STARTUP_FAILURE_MESSAGE_LENGTH,
|
|
241
262
|
QWEN_SERVER_TOKEN_ENV,
|
|
263
|
+
isChannelDeliveryError,
|
|
242
264
|
isChannelWebhookEnqueueError,
|
|
243
265
|
normalizeWorkerDiagnostic
|
|
244
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-LK7CHLVP.js";
|
|
245
267
|
import {
|
|
246
268
|
normalizeServeChannelSelection
|
|
247
|
-
} from "./chunk-
|
|
269
|
+
} from "./chunk-JLU636DO.js";
|
|
270
|
+
import "./chunk-BK2UNYWD.js";
|
|
248
271
|
import {
|
|
249
272
|
redactLogCredentials
|
|
250
273
|
} from "./chunk-M5GB774H.js";
|
|
251
|
-
import "./chunk-WBL3FJEU.js";
|
|
252
|
-
import "./chunk-T2NCM2ET.js";
|
|
253
274
|
import {
|
|
254
275
|
sanitizeLogText
|
|
255
|
-
} from "./chunk-
|
|
276
|
+
} from "./chunk-RWTEFFPU.js";
|
|
256
277
|
import "./chunk-UDXSXLER.js";
|
|
278
|
+
import "./chunk-5HBA2Z7V.js";
|
|
257
279
|
import {
|
|
258
280
|
getDialogSettingKeys,
|
|
259
281
|
getModelProvidersOwnerScope,
|
|
@@ -263,38 +285,23 @@ import {
|
|
|
263
285
|
getWritableScopes,
|
|
264
286
|
loadSettings,
|
|
265
287
|
validateSettingValue
|
|
266
|
-
} from "./chunk-
|
|
288
|
+
} from "./chunk-TEHGS6UP.js";
|
|
267
289
|
import "./chunk-RKUWKYED.js";
|
|
290
|
+
import "./chunk-GOXKNSDZ.js";
|
|
291
|
+
import "./chunk-IDS7MSUP.js";
|
|
268
292
|
import {
|
|
269
293
|
SUPPORTED_LANGUAGES,
|
|
270
294
|
detectSystemLanguage,
|
|
271
295
|
resolveLanguageSetting,
|
|
272
296
|
resolveSupportedLanguage
|
|
273
|
-
} from "./chunk-
|
|
274
|
-
import "./chunk-
|
|
275
|
-
import "./chunk-
|
|
276
|
-
import "./chunk-
|
|
277
|
-
import {
|
|
278
|
-
MAX_REGISTERED_WORKSPACES,
|
|
279
|
-
WorkspaceDisplayNameValidationError,
|
|
280
|
-
WorkspaceRegistrationStoreCommittedError,
|
|
281
|
-
WorkspaceRegistrationStoreLimitError,
|
|
282
|
-
normalizeWorkspaceDisplayName,
|
|
283
|
-
workspaceRegistrationId
|
|
284
|
-
} from "./chunk-AHX6AKPD.js";
|
|
285
|
-
import {
|
|
286
|
-
MAX_WORKSPACE_PATH_LENGTH,
|
|
287
|
-
canonicalizeWorkspace,
|
|
288
|
-
canonicalizeWorkspaces,
|
|
289
|
-
translateAndCheckAbsoluteWorkspacePath
|
|
290
|
-
} from "./chunk-2RFKHEXL.js";
|
|
291
|
-
import "./chunk-5HBA2Z7V.js";
|
|
292
|
-
import "./chunk-IDS7MSUP.js";
|
|
293
|
-
import "./chunk-3F2JUWCH.js";
|
|
297
|
+
} from "./chunk-LKEJ26GS.js";
|
|
298
|
+
import "./chunk-LH2BYDQ5.js";
|
|
299
|
+
import "./chunk-6PEXNQTX.js";
|
|
300
|
+
import "./chunk-YX324OPW.js";
|
|
294
301
|
import "./chunk-VJNBRRZG.js";
|
|
295
302
|
import {
|
|
296
303
|
getWorkspaceTrustStatus
|
|
297
|
-
} from "./chunk-
|
|
304
|
+
} from "./chunk-Z2BC6UJ5.js";
|
|
298
305
|
import "./chunk-ALGGS7UH.js";
|
|
299
306
|
import {
|
|
300
307
|
isWithinRoot as isWithinRoot2
|
|
@@ -345,10 +352,12 @@ import {
|
|
|
345
352
|
fetchGitDiffHunksForFile,
|
|
346
353
|
fetchGitLog,
|
|
347
354
|
getGitWorkingTreeStatus,
|
|
355
|
+
getSubagentSessionDir,
|
|
348
356
|
glob,
|
|
349
357
|
loadIgnoreRules,
|
|
350
358
|
loadUsageHistoryWithLive,
|
|
351
359
|
parseInstallSource,
|
|
360
|
+
readAgentMeta,
|
|
352
361
|
readWorktreeSession,
|
|
353
362
|
redactUrlCredentials,
|
|
354
363
|
resolveBranchName,
|
|
@@ -360,22 +369,19 @@ import {
|
|
|
360
369
|
writeWorkspaceContextFile,
|
|
361
370
|
writeWorktreeSession,
|
|
362
371
|
writeWorktreeSessionMarker
|
|
363
|
-
} from "./chunk-
|
|
364
|
-
import "./chunk-T4TZQJ7W.js";
|
|
365
|
-
import "./chunk-H6XPXXMH.js";
|
|
372
|
+
} from "./chunk-PHOF65IG.js";
|
|
366
373
|
import "./chunk-5M6IDOMF.js";
|
|
367
|
-
import "./chunk-
|
|
368
|
-
import "./chunk-
|
|
369
|
-
import "./chunk-
|
|
370
|
-
import "./chunk-E2UVIFI2.js";
|
|
374
|
+
import "./chunk-TWPJO254.js";
|
|
375
|
+
import "./chunk-H6XPXXMH.js";
|
|
376
|
+
import "./chunk-K4XWPEWB.js";
|
|
371
377
|
import {
|
|
372
378
|
MAX_JOBS,
|
|
373
379
|
nextDurableFireMs
|
|
374
|
-
} from "./chunk-
|
|
380
|
+
} from "./chunk-TOFQCPDC.js";
|
|
375
381
|
import {
|
|
376
382
|
nextFireTime,
|
|
377
383
|
parseCron
|
|
378
|
-
} from "./chunk-
|
|
384
|
+
} from "./chunk-IRH27ZC2.js";
|
|
379
385
|
import "./chunk-VDDGDZMA.js";
|
|
380
386
|
import {
|
|
381
387
|
appendCronRun,
|
|
@@ -384,22 +390,27 @@ import {
|
|
|
384
390
|
readCronTasks,
|
|
385
391
|
taskHasLegacyCondition,
|
|
386
392
|
updateCronTasks
|
|
387
|
-
} from "./chunk-
|
|
388
|
-
import "./chunk-
|
|
393
|
+
} from "./chunk-FNQ6T3CV.js";
|
|
394
|
+
import "./chunk-ZOIFNCKL.js";
|
|
395
|
+
import "./chunk-PWTZEM3C.js";
|
|
396
|
+
import "./chunk-KRXPRVGL.js";
|
|
389
397
|
import "./chunk-6PVPNMXU.js";
|
|
390
|
-
import "./chunk-
|
|
398
|
+
import "./chunk-MZAXJAUM.js";
|
|
399
|
+
import "./chunk-SZRN75WQ.js";
|
|
400
|
+
import "./chunk-HTO4JFDZ.js";
|
|
391
401
|
import "./chunk-CPBF7KYF.js";
|
|
392
|
-
import "./chunk-7VUQQBR7.js";
|
|
393
|
-
import "./chunk-LIZRAKPB.js";
|
|
394
402
|
import {
|
|
395
403
|
APPROVAL_MODES,
|
|
396
404
|
SubagentError,
|
|
397
405
|
SubagentErrorCode
|
|
398
|
-
} from "./chunk-
|
|
406
|
+
} from "./chunk-L26JL52R.js";
|
|
399
407
|
import "./chunk-6AM5D4ME.js";
|
|
408
|
+
import "./chunk-JZA3JUDJ.js";
|
|
409
|
+
import "./chunk-3QMGYBFN.js";
|
|
400
410
|
import "./chunk-JCW2R7WC.js";
|
|
401
|
-
import "./chunk-
|
|
402
|
-
import "./chunk-
|
|
411
|
+
import "./chunk-M5JM7OSF.js";
|
|
412
|
+
import "./chunk-OHNBB4XR.js";
|
|
413
|
+
import "./chunk-E5TUC6CA.js";
|
|
403
414
|
import {
|
|
404
415
|
QwenOAuth2Client,
|
|
405
416
|
QwenOAuthPollError,
|
|
@@ -408,57 +419,69 @@ import {
|
|
|
408
419
|
isDeviceAuthorizationSuccess,
|
|
409
420
|
isDeviceTokenPending,
|
|
410
421
|
isDeviceTokenSuccess
|
|
411
|
-
} from "./chunk-
|
|
422
|
+
} from "./chunk-EPDRMGT4.js";
|
|
412
423
|
import "./chunk-JESCGQM3.js";
|
|
413
|
-
import "./chunk-
|
|
414
|
-
import "./chunk-
|
|
424
|
+
import "./chunk-NH6KE4JX.js";
|
|
425
|
+
import "./chunk-USTWD7QV.js";
|
|
415
426
|
import "./chunk-XVNQMZ2I.js";
|
|
416
|
-
import "./chunk-CR3C7WXL.js";
|
|
417
427
|
import "./chunk-FODK6UMO.js";
|
|
418
428
|
import "./chunk-GLNBDYUX.js";
|
|
419
429
|
import "./chunk-DJ2GSRLV.js";
|
|
430
|
+
import "./chunk-ZJHVAS7M.js";
|
|
420
431
|
import {
|
|
421
432
|
addDaemonRequestAttribute,
|
|
422
|
-
decodeBufferWithEncodingInfo,
|
|
423
433
|
emitDaemonLog,
|
|
424
|
-
getAllGeminiMdFilenames,
|
|
425
434
|
hashDaemonWorkspace,
|
|
426
|
-
isBinaryFile,
|
|
427
|
-
isWithinRoot,
|
|
428
435
|
recordDaemonBridgeError,
|
|
429
436
|
recordDaemonError,
|
|
430
437
|
recordDaemonHttpRequest,
|
|
431
438
|
recordDaemonHttpResponse,
|
|
432
439
|
withDaemonRequestSpan
|
|
433
|
-
} from "./chunk-
|
|
440
|
+
} from "./chunk-NIBLUX3Y.js";
|
|
441
|
+
import "./chunk-BPJSQIJX.js";
|
|
442
|
+
import "./chunk-P3QQPMQA.js";
|
|
443
|
+
import "./chunk-6FGBXPWM.js";
|
|
444
|
+
import "./chunk-LS77BEZP.js";
|
|
445
|
+
import "./chunk-CR3C7WXL.js";
|
|
446
|
+
import {
|
|
447
|
+
decodeBufferWithEncodingInfo,
|
|
448
|
+
getAllGeminiMdFilenames,
|
|
449
|
+
isBinaryFile,
|
|
450
|
+
isWithinRoot,
|
|
451
|
+
parseLineTolerant,
|
|
452
|
+
read
|
|
453
|
+
} from "./chunk-CIKQ7KKO.js";
|
|
434
454
|
import "./chunk-VGC4I5JJ.js";
|
|
435
|
-
import "./chunk-
|
|
436
|
-
import "./chunk-
|
|
455
|
+
import "./chunk-MUP3T3AD.js";
|
|
456
|
+
import "./chunk-IKCX4CCL.js";
|
|
457
|
+
import "./chunk-46UV252V.js";
|
|
437
458
|
import "./chunk-A4UCTEB5.js";
|
|
438
459
|
import "./chunk-XWRJCPHC.js";
|
|
439
|
-
import "./chunk-
|
|
440
|
-
import "./chunk-
|
|
441
|
-
import "./chunk-
|
|
442
|
-
import
|
|
443
|
-
|
|
444
|
-
} from "./chunk-TYAMGABM.js";
|
|
445
|
-
import "./chunk-FCMNKVXT.js";
|
|
446
|
-
import "./chunk-7362QS5B.js";
|
|
460
|
+
import "./chunk-UW5EOVUN.js";
|
|
461
|
+
import "./chunk-2JZBVYTU.js";
|
|
462
|
+
import "./chunk-5I2IWRSH.js";
|
|
463
|
+
import "./chunk-A5L3JMUA.js";
|
|
464
|
+
import "./chunk-MB4MZHMJ.js";
|
|
447
465
|
import "./chunk-HTR4WV6U.js";
|
|
448
|
-
import "./chunk-
|
|
466
|
+
import "./chunk-BULDBTYC.js";
|
|
449
467
|
import "./chunk-U7ZFW55U.js";
|
|
450
|
-
import "./chunk-
|
|
451
|
-
import "./chunk-
|
|
468
|
+
import "./chunk-UUUTRMI2.js";
|
|
469
|
+
import "./chunk-PR75REBZ.js";
|
|
452
470
|
import {
|
|
453
471
|
FatalConfigError,
|
|
454
472
|
Storage,
|
|
455
473
|
createDebugLogger,
|
|
456
474
|
runWithoutDebugLogSession
|
|
457
|
-
} from "./chunk-
|
|
475
|
+
} from "./chunk-NL7LTRLR.js";
|
|
458
476
|
import "./chunk-75DOP5OR.js";
|
|
459
477
|
import "./chunk-DMTGGOSA.js";
|
|
460
478
|
import "./chunk-YQ3U5MUC.js";
|
|
461
|
-
import
|
|
479
|
+
import {
|
|
480
|
+
import_websocket_server
|
|
481
|
+
} from "./chunk-TYAMGABM.js";
|
|
482
|
+
import "./chunk-FCMNKVXT.js";
|
|
483
|
+
import "./chunk-AMDSOFFV.js";
|
|
484
|
+
import "./chunk-TARRHLLG.js";
|
|
462
485
|
import {
|
|
463
486
|
init_esbuild_shims
|
|
464
487
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -650,9 +673,9 @@ async function findExistingAncestor(absolute) {
|
|
|
650
673
|
let current = absolute;
|
|
651
674
|
const tailParts = [];
|
|
652
675
|
for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
|
|
653
|
-
let
|
|
676
|
+
let stat3 = null;
|
|
654
677
|
try {
|
|
655
|
-
|
|
678
|
+
stat3 = await fsp.stat(current);
|
|
656
679
|
} catch (err) {
|
|
657
680
|
const code = err?.code;
|
|
658
681
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -660,8 +683,8 @@ async function findExistingAncestor(absolute) {
|
|
|
660
683
|
throw err;
|
|
661
684
|
}
|
|
662
685
|
}
|
|
663
|
-
if (
|
|
664
|
-
if (tailParts.length > 0 && !
|
|
686
|
+
if (stat3) {
|
|
687
|
+
if (tailParts.length > 0 && !stat3.isDirectory()) {
|
|
665
688
|
throw new FsError(
|
|
666
689
|
"parse_error",
|
|
667
690
|
`path component is not a directory: ${absolute}`,
|
|
@@ -734,7 +757,7 @@ async function resolveWithinWorkspace(input, boundWorkspaces, intent) {
|
|
|
734
757
|
boundCanonicals
|
|
735
758
|
);
|
|
736
759
|
if (boundCanonical !== void 0) {
|
|
737
|
-
const finalPathIsSymlink = await fsp.lstat(absolute).then((
|
|
760
|
+
const finalPathIsSymlink = await fsp.lstat(absolute).then((stat3) => stat3.isSymbolicLink()).catch((lstatErr) => {
|
|
738
761
|
if (lstatErr.code === "ENOENT" || lstatErr.code === "ENOTDIR") {
|
|
739
762
|
return false;
|
|
740
763
|
}
|
|
@@ -1225,8 +1248,8 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1225
1248
|
const toRead = Math.min(maxBytes, available);
|
|
1226
1249
|
buf = Buffer.allocUnsafe(toRead);
|
|
1227
1250
|
if (toRead > 0) {
|
|
1228
|
-
const
|
|
1229
|
-
buf =
|
|
1251
|
+
const read2 = await fh.read(buf, 0, toRead, offset);
|
|
1252
|
+
buf = read2.bytesRead === toRead ? buf : buf.subarray(0, read2.bytesRead);
|
|
1230
1253
|
}
|
|
1231
1254
|
const afterRead = await fh.stat();
|
|
1232
1255
|
assertSameFile(st, afterRead, p, "read");
|
|
@@ -1767,17 +1790,17 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1767
1790
|
* for their `sendFsError` serializer.
|
|
1768
1791
|
*/
|
|
1769
1792
|
recordAndWrap(err, intent, input) {
|
|
1770
|
-
const
|
|
1793
|
+
const fs6 = wrapAsFsError(err);
|
|
1771
1794
|
this.deps.audit.recordDenied(this.deps.ctx, {
|
|
1772
1795
|
intent,
|
|
1773
1796
|
input,
|
|
1774
|
-
errorKind:
|
|
1775
|
-
hint:
|
|
1797
|
+
errorKind: fs6.kind,
|
|
1798
|
+
hint: fs6.hint,
|
|
1776
1799
|
// Quote the underlying OS / FsError message so audit
|
|
1777
1800
|
// consumers debugging a production incident can see the
|
|
1778
1801
|
// actual cause (errno text, byte counts, glob pattern,
|
|
1779
1802
|
// etc.) rather than just `errorKind` + `hint`.
|
|
1780
|
-
message:
|
|
1803
|
+
message: fs6.message,
|
|
1781
1804
|
// For glob denials (parse_error pattern rejection,
|
|
1782
1805
|
// catastrophic walk failures) the input IS the pattern
|
|
1783
1806
|
// already; surfacing it on the dedicated `pattern` field
|
|
@@ -1786,7 +1809,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1786
1809
|
// branching on intent.
|
|
1787
1810
|
pattern: intent === "glob" ? input : void 0
|
|
1788
1811
|
});
|
|
1789
|
-
return
|
|
1812
|
+
return fs6;
|
|
1790
1813
|
}
|
|
1791
1814
|
};
|
|
1792
1815
|
var CONTENT_HASH_RE = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -1894,9 +1917,9 @@ async function readStableRegularFileBuffer(p, pre) {
|
|
|
1894
1917
|
const out = Buffer.alloc(opened.size);
|
|
1895
1918
|
let offset = 0;
|
|
1896
1919
|
while (offset < opened.size) {
|
|
1897
|
-
const
|
|
1898
|
-
if (
|
|
1899
|
-
offset +=
|
|
1920
|
+
const read2 = await fh.read(out, offset, opened.size - offset, offset);
|
|
1921
|
+
if (read2.bytesRead === 0) break;
|
|
1922
|
+
offset += read2.bytesRead;
|
|
1900
1923
|
}
|
|
1901
1924
|
const afterRead = await fh.stat();
|
|
1902
1925
|
assertSameFile(opened, afterRead, p, "read");
|
|
@@ -2151,15 +2174,15 @@ async function hashRegularFileAtPath(p, pre) {
|
|
|
2151
2174
|
const buf = Buffer.allocUnsafe(64 * 1024);
|
|
2152
2175
|
let offset = 0;
|
|
2153
2176
|
while (offset < opened.size) {
|
|
2154
|
-
const
|
|
2177
|
+
const read2 = await fh.read(
|
|
2155
2178
|
buf,
|
|
2156
2179
|
0,
|
|
2157
2180
|
Math.min(buf.length, opened.size - offset),
|
|
2158
2181
|
offset
|
|
2159
2182
|
);
|
|
2160
|
-
if (
|
|
2161
|
-
hash.update(buf.subarray(0,
|
|
2162
|
-
offset +=
|
|
2183
|
+
if (read2.bytesRead === 0) break;
|
|
2184
|
+
hash.update(buf.subarray(0, read2.bytesRead));
|
|
2185
|
+
offset += read2.bytesRead;
|
|
2163
2186
|
}
|
|
2164
2187
|
} finally {
|
|
2165
2188
|
await fh.close();
|
|
@@ -2523,12 +2546,12 @@ __name(applyReadHeaders, "applyReadHeaders");
|
|
|
2523
2546
|
function sendFsError(res, err, route) {
|
|
2524
2547
|
applyReadHeaders(res);
|
|
2525
2548
|
if (isFsError(err)) {
|
|
2526
|
-
const
|
|
2527
|
-
res.status(
|
|
2528
|
-
errorKind:
|
|
2529
|
-
error:
|
|
2530
|
-
hint:
|
|
2531
|
-
status:
|
|
2549
|
+
const fs6 = err;
|
|
2550
|
+
res.status(fs6.status).json({
|
|
2551
|
+
errorKind: fs6.kind,
|
|
2552
|
+
error: fs6.message,
|
|
2553
|
+
hint: fs6.hint,
|
|
2554
|
+
status: fs6.status
|
|
2532
2555
|
});
|
|
2533
2556
|
return;
|
|
2534
2557
|
}
|
|
@@ -2630,13 +2653,13 @@ async function handleGetFile(req, res, deps) {
|
|
|
2630
2653
|
});
|
|
2631
2654
|
return;
|
|
2632
2655
|
}
|
|
2633
|
-
const
|
|
2656
|
+
const fs6 = factory.forRequest({
|
|
2634
2657
|
originatorClientId: clientId ?? void 0,
|
|
2635
2658
|
route: ROUTE2
|
|
2636
2659
|
});
|
|
2637
2660
|
try {
|
|
2638
|
-
const resolved = await
|
|
2639
|
-
const out = await
|
|
2661
|
+
const resolved = await fs6.resolve(queryPath, "read");
|
|
2662
|
+
const out = await fs6.readText(resolved, { maxBytes, line, limit });
|
|
2640
2663
|
const returnedBytes = Buffer.byteLength(out.content, "utf-8");
|
|
2641
2664
|
applyReadHeaders(res);
|
|
2642
2665
|
res.status(200).json({
|
|
@@ -2690,13 +2713,13 @@ async function handleGetFileBytes(req, res, deps) {
|
|
|
2690
2713
|
});
|
|
2691
2714
|
return;
|
|
2692
2715
|
}
|
|
2693
|
-
const
|
|
2716
|
+
const fs6 = factory.forRequest({
|
|
2694
2717
|
originatorClientId: clientId ?? void 0,
|
|
2695
2718
|
route: ROUTE2
|
|
2696
2719
|
});
|
|
2697
2720
|
try {
|
|
2698
|
-
const resolved = await
|
|
2699
|
-
const out = await
|
|
2721
|
+
const resolved = await fs6.resolve(queryPath, "read");
|
|
2722
|
+
const out = await fs6.readBytesWindow(resolved, {
|
|
2700
2723
|
offset: offset ?? 0,
|
|
2701
2724
|
maxBytes: maxBytes ?? DEFAULT_FILE_BYTES_MAX_BYTES
|
|
2702
2725
|
});
|
|
@@ -2724,13 +2747,13 @@ async function handleGetStat(req, res, deps) {
|
|
|
2724
2747
|
if (clientId === null) return;
|
|
2725
2748
|
const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
|
|
2726
2749
|
if (queryPath === null) return;
|
|
2727
|
-
const
|
|
2750
|
+
const fs6 = factory.forRequest({
|
|
2728
2751
|
originatorClientId: clientId ?? void 0,
|
|
2729
2752
|
route: ROUTE2
|
|
2730
2753
|
});
|
|
2731
2754
|
try {
|
|
2732
|
-
const resolved = await
|
|
2733
|
-
const st = await
|
|
2755
|
+
const resolved = await fs6.resolve(queryPath, "stat");
|
|
2756
|
+
const st = await fs6.stat(resolved);
|
|
2734
2757
|
applyReadHeaders(res);
|
|
2735
2758
|
res.status(200).json({
|
|
2736
2759
|
kind: "stat",
|
|
@@ -2753,13 +2776,13 @@ async function handleGetList(req, res, deps) {
|
|
|
2753
2776
|
const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
|
|
2754
2777
|
if (queryPath === null) return;
|
|
2755
2778
|
const includeIgnored = parseBoolFlag(req.query["includeIgnored"]);
|
|
2756
|
-
const
|
|
2779
|
+
const fs6 = factory.forRequest({
|
|
2757
2780
|
originatorClientId: clientId ?? void 0,
|
|
2758
2781
|
route: ROUTE2
|
|
2759
2782
|
});
|
|
2760
2783
|
try {
|
|
2761
|
-
const resolved = await
|
|
2762
|
-
const entries = await
|
|
2784
|
+
const resolved = await fs6.resolve(queryPath, "list");
|
|
2785
|
+
const entries = await fs6.list(resolved, {
|
|
2763
2786
|
includeIgnored,
|
|
2764
2787
|
maxEntries: MAX_LIST_ENTRIES + 1
|
|
2765
2788
|
});
|
|
@@ -2812,15 +2835,15 @@ async function handleGetGlob(req, res, deps) {
|
|
|
2812
2835
|
}
|
|
2813
2836
|
const cwdRaw = req.query["cwd"];
|
|
2814
2837
|
const cwdString = typeof cwdRaw === "string" && cwdRaw.length > 0 ? cwdRaw : void 0;
|
|
2815
|
-
const
|
|
2838
|
+
const fs6 = factory.forRequest({
|
|
2816
2839
|
originatorClientId: clientId ?? void 0,
|
|
2817
2840
|
route: ROUTE2
|
|
2818
2841
|
});
|
|
2819
2842
|
const start = performance.now();
|
|
2820
2843
|
try {
|
|
2821
|
-
const cwdResolved = cwdString ? await
|
|
2844
|
+
const cwdResolved = cwdString ? await fs6.resolve(cwdString, "list") : void 0;
|
|
2822
2845
|
const cap = maxResults ?? DEFAULT_GLOB_MAX_RESULTS;
|
|
2823
|
-
const probe = await
|
|
2846
|
+
const probe = await fs6.glob(pattern, {
|
|
2824
2847
|
cwd: cwdResolved,
|
|
2825
2848
|
includeIgnored,
|
|
2826
2849
|
maxResults: cap + 1
|
|
@@ -2994,7 +3017,7 @@ function validateClientId(clientId, deps, res) {
|
|
|
2994
3017
|
}
|
|
2995
3018
|
__name(validateClientId, "validateClientId");
|
|
2996
3019
|
function createSetupGithubFileOps(factory, route, originatorClientId) {
|
|
2997
|
-
const
|
|
3020
|
+
const fs6 = factory.forRequest({
|
|
2998
3021
|
route,
|
|
2999
3022
|
...originatorClientId ? { originatorClientId } : {}
|
|
3000
3023
|
});
|
|
@@ -3017,14 +3040,14 @@ function createSetupGithubFileOps(factory, route, originatorClientId) {
|
|
|
3017
3040
|
]);
|
|
3018
3041
|
},
|
|
3019
3042
|
async writeTextFile(_gitRepoRoot, relativePath, content) {
|
|
3020
|
-
const resolved = await
|
|
3021
|
-
const out = await
|
|
3043
|
+
const resolved = await fs6.resolve(relativePath, "write");
|
|
3044
|
+
const out = await fs6.writeTextOverwrite(resolved, content);
|
|
3022
3045
|
return { sizeBytes: out.sizeBytes };
|
|
3023
3046
|
},
|
|
3024
3047
|
async readTextFile(_gitRepoRoot, relativePath) {
|
|
3025
3048
|
try {
|
|
3026
|
-
const resolved = await
|
|
3027
|
-
const out = await
|
|
3049
|
+
const resolved = await fs6.resolve(relativePath, "read");
|
|
3050
|
+
const out = await fs6.readText(resolved);
|
|
3028
3051
|
return out.content;
|
|
3029
3052
|
} catch (error2) {
|
|
3030
3053
|
if (isFsError(error2) && error2.kind === "path_not_found") {
|
|
@@ -3045,15 +3068,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
|
|
|
3045
3068
|
checkedSegments.push(segment);
|
|
3046
3069
|
const label = `Workspace path "${checkedSegments.join("/")}"`;
|
|
3047
3070
|
try {
|
|
3048
|
-
const
|
|
3049
|
-
if (
|
|
3071
|
+
const stat3 = await fsp3.lstat(current);
|
|
3072
|
+
if (stat3.isSymbolicLink()) {
|
|
3050
3073
|
throw new SetupGithubError(
|
|
3051
3074
|
"github_setup_invalid_workspace",
|
|
3052
3075
|
`${label} must not be a symlink.`,
|
|
3053
3076
|
400
|
|
3054
3077
|
);
|
|
3055
3078
|
}
|
|
3056
|
-
if (!
|
|
3079
|
+
if (!stat3.isDirectory()) {
|
|
3057
3080
|
throw new SetupGithubError(
|
|
3058
3081
|
"github_setup_invalid_workspace",
|
|
3059
3082
|
`${label} must be a directory.`,
|
|
@@ -3090,15 +3113,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
|
|
|
3090
3113
|
}
|
|
3091
3114
|
__name(ensureDirectoryWithoutSymlink, "ensureDirectoryWithoutSymlink");
|
|
3092
3115
|
async function assertDirectoryWithoutSymlink(target, label) {
|
|
3093
|
-
const
|
|
3094
|
-
if (
|
|
3116
|
+
const stat3 = await fsp3.lstat(target);
|
|
3117
|
+
if (stat3.isSymbolicLink()) {
|
|
3095
3118
|
throw new SetupGithubError(
|
|
3096
3119
|
"github_setup_invalid_workspace",
|
|
3097
3120
|
`${label} must not be a symlink.`,
|
|
3098
3121
|
400
|
|
3099
3122
|
);
|
|
3100
3123
|
}
|
|
3101
|
-
if (!
|
|
3124
|
+
if (!stat3.isDirectory()) {
|
|
3102
3125
|
throw new SetupGithubError(
|
|
3103
3126
|
"github_setup_invalid_workspace",
|
|
3104
3127
|
`${label} must be a directory.`,
|
|
@@ -4739,12 +4762,12 @@ async function collectWorkspaceMemoryStatus(boundWorkspace) {
|
|
|
4739
4762
|
for (const filename of filenames) {
|
|
4740
4763
|
const candidate = path8.join(globalDir, filename);
|
|
4741
4764
|
try {
|
|
4742
|
-
const
|
|
4743
|
-
if (
|
|
4765
|
+
const stat3 = await fs.stat(candidate);
|
|
4766
|
+
if (stat3.isFile()) {
|
|
4744
4767
|
files.push({
|
|
4745
4768
|
absolutePath: candidate,
|
|
4746
4769
|
scope: "global",
|
|
4747
|
-
bytes:
|
|
4770
|
+
bytes: stat3.size
|
|
4748
4771
|
});
|
|
4749
4772
|
}
|
|
4750
4773
|
} catch (err) {
|
|
@@ -4788,12 +4811,12 @@ async function walkWorkspaceForMemory(start, filenames, errors) {
|
|
|
4788
4811
|
for (const filename of filenames) {
|
|
4789
4812
|
const candidate = path8.join(start, filename);
|
|
4790
4813
|
try {
|
|
4791
|
-
const
|
|
4792
|
-
if (
|
|
4814
|
+
const stat3 = await fs.stat(candidate);
|
|
4815
|
+
if (stat3.isFile()) {
|
|
4793
4816
|
out.push({
|
|
4794
4817
|
absolutePath: candidate,
|
|
4795
4818
|
scope: "workspace",
|
|
4796
|
-
bytes:
|
|
4819
|
+
bytes: stat3.size
|
|
4797
4820
|
});
|
|
4798
4821
|
}
|
|
4799
4822
|
} catch (err) {
|
|
@@ -4819,6 +4842,7 @@ __name(isEnoent, "isEnoent");
|
|
|
4819
4842
|
// packages/cli/src/serve/workspace-agents.ts
|
|
4820
4843
|
init_esbuild_shims();
|
|
4821
4844
|
import { promises as fs2 } from "node:fs";
|
|
4845
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4822
4846
|
var AGENT_TYPE_PATTERN = /^[\p{L}\p{N}_-]+$/u;
|
|
4823
4847
|
var AGENT_TYPE_MAX_LENGTH = 64;
|
|
4824
4848
|
var AGENT_TYPE_MIN_LENGTH = 2;
|
|
@@ -4826,6 +4850,27 @@ var MAX_DESCRIPTION_BYTES = 256 * 1024;
|
|
|
4826
4850
|
var MAX_SYSTEM_PROMPT_BYTES = 256 * 1024;
|
|
4827
4851
|
var MAX_TOOLS_ENTRIES = 256;
|
|
4828
4852
|
var MAX_TOOL_ID_LENGTH = 256;
|
|
4853
|
+
var MAX_RECORD_ENTRIES = 128;
|
|
4854
|
+
var SUBAGENT_APPROVAL_MODES = [...APPROVAL_MODES, "bubble"];
|
|
4855
|
+
var SUBAGENT_PERMISSION_MODES = [
|
|
4856
|
+
"acceptEdits",
|
|
4857
|
+
"auto",
|
|
4858
|
+
"bypassPermissions",
|
|
4859
|
+
"default",
|
|
4860
|
+
"dontAsk",
|
|
4861
|
+
"plan"
|
|
4862
|
+
];
|
|
4863
|
+
var SUBAGENT_COLORS = [
|
|
4864
|
+
"auto",
|
|
4865
|
+
"red",
|
|
4866
|
+
"blue",
|
|
4867
|
+
"green",
|
|
4868
|
+
"yellow",
|
|
4869
|
+
"purple",
|
|
4870
|
+
"orange",
|
|
4871
|
+
"pink",
|
|
4872
|
+
"cyan"
|
|
4873
|
+
];
|
|
4829
4874
|
function mountWorkspaceAgentsRoutes(app, deps) {
|
|
4830
4875
|
const manager = createDaemonSubagentManager(deps.boundWorkspace);
|
|
4831
4876
|
app.get("/workspace/agents", async (_req, res) => {
|
|
@@ -4864,7 +4909,11 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
4864
4909
|
return;
|
|
4865
4910
|
}
|
|
4866
4911
|
const level = scope === "workspace" ? "project" : "user";
|
|
4867
|
-
const config = parseAgentConfig(
|
|
4912
|
+
const config = parseAgentConfig(
|
|
4913
|
+
restoreAgentMcpServerSecrets(body, deps.boundWorkspace, level),
|
|
4914
|
+
level,
|
|
4915
|
+
res
|
|
4916
|
+
);
|
|
4868
4917
|
if (!config) return;
|
|
4869
4918
|
const collision = await manager.loadSubagent(config.name, level);
|
|
4870
4919
|
if (collision) {
|
|
@@ -4980,7 +5029,9 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
4980
5029
|
const agentType = validateAgentType(req, res);
|
|
4981
5030
|
if (agentType === null) return;
|
|
4982
5031
|
try {
|
|
4983
|
-
const
|
|
5032
|
+
const scopedLevel = parseScopeQuery(req, res);
|
|
5033
|
+
if (scopedLevel === null) return;
|
|
5034
|
+
const config = await manager.loadSubagent(agentType, scopedLevel);
|
|
4984
5035
|
if (!config) {
|
|
4985
5036
|
res.status(404).json({
|
|
4986
5037
|
error: `Subagent "${agentType}" not found`,
|
|
@@ -5009,9 +5060,6 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
5009
5060
|
const clientIdResult = resolveOriginatorClientId(deps, req, res);
|
|
5010
5061
|
if (clientIdResult === null) return;
|
|
5011
5062
|
const originatorClientId = clientIdResult;
|
|
5012
|
-
const body = deps.safeBody(req);
|
|
5013
|
-
const updates = parseAgentUpdates(body, res);
|
|
5014
|
-
if (!updates) return;
|
|
5015
5063
|
const preferredLevel = parseScopeQuery(req, res);
|
|
5016
5064
|
if (preferredLevel === null) return;
|
|
5017
5065
|
const existing = await manager.loadSubagent(agentType, preferredLevel);
|
|
@@ -5026,6 +5074,14 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
5026
5074
|
if (assertMutableLevel(existing, agentType, res)) {
|
|
5027
5075
|
return;
|
|
5028
5076
|
}
|
|
5077
|
+
const body = restoreAgentMcpServerSecrets(
|
|
5078
|
+
deps.safeBody(req),
|
|
5079
|
+
deps.boundWorkspace,
|
|
5080
|
+
existing.level,
|
|
5081
|
+
existing.mcpServers
|
|
5082
|
+
);
|
|
5083
|
+
const updates = parseAgentUpdates(body, res);
|
|
5084
|
+
if (!updates) return;
|
|
5029
5085
|
if (Object.keys(updates).length === 0) {
|
|
5030
5086
|
res.status(400).json({
|
|
5031
5087
|
error: "`POST /workspace/agents/:agentType` requires at least one updatable field in the body",
|
|
@@ -5269,7 +5325,11 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5269
5325
|
const level = parseWorkspaceOnlyAgentBodyScope(body, res);
|
|
5270
5326
|
if (level === null) return;
|
|
5271
5327
|
const manager = createDaemonSubagentManager(runtime.workspaceCwd);
|
|
5272
|
-
const config = parseAgentConfig(
|
|
5328
|
+
const config = parseAgentConfig(
|
|
5329
|
+
restoreAgentMcpServerSecrets(body, runtime.workspaceCwd, level),
|
|
5330
|
+
level,
|
|
5331
|
+
res
|
|
5332
|
+
);
|
|
5273
5333
|
if (!config) return;
|
|
5274
5334
|
const collision = await manager.loadSubagent(config.name, level);
|
|
5275
5335
|
if (collision) {
|
|
@@ -5358,9 +5418,6 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5358
5418
|
const clientIdResult = resolveOriginatorClientId(routeDeps, req, res);
|
|
5359
5419
|
if (clientIdResult === null) return;
|
|
5360
5420
|
const originatorClientId = clientIdResult;
|
|
5361
|
-
const body = deps.safeBody(req);
|
|
5362
|
-
const updates = parseAgentUpdates(body, res);
|
|
5363
|
-
if (!updates) return;
|
|
5364
5421
|
const manager = createDaemonSubagentManager(runtime.workspaceCwd);
|
|
5365
5422
|
const existing = await manager.loadSubagent(agentType, scopedLevel);
|
|
5366
5423
|
if (!existing) {
|
|
@@ -5372,6 +5429,14 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5372
5429
|
return;
|
|
5373
5430
|
}
|
|
5374
5431
|
if (assertMutableLevel(existing, agentType, res)) return;
|
|
5432
|
+
const body = restoreAgentMcpServerSecrets(
|
|
5433
|
+
deps.safeBody(req),
|
|
5434
|
+
runtime.workspaceCwd,
|
|
5435
|
+
existing.level,
|
|
5436
|
+
existing.mcpServers
|
|
5437
|
+
);
|
|
5438
|
+
const updates = parseAgentUpdates(body, res);
|
|
5439
|
+
if (!updates) return;
|
|
5375
5440
|
if (Object.keys(updates).length === 0) {
|
|
5376
5441
|
res.status(400).json({
|
|
5377
5442
|
error: "`POST /workspaces/:workspace/agents/:agentType` requires at least one updatable field in the body",
|
|
@@ -5627,6 +5692,22 @@ function rejectWorkspaceQualifiedAgentScope(scope, res) {
|
|
|
5627
5692
|
return null;
|
|
5628
5693
|
}
|
|
5629
5694
|
__name(rejectWorkspaceQualifiedAgentScope, "rejectWorkspaceQualifiedAgentScope");
|
|
5695
|
+
function restoreAgentMcpServerSecrets(body, workspace, level, currentAgentServers) {
|
|
5696
|
+
const incoming = body["mcpServers"];
|
|
5697
|
+
if (typeof incoming !== "object" || incoming === null || Array.isArray(incoming)) {
|
|
5698
|
+
return body;
|
|
5699
|
+
}
|
|
5700
|
+
const settings = loadSettings(workspace);
|
|
5701
|
+
const configuredServers = level === "user" ? settings.user.settings.mcpServers ?? {} : settings.merged.mcpServers ?? {};
|
|
5702
|
+
return {
|
|
5703
|
+
...body,
|
|
5704
|
+
mcpServers: restoreRedactedMcpServersSetting(incoming, {
|
|
5705
|
+
...configuredServers,
|
|
5706
|
+
...currentAgentServers
|
|
5707
|
+
})
|
|
5708
|
+
};
|
|
5709
|
+
}
|
|
5710
|
+
__name(restoreAgentMcpServerSecrets, "restoreAgentMcpServerSecrets");
|
|
5630
5711
|
function sendCreateAgentError(res, err, name) {
|
|
5631
5712
|
if (!(err instanceof SubagentError)) return false;
|
|
5632
5713
|
if (err.code === SubagentErrorCode.ALREADY_EXISTS) {
|
|
@@ -5768,22 +5849,73 @@ function parseAgentConfig(body, level, res) {
|
|
|
5768
5849
|
if (tools !== void 0) config.tools = tools;
|
|
5769
5850
|
if (disallowedTools !== void 0) config.disallowedTools = disallowedTools;
|
|
5770
5851
|
if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
|
|
5771
|
-
if (typeof body["model"] === "string")
|
|
5852
|
+
if (typeof body["model"] === "string") {
|
|
5853
|
+
if (!body["model"].trim()) {
|
|
5854
|
+
return sendInvalidConfig(res, "`model` must not be empty when provided");
|
|
5855
|
+
}
|
|
5856
|
+
config.model = body["model"].trim();
|
|
5857
|
+
}
|
|
5772
5858
|
if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
|
|
5773
|
-
if (typeof body["color"] === "string")
|
|
5859
|
+
if (typeof body["color"] === "string") {
|
|
5860
|
+
if (!SUBAGENT_COLORS.includes(body["color"])) {
|
|
5861
|
+
return sendInvalidConfig(
|
|
5862
|
+
res,
|
|
5863
|
+
`\`color\` must be one of ${JSON.stringify(SUBAGENT_COLORS)}`
|
|
5864
|
+
);
|
|
5865
|
+
}
|
|
5866
|
+
config.color = body["color"];
|
|
5867
|
+
}
|
|
5774
5868
|
if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
|
|
5775
5869
|
return void 0;
|
|
5776
5870
|
}
|
|
5777
5871
|
if (typeof body["approvalMode"] === "string") {
|
|
5778
|
-
if (!
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
return void 0;
|
|
5872
|
+
if (!SUBAGENT_APPROVAL_MODES.includes(body["approvalMode"])) {
|
|
5873
|
+
return sendInvalidConfig(
|
|
5874
|
+
res,
|
|
5875
|
+
`\`approvalMode\` must be one of ${JSON.stringify(SUBAGENT_APPROVAL_MODES)}`
|
|
5876
|
+
);
|
|
5784
5877
|
}
|
|
5785
5878
|
config.approvalMode = body["approvalMode"];
|
|
5786
5879
|
}
|
|
5880
|
+
if (rejectIfPresentWrongType(body, "permissionMode", "string", res)) {
|
|
5881
|
+
return void 0;
|
|
5882
|
+
}
|
|
5883
|
+
if (typeof body["permissionMode"] === "string") {
|
|
5884
|
+
if (!SUBAGENT_PERMISSION_MODES.includes(body["permissionMode"])) {
|
|
5885
|
+
return sendInvalidConfig(
|
|
5886
|
+
res,
|
|
5887
|
+
`\`permissionMode\` must be one of ${JSON.stringify(SUBAGENT_PERMISSION_MODES)}`
|
|
5888
|
+
);
|
|
5889
|
+
}
|
|
5890
|
+
config.permissionMode = body["permissionMode"];
|
|
5891
|
+
}
|
|
5892
|
+
if ("maxTurns" in body) {
|
|
5893
|
+
const maxTurns = parseMaxTurns(body["maxTurns"], res);
|
|
5894
|
+
if (maxTurns === null) return void 0;
|
|
5895
|
+
config.maxTurns = maxTurns;
|
|
5896
|
+
}
|
|
5897
|
+
if ("mcpServers" in body) {
|
|
5898
|
+
const mcpServers = parseRecordField(
|
|
5899
|
+
body["mcpServers"],
|
|
5900
|
+
"mcpServers",
|
|
5901
|
+
(value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
5902
|
+
"an object of server names to server configuration objects",
|
|
5903
|
+
res
|
|
5904
|
+
);
|
|
5905
|
+
if (mcpServers === null) return void 0;
|
|
5906
|
+
if (Object.keys(mcpServers).length > 0) config.mcpServers = mcpServers;
|
|
5907
|
+
}
|
|
5908
|
+
if ("hooks" in body) {
|
|
5909
|
+
const hooks = parseRecordField(
|
|
5910
|
+
body["hooks"],
|
|
5911
|
+
"hooks",
|
|
5912
|
+
Array.isArray,
|
|
5913
|
+
"an object of hook event names to matcher arrays",
|
|
5914
|
+
res
|
|
5915
|
+
);
|
|
5916
|
+
if (hooks === null) return void 0;
|
|
5917
|
+
if (Object.keys(hooks).length > 0) config.hooks = hooks;
|
|
5918
|
+
}
|
|
5787
5919
|
if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
|
|
5788
5920
|
return void 0;
|
|
5789
5921
|
}
|
|
@@ -5853,24 +5985,87 @@ function parseAgentUpdates(body, res) {
|
|
|
5853
5985
|
updates.disallowedTools = disallowedTools;
|
|
5854
5986
|
}
|
|
5855
5987
|
}
|
|
5856
|
-
if (
|
|
5857
|
-
|
|
5858
|
-
if (rejectIfPresentWrongType(body, "
|
|
5859
|
-
if (typeof body["color"] === "string") updates.color = body["color"];
|
|
5860
|
-
if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
|
|
5988
|
+
if (body["model"] === null) {
|
|
5989
|
+
updates.model = void 0;
|
|
5990
|
+
} else if (rejectIfPresentWrongType(body, "model", "string", res)) {
|
|
5861
5991
|
return void 0;
|
|
5992
|
+
} else if (typeof body["model"] === "string") {
|
|
5993
|
+
if (!body["model"].trim()) {
|
|
5994
|
+
return sendInvalidConfig(res, "`model` must not be empty when provided");
|
|
5995
|
+
}
|
|
5996
|
+
updates.model = body["model"].trim();
|
|
5862
5997
|
}
|
|
5863
|
-
if (
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
return
|
|
5998
|
+
if (body["color"] === null) {
|
|
5999
|
+
updates.color = void 0;
|
|
6000
|
+
} else if (rejectIfPresentWrongType(body, "color", "string", res)) {
|
|
6001
|
+
return void 0;
|
|
6002
|
+
} else if (typeof body["color"] === "string") {
|
|
6003
|
+
if (!SUBAGENT_COLORS.includes(body["color"])) {
|
|
6004
|
+
return sendInvalidConfig(
|
|
6005
|
+
res,
|
|
6006
|
+
`\`color\` must be one of ${JSON.stringify(SUBAGENT_COLORS)}`
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
updates.color = body["color"];
|
|
6010
|
+
}
|
|
6011
|
+
if (body["approvalMode"] === null) {
|
|
6012
|
+
updates.approvalMode = void 0;
|
|
6013
|
+
} else if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
|
|
6014
|
+
return void 0;
|
|
6015
|
+
} else if (typeof body["approvalMode"] === "string") {
|
|
6016
|
+
if (!SUBAGENT_APPROVAL_MODES.includes(body["approvalMode"])) {
|
|
6017
|
+
return sendInvalidConfig(
|
|
6018
|
+
res,
|
|
6019
|
+
`\`approvalMode\` must be one of ${JSON.stringify(SUBAGENT_APPROVAL_MODES)}`
|
|
6020
|
+
);
|
|
5870
6021
|
}
|
|
5871
6022
|
updates.approvalMode = body["approvalMode"];
|
|
5872
6023
|
}
|
|
5873
|
-
if (
|
|
6024
|
+
if (body["permissionMode"] === null) {
|
|
6025
|
+
updates.permissionMode = void 0;
|
|
6026
|
+
} else if (rejectIfPresentWrongType(body, "permissionMode", "string", res)) {
|
|
6027
|
+
return void 0;
|
|
6028
|
+
} else if (typeof body["permissionMode"] === "string") {
|
|
6029
|
+
if (!SUBAGENT_PERMISSION_MODES.includes(body["permissionMode"])) {
|
|
6030
|
+
return sendInvalidConfig(
|
|
6031
|
+
res,
|
|
6032
|
+
`\`permissionMode\` must be one of ${JSON.stringify(SUBAGENT_PERMISSION_MODES)}`
|
|
6033
|
+
);
|
|
6034
|
+
}
|
|
6035
|
+
updates.permissionMode = body["permissionMode"];
|
|
6036
|
+
}
|
|
6037
|
+
if ("maxTurns" in body) {
|
|
6038
|
+
if (body["maxTurns"] === null) {
|
|
6039
|
+
updates.maxTurns = void 0;
|
|
6040
|
+
} else {
|
|
6041
|
+
const maxTurns = parseMaxTurns(body["maxTurns"], res);
|
|
6042
|
+
if (maxTurns === null) return void 0;
|
|
6043
|
+
updates.maxTurns = maxTurns;
|
|
6044
|
+
}
|
|
6045
|
+
}
|
|
6046
|
+
if ("mcpServers" in body) {
|
|
6047
|
+
const mcpServers = parseRecordField(
|
|
6048
|
+
body["mcpServers"],
|
|
6049
|
+
"mcpServers",
|
|
6050
|
+
(value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
6051
|
+
"an object of server names to server configuration objects",
|
|
6052
|
+
res
|
|
6053
|
+
);
|
|
6054
|
+
if (mcpServers === null) return void 0;
|
|
6055
|
+
updates.mcpServers = mcpServers;
|
|
6056
|
+
}
|
|
6057
|
+
if ("hooks" in body) {
|
|
6058
|
+
const hooks = parseRecordField(
|
|
6059
|
+
body["hooks"],
|
|
6060
|
+
"hooks",
|
|
6061
|
+
Array.isArray,
|
|
6062
|
+
"an object of hook event names to matcher arrays",
|
|
6063
|
+
res
|
|
6064
|
+
);
|
|
6065
|
+
if (hooks === null) return void 0;
|
|
6066
|
+
updates.hooks = hooks;
|
|
6067
|
+
}
|
|
6068
|
+
if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
|
|
5874
6069
|
return void 0;
|
|
5875
6070
|
}
|
|
5876
6071
|
if (typeof body["background"] === "boolean") {
|
|
@@ -5910,6 +6105,43 @@ function parseStringArray(value, field, res) {
|
|
|
5910
6105
|
return value;
|
|
5911
6106
|
}
|
|
5912
6107
|
__name(parseStringArray, "parseStringArray");
|
|
6108
|
+
function sendInvalidConfig(res, error2) {
|
|
6109
|
+
res.status(422).json({ error: error2, code: "invalid_config" });
|
|
6110
|
+
return void 0;
|
|
6111
|
+
}
|
|
6112
|
+
__name(sendInvalidConfig, "sendInvalidConfig");
|
|
6113
|
+
function parseMaxTurns(value, res) {
|
|
6114
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
|
|
6115
|
+
sendInvalidConfig(res, "`maxTurns` must be a positive integer");
|
|
6116
|
+
return null;
|
|
6117
|
+
}
|
|
6118
|
+
return value;
|
|
6119
|
+
}
|
|
6120
|
+
__name(parseMaxTurns, "parseMaxTurns");
|
|
6121
|
+
function parseRecordField(value, field, isValidEntry, expected, res) {
|
|
6122
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
6123
|
+
sendInvalidConfig(res, `\`${field}\` must be ${expected}`);
|
|
6124
|
+
return null;
|
|
6125
|
+
}
|
|
6126
|
+
const entries = Object.entries(value);
|
|
6127
|
+
if (entries.length > MAX_RECORD_ENTRIES) {
|
|
6128
|
+
sendInvalidConfig(
|
|
6129
|
+
res,
|
|
6130
|
+
`\`${field}\` exceeds the ${MAX_RECORD_ENTRIES}-entry limit`
|
|
6131
|
+
);
|
|
6132
|
+
return null;
|
|
6133
|
+
}
|
|
6134
|
+
const output = {};
|
|
6135
|
+
for (const [key, entry] of entries) {
|
|
6136
|
+
if (!key || key.length > MAX_TOOL_ID_LENGTH || key === "__proto__" || key === "constructor" || key === "prototype" || !isValidEntry(entry)) {
|
|
6137
|
+
sendInvalidConfig(res, `\`${field}\` must be ${expected}`);
|
|
6138
|
+
return null;
|
|
6139
|
+
}
|
|
6140
|
+
output[key] = entry;
|
|
6141
|
+
}
|
|
6142
|
+
return output;
|
|
6143
|
+
}
|
|
6144
|
+
__name(parseRecordField, "parseRecordField");
|
|
5913
6145
|
function rejectIfPresentWrongType(body, key, expected, res) {
|
|
5914
6146
|
if (!(key in body)) return false;
|
|
5915
6147
|
if (typeof body[key] === expected) return false;
|
|
@@ -5933,13 +6165,31 @@ function isNoOpUpdate(existing, updates) {
|
|
|
5933
6165
|
if (updates.disallowedTools !== void 0 && !shallowArrayEqual(updates.disallowedTools, existing.disallowedTools)) {
|
|
5934
6166
|
return false;
|
|
5935
6167
|
}
|
|
5936
|
-
if (
|
|
6168
|
+
if ("model" in updates && updates.model !== existing.model) {
|
|
6169
|
+
return false;
|
|
6170
|
+
}
|
|
6171
|
+
if ("color" in updates && updates.color !== existing.color) {
|
|
6172
|
+
return false;
|
|
6173
|
+
}
|
|
6174
|
+
if ("approvalMode" in updates && updates.approvalMode !== existing.approvalMode) {
|
|
6175
|
+
return false;
|
|
6176
|
+
}
|
|
6177
|
+
if ("permissionMode" in updates && updates.permissionMode !== existing.permissionMode) {
|
|
6178
|
+
return false;
|
|
6179
|
+
}
|
|
6180
|
+
if ("maxTurns" in updates && updates.maxTurns !== existing.maxTurns) {
|
|
5937
6181
|
return false;
|
|
5938
6182
|
}
|
|
5939
|
-
if (updates.
|
|
6183
|
+
if (updates.mcpServers !== void 0 && !isDeepStrictEqual(
|
|
6184
|
+
normalizedRecord(updates.mcpServers),
|
|
6185
|
+
normalizedRecord(existing.mcpServers)
|
|
6186
|
+
)) {
|
|
5940
6187
|
return false;
|
|
5941
6188
|
}
|
|
5942
|
-
if (updates.
|
|
6189
|
+
if (updates.hooks !== void 0 && !isDeepStrictEqual(
|
|
6190
|
+
normalizedRecord(updates.hooks),
|
|
6191
|
+
normalizedRecord(existing.hooks)
|
|
6192
|
+
)) {
|
|
5943
6193
|
return false;
|
|
5944
6194
|
}
|
|
5945
6195
|
if (updates.background !== void 0 && updates.background !== existing.background) {
|
|
@@ -5958,6 +6208,19 @@ function isNoOpUpdate(existing, updates) {
|
|
|
5958
6208
|
return true;
|
|
5959
6209
|
}
|
|
5960
6210
|
__name(isNoOpUpdate, "isNoOpUpdate");
|
|
6211
|
+
function normalizedRecord(value) {
|
|
6212
|
+
if (!value || Object.keys(value).length === 0) return void 0;
|
|
6213
|
+
return normalizeRecordValue(value);
|
|
6214
|
+
}
|
|
6215
|
+
__name(normalizedRecord, "normalizedRecord");
|
|
6216
|
+
function normalizeRecordValue(value) {
|
|
6217
|
+
if (Array.isArray(value)) return value.map(normalizeRecordValue);
|
|
6218
|
+
if (typeof value !== "object" || value === null) return value;
|
|
6219
|
+
return Object.fromEntries(
|
|
6220
|
+
Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, normalizeRecordValue(entry)])
|
|
6221
|
+
);
|
|
6222
|
+
}
|
|
6223
|
+
__name(normalizeRecordValue, "normalizeRecordValue");
|
|
5961
6224
|
function shallowArrayEqual(a, b) {
|
|
5962
6225
|
if (a === b) return true;
|
|
5963
6226
|
if (!a || !b) return false;
|
|
@@ -6010,10 +6273,30 @@ function toSummary(config) {
|
|
|
6010
6273
|
isBuiltin: config.isBuiltin === true || config.level === "builtin",
|
|
6011
6274
|
hasTools: Array.isArray(config.tools) && config.tools.length > 0
|
|
6012
6275
|
};
|
|
6276
|
+
if (config.tools) summary.tools = [...config.tools];
|
|
6277
|
+
if (config.disallowedTools) {
|
|
6278
|
+
summary.disallowedTools = [...config.disallowedTools];
|
|
6279
|
+
}
|
|
6013
6280
|
if (config.model) summary.model = config.model;
|
|
6014
6281
|
if (config.color) summary.color = config.color;
|
|
6015
6282
|
if (config.background !== void 0) summary.background = config.background;
|
|
6016
6283
|
if (config.approvalMode) summary.approvalMode = config.approvalMode;
|
|
6284
|
+
if (config.permissionMode) summary.permissionMode = config.permissionMode;
|
|
6285
|
+
if (config.maxTurns !== void 0) summary.maxTurns = config.maxTurns;
|
|
6286
|
+
if (config.mcpServers) {
|
|
6287
|
+
summary.mcpServerNames = Object.keys(config.mcpServers);
|
|
6288
|
+
}
|
|
6289
|
+
if (config.hooks) summary.hookEvents = Object.keys(config.hooks);
|
|
6290
|
+
if (config.runConfig) {
|
|
6291
|
+
const runConfig = {};
|
|
6292
|
+
if (typeof config.runConfig.max_time_minutes === "number") {
|
|
6293
|
+
runConfig.max_time_minutes = config.runConfig.max_time_minutes;
|
|
6294
|
+
}
|
|
6295
|
+
if (typeof config.runConfig.max_turns === "number") {
|
|
6296
|
+
runConfig.max_turns = config.runConfig.max_turns;
|
|
6297
|
+
}
|
|
6298
|
+
summary.runConfig = runConfig;
|
|
6299
|
+
}
|
|
6017
6300
|
if (config.extensionName) summary.extensionName = config.extensionName;
|
|
6018
6301
|
if (config.filePath) summary.filePath = config.filePath;
|
|
6019
6302
|
return summary;
|
|
@@ -6024,20 +6307,10 @@ function toDetail(config) {
|
|
|
6024
6307
|
...toSummary(config),
|
|
6025
6308
|
systemPrompt: config.systemPrompt
|
|
6026
6309
|
};
|
|
6027
|
-
if (config.
|
|
6028
|
-
|
|
6029
|
-
detail.disallowedTools = [...config.disallowedTools];
|
|
6030
|
-
}
|
|
6031
|
-
if (config.runConfig) {
|
|
6032
|
-
const runConfig = {};
|
|
6033
|
-
if (typeof config.runConfig.max_time_minutes === "number") {
|
|
6034
|
-
runConfig.max_time_minutes = config.runConfig.max_time_minutes;
|
|
6035
|
-
}
|
|
6036
|
-
if (typeof config.runConfig.max_turns === "number") {
|
|
6037
|
-
runConfig.max_turns = config.runConfig.max_turns;
|
|
6038
|
-
}
|
|
6039
|
-
detail.runConfig = runConfig;
|
|
6310
|
+
if (config.mcpServers) {
|
|
6311
|
+
detail.mcpServers = redactMcpServersSetting(config.mcpServers);
|
|
6040
6312
|
}
|
|
6313
|
+
if (config.hooks) detail.hooks = config.hooks;
|
|
6041
6314
|
return detail;
|
|
6042
6315
|
}
|
|
6043
6316
|
__name(toDetail, "toDetail");
|
|
@@ -9045,7 +9318,7 @@ var AcpDispatcher = class {
|
|
|
9045
9318
|
);
|
|
9046
9319
|
return;
|
|
9047
9320
|
}
|
|
9048
|
-
const
|
|
9321
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9049
9322
|
originatorClientId: conn.clientId,
|
|
9050
9323
|
route: `ACP ${method}`
|
|
9051
9324
|
});
|
|
@@ -9097,8 +9370,8 @@ var AcpDispatcher = class {
|
|
|
9097
9370
|
);
|
|
9098
9371
|
return;
|
|
9099
9372
|
}
|
|
9100
|
-
const resolved = await
|
|
9101
|
-
const out = await
|
|
9373
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9374
|
+
const out = await fs6.readText(resolved, { maxBytes, line, limit });
|
|
9102
9375
|
this.replyConn(conn, id, {
|
|
9103
9376
|
path: p,
|
|
9104
9377
|
content: out.content,
|
|
@@ -9120,7 +9393,7 @@ var AcpDispatcher = class {
|
|
|
9120
9393
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9121
9394
|
return;
|
|
9122
9395
|
}
|
|
9123
|
-
const
|
|
9396
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9124
9397
|
originatorClientId: conn.clientId,
|
|
9125
9398
|
route: `ACP ${method}`
|
|
9126
9399
|
});
|
|
@@ -9156,8 +9429,8 @@ var AcpDispatcher = class {
|
|
|
9156
9429
|
);
|
|
9157
9430
|
return;
|
|
9158
9431
|
}
|
|
9159
|
-
const resolved = await
|
|
9160
|
-
const buf = await
|
|
9432
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9433
|
+
const buf = await fs6.readBytesWindow(resolved, { offset, maxBytes });
|
|
9161
9434
|
this.replyConn(conn, id, { path: p, ...buf });
|
|
9162
9435
|
return;
|
|
9163
9436
|
}
|
|
@@ -9175,12 +9448,12 @@ var AcpDispatcher = class {
|
|
|
9175
9448
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9176
9449
|
return;
|
|
9177
9450
|
}
|
|
9178
|
-
const
|
|
9451
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9179
9452
|
originatorClientId: conn.clientId,
|
|
9180
9453
|
route: `ACP ${method}`
|
|
9181
9454
|
});
|
|
9182
|
-
const resolved = await
|
|
9183
|
-
const result = await
|
|
9455
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9456
|
+
const result = await fs6.stat(resolved);
|
|
9184
9457
|
this.replyConn(conn, id, { path: p, ...result });
|
|
9185
9458
|
return;
|
|
9186
9459
|
}
|
|
@@ -9198,13 +9471,13 @@ var AcpDispatcher = class {
|
|
|
9198
9471
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9199
9472
|
return;
|
|
9200
9473
|
}
|
|
9201
|
-
const
|
|
9474
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9202
9475
|
originatorClientId: conn.clientId,
|
|
9203
9476
|
route: `ACP ${method}`
|
|
9204
9477
|
});
|
|
9205
|
-
const resolved = await
|
|
9478
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9206
9479
|
const MAX_LIST = 2e3;
|
|
9207
|
-
const entries = await
|
|
9480
|
+
const entries = await fs6.list(resolved, { maxEntries: MAX_LIST + 1 });
|
|
9208
9481
|
const truncated = entries.length > MAX_LIST;
|
|
9209
9482
|
this.replyConn(conn, id, {
|
|
9210
9483
|
path: p,
|
|
@@ -9229,7 +9502,7 @@ var AcpDispatcher = class {
|
|
|
9229
9502
|
);
|
|
9230
9503
|
return;
|
|
9231
9504
|
}
|
|
9232
|
-
const
|
|
9505
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9233
9506
|
originatorClientId: conn.clientId,
|
|
9234
9507
|
route: `ACP ${method}`
|
|
9235
9508
|
});
|
|
@@ -9249,7 +9522,7 @@ var AcpDispatcher = class {
|
|
|
9249
9522
|
);
|
|
9250
9523
|
return;
|
|
9251
9524
|
}
|
|
9252
|
-
const matches = await
|
|
9525
|
+
const matches = await fs6.glob(pattern, {
|
|
9253
9526
|
maxResults: maxResults + 1
|
|
9254
9527
|
});
|
|
9255
9528
|
const truncated = matches.length > maxResults;
|
|
@@ -9281,11 +9554,11 @@ var AcpDispatcher = class {
|
|
|
9281
9554
|
);
|
|
9282
9555
|
return;
|
|
9283
9556
|
}
|
|
9284
|
-
const
|
|
9557
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9285
9558
|
originatorClientId: conn.clientId,
|
|
9286
9559
|
route: `ACP ${method}`
|
|
9287
9560
|
});
|
|
9288
|
-
const resolved = await
|
|
9561
|
+
const resolved = await fs6.resolve(p, "write");
|
|
9289
9562
|
if (Buffer.byteLength(params["content"], "utf8") > 10 * 1024 * 1024) {
|
|
9290
9563
|
if (id !== void 0)
|
|
9291
9564
|
conn.sendConn(
|
|
@@ -9293,7 +9566,7 @@ var AcpDispatcher = class {
|
|
|
9293
9566
|
);
|
|
9294
9567
|
return;
|
|
9295
9568
|
}
|
|
9296
|
-
await
|
|
9569
|
+
await fs6.writeTextOverwrite(resolved, params["content"]);
|
|
9297
9570
|
this.replyConn(conn, id, { ok: true, path: p });
|
|
9298
9571
|
return;
|
|
9299
9572
|
}
|
|
@@ -9322,12 +9595,12 @@ var AcpDispatcher = class {
|
|
|
9322
9595
|
);
|
|
9323
9596
|
return;
|
|
9324
9597
|
}
|
|
9325
|
-
const
|
|
9598
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9326
9599
|
originatorClientId: conn.clientId,
|
|
9327
9600
|
route: `ACP ${method}`
|
|
9328
9601
|
});
|
|
9329
|
-
const resolved = await
|
|
9330
|
-
const result = await
|
|
9602
|
+
const resolved = await fs6.resolve(p, "write");
|
|
9603
|
+
const result = await fs6.edit(
|
|
9331
9604
|
resolved,
|
|
9332
9605
|
params["oldText"],
|
|
9333
9606
|
params["newText"]
|
|
@@ -9871,11 +10144,24 @@ var AcpDispatcher = class {
|
|
|
9871
10144
|
}
|
|
9872
10145
|
}
|
|
9873
10146
|
}
|
|
10147
|
+
/**
|
|
10148
|
+
* Current epoch token of the session's event bus, or `undefined` when
|
|
10149
|
+
* the session is unknown (torn down between ownership check and header
|
|
10150
|
+
* write). The `/acp` GET route advertises it as `X-Qwen-Event-Epoch`
|
|
10151
|
+
* BEFORE `stream.open()` flushes headers (DAEMON-001).
|
|
10152
|
+
*/
|
|
10153
|
+
getSessionEventEpoch(sessionId) {
|
|
10154
|
+
try {
|
|
10155
|
+
return this.bridge.getSessionEventEpoch(sessionId);
|
|
10156
|
+
} catch {
|
|
10157
|
+
return void 0;
|
|
10158
|
+
}
|
|
10159
|
+
}
|
|
9874
10160
|
/**
|
|
9875
10161
|
* Bind a session-scoped SSE stream to the bridge's event stream,
|
|
9876
10162
|
* translating each `BridgeEvent` into a JSON-RPC frame (design §4.2).
|
|
9877
10163
|
*/
|
|
9878
|
-
async pumpSessionEvents(conn, sessionId, signal, lastEventId) {
|
|
10164
|
+
async pumpSessionEvents(conn, sessionId, signal, lastEventId, epoch) {
|
|
9879
10165
|
try {
|
|
9880
10166
|
let lastDeliveredId = lastEventId ?? 0;
|
|
9881
10167
|
let sawEviction = false;
|
|
@@ -9883,6 +10169,11 @@ var AcpDispatcher = class {
|
|
|
9883
10169
|
if (conn.hasInitialReplayPending(sessionId)) {
|
|
9884
10170
|
const snapshot = this.bridge.getSessionReplaySnapshot(sessionId);
|
|
9885
10171
|
if (snapshot) {
|
|
10172
|
+
if (snapshot.degraded) {
|
|
10173
|
+
writeStderrLine(
|
|
10174
|
+
`qwen serve: /acp initial replay used a DEGRADED snapshot (compaction failure) session=${logSafe(sessionId)}; replay may be incomplete`
|
|
10175
|
+
);
|
|
10176
|
+
}
|
|
9886
10177
|
const snapshotEvents = [
|
|
9887
10178
|
...snapshot.compactedTurns,
|
|
9888
10179
|
...snapshot.liveJournal
|
|
@@ -9915,7 +10206,8 @@ var AcpDispatcher = class {
|
|
|
9915
10206
|
}
|
|
9916
10207
|
const iterable = this.bridge.subscribeEvents(sessionId, {
|
|
9917
10208
|
signal,
|
|
9918
|
-
...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {}
|
|
10209
|
+
...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {},
|
|
10210
|
+
...epoch !== void 0 ? { epoch } : {}
|
|
9919
10211
|
});
|
|
9920
10212
|
for await (const event of iterable) {
|
|
9921
10213
|
if (signal.aborted) break;
|
|
@@ -11028,6 +11320,17 @@ function parseLastEventId2(raw, logPrefix = "") {
|
|
|
11028
11320
|
return n;
|
|
11029
11321
|
}
|
|
11030
11322
|
__name(parseLastEventId2, "parseLastEventId");
|
|
11323
|
+
function parseEventEpochHeader(raw, logPrefix = "") {
|
|
11324
|
+
if (typeof raw !== "string" || raw.length === 0) return void 0;
|
|
11325
|
+
if (raw.length > 64 || !/^[\w-]+$/.test(raw)) {
|
|
11326
|
+
writeStderrLine(
|
|
11327
|
+
`qwen serve: ${logPrefix}rejected X-Qwen-Event-Epoch ${safeLogValue2(raw)} (expected [A-Za-z0-9_-]{1,64})`
|
|
11328
|
+
);
|
|
11329
|
+
return void 0;
|
|
11330
|
+
}
|
|
11331
|
+
return raw;
|
|
11332
|
+
}
|
|
11333
|
+
__name(parseEventEpochHeader, "parseEventEpochHeader");
|
|
11031
11334
|
|
|
11032
11335
|
// packages/cli/src/serve/acp-http/client-mcp-ws.ts
|
|
11033
11336
|
init_esbuild_shims();
|
|
@@ -12391,11 +12694,19 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
12391
12694
|
},
|
|
12392
12695
|
() => conn.touch()
|
|
12393
12696
|
);
|
|
12394
|
-
stream.open();
|
|
12395
12697
|
const lastEventId = parseLastEventId2(
|
|
12396
12698
|
headerOf(req, "last-event-id"),
|
|
12397
12699
|
"/acp "
|
|
12398
12700
|
);
|
|
12701
|
+
const eventEpoch = parseEventEpochHeader(
|
|
12702
|
+
headerOf(req, "x-qwen-event-epoch"),
|
|
12703
|
+
"/acp "
|
|
12704
|
+
);
|
|
12705
|
+
const busEpoch = mount.dispatcher.getSessionEventEpoch(sessionId);
|
|
12706
|
+
if (busEpoch !== void 0) {
|
|
12707
|
+
res.setHeader("X-Qwen-Event-Epoch", busEpoch);
|
|
12708
|
+
}
|
|
12709
|
+
stream.open();
|
|
12399
12710
|
conn.attachSessionStream(sessionId, stream, ac, lastEventId);
|
|
12400
12711
|
const onPumpSettled = /* @__PURE__ */ __name(() => {
|
|
12401
12712
|
if (stream.isClosed) {
|
|
@@ -12411,7 +12722,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
12411
12722
|
);
|
|
12412
12723
|
}
|
|
12413
12724
|
}, "onPumpSettled");
|
|
12414
|
-
void mount.dispatcher.pumpSessionEvents(conn, sessionId, ac.signal, lastEventId).then(onPumpSettled, (err) => {
|
|
12725
|
+
void mount.dispatcher.pumpSessionEvents(conn, sessionId, ac.signal, lastEventId, eventEpoch).then(onPumpSettled, (err) => {
|
|
12415
12726
|
writeStderrLine(
|
|
12416
12727
|
`qwen serve: ${mount.routeLabel} event pump error (${logSafe(sessionId)}, lastEventId=${lastEventId ?? "none"}): ${logSafe(err instanceof Error ? err.message : String(err))}`
|
|
12417
12728
|
);
|
|
@@ -13864,6 +14175,130 @@ function mountWebShellSpaFallback(app, webShellDir, frameAncestors = []) {
|
|
|
13864
14175
|
}
|
|
13865
14176
|
__name(mountWebShellSpaFallback, "mountWebShellSpaFallback");
|
|
13866
14177
|
|
|
14178
|
+
// packages/cli/src/serve/workspace-generation.ts
|
|
14179
|
+
init_esbuild_shims();
|
|
14180
|
+
|
|
14181
|
+
// packages/cli/src/serve/generation-sse.ts
|
|
14182
|
+
init_esbuild_shims();
|
|
14183
|
+
var GENERATION_HEARTBEAT_MS = 15e3;
|
|
14184
|
+
function formatGenerationSse(event, data) {
|
|
14185
|
+
return `event: ${event}
|
|
14186
|
+
data: ${JSON.stringify({ v: 1, ...data })}
|
|
14187
|
+
|
|
14188
|
+
`;
|
|
14189
|
+
}
|
|
14190
|
+
__name(formatGenerationSse, "formatGenerationSse");
|
|
14191
|
+
function writeGenerationSseChunk(res, chunk) {
|
|
14192
|
+
if (res.destroyed) {
|
|
14193
|
+
return Promise.reject(new Error("Generation SSE connection destroyed"));
|
|
14194
|
+
}
|
|
14195
|
+
const writable = res.write(chunk);
|
|
14196
|
+
const flush = res.flush;
|
|
14197
|
+
flush?.call(res);
|
|
14198
|
+
if (writable) {
|
|
14199
|
+
return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
|
|
14200
|
+
}
|
|
14201
|
+
return new Promise((resolve6, reject) => {
|
|
14202
|
+
const cleanup = /* @__PURE__ */ __name(() => {
|
|
14203
|
+
res.off("drain", onDrain);
|
|
14204
|
+
res.off("close", onClose);
|
|
14205
|
+
res.off("error", onError);
|
|
14206
|
+
}, "cleanup");
|
|
14207
|
+
const onDrain = /* @__PURE__ */ __name(() => {
|
|
14208
|
+
cleanup();
|
|
14209
|
+
resolve6();
|
|
14210
|
+
}, "onDrain");
|
|
14211
|
+
const onClose = /* @__PURE__ */ __name(() => {
|
|
14212
|
+
cleanup();
|
|
14213
|
+
reject(new Error("Generation SSE connection closed"));
|
|
14214
|
+
}, "onClose");
|
|
14215
|
+
const onError = /* @__PURE__ */ __name((error2) => {
|
|
14216
|
+
cleanup();
|
|
14217
|
+
reject(error2);
|
|
14218
|
+
}, "onError");
|
|
14219
|
+
res.once("drain", onDrain);
|
|
14220
|
+
res.once("close", onClose);
|
|
14221
|
+
res.once("error", onError);
|
|
14222
|
+
if (res.destroyed) onClose();
|
|
14223
|
+
});
|
|
14224
|
+
}
|
|
14225
|
+
__name(writeGenerationSseChunk, "writeGenerationSseChunk");
|
|
14226
|
+
|
|
14227
|
+
// packages/cli/src/serve/workspace-generation.ts
|
|
14228
|
+
function mountWorkspaceGenerationRoutes(app, deps) {
|
|
14229
|
+
app.post("/workspace/generate", deps.mutate(), async (req, res) => {
|
|
14230
|
+
const body = deps.safeBody(req);
|
|
14231
|
+
const prompt = body["prompt"];
|
|
14232
|
+
if (typeof prompt !== "string" || prompt.trim().length === 0 || Buffer.byteLength(prompt, "utf8") > GENERATION_MAX_PROMPT_BYTES) {
|
|
14233
|
+
res.status(400).json({
|
|
14234
|
+
error: `\`prompt\` must be a non-empty string no larger than ${GENERATION_MAX_PROMPT_BYTES} UTF-8 bytes`,
|
|
14235
|
+
code: "invalid_prompt"
|
|
14236
|
+
});
|
|
14237
|
+
return;
|
|
14238
|
+
}
|
|
14239
|
+
const clientId = deps.parseClientId(req, res);
|
|
14240
|
+
if (clientId === null) return;
|
|
14241
|
+
if (!deps.bridge.generateWorkspaceContent) {
|
|
14242
|
+
res.status(501).json({
|
|
14243
|
+
error: "Workspace generation is not supported by this bridge",
|
|
14244
|
+
code: "generation_not_supported"
|
|
14245
|
+
});
|
|
14246
|
+
return;
|
|
14247
|
+
}
|
|
14248
|
+
const abort = new AbortController();
|
|
14249
|
+
let completed = false;
|
|
14250
|
+
const onClose = /* @__PURE__ */ __name(() => {
|
|
14251
|
+
if (!completed) abort.abort();
|
|
14252
|
+
}, "onClose");
|
|
14253
|
+
res.once("close", onClose);
|
|
14254
|
+
const stream = deps.bridge.generateWorkspaceContent(
|
|
14255
|
+
prompt.trim(),
|
|
14256
|
+
abort.signal,
|
|
14257
|
+
clientId
|
|
14258
|
+
);
|
|
14259
|
+
res.status(200);
|
|
14260
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
14261
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
14262
|
+
res.setHeader("Connection", "keep-alive");
|
|
14263
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
14264
|
+
res.flushHeaders();
|
|
14265
|
+
let writeChain = Promise.resolve();
|
|
14266
|
+
const write = /* @__PURE__ */ __name((chunk) => {
|
|
14267
|
+
writeChain = writeChain.then(() => writeGenerationSseChunk(res, chunk));
|
|
14268
|
+
return writeChain;
|
|
14269
|
+
}, "write");
|
|
14270
|
+
await write(": connected\n\n");
|
|
14271
|
+
const heartbeat = setInterval(() => {
|
|
14272
|
+
void write(": heartbeat\n\n").catch(() => abort.abort());
|
|
14273
|
+
}, GENERATION_HEARTBEAT_MS);
|
|
14274
|
+
heartbeat.unref();
|
|
14275
|
+
try {
|
|
14276
|
+
for await (const event of stream) {
|
|
14277
|
+
await write(formatGenerationSse(event.type, event));
|
|
14278
|
+
}
|
|
14279
|
+
} catch (error2) {
|
|
14280
|
+
if (!abort.signal.aborted && !res.destroyed) {
|
|
14281
|
+
writeStderrLine(
|
|
14282
|
+
`qwen serve: POST /workspace/generate failed: ${error2 instanceof Error ? error2.stack ?? error2.message : String(error2)}`
|
|
14283
|
+
);
|
|
14284
|
+
await write(
|
|
14285
|
+
formatGenerationSse("error", {
|
|
14286
|
+
type: "error",
|
|
14287
|
+
code: "generation_failed",
|
|
14288
|
+
message: "Generation failed"
|
|
14289
|
+
})
|
|
14290
|
+
).catch(() => void 0);
|
|
14291
|
+
}
|
|
14292
|
+
} finally {
|
|
14293
|
+
completed = true;
|
|
14294
|
+
clearInterval(heartbeat);
|
|
14295
|
+
res.off("close", onClose);
|
|
14296
|
+
if (!res.destroyed) res.end();
|
|
14297
|
+
}
|
|
14298
|
+
});
|
|
14299
|
+
}
|
|
14300
|
+
__name(mountWorkspaceGenerationRoutes, "mountWorkspaceGenerationRoutes");
|
|
14301
|
+
|
|
13867
14302
|
// packages/cli/src/serve/routes/daemon-status.ts
|
|
13868
14303
|
init_esbuild_shims();
|
|
13869
14304
|
function registerDaemonStatusRoutes(app, deps) {
|
|
@@ -17518,13 +17953,13 @@ async function handlePostFileWrite(req, res, deps) {
|
|
|
17518
17953
|
req
|
|
17519
17954
|
);
|
|
17520
17955
|
if (originatorClientId === null) return;
|
|
17521
|
-
const
|
|
17956
|
+
const fs6 = factory.forRequest({
|
|
17522
17957
|
originatorClientId,
|
|
17523
17958
|
route: ROUTE2
|
|
17524
17959
|
});
|
|
17525
17960
|
try {
|
|
17526
|
-
const resolved = await
|
|
17527
|
-
const out = await
|
|
17961
|
+
const resolved = await fs6.resolve(queryPath, "write");
|
|
17962
|
+
const out = await fs6.writeTextAtomic(resolved, content, {
|
|
17528
17963
|
mode,
|
|
17529
17964
|
...expectedHash ? { expectedHash } : {},
|
|
17530
17965
|
...bom !== void 0 ? { bom } : {},
|
|
@@ -17577,13 +18012,13 @@ async function handlePostFileEdit(req, res, deps) {
|
|
|
17577
18012
|
req
|
|
17578
18013
|
);
|
|
17579
18014
|
if (originatorClientId === null) return;
|
|
17580
|
-
const
|
|
18015
|
+
const fs6 = factory.forRequest({
|
|
17581
18016
|
originatorClientId,
|
|
17582
18017
|
route: ROUTE2
|
|
17583
18018
|
});
|
|
17584
18019
|
try {
|
|
17585
|
-
const resolved = await
|
|
17586
|
-
const out = await
|
|
18020
|
+
const resolved = await fs6.resolve(queryPath, "edit");
|
|
18021
|
+
const out = await fs6.editAtomic(resolved, oldText, newText, {
|
|
17587
18022
|
expectedHash
|
|
17588
18023
|
});
|
|
17589
18024
|
applyReadHeaders(res);
|
|
@@ -17911,6 +18346,18 @@ var legacySessionTelemetryRoutes = [
|
|
|
17911
18346
|
attribution: "handler_resolved",
|
|
17912
18347
|
route: "GET /session/:id/tasks"
|
|
17913
18348
|
},
|
|
18349
|
+
{
|
|
18350
|
+
method: "GET",
|
|
18351
|
+
path: "/session/:id/subagents/:toolCallId",
|
|
18352
|
+
attribution: "handler_resolved",
|
|
18353
|
+
route: "GET /session/:id/subagents/:toolCallId"
|
|
18354
|
+
},
|
|
18355
|
+
{
|
|
18356
|
+
method: "POST",
|
|
18357
|
+
path: "/session/:id/subagents/:toolCallId/cancel",
|
|
18358
|
+
attribution: "handler_resolved",
|
|
18359
|
+
route: "POST /session/:id/subagents/:toolCallId/cancel"
|
|
18360
|
+
},
|
|
17914
18361
|
{
|
|
17915
18362
|
method: "GET",
|
|
17916
18363
|
path: "/session/:id/lsp",
|
|
@@ -18593,7 +19040,7 @@ __name(registerPermissionRoutes, "registerPermissionRoutes");
|
|
|
18593
19040
|
// packages/cli/src/serve/routes/session.ts
|
|
18594
19041
|
init_esbuild_shims();
|
|
18595
19042
|
import * as crypto3 from "node:crypto";
|
|
18596
|
-
import * as
|
|
19043
|
+
import * as fs4 from "node:fs";
|
|
18597
19044
|
import * as path10 from "node:path";
|
|
18598
19045
|
|
|
18599
19046
|
// packages/cli/src/serve/server/prompt-deadline.ts
|
|
@@ -18886,7 +19333,17 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
18886
19333
|
organization
|
|
18887
19334
|
)
|
|
18888
19335
|
);
|
|
18889
|
-
} else if (
|
|
19336
|
+
} else if (
|
|
19337
|
+
// `listAllPersistedSummaries` already scanned every persisted
|
|
19338
|
+
// session when the scan wasn't truncated, so a `sessionId` missing
|
|
19339
|
+
// from `bySessionId` is definitively new — no disk re-check
|
|
19340
|
+
// needed. Re-checking here raced a session that persists its
|
|
19341
|
+
// first write (e.g. a `displayName` update) between the scan
|
|
19342
|
+
// above and this point: `existing` stayed undefined but
|
|
19343
|
+
// `sessionExists` flipped to true, silently dropping the live
|
|
19344
|
+
// session from the response instead of merging it.
|
|
19345
|
+
!persisted.truncated || !await sessionService.sessionExists(live.sessionId)
|
|
19346
|
+
) {
|
|
18890
19347
|
bySessionId.set(
|
|
18891
19348
|
live.sessionId,
|
|
18892
19349
|
applyOrganization(
|
|
@@ -18968,7 +19425,13 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
|
|
|
18968
19425
|
live.sessionId,
|
|
18969
19426
|
mergeLiveSessionSummary(existing, live)
|
|
18970
19427
|
);
|
|
18971
|
-
} else if (
|
|
19428
|
+
} else if (
|
|
19429
|
+
// See the matching comment in
|
|
19430
|
+
// `listOrganizedWorkspaceSessionsForResponse`: an untruncated scan
|
|
19431
|
+
// already covers every persisted session, so skip the racy
|
|
19432
|
+
// re-check when nothing was truncated.
|
|
19433
|
+
!persisted.truncated || !await sessionService.sessionExists(live.sessionId)
|
|
19434
|
+
) {
|
|
18972
19435
|
bySessionId.set(live.sessionId, {
|
|
18973
19436
|
...live,
|
|
18974
19437
|
createdAt: live.createdAt,
|
|
@@ -19071,7 +19534,14 @@ async function listWorkspaceSessionsForResponse(bridge, workspaceCwd, options, r
|
|
|
19071
19534
|
const existing = bySessionId.get(live.sessionId);
|
|
19072
19535
|
if (existing) {
|
|
19073
19536
|
bySessionId.set(live.sessionId, mergeLiveSessionSummary(existing, live));
|
|
19074
|
-
} else if (isFirstPage &&
|
|
19537
|
+
} else if (isFirstPage && // If this is a complete scan (no further pages), a missing
|
|
19538
|
+
// `sessionId` here is definitively new — no disk re-check needed.
|
|
19539
|
+
// Re-checking raced a session that persists its first write (e.g. a
|
|
19540
|
+
// `displayName` update) between the scan above and this point:
|
|
19541
|
+
// `existing` stayed undefined but `sessionExists` flipped to true,
|
|
19542
|
+
// silently dropping the live session from the response instead of
|
|
19543
|
+
// merging it.
|
|
19544
|
+
(persisted.nextCursor == null || !await sessionService.sessionExists(live.sessionId))) {
|
|
19075
19545
|
bySessionId.set(live.sessionId, {
|
|
19076
19546
|
...live,
|
|
19077
19547
|
createdAt: live.createdAt,
|
|
@@ -19199,73 +19669,811 @@ async function exportSessionTranscript(params) {
|
|
|
19199
19669
|
}
|
|
19200
19670
|
__name(exportSessionTranscript, "exportSessionTranscript");
|
|
19201
19671
|
|
|
19202
|
-
// packages/cli/src/serve/
|
|
19203
|
-
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
var
|
|
19207
|
-
var
|
|
19208
|
-
|
|
19209
|
-
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
|
|
19213
|
-
|
|
19214
|
-
|
|
19672
|
+
// packages/cli/src/serve/server/git-branch-ops.ts
|
|
19673
|
+
init_esbuild_shims();
|
|
19674
|
+
import { execFile } from "node:child_process";
|
|
19675
|
+
import { promisify } from "node:util";
|
|
19676
|
+
var execFileAsync = promisify(execFile);
|
|
19677
|
+
var GIT_BRANCH_TIMEOUT_MS = 3e4;
|
|
19678
|
+
async function branchExists(cwd, name) {
|
|
19679
|
+
try {
|
|
19680
|
+
await execFileAsync(
|
|
19681
|
+
"git",
|
|
19682
|
+
["rev-parse", "--verify", `refs/heads/${name}`],
|
|
19683
|
+
{ cwd, timeout: GIT_BRANCH_TIMEOUT_MS }
|
|
19684
|
+
);
|
|
19685
|
+
return true;
|
|
19686
|
+
} catch {
|
|
19687
|
+
return false;
|
|
19688
|
+
}
|
|
19689
|
+
}
|
|
19690
|
+
__name(branchExists, "branchExists");
|
|
19691
|
+
async function isDirtyTree(cwd) {
|
|
19692
|
+
const { stdout } = await execFileAsync(
|
|
19693
|
+
"git",
|
|
19694
|
+
["status", "--porcelain", "--untracked-files=no"],
|
|
19695
|
+
{
|
|
19696
|
+
cwd,
|
|
19697
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
19698
|
+
timeout: GIT_BRANCH_TIMEOUT_MS
|
|
19699
|
+
}
|
|
19215
19700
|
);
|
|
19701
|
+
return stdout.trim().length > 0;
|
|
19702
|
+
}
|
|
19703
|
+
__name(isDirtyTree, "isDirtyTree");
|
|
19704
|
+
async function getHeadCommit(cwd) {
|
|
19705
|
+
return execFileAsync("git", ["rev-parse", "HEAD"], {
|
|
19706
|
+
cwd,
|
|
19707
|
+
timeout: GIT_BRANCH_TIMEOUT_MS
|
|
19708
|
+
}).then(({ stdout }) => stdout.trim()).catch(() => void 0);
|
|
19709
|
+
}
|
|
19710
|
+
__name(getHeadCommit, "getHeadCommit");
|
|
19711
|
+
async function createBranch(cwd, name) {
|
|
19712
|
+
await execFileAsync("git", ["checkout", "-b", name], {
|
|
19713
|
+
cwd,
|
|
19714
|
+
timeout: GIT_BRANCH_TIMEOUT_MS
|
|
19715
|
+
});
|
|
19216
19716
|
}
|
|
19217
|
-
__name(
|
|
19218
|
-
function
|
|
19219
|
-
|
|
19220
|
-
|
|
19221
|
-
|
|
19222
|
-
|
|
19717
|
+
__name(createBranch, "createBranch");
|
|
19718
|
+
async function checkoutRef(cwd, ref) {
|
|
19719
|
+
await execFileAsync("git", ["checkout", ref], {
|
|
19720
|
+
cwd,
|
|
19721
|
+
timeout: GIT_BRANCH_TIMEOUT_MS
|
|
19722
|
+
});
|
|
19223
19723
|
}
|
|
19224
|
-
__name(
|
|
19225
|
-
function
|
|
19226
|
-
|
|
19227
|
-
|
|
19228
|
-
|
|
19229
|
-
const writable = res.write(chunk);
|
|
19230
|
-
const flush = res.flush;
|
|
19231
|
-
flush?.call(res);
|
|
19232
|
-
if (writable) {
|
|
19233
|
-
return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
|
|
19234
|
-
}
|
|
19235
|
-
return new Promise((resolve6, reject) => {
|
|
19236
|
-
const cleanup = /* @__PURE__ */ __name(() => {
|
|
19237
|
-
res.off("drain", onDrain);
|
|
19238
|
-
res.off("close", onClose);
|
|
19239
|
-
res.off("error", onError);
|
|
19240
|
-
}, "cleanup");
|
|
19241
|
-
const onDrain = /* @__PURE__ */ __name(() => {
|
|
19242
|
-
cleanup();
|
|
19243
|
-
resolve6();
|
|
19244
|
-
}, "onDrain");
|
|
19245
|
-
const onClose = /* @__PURE__ */ __name(() => {
|
|
19246
|
-
cleanup();
|
|
19247
|
-
reject(new Error("Generation SSE connection closed"));
|
|
19248
|
-
}, "onClose");
|
|
19249
|
-
const onError = /* @__PURE__ */ __name((error2) => {
|
|
19250
|
-
cleanup();
|
|
19251
|
-
reject(error2);
|
|
19252
|
-
}, "onError");
|
|
19253
|
-
res.once("drain", onDrain);
|
|
19254
|
-
res.once("close", onClose);
|
|
19255
|
-
res.once("error", onError);
|
|
19256
|
-
if (res.destroyed) onClose();
|
|
19724
|
+
__name(checkoutRef, "checkoutRef");
|
|
19725
|
+
async function deleteBranch(cwd, name) {
|
|
19726
|
+
await execFileAsync("git", ["branch", "-D", name], {
|
|
19727
|
+
cwd,
|
|
19728
|
+
timeout: GIT_BRANCH_TIMEOUT_MS
|
|
19257
19729
|
});
|
|
19258
19730
|
}
|
|
19259
|
-
__name(
|
|
19260
|
-
|
|
19261
|
-
|
|
19731
|
+
__name(deleteBranch, "deleteBranch");
|
|
19732
|
+
|
|
19733
|
+
// packages/cli/src/serve/virtual-subagent-sessions.ts
|
|
19734
|
+
init_esbuild_shims();
|
|
19735
|
+
import * as fs3 from "node:fs/promises";
|
|
19736
|
+
import { createReadStream } from "node:fs";
|
|
19737
|
+
import readline from "node:readline";
|
|
19738
|
+
var PREFIX = "subagent.";
|
|
19739
|
+
var POLL_INTERVAL_MS = 250;
|
|
19740
|
+
var TARGET_RETENTION_MS = 6e4;
|
|
19741
|
+
async function readFirstUserText(filePath) {
|
|
19742
|
+
const stream = createReadStream(filePath);
|
|
19743
|
+
const lines = readline.createInterface({
|
|
19744
|
+
input: stream,
|
|
19745
|
+
crlfDelay: Infinity
|
|
19746
|
+
});
|
|
19747
|
+
try {
|
|
19748
|
+
for await (const line of lines) {
|
|
19749
|
+
const trimmed = line.trim();
|
|
19750
|
+
if (!trimmed) continue;
|
|
19751
|
+
for (const record of parseLineTolerant(trimmed, filePath)) {
|
|
19752
|
+
if (record.type !== "user") continue;
|
|
19753
|
+
return record.message?.parts?.find(
|
|
19754
|
+
(part) => typeof part.text === "string"
|
|
19755
|
+
)?.text;
|
|
19756
|
+
}
|
|
19757
|
+
}
|
|
19758
|
+
return void 0;
|
|
19759
|
+
} catch (error2) {
|
|
19760
|
+
if (error2.code === "ENOENT") return void 0;
|
|
19761
|
+
throw error2;
|
|
19762
|
+
} finally {
|
|
19763
|
+
lines.close();
|
|
19764
|
+
stream.destroy();
|
|
19765
|
+
}
|
|
19766
|
+
}
|
|
19767
|
+
__name(readFirstUserText, "readFirstUserText");
|
|
19768
|
+
function asRecord(value) {
|
|
19769
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
19770
|
+
}
|
|
19771
|
+
__name(asRecord, "asRecord");
|
|
19772
|
+
function finiteNonNegative(value) {
|
|
19773
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
19774
|
+
}
|
|
19775
|
+
__name(finiteNonNegative, "finiteNonNegative");
|
|
19776
|
+
function normalizeTaskStatus(status) {
|
|
19777
|
+
if (typeof status !== "string") return void 0;
|
|
19778
|
+
if (status === "success") return "completed";
|
|
19779
|
+
if (status === "error") return "failed";
|
|
19780
|
+
if (status === "background") return "running";
|
|
19781
|
+
return status;
|
|
19782
|
+
}
|
|
19783
|
+
__name(normalizeTaskStatus, "normalizeTaskStatus");
|
|
19784
|
+
function isTerminalTaskStatus(status) {
|
|
19785
|
+
return status === "completed" || status === "failed" || status === "cancelled" || status === "canceled";
|
|
19786
|
+
}
|
|
19787
|
+
__name(isTerminalTaskStatus, "isTerminalTaskStatus");
|
|
19788
|
+
function preferTerminalTaskStatus(metricsStatus, selectedStatus) {
|
|
19789
|
+
return !isTerminalTaskStatus(metricsStatus) && isTerminalTaskStatus(selectedStatus) ? selectedStatus : metricsStatus ?? selectedStatus;
|
|
19790
|
+
}
|
|
19791
|
+
__name(preferTerminalTaskStatus, "preferTerminalTaskStatus");
|
|
19792
|
+
function durationBetween(start, end) {
|
|
19793
|
+
if (!end) return void 0;
|
|
19794
|
+
const startTime = Date.parse(start);
|
|
19795
|
+
const endTime = Date.parse(end);
|
|
19796
|
+
return Number.isFinite(startTime) && Number.isFinite(endTime) ? Math.max(0, endTime - startTime) : void 0;
|
|
19797
|
+
}
|
|
19798
|
+
__name(durationBetween, "durationBetween");
|
|
19799
|
+
function findToolCallMetrics(records, toolCallId) {
|
|
19800
|
+
const toolResult = records.find(
|
|
19801
|
+
(record) => record.toolCallResult?.callId === toolCallId
|
|
19802
|
+
)?.toolCallResult;
|
|
19803
|
+
const display = asRecord(toolResult?.resultDisplay);
|
|
19804
|
+
const summary = asRecord(display?.["executionSummary"]);
|
|
19805
|
+
return {
|
|
19806
|
+
status: normalizeTaskStatus(display?.["status"]) ?? normalizeTaskStatus(toolResult?.status),
|
|
19807
|
+
durationMs: finiteNonNegative(summary?.["totalDurationMs"]),
|
|
19808
|
+
totalTokens: finiteNonNegative(summary?.["totalTokens"]) ?? finiteNonNegative(display?.["tokenCount"]),
|
|
19809
|
+
inputTokens: finiteNonNegative(summary?.["inputTokens"]),
|
|
19810
|
+
outputTokens: finiteNonNegative(summary?.["outputTokens"]),
|
|
19811
|
+
cachedTokens: finiteNonNegative(summary?.["cachedTokens"])
|
|
19812
|
+
};
|
|
19262
19813
|
}
|
|
19263
|
-
__name(
|
|
19264
|
-
function
|
|
19265
|
-
return
|
|
19814
|
+
__name(findToolCallMetrics, "findToolCallMetrics");
|
|
19815
|
+
function encodePart(value) {
|
|
19816
|
+
return Buffer.from(value, "utf8").toString("base64url");
|
|
19266
19817
|
}
|
|
19267
|
-
__name(
|
|
19268
|
-
function
|
|
19818
|
+
__name(encodePart, "encodePart");
|
|
19819
|
+
function decodePart(value) {
|
|
19820
|
+
try {
|
|
19821
|
+
return Buffer.from(value, "base64url").toString("utf8");
|
|
19822
|
+
} catch {
|
|
19823
|
+
return void 0;
|
|
19824
|
+
}
|
|
19825
|
+
}
|
|
19826
|
+
__name(decodePart, "decodePart");
|
|
19827
|
+
function isValidVirtualSessionPart(value) {
|
|
19828
|
+
return /^[a-zA-Z0-9_-]{1,500}$/.test(value);
|
|
19829
|
+
}
|
|
19830
|
+
__name(isValidVirtualSessionPart, "isValidVirtualSessionPart");
|
|
19831
|
+
function createVirtualSubagentSessionId(parentSessionId, agentId) {
|
|
19832
|
+
if (!isValidVirtualSessionPart(parentSessionId) || !isValidVirtualSessionPart(agentId)) {
|
|
19833
|
+
throw new Error("Virtual subagent session ids require valid id parts");
|
|
19834
|
+
}
|
|
19835
|
+
return `${PREFIX}${encodePart(parentSessionId)}.${encodePart(agentId)}`;
|
|
19836
|
+
}
|
|
19837
|
+
__name(createVirtualSubagentSessionId, "createVirtualSubagentSessionId");
|
|
19838
|
+
function parseVirtualSubagentSessionId(sessionId) {
|
|
19839
|
+
if (!sessionId.startsWith(PREFIX) || sessionId.length > 2e3) {
|
|
19840
|
+
return void 0;
|
|
19841
|
+
}
|
|
19842
|
+
const parts = sessionId.slice(PREFIX.length).split(".");
|
|
19843
|
+
if (parts.length !== 2) return void 0;
|
|
19844
|
+
const parentSessionId = decodePart(parts[0]);
|
|
19845
|
+
const agentId = decodePart(parts[1]);
|
|
19846
|
+
if (!parentSessionId || !agentId || !isValidVirtualSessionPart(parentSessionId) || !isValidVirtualSessionPart(agentId)) {
|
|
19847
|
+
return void 0;
|
|
19848
|
+
}
|
|
19849
|
+
return { parentSessionId, agentId };
|
|
19850
|
+
}
|
|
19851
|
+
__name(parseVirtualSubagentSessionId, "parseVirtualSubagentSessionId");
|
|
19852
|
+
function replayCursorState(sessionId, position, leafUuid, startTime, lastUpdated) {
|
|
19853
|
+
return {
|
|
19854
|
+
v: 1,
|
|
19855
|
+
sessionId,
|
|
19856
|
+
fileIdentity: { dev: 0, ino: 0 },
|
|
19857
|
+
snapshotSize: position,
|
|
19858
|
+
position,
|
|
19859
|
+
leafUuid,
|
|
19860
|
+
startTime,
|
|
19861
|
+
lastUpdated
|
|
19862
|
+
};
|
|
19863
|
+
}
|
|
19864
|
+
__name(replayCursorState, "replayCursorState");
|
|
19865
|
+
var VirtualSubagentTarget = class _VirtualSubagentTarget {
|
|
19866
|
+
constructor(sessionId, parentSessionId, task, workspaceCwd, onExpired) {
|
|
19867
|
+
this.sessionId = sessionId;
|
|
19868
|
+
this.parentSessionId = parentSessionId;
|
|
19869
|
+
this.task = task;
|
|
19870
|
+
this.workspaceCwd = workspaceCwd;
|
|
19871
|
+
this.onExpired = onExpired;
|
|
19872
|
+
}
|
|
19873
|
+
static {
|
|
19874
|
+
__name(this, "VirtualSubagentTarget");
|
|
19875
|
+
}
|
|
19876
|
+
bus = new EventBus(1024, 8);
|
|
19877
|
+
events = [];
|
|
19878
|
+
snapshotDelivered = false;
|
|
19879
|
+
offset = 0;
|
|
19880
|
+
transcriptIdentity;
|
|
19881
|
+
streamOffset = 0;
|
|
19882
|
+
streamIdentity;
|
|
19883
|
+
streamReady = false;
|
|
19884
|
+
canonicalThroughTimestamp = 0;
|
|
19885
|
+
completedStreamRounds = /* @__PURE__ */ new Set();
|
|
19886
|
+
streamedRounds = /* @__PURE__ */ new Set();
|
|
19887
|
+
streamRunIds = /* @__PURE__ */ new Set();
|
|
19888
|
+
legacyStreamedSinceCanonical = false;
|
|
19889
|
+
replayState;
|
|
19890
|
+
initialized = false;
|
|
19891
|
+
refreshPromise = Promise.resolve();
|
|
19892
|
+
snapshotPromise = Promise.resolve();
|
|
19893
|
+
pollTimer;
|
|
19894
|
+
subscribers = 0;
|
|
19895
|
+
retentionTimer;
|
|
19896
|
+
updateStatus(status) {
|
|
19897
|
+
const wasRunning = this.task.status === "running";
|
|
19898
|
+
this.task.status = status;
|
|
19899
|
+
if (status !== "running" && this.pollTimer) {
|
|
19900
|
+
clearInterval(this.pollTimer);
|
|
19901
|
+
this.pollTimer = void 0;
|
|
19902
|
+
}
|
|
19903
|
+
if (wasRunning && status !== "running") {
|
|
19904
|
+
void this.refreshLive().catch(() => void 0);
|
|
19905
|
+
}
|
|
19906
|
+
}
|
|
19907
|
+
rememberEvent(event) {
|
|
19908
|
+
if (event && !this.snapshotDelivered) this.events.push(event);
|
|
19909
|
+
}
|
|
19910
|
+
resetCanonicalState() {
|
|
19911
|
+
this.offset = 0;
|
|
19912
|
+
this.replayState = void 0;
|
|
19913
|
+
this.canonicalThroughTimestamp = 0;
|
|
19914
|
+
this.completedStreamRounds.clear();
|
|
19915
|
+
this.streamRunIds.clear();
|
|
19916
|
+
this.streamedRounds.clear();
|
|
19917
|
+
this.legacyStreamedSinceCanonical = false;
|
|
19918
|
+
}
|
|
19919
|
+
resetStreamState() {
|
|
19920
|
+
this.streamOffset = 0;
|
|
19921
|
+
this.completedStreamRounds.clear();
|
|
19922
|
+
this.streamRunIds.clear();
|
|
19923
|
+
this.streamedRounds.clear();
|
|
19924
|
+
this.legacyStreamedSinceCanonical = false;
|
|
19925
|
+
}
|
|
19926
|
+
async readNewRecords(endOffset) {
|
|
19927
|
+
let handle;
|
|
19928
|
+
try {
|
|
19929
|
+
handle = await fs3.open(this.task.outputFile, "r");
|
|
19930
|
+
const stat3 = await handle.stat();
|
|
19931
|
+
const identity = `${stat3.dev}:${stat3.ino}`;
|
|
19932
|
+
if (this.transcriptIdentity !== void 0 && this.transcriptIdentity !== identity || stat3.size < this.offset) {
|
|
19933
|
+
this.resetCanonicalState();
|
|
19934
|
+
}
|
|
19935
|
+
this.transcriptIdentity = identity;
|
|
19936
|
+
const size = Math.min(stat3.size, endOffset ?? stat3.size);
|
|
19937
|
+
if (size <= this.offset) return [];
|
|
19938
|
+
const bytes = Buffer.alloc(size - this.offset);
|
|
19939
|
+
const { bytesRead } = await handle.read(
|
|
19940
|
+
bytes,
|
|
19941
|
+
0,
|
|
19942
|
+
bytes.length,
|
|
19943
|
+
this.offset
|
|
19944
|
+
);
|
|
19945
|
+
const chunk = bytes.subarray(0, bytesRead);
|
|
19946
|
+
const lastNewline = chunk.lastIndexOf(10);
|
|
19947
|
+
if (lastNewline < 0) return [];
|
|
19948
|
+
const complete = chunk.subarray(0, lastNewline + 1);
|
|
19949
|
+
this.offset += complete.length;
|
|
19950
|
+
return complete.toString("utf8").split("\n").flatMap((line) => {
|
|
19951
|
+
const trimmed = line.trim();
|
|
19952
|
+
return trimmed ? parseLineTolerant(trimmed, this.task.outputFile) : [];
|
|
19953
|
+
});
|
|
19954
|
+
} catch (error2) {
|
|
19955
|
+
if (error2.code === "ENOENT") {
|
|
19956
|
+
if (this.transcriptIdentity !== void 0) {
|
|
19957
|
+
this.transcriptIdentity = void 0;
|
|
19958
|
+
this.resetCanonicalState();
|
|
19959
|
+
}
|
|
19960
|
+
return [];
|
|
19961
|
+
}
|
|
19962
|
+
throw error2;
|
|
19963
|
+
} finally {
|
|
19964
|
+
await handle?.close();
|
|
19965
|
+
}
|
|
19966
|
+
}
|
|
19967
|
+
async readStreamUpdates(endOffset) {
|
|
19968
|
+
const replayingExisting = !this.streamReady;
|
|
19969
|
+
this.streamReady = true;
|
|
19970
|
+
const filePath = `${this.task.outputFile}.stream`;
|
|
19971
|
+
let handle;
|
|
19972
|
+
try {
|
|
19973
|
+
handle = await fs3.open(filePath, "r");
|
|
19974
|
+
const stat3 = await handle.stat();
|
|
19975
|
+
const identity = `${stat3.dev}:${stat3.ino}`;
|
|
19976
|
+
if (this.streamIdentity !== void 0 && this.streamIdentity !== identity) {
|
|
19977
|
+
this.resetStreamState();
|
|
19978
|
+
}
|
|
19979
|
+
this.streamIdentity = identity;
|
|
19980
|
+
if (stat3.size < this.streamOffset) this.resetStreamState();
|
|
19981
|
+
const size = Math.min(stat3.size, endOffset ?? stat3.size);
|
|
19982
|
+
if (size <= this.streamOffset) return;
|
|
19983
|
+
const bytes = Buffer.alloc(size - this.streamOffset);
|
|
19984
|
+
const { bytesRead } = await handle.read(
|
|
19985
|
+
bytes,
|
|
19986
|
+
0,
|
|
19987
|
+
bytes.length,
|
|
19988
|
+
this.streamOffset
|
|
19989
|
+
);
|
|
19990
|
+
const chunk = bytes.subarray(0, bytesRead);
|
|
19991
|
+
const lastNewline = chunk.lastIndexOf(10);
|
|
19992
|
+
if (lastNewline < 0) return;
|
|
19993
|
+
const complete = chunk.subarray(0, lastNewline + 1);
|
|
19994
|
+
this.streamOffset += complete.length;
|
|
19995
|
+
const records = complete.toString("utf8").split("\n").flatMap((line) => {
|
|
19996
|
+
const trimmed = line.trim();
|
|
19997
|
+
return trimmed ? parseLineTolerant(trimmed, filePath) : [];
|
|
19998
|
+
});
|
|
19999
|
+
for (const record of records) {
|
|
20000
|
+
if (record.v !== 1 || typeof record.text !== "string" || typeof record.timestamp !== "number") {
|
|
20001
|
+
continue;
|
|
20002
|
+
}
|
|
20003
|
+
const roundKey = typeof record.runId === "string" && typeof record.round === "number" ? `${record.runId}:${record.round}` : void 0;
|
|
20004
|
+
if (typeof record.runId === "string") {
|
|
20005
|
+
this.streamRunIds.add(record.runId);
|
|
20006
|
+
}
|
|
20007
|
+
if ((roundKey ? this.completedStreamRounds.has(roundKey) : record.timestamp <= this.canonicalThroughTimestamp) || replayingExisting && typeof record.round !== "number") {
|
|
20008
|
+
continue;
|
|
20009
|
+
}
|
|
20010
|
+
const event = this.bus.publish({
|
|
20011
|
+
type: "session_update",
|
|
20012
|
+
data: createTranscriptMessageUpdate({
|
|
20013
|
+
role: "assistant",
|
|
20014
|
+
text: record.text,
|
|
20015
|
+
timestamp: record.timestamp,
|
|
20016
|
+
...record.thought ? { thought: true } : {}
|
|
20017
|
+
})
|
|
20018
|
+
});
|
|
20019
|
+
this.rememberEvent(event);
|
|
20020
|
+
if (roundKey) this.streamedRounds.add(roundKey);
|
|
20021
|
+
else this.legacyStreamedSinceCanonical = true;
|
|
20022
|
+
}
|
|
20023
|
+
for (const completed of this.completedStreamRounds) {
|
|
20024
|
+
const runId = completed.slice(0, completed.lastIndexOf(":"));
|
|
20025
|
+
if (!this.streamRunIds.has(runId)) {
|
|
20026
|
+
this.completedStreamRounds.delete(completed);
|
|
20027
|
+
}
|
|
20028
|
+
}
|
|
20029
|
+
} catch (error2) {
|
|
20030
|
+
if (error2.code !== "ENOENT") throw error2;
|
|
20031
|
+
this.streamIdentity = void 0;
|
|
20032
|
+
this.streamOffset = 0;
|
|
20033
|
+
this.streamRunIds.clear();
|
|
20034
|
+
this.streamedRounds.clear();
|
|
20035
|
+
this.legacyStreamedSinceCanonical = false;
|
|
20036
|
+
} finally {
|
|
20037
|
+
await handle?.close();
|
|
20038
|
+
}
|
|
20039
|
+
}
|
|
20040
|
+
refreshOnce = /* @__PURE__ */ __name(async (endOffset) => {
|
|
20041
|
+
let records = await this.readNewRecords(endOffset);
|
|
20042
|
+
if (records.length === 0) {
|
|
20043
|
+
this.initialized = true;
|
|
20044
|
+
return;
|
|
20045
|
+
}
|
|
20046
|
+
for (const record of records) {
|
|
20047
|
+
if (record.type === "assistant" && (record.usageMetadata !== void 0 || record.message?.parts?.some((part) => typeof part.text === "string"))) {
|
|
20048
|
+
if (typeof record.agentRunId === "string" && typeof record.agentRound === "number") {
|
|
20049
|
+
this.completedStreamRounds.add(
|
|
20050
|
+
`${record.agentRunId}:${record.agentRound}`
|
|
20051
|
+
);
|
|
20052
|
+
}
|
|
20053
|
+
const timestamp = Date.parse(record.timestamp);
|
|
20054
|
+
if (Number.isFinite(timestamp)) {
|
|
20055
|
+
this.canonicalThroughTimestamp = Math.max(
|
|
20056
|
+
this.canonicalThroughTimestamp,
|
|
20057
|
+
timestamp
|
|
20058
|
+
);
|
|
20059
|
+
}
|
|
20060
|
+
}
|
|
20061
|
+
}
|
|
20062
|
+
if (this.streamedRounds.size > 0 || this.legacyStreamedSinceCanonical) {
|
|
20063
|
+
records = records.filter((record) => {
|
|
20064
|
+
const roundKey = typeof record.agentRunId === "string" && typeof record.agentRound === "number" ? `${record.agentRunId}:${record.agentRound}` : void 0;
|
|
20065
|
+
if (roundKey && this.streamedRounds.delete(roundKey)) return false;
|
|
20066
|
+
if (!this.legacyStreamedSinceCanonical || record.type !== "assistant" || record.message?.parts?.some((part) => part.functionCall)) {
|
|
20067
|
+
return true;
|
|
20068
|
+
}
|
|
20069
|
+
this.legacyStreamedSinceCanonical = false;
|
|
20070
|
+
return false;
|
|
20071
|
+
});
|
|
20072
|
+
if (records.length === 0) {
|
|
20073
|
+
this.initialized = true;
|
|
20074
|
+
return;
|
|
20075
|
+
}
|
|
20076
|
+
}
|
|
20077
|
+
const startTime = records[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
20078
|
+
const lastUpdated = records[records.length - 1]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
20079
|
+
const page = {
|
|
20080
|
+
sessionId: this.sessionId,
|
|
20081
|
+
filePath: this.task.outputFile,
|
|
20082
|
+
records,
|
|
20083
|
+
gaps: [],
|
|
20084
|
+
hasMore: true,
|
|
20085
|
+
replay: this.replayState,
|
|
20086
|
+
startTime,
|
|
20087
|
+
lastUpdated,
|
|
20088
|
+
nextCursorState: replayCursorState(
|
|
20089
|
+
this.sessionId,
|
|
20090
|
+
this.offset,
|
|
20091
|
+
records[records.length - 1]?.uuid ?? "",
|
|
20092
|
+
startTime,
|
|
20093
|
+
lastUpdated
|
|
20094
|
+
)
|
|
20095
|
+
};
|
|
20096
|
+
let nextReplayState;
|
|
20097
|
+
const replay = await replayTranscriptRecordPage({
|
|
20098
|
+
sessionId: this.sessionId,
|
|
20099
|
+
page,
|
|
20100
|
+
encodeCursor: /* @__PURE__ */ __name((state) => {
|
|
20101
|
+
nextReplayState = state.replay;
|
|
20102
|
+
return "virtual-subagent-replay";
|
|
20103
|
+
}, "encodeCursor")
|
|
20104
|
+
});
|
|
20105
|
+
this.replayState = nextReplayState;
|
|
20106
|
+
const inputs = replay.updates.map((update) => ({
|
|
20107
|
+
type: "session_update",
|
|
20108
|
+
data: update
|
|
20109
|
+
}));
|
|
20110
|
+
const published = this.initialized ? inputs.flatMap((input) => {
|
|
20111
|
+
const event = this.bus.publish(input);
|
|
20112
|
+
return event ? [event] : [];
|
|
20113
|
+
}) : this.bus.seedReplayEvents(inputs);
|
|
20114
|
+
if (!this.snapshotDelivered) this.events.push(...published);
|
|
20115
|
+
this.initialized = true;
|
|
20116
|
+
}, "refreshOnce");
|
|
20117
|
+
refreshAt(bounds) {
|
|
20118
|
+
return this.refreshOnce(bounds?.transcript).then(async () => {
|
|
20119
|
+
if (this.task.status === "running") {
|
|
20120
|
+
await this.readStreamUpdates(bounds?.stream);
|
|
20121
|
+
}
|
|
20122
|
+
});
|
|
20123
|
+
}
|
|
20124
|
+
enqueueRefresh(work) {
|
|
20125
|
+
const result = this.refreshPromise.catch(() => void 0).then(work);
|
|
20126
|
+
this.refreshPromise = result.then(
|
|
20127
|
+
() => void 0,
|
|
20128
|
+
() => void 0
|
|
20129
|
+
);
|
|
20130
|
+
return result;
|
|
20131
|
+
}
|
|
20132
|
+
refreshLive() {
|
|
20133
|
+
return this.enqueueRefresh(() => this.refreshAt());
|
|
20134
|
+
}
|
|
20135
|
+
async captureReadBounds() {
|
|
20136
|
+
const size = /* @__PURE__ */ __name(async (filePath) => {
|
|
20137
|
+
try {
|
|
20138
|
+
return (await fs3.stat(filePath)).size;
|
|
20139
|
+
} catch (error2) {
|
|
20140
|
+
if (error2.code === "ENOENT") return 0;
|
|
20141
|
+
throw error2;
|
|
20142
|
+
}
|
|
20143
|
+
}, "size");
|
|
20144
|
+
const [transcript, stream] = await Promise.all([
|
|
20145
|
+
size(this.task.outputFile),
|
|
20146
|
+
size(`${this.task.outputFile}.stream`)
|
|
20147
|
+
]);
|
|
20148
|
+
return { transcript, stream };
|
|
20149
|
+
}
|
|
20150
|
+
async createSnapshotOnce() {
|
|
20151
|
+
if (!this.snapshotDelivered) {
|
|
20152
|
+
await this.refreshLive();
|
|
20153
|
+
const snapshot = [...this.events];
|
|
20154
|
+
this.events.length = 0;
|
|
20155
|
+
this.snapshotDelivered = true;
|
|
20156
|
+
return { events: snapshot, lastEventId: this.bus.lastEventId };
|
|
20157
|
+
}
|
|
20158
|
+
return this.enqueueRefresh(async () => {
|
|
20159
|
+
const bounds = await this.captureReadBounds();
|
|
20160
|
+
const target = new _VirtualSubagentTarget(
|
|
20161
|
+
this.sessionId,
|
|
20162
|
+
this.parentSessionId,
|
|
20163
|
+
this.task,
|
|
20164
|
+
this.workspaceCwd,
|
|
20165
|
+
() => void 0
|
|
20166
|
+
);
|
|
20167
|
+
await target.refreshAt(bounds);
|
|
20168
|
+
await this.refreshAt(bounds);
|
|
20169
|
+
return {
|
|
20170
|
+
events: [...target.events],
|
|
20171
|
+
lastEventId: this.bus.lastEventId
|
|
20172
|
+
};
|
|
20173
|
+
});
|
|
20174
|
+
}
|
|
20175
|
+
createSnapshot() {
|
|
20176
|
+
const snapshot = this.snapshotPromise.then(() => this.createSnapshotOnce());
|
|
20177
|
+
this.snapshotPromise = snapshot.then(
|
|
20178
|
+
() => void 0,
|
|
20179
|
+
() => void 0
|
|
20180
|
+
);
|
|
20181
|
+
return snapshot;
|
|
20182
|
+
}
|
|
20183
|
+
async load(clientId) {
|
|
20184
|
+
const snapshot = await this.createSnapshot();
|
|
20185
|
+
if (this.subscribers === 0) this.scheduleRetention();
|
|
20186
|
+
return {
|
|
20187
|
+
sessionId: this.sessionId,
|
|
20188
|
+
workspaceCwd: this.workspaceCwd,
|
|
20189
|
+
attached: true,
|
|
20190
|
+
...clientId ? { clientId } : {},
|
|
20191
|
+
createdAt: new Date(this.task.startTime).toISOString(),
|
|
20192
|
+
hasActivePrompt: this.task.status === "running",
|
|
20193
|
+
state: {},
|
|
20194
|
+
compactedReplay: snapshot.events,
|
|
20195
|
+
liveJournal: [],
|
|
20196
|
+
historyHasMore: false,
|
|
20197
|
+
lastEventId: snapshot.lastEventId
|
|
20198
|
+
};
|
|
20199
|
+
}
|
|
20200
|
+
async *iterate(opts) {
|
|
20201
|
+
if (this.retentionTimer) {
|
|
20202
|
+
clearTimeout(this.retentionTimer);
|
|
20203
|
+
this.retentionTimer = void 0;
|
|
20204
|
+
}
|
|
20205
|
+
this.subscribers++;
|
|
20206
|
+
try {
|
|
20207
|
+
await this.refreshLive();
|
|
20208
|
+
if (!this.snapshotDelivered) {
|
|
20209
|
+
this.events.length = 0;
|
|
20210
|
+
this.snapshotDelivered = true;
|
|
20211
|
+
}
|
|
20212
|
+
if (this.task.status === "running" && !this.pollTimer) {
|
|
20213
|
+
this.pollTimer = setInterval(() => {
|
|
20214
|
+
void this.refreshLive().catch(() => void 0);
|
|
20215
|
+
}, POLL_INTERVAL_MS);
|
|
20216
|
+
this.pollTimer.unref();
|
|
20217
|
+
}
|
|
20218
|
+
yield* this.bus.subscribe(opts);
|
|
20219
|
+
} finally {
|
|
20220
|
+
this.subscribers--;
|
|
20221
|
+
if (this.subscribers === 0) {
|
|
20222
|
+
if (this.pollTimer) clearInterval(this.pollTimer);
|
|
20223
|
+
this.pollTimer = void 0;
|
|
20224
|
+
this.scheduleRetention();
|
|
20225
|
+
}
|
|
20226
|
+
}
|
|
20227
|
+
}
|
|
20228
|
+
subscribe(opts) {
|
|
20229
|
+
return {
|
|
20230
|
+
[Symbol.asyncIterator]: () => this.iterate(opts)
|
|
20231
|
+
};
|
|
20232
|
+
}
|
|
20233
|
+
scheduleRetention() {
|
|
20234
|
+
if (this.retentionTimer) clearTimeout(this.retentionTimer);
|
|
20235
|
+
this.retentionTimer = setTimeout(this.onExpired, TARGET_RETENTION_MS);
|
|
20236
|
+
this.retentionTimer.unref();
|
|
20237
|
+
}
|
|
20238
|
+
};
|
|
20239
|
+
var VirtualSubagentSessions = class {
|
|
20240
|
+
static {
|
|
20241
|
+
__name(this, "VirtualSubagentSessions");
|
|
20242
|
+
}
|
|
20243
|
+
targets = /* @__PURE__ */ new Map();
|
|
20244
|
+
async findTask(runtime, parentSessionId, predicate) {
|
|
20245
|
+
const status = await runtime.bridge.getSessionTasksStatus(parentSessionId);
|
|
20246
|
+
const task = status.tasks.find(
|
|
20247
|
+
(candidate) => candidate.kind === "agent" && typeof candidate.outputFile === "string" && predicate(candidate)
|
|
20248
|
+
);
|
|
20249
|
+
if (task?.kind === "agent" && task.outputFile) {
|
|
20250
|
+
return {
|
|
20251
|
+
id: task.id,
|
|
20252
|
+
title: task.label,
|
|
20253
|
+
outputFile: task.outputFile,
|
|
20254
|
+
status: task.status,
|
|
20255
|
+
startTime: task.startTime,
|
|
20256
|
+
durationMs: task.stats?.durationMs ?? (task.endTime === void 0 ? void 0 : Math.max(0, task.endTime - task.startTime)),
|
|
20257
|
+
totalTokens: task.stats?.totalTokens
|
|
20258
|
+
};
|
|
20259
|
+
}
|
|
20260
|
+
const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
|
|
20261
|
+
const projectDir = Storage.runWithRuntimeBaseDir(
|
|
20262
|
+
runtimeDir,
|
|
20263
|
+
runtime.workspaceCwd,
|
|
20264
|
+
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
20265
|
+
);
|
|
20266
|
+
const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
|
|
20267
|
+
let names;
|
|
20268
|
+
try {
|
|
20269
|
+
names = await fs3.readdir(sessionDir);
|
|
20270
|
+
} catch (error2) {
|
|
20271
|
+
if (error2.code === "ENOENT") return void 0;
|
|
20272
|
+
throw error2;
|
|
20273
|
+
}
|
|
20274
|
+
for (const name of names) {
|
|
20275
|
+
if (!name.endsWith(".meta.json")) continue;
|
|
20276
|
+
const metaPath = `${sessionDir}/${name}`;
|
|
20277
|
+
const meta = readAgentMeta(metaPath);
|
|
20278
|
+
if (!meta || !predicate({
|
|
20279
|
+
kind: "agent",
|
|
20280
|
+
id: meta.agentId,
|
|
20281
|
+
toolUseId: meta.toolUseId,
|
|
20282
|
+
outputFile: metaPath.slice(0, -".meta.json".length) + ".jsonl"
|
|
20283
|
+
})) {
|
|
20284
|
+
continue;
|
|
20285
|
+
}
|
|
20286
|
+
return {
|
|
20287
|
+
id: meta.agentId,
|
|
20288
|
+
title: meta.description || meta.agentType,
|
|
20289
|
+
outputFile: metaPath.slice(0, -".meta.json".length) + ".jsonl",
|
|
20290
|
+
status: meta.status ?? "completed",
|
|
20291
|
+
startTime: Number.isFinite(Date.parse(meta.createdAt)) ? Date.parse(meta.createdAt) : Date.now(),
|
|
20292
|
+
durationMs: durationBetween(meta.createdAt, meta.lastUpdatedAt)
|
|
20293
|
+
};
|
|
20294
|
+
}
|
|
20295
|
+
return void 0;
|
|
20296
|
+
}
|
|
20297
|
+
async findLegacyTaskByToolCall(runtime, parentSessionId, toolCallId) {
|
|
20298
|
+
const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
|
|
20299
|
+
const projectDir = Storage.runWithRuntimeBaseDir(
|
|
20300
|
+
runtimeDir,
|
|
20301
|
+
runtime.workspaceCwd,
|
|
20302
|
+
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
20303
|
+
);
|
|
20304
|
+
const parentRecords = await read(
|
|
20305
|
+
`${projectDir}/chats/${parentSessionId}.jsonl`
|
|
20306
|
+
);
|
|
20307
|
+
let root;
|
|
20308
|
+
for (const record of parentRecords) {
|
|
20309
|
+
for (const part of record.message?.parts ?? []) {
|
|
20310
|
+
const call = part.functionCall;
|
|
20311
|
+
if (call?.id !== toolCallId || call.name !== "agent") continue;
|
|
20312
|
+
const args = call.args;
|
|
20313
|
+
root = {
|
|
20314
|
+
timestamp: Date.parse(record.timestamp),
|
|
20315
|
+
...typeof args?.["description"] === "string" ? { description: args["description"] } : {},
|
|
20316
|
+
...typeof args?.["prompt"] === "string" ? { prompt: args["prompt"] } : {},
|
|
20317
|
+
...typeof args?.["subagent_type"] === "string" ? { agentType: args["subagent_type"] } : {}
|
|
20318
|
+
};
|
|
20319
|
+
break;
|
|
20320
|
+
}
|
|
20321
|
+
if (root) break;
|
|
20322
|
+
}
|
|
20323
|
+
if (!root) return void 0;
|
|
20324
|
+
const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
|
|
20325
|
+
let names;
|
|
20326
|
+
try {
|
|
20327
|
+
names = await fs3.readdir(sessionDir);
|
|
20328
|
+
} catch (error2) {
|
|
20329
|
+
if (error2.code === "ENOENT") return void 0;
|
|
20330
|
+
throw error2;
|
|
20331
|
+
}
|
|
20332
|
+
const candidates = [];
|
|
20333
|
+
for (const name of names) {
|
|
20334
|
+
if (!name.endsWith(".meta.json")) continue;
|
|
20335
|
+
const metaPath = `${sessionDir}/${name}`;
|
|
20336
|
+
const meta = readAgentMeta(metaPath);
|
|
20337
|
+
if (!meta) continue;
|
|
20338
|
+
const outputFile = metaPath.slice(0, -".meta.json".length) + ".jsonl";
|
|
20339
|
+
const launchPrompt = await readFirstUserText(outputFile);
|
|
20340
|
+
let score = 0;
|
|
20341
|
+
if (root.prompt && launchPrompt === root.prompt) score += 8;
|
|
20342
|
+
if (root.description && meta.description === root.description) score += 4;
|
|
20343
|
+
if (root.agentType && meta.agentType === root.agentType) score += 2;
|
|
20344
|
+
const startTime = Date.parse(meta.createdAt);
|
|
20345
|
+
const delta = Math.abs(startTime - root.timestamp);
|
|
20346
|
+
if (Number.isFinite(delta) && delta <= 6e4) score += 1;
|
|
20347
|
+
if (score === 0) continue;
|
|
20348
|
+
candidates.push({
|
|
20349
|
+
id: meta.agentId,
|
|
20350
|
+
title: meta.description || meta.agentType,
|
|
20351
|
+
outputFile,
|
|
20352
|
+
status: meta.status ?? "completed",
|
|
20353
|
+
startTime: Number.isFinite(startTime) ? startTime : Date.now(),
|
|
20354
|
+
durationMs: durationBetween(meta.createdAt, meta.lastUpdatedAt),
|
|
20355
|
+
score,
|
|
20356
|
+
delta
|
|
20357
|
+
});
|
|
20358
|
+
}
|
|
20359
|
+
candidates.sort((a, b) => b.score - a.score || a.delta - b.delta);
|
|
20360
|
+
const selected = candidates[0];
|
|
20361
|
+
if (!selected) return void 0;
|
|
20362
|
+
const metrics = findToolCallMetrics(parentRecords, toolCallId);
|
|
20363
|
+
return {
|
|
20364
|
+
...selected,
|
|
20365
|
+
status: preferTerminalTaskStatus(metrics.status, selected.status),
|
|
20366
|
+
durationMs: metrics.durationMs ?? selected.durationMs,
|
|
20367
|
+
totalTokens: metrics.totalTokens ?? selected.totalTokens,
|
|
20368
|
+
inputTokens: metrics.inputTokens ?? selected.inputTokens,
|
|
20369
|
+
outputTokens: metrics.outputTokens ?? selected.outputTokens,
|
|
20370
|
+
cachedTokens: metrics.cachedTokens ?? selected.cachedTokens
|
|
20371
|
+
};
|
|
20372
|
+
}
|
|
20373
|
+
async readParentToolCallMetrics(runtime, parentSessionId, toolCallId) {
|
|
20374
|
+
const runtimeDir = runtime.env.effectiveEnv?.["QWEN_RUNTIME_DIR"];
|
|
20375
|
+
const projectDir = Storage.runWithRuntimeBaseDir(
|
|
20376
|
+
runtimeDir,
|
|
20377
|
+
runtime.workspaceCwd,
|
|
20378
|
+
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
20379
|
+
);
|
|
20380
|
+
const records = await read(
|
|
20381
|
+
`${projectDir}/chats/${parentSessionId}.jsonl`
|
|
20382
|
+
);
|
|
20383
|
+
return findToolCallMetrics(records, toolCallId);
|
|
20384
|
+
}
|
|
20385
|
+
async resolve(runtime, parentSessionId, toolCallId) {
|
|
20386
|
+
let task = await this.findTask(
|
|
20387
|
+
runtime,
|
|
20388
|
+
parentSessionId,
|
|
20389
|
+
(candidate) => candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
|
|
20390
|
+
);
|
|
20391
|
+
const metrics = task && task.status !== "running" ? await this.readParentToolCallMetrics(
|
|
20392
|
+
runtime,
|
|
20393
|
+
parentSessionId,
|
|
20394
|
+
toolCallId
|
|
20395
|
+
) : void 0;
|
|
20396
|
+
task ??= await this.findLegacyTaskByToolCall(
|
|
20397
|
+
runtime,
|
|
20398
|
+
parentSessionId,
|
|
20399
|
+
toolCallId
|
|
20400
|
+
);
|
|
20401
|
+
if (!task) return void 0;
|
|
20402
|
+
const sessionId = createVirtualSubagentSessionId(parentSessionId, task.id);
|
|
20403
|
+
const status = task.status;
|
|
20404
|
+
this.targets.get(`${runtime.workspaceId}:${sessionId}`)?.updateStatus(status);
|
|
20405
|
+
return {
|
|
20406
|
+
sessionId,
|
|
20407
|
+
taskId: task.id,
|
|
20408
|
+
title: task.title,
|
|
20409
|
+
status,
|
|
20410
|
+
durationMs: metrics?.durationMs ?? task.durationMs,
|
|
20411
|
+
totalTokens: metrics?.totalTokens ?? task.totalTokens,
|
|
20412
|
+
inputTokens: metrics?.inputTokens ?? task.inputTokens,
|
|
20413
|
+
outputTokens: metrics?.outputTokens ?? task.outputTokens,
|
|
20414
|
+
cachedTokens: metrics?.cachedTokens ?? task.cachedTokens
|
|
20415
|
+
};
|
|
20416
|
+
}
|
|
20417
|
+
async getTarget(runtime, sessionId) {
|
|
20418
|
+
const targetKey = `${runtime.workspaceId}:${sessionId}`;
|
|
20419
|
+
const cached = this.targets.get(targetKey);
|
|
20420
|
+
if (cached) return cached;
|
|
20421
|
+
const key = parseVirtualSubagentSessionId(sessionId);
|
|
20422
|
+
if (!key) return void 0;
|
|
20423
|
+
const task = await this.findTask(
|
|
20424
|
+
runtime,
|
|
20425
|
+
key.parentSessionId,
|
|
20426
|
+
(candidate) => candidate.id === key.agentId
|
|
20427
|
+
);
|
|
20428
|
+
if (!task) return void 0;
|
|
20429
|
+
const existing = this.targets.get(targetKey);
|
|
20430
|
+
if (existing) return existing;
|
|
20431
|
+
const target = new VirtualSubagentTarget(
|
|
20432
|
+
sessionId,
|
|
20433
|
+
key.parentSessionId,
|
|
20434
|
+
task,
|
|
20435
|
+
runtime.workspaceCwd,
|
|
20436
|
+
() => this.targets.delete(targetKey)
|
|
20437
|
+
);
|
|
20438
|
+
this.targets.set(targetKey, target);
|
|
20439
|
+
return target;
|
|
20440
|
+
}
|
|
20441
|
+
async load(runtime, sessionId, clientId) {
|
|
20442
|
+
return (await this.getTarget(runtime, sessionId))?.load(clientId);
|
|
20443
|
+
}
|
|
20444
|
+
async subscribe(runtime, sessionId, opts) {
|
|
20445
|
+
return (await this.getTarget(runtime, sessionId))?.subscribe(opts);
|
|
20446
|
+
}
|
|
20447
|
+
};
|
|
20448
|
+
|
|
20449
|
+
// packages/cli/src/serve/routes/session.ts
|
|
20450
|
+
var GIT_RESERVED_BRANCH = "HEAD";
|
|
20451
|
+
var MAX_BRANCH_NAME_BYTES = 1e3;
|
|
20452
|
+
var MAX_BRANCH_COMPONENT_BYTES = 200;
|
|
20453
|
+
var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
|
|
20454
|
+
var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
|
|
20455
|
+
var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
|
|
20456
|
+
var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
|
|
20457
|
+
var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
|
|
20458
|
+
"POST /session/:id/branch",
|
|
20459
|
+
"POST /session/:id/fork",
|
|
20460
|
+
"POST /session/:id/cd"
|
|
20461
|
+
];
|
|
20462
|
+
function isPrimaryOnlyLiveSessionRoute(route) {
|
|
20463
|
+
return PRIMARY_ONLY_LIVE_SESSION_ROUTES.includes(
|
|
20464
|
+
route
|
|
20465
|
+
);
|
|
20466
|
+
}
|
|
20467
|
+
__name(isPrimaryOnlyLiveSessionRoute, "isPrimaryOnlyLiveSessionRoute");
|
|
20468
|
+
function isReadOnlyWorkspaceInspection(runtime) {
|
|
20469
|
+
return !runtime.primary && !runtime.trusted;
|
|
20470
|
+
}
|
|
20471
|
+
__name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
|
|
20472
|
+
function runWorkspaceInspectionWithLogPolicy(runtime, read2) {
|
|
20473
|
+
return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(read2) : read2();
|
|
20474
|
+
}
|
|
20475
|
+
__name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
|
|
20476
|
+
function requireSessionArtifactClientId(clientId, res) {
|
|
19269
20477
|
if (clientId !== void 0) return true;
|
|
19270
20478
|
res.status(403).json({
|
|
19271
20479
|
error: "Session artifact access requires a session-bound client id",
|
|
@@ -19425,11 +20633,40 @@ function registerSessionRoutes(app, deps) {
|
|
|
19425
20633
|
sendBridgeError: sendBridgeError2,
|
|
19426
20634
|
daemonLog,
|
|
19427
20635
|
promptDeadlineMs,
|
|
19428
|
-
sessionShellCommandEnabled
|
|
20636
|
+
sessionShellCommandEnabled,
|
|
20637
|
+
virtualSubagentSessions
|
|
19429
20638
|
} = deps;
|
|
19430
20639
|
const LANGUAGE_CODES = deps.languageCodes;
|
|
19431
20640
|
const transcriptCursorMasterKey = crypto3.randomBytes(32);
|
|
19432
20641
|
const transcriptCursorCodecs = /* @__PURE__ */ new Map();
|
|
20642
|
+
const activeBranchSessions = /* @__PURE__ */ new Map();
|
|
20643
|
+
const inFlightBranchWorkspaces = /* @__PURE__ */ new Set();
|
|
20644
|
+
const clearBranchSessionEntry = /* @__PURE__ */ __name((sessionId) => {
|
|
20645
|
+
for (const [cwd, sid] of activeBranchSessions) {
|
|
20646
|
+
if (sid === sessionId) {
|
|
20647
|
+
activeBranchSessions.delete(cwd);
|
|
20648
|
+
}
|
|
20649
|
+
}
|
|
20650
|
+
}, "clearBranchSessionEntry");
|
|
20651
|
+
const rollbackBranchCreation = /* @__PURE__ */ __name(async (cwd, meta, baseCommit, log2) => {
|
|
20652
|
+
activeBranchSessions.delete(cwd);
|
|
20653
|
+
inFlightBranchWorkspaces.delete(cwd);
|
|
20654
|
+
const baseRestored = await checkoutRef(
|
|
20655
|
+
cwd,
|
|
20656
|
+
meta.baseBranch === "HEAD" && baseCommit ? baseCommit : meta.baseBranch
|
|
20657
|
+
).then(() => true).catch((rollbackErr) => {
|
|
20658
|
+
log2?.warn("branch rollback checkout failed", {
|
|
20659
|
+
error: rollbackErr
|
|
20660
|
+
});
|
|
20661
|
+
return false;
|
|
20662
|
+
});
|
|
20663
|
+
if (!baseRestored) return;
|
|
20664
|
+
await deleteBranch(cwd, meta.name).catch((rollbackErr) => {
|
|
20665
|
+
log2?.warn("branch rollback delete failed", {
|
|
20666
|
+
error: rollbackErr
|
|
20667
|
+
});
|
|
20668
|
+
});
|
|
20669
|
+
}, "rollbackBranchCreation");
|
|
19433
20670
|
const getTranscriptCursorCodec = /* @__PURE__ */ __name((runtime) => {
|
|
19434
20671
|
const canonicalCwd = canonicalizeWorkspace(runtime.workspaceCwd);
|
|
19435
20672
|
const cacheKey = `${runtime.workspaceId}\0${canonicalCwd}`;
|
|
@@ -20010,6 +21247,138 @@ function registerSessionRoutes(app, deps) {
|
|
|
20010
21247
|
}
|
|
20011
21248
|
const clientId = parseClientIdHeader(req, res);
|
|
20012
21249
|
if (clientId === null) return;
|
|
21250
|
+
let branchMeta;
|
|
21251
|
+
let branchBaseCommit;
|
|
21252
|
+
const rawBranch = body["branch"];
|
|
21253
|
+
if (rawBranch !== void 0 && rawBranch !== null) {
|
|
21254
|
+
if (body["worktree"] !== void 0 && body["worktree"] !== null) {
|
|
21255
|
+
res.status(400).json({
|
|
21256
|
+
error: "`branch` and `worktree` are mutually exclusive",
|
|
21257
|
+
code: "branch_and_worktree_conflict"
|
|
21258
|
+
});
|
|
21259
|
+
return;
|
|
21260
|
+
}
|
|
21261
|
+
if (typeof rawBranch !== "object" || Array.isArray(rawBranch)) {
|
|
21262
|
+
res.status(400).json({
|
|
21263
|
+
error: '`branch` must be an object (e.g. `{"name":"feat/my-feature"}`)',
|
|
21264
|
+
code: "invalid_branch"
|
|
21265
|
+
});
|
|
21266
|
+
return;
|
|
21267
|
+
}
|
|
21268
|
+
const branchReq = rawBranch;
|
|
21269
|
+
const branchName = branchReq["name"];
|
|
21270
|
+
if (typeof branchName !== "string" || branchName.length === 0) {
|
|
21271
|
+
res.status(400).json({
|
|
21272
|
+
error: "`branch.name` must be a non-empty string",
|
|
21273
|
+
code: "branch_invalid_name"
|
|
21274
|
+
});
|
|
21275
|
+
return;
|
|
21276
|
+
}
|
|
21277
|
+
if (/[^\p{L}\p{N}._/-]/u.test(branchName) || branchName.includes("..") || branchName.includes("//") || branchName.startsWith(".") || branchName.startsWith("-") || branchName.startsWith("/") || branchName.endsWith("/") || branchName.endsWith(".") || branchName.endsWith(".git") || branchName.includes("@{") || branchName.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")) || branchName.toUpperCase() === GIT_RESERVED_BRANCH || Buffer.byteLength(branchName, "utf8") > MAX_BRANCH_NAME_BYTES || branchName.split("/").some(
|
|
21278
|
+
(c) => Buffer.byteLength(c, "utf8") > MAX_BRANCH_COMPONENT_BYTES
|
|
21279
|
+
)) {
|
|
21280
|
+
res.status(400).json({
|
|
21281
|
+
error: `Invalid branch name: ${branchName}`,
|
|
21282
|
+
code: "branch_invalid_name"
|
|
21283
|
+
});
|
|
21284
|
+
return;
|
|
21285
|
+
}
|
|
21286
|
+
const existingBranchSession = activeBranchSessions.get(workspaceCwd);
|
|
21287
|
+
if (existingBranchSession) {
|
|
21288
|
+
try {
|
|
21289
|
+
runtime.bridge.getSessionSummary(existingBranchSession);
|
|
21290
|
+
res.status(409).json({
|
|
21291
|
+
error: "A branch session is already active for this workspace",
|
|
21292
|
+
code: "branch_session_conflict",
|
|
21293
|
+
existingSessionId: existingBranchSession
|
|
21294
|
+
});
|
|
21295
|
+
return;
|
|
21296
|
+
} catch {
|
|
21297
|
+
activeBranchSessions.delete(workspaceCwd);
|
|
21298
|
+
}
|
|
21299
|
+
}
|
|
21300
|
+
const sharedCheckoutSession = runtime.bridge.listWorkspaceSessions(workspaceCwd).find((session) => !session.worktree && session.clientCount > 0);
|
|
21301
|
+
if (sharedCheckoutSession) {
|
|
21302
|
+
res.status(409).json({
|
|
21303
|
+
error: "Another session is already active in this workspace; creating a branch would move its shared checkout",
|
|
21304
|
+
code: "branch_session_conflict",
|
|
21305
|
+
existingSessionId: sharedCheckoutSession.sessionId
|
|
21306
|
+
});
|
|
21307
|
+
return;
|
|
21308
|
+
}
|
|
21309
|
+
let wtService;
|
|
21310
|
+
try {
|
|
21311
|
+
wtService = new GitWorktreeService(workspaceCwd);
|
|
21312
|
+
} catch {
|
|
21313
|
+
res.status(500).json({
|
|
21314
|
+
error: "Failed to initialize git service",
|
|
21315
|
+
code: "branch_init_failed"
|
|
21316
|
+
});
|
|
21317
|
+
return;
|
|
21318
|
+
}
|
|
21319
|
+
if (!await wtService.isGitRepository()) {
|
|
21320
|
+
res.status(400).json({
|
|
21321
|
+
error: "Branch creation requires a git repository",
|
|
21322
|
+
code: "branch_not_git_repo"
|
|
21323
|
+
});
|
|
21324
|
+
return;
|
|
21325
|
+
}
|
|
21326
|
+
if (await branchExists(workspaceCwd, branchName)) {
|
|
21327
|
+
res.status(409).json({
|
|
21328
|
+
error: `Branch "${branchName}" already exists`,
|
|
21329
|
+
code: "branch_already_exists"
|
|
21330
|
+
});
|
|
21331
|
+
return;
|
|
21332
|
+
}
|
|
21333
|
+
let dirty;
|
|
21334
|
+
try {
|
|
21335
|
+
dirty = await isDirtyTree(workspaceCwd);
|
|
21336
|
+
} catch {
|
|
21337
|
+
res.status(500).json({
|
|
21338
|
+
error: "Failed to check working tree status",
|
|
21339
|
+
code: "branch_status_failed"
|
|
21340
|
+
});
|
|
21341
|
+
return;
|
|
21342
|
+
}
|
|
21343
|
+
if (dirty) {
|
|
21344
|
+
res.status(409).json({
|
|
21345
|
+
error: "Uncommitted changes detected. Commit or stash first.",
|
|
21346
|
+
code: "branch_dirty_tree"
|
|
21347
|
+
});
|
|
21348
|
+
return;
|
|
21349
|
+
}
|
|
21350
|
+
const baseCommit = await getHeadCommit(workspaceCwd);
|
|
21351
|
+
const baseBranch = await wtService.getCurrentBranch().catch(() => "HEAD");
|
|
21352
|
+
if (inFlightBranchWorkspaces.has(workspaceCwd) || activeBranchSessions.has(workspaceCwd)) {
|
|
21353
|
+
res.status(409).json({
|
|
21354
|
+
error: "A branch session is already being created for this workspace",
|
|
21355
|
+
code: "branch_session_conflict"
|
|
21356
|
+
});
|
|
21357
|
+
return;
|
|
21358
|
+
}
|
|
21359
|
+
inFlightBranchWorkspaces.add(workspaceCwd);
|
|
21360
|
+
try {
|
|
21361
|
+
await createBranch(workspaceCwd, branchName);
|
|
21362
|
+
} catch (checkoutErr) {
|
|
21363
|
+
daemonLog?.warn("branch checkout failed", {
|
|
21364
|
+
error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
|
|
21365
|
+
});
|
|
21366
|
+
await rollbackBranchCreation(
|
|
21367
|
+
workspaceCwd,
|
|
21368
|
+
{ name: branchName, baseBranch },
|
|
21369
|
+
baseCommit,
|
|
21370
|
+
daemonLog
|
|
21371
|
+
);
|
|
21372
|
+
res.status(500).json({
|
|
21373
|
+
error: "Failed to create branch",
|
|
21374
|
+
code: "branch_checkout_failed"
|
|
21375
|
+
});
|
|
21376
|
+
return;
|
|
21377
|
+
}
|
|
21378
|
+
branchMeta = { name: branchName, baseBranch };
|
|
21379
|
+
branchBaseCommit = baseCommit;
|
|
21380
|
+
sessionScope = "thread";
|
|
21381
|
+
}
|
|
20013
21382
|
let worktreeMeta;
|
|
20014
21383
|
const rawWorktree = body["worktree"];
|
|
20015
21384
|
if (rawWorktree !== void 0 && rawWorktree !== null) {
|
|
@@ -20081,7 +21450,8 @@ function registerSessionRoutes(app, deps) {
|
|
|
20081
21450
|
...approvalMode !== void 0 ? { approvalMode } : {},
|
|
20082
21451
|
...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
|
|
20083
21452
|
...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
|
|
20084
|
-
...worktreeMeta ? { worktree: worktreeMeta } : {}
|
|
21453
|
+
...worktreeMeta ? { worktree: worktreeMeta } : {},
|
|
21454
|
+
...branchMeta ? { branch: branchMeta } : {}
|
|
20085
21455
|
});
|
|
20086
21456
|
if (daemonLog) {
|
|
20087
21457
|
daemonLog.info(
|
|
@@ -20112,12 +21482,30 @@ function registerSessionRoutes(app, deps) {
|
|
|
20112
21482
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
20113
21483
|
});
|
|
20114
21484
|
}
|
|
21485
|
+
if (branchMeta) {
|
|
21486
|
+
await rollbackBranchCreation(
|
|
21487
|
+
workspaceCwd,
|
|
21488
|
+
branchMeta,
|
|
21489
|
+
branchBaseCommit,
|
|
21490
|
+
daemonLog
|
|
21491
|
+
);
|
|
21492
|
+
}
|
|
21493
|
+
} else if (branchMeta) {
|
|
21494
|
+
activeBranchSessions.set(workspaceCwd, session.sessionId);
|
|
21495
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
20115
21496
|
}
|
|
20116
21497
|
} catch {
|
|
21498
|
+
if (branchMeta) {
|
|
21499
|
+
activeBranchSessions.set(workspaceCwd, session.sessionId);
|
|
21500
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21501
|
+
}
|
|
20117
21502
|
}
|
|
20118
21503
|
} else {
|
|
20119
21504
|
runtime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
|
|
20120
21505
|
});
|
|
21506
|
+
if (branchMeta) {
|
|
21507
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21508
|
+
}
|
|
20121
21509
|
}
|
|
20122
21510
|
return;
|
|
20123
21511
|
}
|
|
@@ -20182,18 +21570,79 @@ function registerSessionRoutes(app, deps) {
|
|
|
20182
21570
|
return;
|
|
20183
21571
|
}
|
|
20184
21572
|
}
|
|
21573
|
+
if (branchMeta) {
|
|
21574
|
+
activeBranchSessions.set(workspaceCwd, session.sessionId);
|
|
21575
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21576
|
+
}
|
|
20185
21577
|
res.status(200).json(session);
|
|
20186
21578
|
} catch (err) {
|
|
20187
21579
|
if (worktreeMeta) {
|
|
20188
21580
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
20189
21581
|
});
|
|
20190
21582
|
}
|
|
21583
|
+
if (branchMeta) {
|
|
21584
|
+
await rollbackBranchCreation(
|
|
21585
|
+
workspaceCwd,
|
|
21586
|
+
branchMeta,
|
|
21587
|
+
branchBaseCommit,
|
|
21588
|
+
daemonLog
|
|
21589
|
+
);
|
|
21590
|
+
}
|
|
20191
21591
|
sendBridgeError2(res, err, { route: "POST /session" });
|
|
20192
21592
|
}
|
|
20193
21593
|
});
|
|
20194
21594
|
const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
|
|
20195
21595
|
const sessionId = requireSessionId(req, res);
|
|
20196
21596
|
if (!sessionId) return;
|
|
21597
|
+
const virtualKey = parseVirtualSubagentSessionId(sessionId);
|
|
21598
|
+
if (virtualKey) {
|
|
21599
|
+
const route2 = `POST /session/:id/${action}`;
|
|
21600
|
+
if (action !== "load") {
|
|
21601
|
+
res.status(400).json({
|
|
21602
|
+
error: `Virtual subagent sessions do not support ${action}`,
|
|
21603
|
+
code: "unsupported_action",
|
|
21604
|
+
sessionId
|
|
21605
|
+
});
|
|
21606
|
+
return;
|
|
21607
|
+
}
|
|
21608
|
+
if (!virtualSubagentSessions) {
|
|
21609
|
+
res.status(404).json({
|
|
21610
|
+
error: `No session with id "${sessionId}"`,
|
|
21611
|
+
code: "session_not_found",
|
|
21612
|
+
sessionId
|
|
21613
|
+
});
|
|
21614
|
+
return;
|
|
21615
|
+
}
|
|
21616
|
+
const runtime2 = requireSessionRuntime({
|
|
21617
|
+
sessionId: virtualKey.parentSessionId,
|
|
21618
|
+
route: route2,
|
|
21619
|
+
res,
|
|
21620
|
+
workspaceRegistry,
|
|
21621
|
+
daemonLog
|
|
21622
|
+
});
|
|
21623
|
+
if (!runtime2) return;
|
|
21624
|
+
const clientId2 = parseClientIdHeader(req, res);
|
|
21625
|
+
if (clientId2 === null) return;
|
|
21626
|
+
try {
|
|
21627
|
+
const session = await virtualSubagentSessions.load(
|
|
21628
|
+
runtime2,
|
|
21629
|
+
sessionId,
|
|
21630
|
+
clientId2
|
|
21631
|
+
);
|
|
21632
|
+
if (!session) {
|
|
21633
|
+
res.status(404).json({
|
|
21634
|
+
error: "Subagent session not found",
|
|
21635
|
+
code: "session_not_found",
|
|
21636
|
+
sessionId
|
|
21637
|
+
});
|
|
21638
|
+
return;
|
|
21639
|
+
}
|
|
21640
|
+
res.status(200).json(session);
|
|
21641
|
+
} catch (err) {
|
|
21642
|
+
sendBridgeError2(res, err, { route: route2, sessionId });
|
|
21643
|
+
}
|
|
21644
|
+
return;
|
|
21645
|
+
}
|
|
20197
21646
|
const body = safeBody(req);
|
|
20198
21647
|
const route = `POST /session/:id/${action}`;
|
|
20199
21648
|
let resolvedRuntime;
|
|
@@ -20283,7 +21732,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
20283
21732
|
path10.join(workspaceCwd, ".qwen", "worktrees")
|
|
20284
21733
|
];
|
|
20285
21734
|
try {
|
|
20286
|
-
realTarget =
|
|
21735
|
+
realTarget = fs4.realpathSync(sidecar.worktreePath);
|
|
20287
21736
|
let repoTop = null;
|
|
20288
21737
|
try {
|
|
20289
21738
|
repoTop = await new GitWorktreeService(
|
|
@@ -20296,7 +21745,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
20296
21745
|
}
|
|
20297
21746
|
const contained = candidateRoots.some((root) => {
|
|
20298
21747
|
try {
|
|
20299
|
-
const realRoot =
|
|
21748
|
+
const realRoot = fs4.realpathSync(root);
|
|
20300
21749
|
const rel = path10.relative(realRoot, realTarget);
|
|
20301
21750
|
return !rel.startsWith("..") && !path10.isAbsolute(rel);
|
|
20302
21751
|
} catch {
|
|
@@ -20339,18 +21788,124 @@ function registerSessionRoutes(app, deps) {
|
|
|
20339
21788
|
}
|
|
20340
21789
|
}
|
|
20341
21790
|
}
|
|
20342
|
-
res.status(200).json(session);
|
|
21791
|
+
res.status(200).json(session);
|
|
21792
|
+
} catch (err) {
|
|
21793
|
+
sendBridgeError2(res, err, {
|
|
21794
|
+
route,
|
|
21795
|
+
sessionId
|
|
21796
|
+
});
|
|
21797
|
+
} finally {
|
|
21798
|
+
releaseRestoreOwner();
|
|
21799
|
+
}
|
|
21800
|
+
}, "restoreSessionHandler");
|
|
21801
|
+
app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
|
|
21802
|
+
app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
|
|
21803
|
+
app.get("/session/:id/subagents/:toolCallId", async (req, res) => {
|
|
21804
|
+
const route = "GET /session/:id/subagents/:toolCallId";
|
|
21805
|
+
const sessionId = requireSessionId(req, res);
|
|
21806
|
+
if (!sessionId) return;
|
|
21807
|
+
if (!virtualSubagentSessions) {
|
|
21808
|
+
res.status(404).json({
|
|
21809
|
+
error: `No session with id "${sessionId}"`,
|
|
21810
|
+
code: "session_not_found",
|
|
21811
|
+
sessionId
|
|
21812
|
+
});
|
|
21813
|
+
return;
|
|
21814
|
+
}
|
|
21815
|
+
const toolCallId = req.params["toolCallId"];
|
|
21816
|
+
if (!toolCallId || toolCallId.length > 500) {
|
|
21817
|
+
res.status(400).json({
|
|
21818
|
+
error: "`toolCallId` must be a non-empty tool call id",
|
|
21819
|
+
code: "invalid_tool_call_id"
|
|
21820
|
+
});
|
|
21821
|
+
return;
|
|
21822
|
+
}
|
|
21823
|
+
const runtime = requireSessionRuntime({
|
|
21824
|
+
sessionId,
|
|
21825
|
+
route,
|
|
21826
|
+
res,
|
|
21827
|
+
workspaceRegistry,
|
|
21828
|
+
daemonLog
|
|
21829
|
+
});
|
|
21830
|
+
if (!runtime) return;
|
|
21831
|
+
try {
|
|
21832
|
+
const resolved = await virtualSubagentSessions.resolve(
|
|
21833
|
+
runtime,
|
|
21834
|
+
sessionId,
|
|
21835
|
+
toolCallId
|
|
21836
|
+
);
|
|
21837
|
+
if (!resolved) {
|
|
21838
|
+
res.status(404).json({
|
|
21839
|
+
error: "Subagent session not found",
|
|
21840
|
+
code: "session_not_found",
|
|
21841
|
+
sessionId,
|
|
21842
|
+
toolCallId
|
|
21843
|
+
});
|
|
21844
|
+
return;
|
|
21845
|
+
}
|
|
21846
|
+
res.status(200).set("Cache-Control", "no-store").json(resolved);
|
|
20343
21847
|
} catch (err) {
|
|
20344
|
-
sendBridgeError2(res, err, {
|
|
21848
|
+
sendBridgeError2(res, err, { route, sessionId });
|
|
21849
|
+
}
|
|
21850
|
+
});
|
|
21851
|
+
app.post(
|
|
21852
|
+
"/session/:id/subagents/:toolCallId/cancel",
|
|
21853
|
+
mutate(),
|
|
21854
|
+
async (req, res) => {
|
|
21855
|
+
const route = "POST /session/:id/subagents/:toolCallId/cancel";
|
|
21856
|
+
const sessionId = requireSessionId(req, res);
|
|
21857
|
+
if (!sessionId) return;
|
|
21858
|
+
if (!virtualSubagentSessions) {
|
|
21859
|
+
res.status(404).json({
|
|
21860
|
+
error: `No session with id "${sessionId}"`,
|
|
21861
|
+
code: "session_not_found",
|
|
21862
|
+
sessionId
|
|
21863
|
+
});
|
|
21864
|
+
return;
|
|
21865
|
+
}
|
|
21866
|
+
const toolCallId = req.params["toolCallId"];
|
|
21867
|
+
if (!toolCallId || toolCallId.length > 500) {
|
|
21868
|
+
res.status(400).json({
|
|
21869
|
+
error: "`toolCallId` must be a non-empty tool call id",
|
|
21870
|
+
code: "invalid_tool_call_id"
|
|
21871
|
+
});
|
|
21872
|
+
return;
|
|
21873
|
+
}
|
|
21874
|
+
const runtime = requireSessionRuntime({
|
|
21875
|
+
sessionId,
|
|
20345
21876
|
route,
|
|
20346
|
-
|
|
21877
|
+
res,
|
|
21878
|
+
workspaceRegistry,
|
|
21879
|
+
daemonLog
|
|
20347
21880
|
});
|
|
20348
|
-
|
|
20349
|
-
|
|
21881
|
+
if (!runtime) return;
|
|
21882
|
+
try {
|
|
21883
|
+
const resolved = await virtualSubagentSessions.resolve(
|
|
21884
|
+
runtime,
|
|
21885
|
+
sessionId,
|
|
21886
|
+
toolCallId
|
|
21887
|
+
);
|
|
21888
|
+
if (!resolved) {
|
|
21889
|
+
res.status(404).json({
|
|
21890
|
+
error: "Subagent session not found",
|
|
21891
|
+
code: "session_not_found",
|
|
21892
|
+
sessionId,
|
|
21893
|
+
toolCallId
|
|
21894
|
+
});
|
|
21895
|
+
return;
|
|
21896
|
+
}
|
|
21897
|
+
res.status(200).json(
|
|
21898
|
+
await runtime.bridge.cancelSessionTask(
|
|
21899
|
+
sessionId,
|
|
21900
|
+
resolved.taskId,
|
|
21901
|
+
"agent"
|
|
21902
|
+
)
|
|
21903
|
+
);
|
|
21904
|
+
} catch (err) {
|
|
21905
|
+
sendBridgeError2(res, err, { route, sessionId });
|
|
21906
|
+
}
|
|
20350
21907
|
}
|
|
20351
|
-
|
|
20352
|
-
app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
|
|
20353
|
-
app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
|
|
21908
|
+
);
|
|
20354
21909
|
app.post(
|
|
20355
21910
|
"/session/:id/branch",
|
|
20356
21911
|
mutate(),
|
|
@@ -20650,6 +22205,28 @@ function registerSessionRoutes(app, deps) {
|
|
|
20650
22205
|
});
|
|
20651
22206
|
app.get(
|
|
20652
22207
|
"/session/:id/context",
|
|
22208
|
+
(req, res, next) => {
|
|
22209
|
+
const sessionId = req.params["id"];
|
|
22210
|
+
const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
|
|
22211
|
+
if (!sessionId || !key) {
|
|
22212
|
+
next();
|
|
22213
|
+
return;
|
|
22214
|
+
}
|
|
22215
|
+
const runtime = requireSessionRuntime({
|
|
22216
|
+
sessionId: key.parentSessionId,
|
|
22217
|
+
route: "GET /session/:id/context",
|
|
22218
|
+
res,
|
|
22219
|
+
workspaceRegistry,
|
|
22220
|
+
daemonLog
|
|
22221
|
+
});
|
|
22222
|
+
if (!runtime) return;
|
|
22223
|
+
res.status(200).json({
|
|
22224
|
+
v: 1,
|
|
22225
|
+
sessionId,
|
|
22226
|
+
workspaceCwd: runtime.workspaceCwd,
|
|
22227
|
+
state: {}
|
|
22228
|
+
});
|
|
22229
|
+
},
|
|
20653
22230
|
withOwnerReadSession(
|
|
20654
22231
|
"GET /session/:id/context",
|
|
20655
22232
|
async (_req, res, sessionId, runtime) => {
|
|
@@ -20681,6 +22258,28 @@ function registerSessionRoutes(app, deps) {
|
|
|
20681
22258
|
);
|
|
20682
22259
|
app.get(
|
|
20683
22260
|
"/session/:id/supported-commands",
|
|
22261
|
+
(req, res, next) => {
|
|
22262
|
+
const sessionId = req.params["id"];
|
|
22263
|
+
const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
|
|
22264
|
+
if (!sessionId || !key) {
|
|
22265
|
+
next();
|
|
22266
|
+
return;
|
|
22267
|
+
}
|
|
22268
|
+
const runtime = requireSessionRuntime({
|
|
22269
|
+
sessionId: key.parentSessionId,
|
|
22270
|
+
route: "GET /session/:id/supported-commands",
|
|
22271
|
+
res,
|
|
22272
|
+
workspaceRegistry,
|
|
22273
|
+
daemonLog
|
|
22274
|
+
});
|
|
22275
|
+
if (!runtime) return;
|
|
22276
|
+
res.status(200).json({
|
|
22277
|
+
v: 1,
|
|
22278
|
+
sessionId,
|
|
22279
|
+
availableCommands: [],
|
|
22280
|
+
availableSkills: []
|
|
22281
|
+
});
|
|
22282
|
+
},
|
|
20684
22283
|
withOwnerReadSession(
|
|
20685
22284
|
"GET /session/:id/supported-commands",
|
|
20686
22285
|
async (_req, res, sessionId, runtime) => {
|
|
@@ -20902,10 +22501,32 @@ function registerSessionRoutes(app, deps) {
|
|
|
20902
22501
|
}
|
|
20903
22502
|
const clientId = parseClientIdHeader(req, res);
|
|
20904
22503
|
if (clientId === null) return;
|
|
22504
|
+
let delivery;
|
|
22505
|
+
if (body["delivery"] !== void 0) {
|
|
22506
|
+
try {
|
|
22507
|
+
delivery = parseChannelDelivery(body["delivery"]);
|
|
22508
|
+
} catch (err) {
|
|
22509
|
+
if (!isChannelDeliveryError(err)) throw err;
|
|
22510
|
+
res.status(400).json({ error: err.message, code: err.code });
|
|
22511
|
+
return;
|
|
22512
|
+
}
|
|
22513
|
+
}
|
|
20905
22514
|
const promptId = crypto3.randomUUID();
|
|
22515
|
+
if (delivery && deps.channelDeliveryAuthorizations) {
|
|
22516
|
+
deps.channelDeliveryAuthorizations.authorizePrompt(
|
|
22517
|
+
runtime.workspaceCwd,
|
|
22518
|
+
{
|
|
22519
|
+
sessionId,
|
|
22520
|
+
deliveryId: promptId,
|
|
22521
|
+
target: delivery.target
|
|
22522
|
+
}
|
|
22523
|
+
);
|
|
22524
|
+
}
|
|
20906
22525
|
const forwardedBody = { ...body };
|
|
20907
22526
|
delete forwardedBody["deadlineMs"];
|
|
22527
|
+
delete forwardedBody["delivery"];
|
|
20908
22528
|
const lastEventId = ownerBridge.getSessionLastEventId(sessionId);
|
|
22529
|
+
const eventEpoch = ownerBridge.getSessionEventEpoch(sessionId);
|
|
20909
22530
|
addDaemonRequestAttribute("qwen-code.prompt_id", promptId);
|
|
20910
22531
|
const abort = new AbortController();
|
|
20911
22532
|
let responseFinished = false;
|
|
@@ -20935,10 +22556,21 @@ function registerSessionRoutes(app, deps) {
|
|
|
20935
22556
|
{
|
|
20936
22557
|
...clientId !== void 0 ? { clientId } : {},
|
|
20937
22558
|
promptId,
|
|
20938
|
-
...effectiveDeadlineMs !== void 0 ? { deadlineMs: effectiveDeadlineMs } : {}
|
|
22559
|
+
...effectiveDeadlineMs !== void 0 ? { deadlineMs: effectiveDeadlineMs } : {},
|
|
22560
|
+
...delivery !== void 0 ? {
|
|
22561
|
+
channelDelivery: {
|
|
22562
|
+
deliveryId: promptId,
|
|
22563
|
+
target: delivery.target
|
|
22564
|
+
}
|
|
22565
|
+
} : {}
|
|
20939
22566
|
}
|
|
20940
22567
|
);
|
|
20941
22568
|
} catch (err) {
|
|
22569
|
+
deps.channelDeliveryAuthorizations?.revokePrompt(
|
|
22570
|
+
runtime.workspaceCwd,
|
|
22571
|
+
sessionId,
|
|
22572
|
+
promptId
|
|
22573
|
+
);
|
|
20942
22574
|
res.off("close", onResClose);
|
|
20943
22575
|
res.off("finish", onResFinish);
|
|
20944
22576
|
if (daemonLog && err instanceof PromptQueueFullError) {
|
|
@@ -20983,12 +22615,23 @@ function registerSessionRoutes(app, deps) {
|
|
|
20983
22615
|
);
|
|
20984
22616
|
}
|
|
20985
22617
|
}
|
|
20986
|
-
).
|
|
22618
|
+
).finally(() => {
|
|
22619
|
+
if (delivery && deps.channelDeliveryAuthorizations) {
|
|
22620
|
+
const revokeTimer = setTimeout(() => {
|
|
22621
|
+
deps.channelDeliveryAuthorizations?.revokePrompt(
|
|
22622
|
+
runtime.workspaceCwd,
|
|
22623
|
+
sessionId,
|
|
22624
|
+
promptId
|
|
22625
|
+
);
|
|
22626
|
+
}, CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS);
|
|
22627
|
+
revokeTimer.unref();
|
|
22628
|
+
}
|
|
22629
|
+
}).catch(() => {
|
|
20987
22630
|
});
|
|
20988
22631
|
if (daemonLog) {
|
|
20989
22632
|
daemonLog.info("prompt enqueued", { sessionId, promptId, clientId });
|
|
20990
22633
|
}
|
|
20991
|
-
res.status(202).json({ promptId, lastEventId });
|
|
22634
|
+
res.status(202).json({ promptId, lastEventId, eventEpoch });
|
|
20992
22635
|
}
|
|
20993
22636
|
)
|
|
20994
22637
|
);
|
|
@@ -21077,6 +22720,29 @@ function registerSessionRoutes(app, deps) {
|
|
|
21077
22720
|
app.post(
|
|
21078
22721
|
"/session/:id/heartbeat",
|
|
21079
22722
|
mutate(),
|
|
22723
|
+
(req, res, next) => {
|
|
22724
|
+
const sessionId = req.params["id"];
|
|
22725
|
+
const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
|
|
22726
|
+
if (!sessionId || !key) {
|
|
22727
|
+
next();
|
|
22728
|
+
return;
|
|
22729
|
+
}
|
|
22730
|
+
const runtime = requireSessionRuntime({
|
|
22731
|
+
sessionId: key.parentSessionId,
|
|
22732
|
+
route: "POST /session/:id/heartbeat",
|
|
22733
|
+
res,
|
|
22734
|
+
workspaceRegistry,
|
|
22735
|
+
daemonLog
|
|
22736
|
+
});
|
|
22737
|
+
if (!runtime) return;
|
|
22738
|
+
const clientId = parseClientIdHeader(req, res);
|
|
22739
|
+
if (clientId === null) return;
|
|
22740
|
+
res.status(200).json({
|
|
22741
|
+
sessionId,
|
|
22742
|
+
...clientId ? { clientId } : {},
|
|
22743
|
+
lastSeenAt: Date.now()
|
|
22744
|
+
});
|
|
22745
|
+
},
|
|
21080
22746
|
withOwnerMutableSession(
|
|
21081
22747
|
"POST /session/:id/heartbeat",
|
|
21082
22748
|
(req, res, sessionId, runtime) => {
|
|
@@ -21093,6 +22759,25 @@ function registerSessionRoutes(app, deps) {
|
|
|
21093
22759
|
app.post(
|
|
21094
22760
|
"/session/:id/detach",
|
|
21095
22761
|
mutate(),
|
|
22762
|
+
(req, res, next) => {
|
|
22763
|
+
const sessionId = req.params["id"];
|
|
22764
|
+
const key = sessionId ? parseVirtualSubagentSessionId(sessionId) : void 0;
|
|
22765
|
+
if (!sessionId || !key) {
|
|
22766
|
+
next();
|
|
22767
|
+
return;
|
|
22768
|
+
}
|
|
22769
|
+
const runtime = requireSessionRuntime({
|
|
22770
|
+
sessionId: key.parentSessionId,
|
|
22771
|
+
route: "POST /session/:id/detach",
|
|
22772
|
+
res,
|
|
22773
|
+
workspaceRegistry,
|
|
22774
|
+
daemonLog
|
|
22775
|
+
});
|
|
22776
|
+
if (!runtime) return;
|
|
22777
|
+
const clientId = parseClientIdHeader(req, res);
|
|
22778
|
+
if (clientId === null) return;
|
|
22779
|
+
res.status(204).end();
|
|
22780
|
+
},
|
|
21096
22781
|
withOwnerMutableSession(
|
|
21097
22782
|
"POST /session/:id/detach",
|
|
21098
22783
|
async (req, res, sessionId, runtime) => {
|
|
@@ -21145,6 +22830,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
21145
22830
|
clientId !== void 0 ? { clientId } : void 0
|
|
21146
22831
|
)
|
|
21147
22832
|
);
|
|
22833
|
+
clearBranchSessionEntry(sessionId);
|
|
21148
22834
|
res.status(204).end();
|
|
21149
22835
|
} catch (err) {
|
|
21150
22836
|
sendBridgeError2(res, err, {
|
|
@@ -21171,6 +22857,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
21171
22857
|
);
|
|
21172
22858
|
}, "onError")
|
|
21173
22859
|
});
|
|
22860
|
+
for (const removedId of result.removed) {
|
|
22861
|
+
clearBranchSessionEntry(removedId);
|
|
22862
|
+
}
|
|
21174
22863
|
res.status(200).json(result);
|
|
21175
22864
|
} catch (err) {
|
|
21176
22865
|
sendBridgeError2(res, err, { route: "POST /sessions/delete" });
|
|
@@ -21245,6 +22934,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
21245
22934
|
);
|
|
21246
22935
|
}, "onError")
|
|
21247
22936
|
});
|
|
22937
|
+
for (const removedId of result.removed) {
|
|
22938
|
+
clearBranchSessionEntry(removedId);
|
|
22939
|
+
}
|
|
21248
22940
|
res.status(200).json(result);
|
|
21249
22941
|
} catch (err) {
|
|
21250
22942
|
sendBridgeError2(res, err, { route });
|
|
@@ -22175,7 +23867,8 @@ function toView(task) {
|
|
|
22175
23867
|
sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
|
|
22176
23868
|
// Absent runs (tool-created / never-fired) normalizes to [] so the client
|
|
22177
23869
|
// never special-cases undefined.
|
|
22178
|
-
runs: Array.isArray(task.runs) ? task.runs : []
|
|
23870
|
+
runs: Array.isArray(task.runs) ? task.runs : [],
|
|
23871
|
+
...task.delivery !== void 0 ? { delivery: task.delivery } : {}
|
|
22179
23872
|
};
|
|
22180
23873
|
}
|
|
22181
23874
|
__name(toView, "toView");
|
|
@@ -22208,7 +23901,13 @@ function canonicalCron(cron) {
|
|
|
22208
23901
|
}
|
|
22209
23902
|
__name(canonicalCron, "canonicalCron");
|
|
22210
23903
|
function registerScheduledTaskCrudRoutes(app, deps) {
|
|
22211
|
-
const {
|
|
23904
|
+
const {
|
|
23905
|
+
prefix,
|
|
23906
|
+
resolveTarget,
|
|
23907
|
+
mutate,
|
|
23908
|
+
safeBody: safeBody2,
|
|
23909
|
+
channelDeliveryAuthorizations
|
|
23910
|
+
} = deps;
|
|
22212
23911
|
const base = `${prefix}/scheduled-tasks`;
|
|
22213
23912
|
app.get(base, async (req, res) => {
|
|
22214
23913
|
const target = resolveTarget(req, res);
|
|
@@ -22285,6 +23984,16 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22285
23984
|
});
|
|
22286
23985
|
return;
|
|
22287
23986
|
}
|
|
23987
|
+
let delivery;
|
|
23988
|
+
if (body["delivery"] !== void 0) {
|
|
23989
|
+
try {
|
|
23990
|
+
delivery = parseChannelDelivery(body["delivery"]);
|
|
23991
|
+
} catch (err) {
|
|
23992
|
+
if (!isChannelDeliveryError(err)) throw err;
|
|
23993
|
+
res.status(400).json({ error: err.message, code: err.code });
|
|
23994
|
+
return;
|
|
23995
|
+
}
|
|
23996
|
+
}
|
|
22288
23997
|
const removedField = findRemovedTaskField(body);
|
|
22289
23998
|
if (removedField) {
|
|
22290
23999
|
res.status(400).json(removedFieldError(removedField));
|
|
@@ -22341,6 +24050,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22341
24050
|
// minute the task was created — same guard cronScheduler.create uses.
|
|
22342
24051
|
lastFiredAt: now - now % 6e4,
|
|
22343
24052
|
enabled,
|
|
24053
|
+
...delivery !== void 0 ? { delivery } : {},
|
|
22344
24054
|
...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
|
|
22345
24055
|
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
22346
24056
|
};
|
|
@@ -22380,6 +24090,15 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22380
24090
|
});
|
|
22381
24091
|
return;
|
|
22382
24092
|
}
|
|
24093
|
+
if (task.delivery && task.sessionId) {
|
|
24094
|
+
channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
|
|
24095
|
+
sessionId: task.sessionId,
|
|
24096
|
+
taskId: task.id,
|
|
24097
|
+
target: task.delivery.target,
|
|
24098
|
+
recurring: task.recurring,
|
|
24099
|
+
lastFiredAt: task.lastFiredAt ?? void 0
|
|
24100
|
+
});
|
|
24101
|
+
}
|
|
22383
24102
|
res.status(201).json(toView(task));
|
|
22384
24103
|
});
|
|
22385
24104
|
app.patch(`${base}/:id`, mutate(), async (req, res) => {
|
|
@@ -22394,6 +24113,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22394
24113
|
const body = safeBody2(req);
|
|
22395
24114
|
const patch = {};
|
|
22396
24115
|
let clearName = false;
|
|
24116
|
+
let clearDelivery = false;
|
|
22397
24117
|
const removedPatchField = findRemovedTaskField(body);
|
|
22398
24118
|
if (removedPatchField) {
|
|
22399
24119
|
res.status(400).json(removedFieldError(removedPatchField));
|
|
@@ -22458,7 +24178,20 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22458
24178
|
}
|
|
22459
24179
|
patch.enabled = body["enabled"];
|
|
22460
24180
|
}
|
|
22461
|
-
if (
|
|
24181
|
+
if ("delivery" in body) {
|
|
24182
|
+
if (body["delivery"] === null) {
|
|
24183
|
+
clearDelivery = true;
|
|
24184
|
+
} else {
|
|
24185
|
+
try {
|
|
24186
|
+
patch.delivery = parseChannelDelivery(body["delivery"]);
|
|
24187
|
+
} catch (err) {
|
|
24188
|
+
if (!isChannelDeliveryError(err)) throw err;
|
|
24189
|
+
res.status(400).json({ error: err.message, code: err.code });
|
|
24190
|
+
return;
|
|
24191
|
+
}
|
|
24192
|
+
}
|
|
24193
|
+
}
|
|
24194
|
+
if (Object.keys(patch).length === 0 && !clearName && !clearDelivery) {
|
|
22462
24195
|
res.status(400).json({
|
|
22463
24196
|
error: "No updatable fields provided",
|
|
22464
24197
|
code: "empty_patch"
|
|
@@ -22485,6 +24218,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22485
24218
|
}
|
|
22486
24219
|
const next = { ...current, ...patch };
|
|
22487
24220
|
if (clearName) delete next.name;
|
|
24221
|
+
if (clearDelivery) delete next.delivery;
|
|
22488
24222
|
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
22489
24223
|
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
22490
24224
|
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
@@ -22539,6 +24273,22 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22539
24273
|
} catch {
|
|
22540
24274
|
}
|
|
22541
24275
|
}
|
|
24276
|
+
if (updated.delivery && updated.sessionId) {
|
|
24277
|
+
channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
|
|
24278
|
+
sessionId: updated.sessionId,
|
|
24279
|
+
taskId: updated.id,
|
|
24280
|
+
target: updated.delivery.target,
|
|
24281
|
+
recurring: updated.recurring,
|
|
24282
|
+
lastFiredAt: updated.lastFiredAt ?? void 0
|
|
24283
|
+
});
|
|
24284
|
+
}
|
|
24285
|
+
if (clearDelivery && updated.sessionId) {
|
|
24286
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
24287
|
+
workspaceCwd,
|
|
24288
|
+
updated.sessionId,
|
|
24289
|
+
updated.id
|
|
24290
|
+
);
|
|
24291
|
+
}
|
|
22542
24292
|
res.status(200).json(toView(updated));
|
|
22543
24293
|
});
|
|
22544
24294
|
app.delete(`${base}/:id`, mutate(), async (req, res) => {
|
|
@@ -22581,6 +24331,13 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22581
24331
|
await bridge.closeSession(boundSessionId).catch(() => {
|
|
22582
24332
|
});
|
|
22583
24333
|
}
|
|
24334
|
+
if (boundSessionId) {
|
|
24335
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
24336
|
+
workspaceCwd,
|
|
24337
|
+
boundSessionId,
|
|
24338
|
+
id
|
|
24339
|
+
);
|
|
24340
|
+
}
|
|
22584
24341
|
res.status(200).json({ deleted: true, id });
|
|
22585
24342
|
});
|
|
22586
24343
|
app.post(`${base}/:id/run`, mutate(), async (req, res) => {
|
|
@@ -22661,17 +24418,30 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22661
24418
|
}
|
|
22662
24419
|
__name(registerScheduledTaskCrudRoutes, "registerScheduledTaskCrudRoutes");
|
|
22663
24420
|
function registerScheduledTasksRoutes(app, deps) {
|
|
22664
|
-
const {
|
|
24421
|
+
const {
|
|
24422
|
+
boundWorkspace,
|
|
24423
|
+
mutate,
|
|
24424
|
+
safeBody: safeBody2,
|
|
24425
|
+
bridge,
|
|
24426
|
+
channelDeliveryAuthorizations
|
|
24427
|
+
} = deps;
|
|
22665
24428
|
registerScheduledTaskCrudRoutes(app, {
|
|
22666
24429
|
prefix: "",
|
|
22667
24430
|
resolveTarget: /* @__PURE__ */ __name(() => ({ workspaceCwd: boundWorkspace, bridge }), "resolveTarget"),
|
|
22668
24431
|
mutate,
|
|
22669
|
-
safeBody: safeBody2
|
|
24432
|
+
safeBody: safeBody2,
|
|
24433
|
+
channelDeliveryAuthorizations
|
|
22670
24434
|
});
|
|
22671
24435
|
}
|
|
22672
24436
|
__name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
|
|
22673
24437
|
function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
22674
|
-
const {
|
|
24438
|
+
const {
|
|
24439
|
+
workspaceRegistry,
|
|
24440
|
+
mutate,
|
|
24441
|
+
safeBody: safeBody2,
|
|
24442
|
+
manageScheduledTaskSessions,
|
|
24443
|
+
channelDeliveryAuthorizations
|
|
24444
|
+
} = deps;
|
|
22675
24445
|
registerScheduledTaskCrudRoutes(app, {
|
|
22676
24446
|
prefix: "/workspaces/:workspace",
|
|
22677
24447
|
resolveTarget: /* @__PURE__ */ __name((req, res) => {
|
|
@@ -22690,7 +24460,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
|
22690
24460
|
};
|
|
22691
24461
|
}, "resolveTarget"),
|
|
22692
24462
|
mutate,
|
|
22693
|
-
safeBody: safeBody2
|
|
24463
|
+
safeBody: safeBody2,
|
|
24464
|
+
channelDeliveryAuthorizations
|
|
22694
24465
|
});
|
|
22695
24466
|
}
|
|
22696
24467
|
__name(registerWorkspaceQualifiedScheduledTasksRoutes, "registerWorkspaceQualifiedScheduledTasksRoutes");
|
|
@@ -22720,6 +24491,77 @@ function parseNameField(raw) {
|
|
|
22720
24491
|
}
|
|
22721
24492
|
__name(parseNameField, "parseNameField");
|
|
22722
24493
|
|
|
24494
|
+
// packages/cli/src/serve/routes/channel-notify.ts
|
|
24495
|
+
init_esbuild_shims();
|
|
24496
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
24497
|
+
function sendDeliveryError(res, error2) {
|
|
24498
|
+
if (!isChannelDeliveryError(error2)) {
|
|
24499
|
+
res.status(502).json({
|
|
24500
|
+
error: "Channel delivery failed.",
|
|
24501
|
+
code: "channel_delivery_failed"
|
|
24502
|
+
});
|
|
24503
|
+
return;
|
|
24504
|
+
}
|
|
24505
|
+
const status = error2.code === "channel_delivery_invalid" ? 400 : error2.code === "channel_delivery_timeout" ? 504 : error2.code === "channel_worker_unavailable" || error2.code === "channel_delivery_queue_full" ? 503 : 502;
|
|
24506
|
+
res.status(status).json({ error: error2.message, code: error2.code });
|
|
24507
|
+
}
|
|
24508
|
+
__name(sendDeliveryError, "sendDeliveryError");
|
|
24509
|
+
function parseNotifyBody(body) {
|
|
24510
|
+
if (!Object.keys(body).every((key) => key === "text" || key === "delivery")) {
|
|
24511
|
+
throw new ChannelDeliveryError(
|
|
24512
|
+
"channel_delivery_invalid",
|
|
24513
|
+
"Invalid channel notification."
|
|
24514
|
+
);
|
|
24515
|
+
}
|
|
24516
|
+
return normalizeChannelDelivery(
|
|
24517
|
+
randomUUID6(),
|
|
24518
|
+
parseChannelDelivery(body["delivery"]),
|
|
24519
|
+
body["text"]
|
|
24520
|
+
);
|
|
24521
|
+
}
|
|
24522
|
+
__name(parseNotifyBody, "parseNotifyBody");
|
|
24523
|
+
function registerChannelNotifyRoutes(app, deps) {
|
|
24524
|
+
const deliver = /* @__PURE__ */ __name(async (workspaceCwd, req, res) => {
|
|
24525
|
+
try {
|
|
24526
|
+
if (!deps.deliverChannelMessage) {
|
|
24527
|
+
throw new ChannelDeliveryError(
|
|
24528
|
+
"channel_worker_unavailable",
|
|
24529
|
+
"Channel worker is not running."
|
|
24530
|
+
);
|
|
24531
|
+
}
|
|
24532
|
+
const request2 = parseNotifyBody(deps.safeBody(req));
|
|
24533
|
+
await deps.deliverChannelMessage(workspaceCwd, request2);
|
|
24534
|
+
res.status(200).json({ delivered: true, deliveryId: request2.deliveryId });
|
|
24535
|
+
} catch (error2) {
|
|
24536
|
+
sendDeliveryError(res, error2);
|
|
24537
|
+
}
|
|
24538
|
+
}, "deliver");
|
|
24539
|
+
app.post(
|
|
24540
|
+
"/workspace/notify",
|
|
24541
|
+
deps.mutate({ strict: true }),
|
|
24542
|
+
async (req, res) => {
|
|
24543
|
+
if (!requireTrustedWorkspaceRuntime(deps.workspaceRegistry.primary, res)) {
|
|
24544
|
+
return;
|
|
24545
|
+
}
|
|
24546
|
+
await deliver(deps.boundWorkspace, req, res);
|
|
24547
|
+
}
|
|
24548
|
+
);
|
|
24549
|
+
app.post(
|
|
24550
|
+
"/workspaces/:workspace/notify",
|
|
24551
|
+
deps.mutate({ strict: true }),
|
|
24552
|
+
async (req, res) => {
|
|
24553
|
+
const runtime = resolveWorkspaceRuntimeFromParam(
|
|
24554
|
+
deps.workspaceRegistry,
|
|
24555
|
+
req,
|
|
24556
|
+
res
|
|
24557
|
+
);
|
|
24558
|
+
if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res)) return;
|
|
24559
|
+
await deliver(runtime.workspaceCwd, req, res);
|
|
24560
|
+
}
|
|
24561
|
+
);
|
|
24562
|
+
}
|
|
24563
|
+
__name(registerChannelNotifyRoutes, "registerChannelNotifyRoutes");
|
|
24564
|
+
|
|
22723
24565
|
// packages/cli/src/serve/routes/goals.ts
|
|
22724
24566
|
init_esbuild_shims();
|
|
22725
24567
|
var PROBE_CONCURRENCY = 10;
|
|
@@ -22988,6 +24830,11 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
22988
24830
|
log.debug("keepalive: readCronTasks failed, skipping this pass", err);
|
|
22989
24831
|
return;
|
|
22990
24832
|
}
|
|
24833
|
+
try {
|
|
24834
|
+
opts.onTasksRead?.(tasks);
|
|
24835
|
+
} catch (err) {
|
|
24836
|
+
log.debug("keepalive: onTasksRead failed", err);
|
|
24837
|
+
}
|
|
22991
24838
|
for (const sessionId of collectBoundSessionIds(tasks)) {
|
|
22992
24839
|
try {
|
|
22993
24840
|
bridge.recordHeartbeat(sessionId);
|
|
@@ -23117,6 +24964,11 @@ async function rehydrateScheduledTaskSessions(deps) {
|
|
|
23117
24964
|
log.debug("rehydrate: readCronTasks failed", err);
|
|
23118
24965
|
return { loaded: [], failed: [] };
|
|
23119
24966
|
}
|
|
24967
|
+
try {
|
|
24968
|
+
deps.onTasksRead?.(tasks);
|
|
24969
|
+
} catch (err) {
|
|
24970
|
+
log.debug("rehydrate: onTasksRead failed", err);
|
|
24971
|
+
}
|
|
23120
24972
|
const sessionIds = collectBoundSessionIds(tasks);
|
|
23121
24973
|
const loaded = [];
|
|
23122
24974
|
const failed = [];
|
|
@@ -23476,6 +25328,7 @@ function createServeFeatures(deps) {
|
|
|
23476
25328
|
persistSettingAvailable,
|
|
23477
25329
|
sessionArtifactsPersistenceAvailable,
|
|
23478
25330
|
sessionGenerationAvailable,
|
|
25331
|
+
workspaceGenerationAvailable,
|
|
23479
25332
|
reloadAvailable,
|
|
23480
25333
|
channelReloadAvailable,
|
|
23481
25334
|
channelControlAvailable,
|
|
@@ -23512,6 +25365,7 @@ function createServeFeatures(deps) {
|
|
|
23512
25365
|
sessionShellCommandEnabled,
|
|
23513
25366
|
sessionArtifactsPersistenceAvailable,
|
|
23514
25367
|
sessionGenerationAvailable: sessionGenerationAvailable(),
|
|
25368
|
+
workspaceGenerationAvailable: workspaceGenerationAvailable(),
|
|
23515
25369
|
rateLimit: opts.rateLimit === true,
|
|
23516
25370
|
reloadAvailable,
|
|
23517
25371
|
channelReloadAvailable: channelReloadAvailable(),
|
|
@@ -24857,16 +26711,19 @@ data: ${dataJson}
|
|
|
24857
26711
|
__name(formatSseFrame, "formatSseFrame");
|
|
24858
26712
|
function registerSseEventsRoutes(app, deps) {
|
|
24859
26713
|
const { workspaceRegistry, daemonLog, sendBridgeError: sendBridgeError2, writerIdleTimeoutMs } = deps;
|
|
24860
|
-
app.get("/session/:id/events", (req, res) => {
|
|
26714
|
+
app.get("/session/:id/events", async (req, res) => {
|
|
24861
26715
|
const sessionId = req.params["id"];
|
|
24862
26716
|
const lastEventId = parseLastEventId(req.headers["last-event-id"]);
|
|
26717
|
+
const eventEpoch = parseEventEpochHeader(req.headers["x-qwen-event-epoch"]);
|
|
24863
26718
|
const maxQueued = parseMaxQueuedQuery(req.query["maxQueued"], res);
|
|
24864
26719
|
if (maxQueued === null) return;
|
|
24865
26720
|
let iter;
|
|
26721
|
+
let busEpoch;
|
|
24866
26722
|
const abort = new AbortController();
|
|
24867
26723
|
try {
|
|
26724
|
+
const virtualKey = parseVirtualSubagentSessionId(sessionId);
|
|
24868
26725
|
const runtime = requireSessionRuntime({
|
|
24869
|
-
sessionId,
|
|
26726
|
+
sessionId: virtualKey?.parentSessionId ?? sessionId,
|
|
24870
26727
|
route: "GET /session/:id/events",
|
|
24871
26728
|
res,
|
|
24872
26729
|
workspaceRegistry,
|
|
@@ -24874,13 +26731,33 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
24874
26731
|
});
|
|
24875
26732
|
if (!runtime) return;
|
|
24876
26733
|
const snapshot = req.query["snapshot"] === "1";
|
|
24877
|
-
const iterable =
|
|
26734
|
+
const iterable = virtualKey ? await deps.virtualSubagentSessions?.subscribe(runtime, sessionId, {
|
|
24878
26735
|
signal: abort.signal,
|
|
24879
26736
|
lastEventId,
|
|
26737
|
+
...maxQueued !== void 0 ? { maxQueued } : {}
|
|
26738
|
+
}) : runtime.bridge.subscribeEvents(sessionId, {
|
|
26739
|
+
signal: abort.signal,
|
|
26740
|
+
lastEventId,
|
|
26741
|
+
...eventEpoch !== void 0 ? { epoch: eventEpoch } : {},
|
|
24880
26742
|
...maxQueued !== void 0 ? { maxQueued } : {},
|
|
24881
26743
|
...snapshot ? { snapshot: true } : {}
|
|
24882
26744
|
});
|
|
26745
|
+
if (!iterable) {
|
|
26746
|
+
res.status(404).json({
|
|
26747
|
+
error: "Subagent session not found",
|
|
26748
|
+
code: "session_not_found",
|
|
26749
|
+
sessionId
|
|
26750
|
+
});
|
|
26751
|
+
return;
|
|
26752
|
+
}
|
|
24883
26753
|
iter = iterable[Symbol.asyncIterator]();
|
|
26754
|
+
if (!virtualKey) {
|
|
26755
|
+
try {
|
|
26756
|
+
busEpoch = runtime.bridge.getSessionEventEpoch(sessionId);
|
|
26757
|
+
} catch {
|
|
26758
|
+
busEpoch = void 0;
|
|
26759
|
+
}
|
|
26760
|
+
}
|
|
24884
26761
|
} catch (err) {
|
|
24885
26762
|
if (err instanceof SubscriberLimitExceededError) {
|
|
24886
26763
|
writeStderrLine(
|
|
@@ -24920,6 +26797,9 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
24920
26797
|
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
24921
26798
|
res.setHeader("Connection", "keep-alive");
|
|
24922
26799
|
res.setHeader("X-Accel-Buffering", "no");
|
|
26800
|
+
if (busEpoch !== void 0) {
|
|
26801
|
+
res.setHeader("X-Qwen-Event-Epoch", busEpoch);
|
|
26802
|
+
}
|
|
24923
26803
|
res.flushHeaders();
|
|
24924
26804
|
activeSseCount++;
|
|
24925
26805
|
let sseCounted = true;
|
|
@@ -25045,7 +26925,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
25045
26925
|
const data = next.value.data;
|
|
25046
26926
|
const gap = typeof data.earliestAvailableId === "number" && typeof data.lastDeliveredId === "number" ? data.earliestAvailableId - data.lastDeliveredId - 1 : void 0;
|
|
25047
26927
|
writeStderrLine(
|
|
25048
|
-
`qwen serve: SSE ring eviction detected (session ${sessionId}): lastEventId=${data.lastDeliveredId ?? "?"}, earliestInRing=${data.earliestAvailableId ?? "?"}, gap=${gap ?? "?"} events, reason=${data.reason ?? "?"}. Consumer must call loadSession to recover.`
|
|
26928
|
+
`qwen serve: SSE ring eviction detected (session ${sessionId}): lastEventId=${data.lastDeliveredId ?? "?"}, earliestInRing=${data.earliestAvailableId ?? "?"}, gap=${gap ?? "?"} events, reason=${data.reason ?? "?"}` + (typeof data.detail === "string" ? `, detail=${data.detail}` : "") + `. Consumer must call loadSession to recover.`
|
|
25049
26929
|
);
|
|
25050
26930
|
}
|
|
25051
26931
|
await writeWithBackpressure(formatSseFrame(next.value));
|
|
@@ -26033,7 +27913,7 @@ __name(registerWorkspaceQualifiedLifecycleRoutes, "registerWorkspaceQualifiedLif
|
|
|
26033
27913
|
|
|
26034
27914
|
// packages/cli/src/serve/routes/workspace-management.ts
|
|
26035
27915
|
init_esbuild_shims();
|
|
26036
|
-
import { readdir, stat } from "node:fs/promises";
|
|
27916
|
+
import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
26037
27917
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
26038
27918
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute7, join as join8, resolve as resolve4, sep as sep3 } from "node:path";
|
|
26039
27919
|
var MAX_PATH_SUGGESTIONS = 50;
|
|
@@ -26255,7 +28135,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26255
28135
|
const suggestions = [];
|
|
26256
28136
|
let truncated = false;
|
|
26257
28137
|
try {
|
|
26258
|
-
const entries = await
|
|
28138
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
26259
28139
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
26260
28140
|
for (const entry of entries) {
|
|
26261
28141
|
if (entry.name.startsWith(".") && !filter.startsWith(".")) continue;
|
|
@@ -26265,7 +28145,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26265
28145
|
let isDir = entry.isDirectory();
|
|
26266
28146
|
if (!isDir && entry.isSymbolicLink()) {
|
|
26267
28147
|
try {
|
|
26268
|
-
isDir = (await
|
|
28148
|
+
isDir = (await stat2(join8(dir, entry.name))).isDirectory();
|
|
26269
28149
|
} catch {
|
|
26270
28150
|
continue;
|
|
26271
28151
|
}
|
|
@@ -26385,7 +28265,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26385
28265
|
return;
|
|
26386
28266
|
}
|
|
26387
28267
|
try {
|
|
26388
|
-
const s = await
|
|
28268
|
+
const s = await stat2(canonical);
|
|
26389
28269
|
if (!s.isDirectory()) {
|
|
26390
28270
|
res.status(400).json({
|
|
26391
28271
|
error: "Path is not a directory",
|
|
@@ -27188,7 +29068,7 @@ __name(registerWorkspaceManagementRoutes, "registerWorkspaceManagementRoutes");
|
|
|
27188
29068
|
|
|
27189
29069
|
// packages/cli/src/serve/routes/workspace-git.ts
|
|
27190
29070
|
init_esbuild_shims();
|
|
27191
|
-
import * as
|
|
29071
|
+
import * as fs5 from "node:fs";
|
|
27192
29072
|
import * as path14 from "node:path";
|
|
27193
29073
|
function registerWorkspaceGitRoutes(app, deps) {
|
|
27194
29074
|
app.get("/workspace/git", async (_req, res) => {
|
|
@@ -27215,8 +29095,8 @@ function registerWorkspaceQualifiedGitRoutes(app, deps) {
|
|
|
27215
29095
|
let gitCwd = runtime.workspaceCwd;
|
|
27216
29096
|
if (typeof rawCwd === "string" && rawCwd.length > 0) {
|
|
27217
29097
|
try {
|
|
27218
|
-
const resolved =
|
|
27219
|
-
const root =
|
|
29098
|
+
const resolved = fs5.realpathSync(path14.resolve(rawCwd));
|
|
29099
|
+
const root = fs5.realpathSync(runtime.workspaceCwd);
|
|
27220
29100
|
const rel = path14.relative(root, resolved);
|
|
27221
29101
|
if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
|
|
27222
29102
|
gitCwd = resolved;
|
|
@@ -27640,6 +29520,38 @@ var WorkspaceGitState = class {
|
|
|
27640
29520
|
|
|
27641
29521
|
// packages/cli/src/serve/routes/workspace-mcp-control.ts
|
|
27642
29522
|
init_esbuild_shims();
|
|
29523
|
+
function parseMcpReloadOptions(body, res) {
|
|
29524
|
+
const forceReconnectAll = body["forceReconnectAll"];
|
|
29525
|
+
if (forceReconnectAll !== void 0 && typeof forceReconnectAll !== "boolean") {
|
|
29526
|
+
res.status(400).json({
|
|
29527
|
+
error: "`forceReconnectAll` must be a boolean",
|
|
29528
|
+
code: "invalid_force_reconnect_all_flag"
|
|
29529
|
+
});
|
|
29530
|
+
return null;
|
|
29531
|
+
}
|
|
29532
|
+
const forceReconnectWhich = body["forceReconnectWhich"];
|
|
29533
|
+
if (forceReconnectWhich !== void 0 && (!Array.isArray(forceReconnectWhich) || forceReconnectWhich.some(
|
|
29534
|
+
(serverName) => typeof serverName !== "string" || serverName.length === 0
|
|
29535
|
+
))) {
|
|
29536
|
+
res.status(400).json({
|
|
29537
|
+
error: "`forceReconnectWhich` must be an array of server names",
|
|
29538
|
+
code: "invalid_force_reconnect_which"
|
|
29539
|
+
});
|
|
29540
|
+
return null;
|
|
29541
|
+
}
|
|
29542
|
+
if (forceReconnectAll === true && forceReconnectWhich !== void 0) {
|
|
29543
|
+
res.status(400).json({
|
|
29544
|
+
error: "`forceReconnectAll` and `forceReconnectWhich` cannot be used together",
|
|
29545
|
+
code: "conflicting_force_reconnect_options"
|
|
29546
|
+
});
|
|
29547
|
+
return null;
|
|
29548
|
+
}
|
|
29549
|
+
return {
|
|
29550
|
+
forceReconnectAll,
|
|
29551
|
+
forceReconnectWhich
|
|
29552
|
+
};
|
|
29553
|
+
}
|
|
29554
|
+
__name(parseMcpReloadOptions, "parseMcpReloadOptions");
|
|
27643
29555
|
function registerWorkspaceMcpControlRoutes(app, deps) {
|
|
27644
29556
|
const {
|
|
27645
29557
|
boundWorkspace,
|
|
@@ -27666,9 +29578,11 @@ function registerWorkspaceMcpControlRoutes(app, deps) {
|
|
|
27666
29578
|
app.post(
|
|
27667
29579
|
"/workspace/mcp/reload",
|
|
27668
29580
|
mutate({ strict: true }),
|
|
27669
|
-
async (
|
|
29581
|
+
async (req, res) => {
|
|
29582
|
+
const options = parseMcpReloadOptions(safeBody2(req), res);
|
|
29583
|
+
if (!options) return;
|
|
27670
29584
|
try {
|
|
27671
|
-
const result = await bridge.reloadWorkspaceMcp();
|
|
29585
|
+
const result = await bridge.reloadWorkspaceMcp(options);
|
|
27672
29586
|
res.status(202).json(result);
|
|
27673
29587
|
} catch (err) {
|
|
27674
29588
|
sendBridgeError2(res, err, { route: "POST /workspace/mcp/reload" });
|
|
@@ -27873,9 +29787,11 @@ function registerWorkspaceQualifiedMcpControlRoutes(app, deps) {
|
|
|
27873
29787
|
res
|
|
27874
29788
|
);
|
|
27875
29789
|
if (!runtime) return;
|
|
29790
|
+
const options = parseMcpReloadOptions(deps.safeBody(req), res);
|
|
29791
|
+
if (!options) return;
|
|
27876
29792
|
const route = "POST /workspaces/:workspace/mcp/reload";
|
|
27877
29793
|
try {
|
|
27878
|
-
const result = await runtime.bridge.reloadWorkspaceMcp();
|
|
29794
|
+
const result = await runtime.bridge.reloadWorkspaceMcp(options);
|
|
27879
29795
|
res.status(202).json(result);
|
|
27880
29796
|
} catch (err) {
|
|
27881
29797
|
deps.sendBridgeError(res, err, { route });
|
|
@@ -29250,6 +31166,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29250
31166
|
(runtime) => runtime.bridge.generateSessionContent !== void 0
|
|
29251
31167
|
);
|
|
29252
31168
|
}, "sessionGenerationAvailable"),
|
|
31169
|
+
workspaceGenerationAvailable: /* @__PURE__ */ __name(() => primaryBridge.generateWorkspaceContent !== void 0, "workspaceGenerationAvailable"),
|
|
29253
31170
|
// Registry injection supplies the primary workspace service through the
|
|
29254
31171
|
// runtime, so it has the same reload surface as legacy deps.workspace.
|
|
29255
31172
|
reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
|
|
@@ -29543,6 +31460,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29543
31460
|
maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
|
|
29544
31461
|
languageCodes
|
|
29545
31462
|
});
|
|
31463
|
+
registerChannelNotifyRoutes(app, {
|
|
31464
|
+
boundWorkspace: primaryBoundWorkspace,
|
|
31465
|
+
workspaceRegistry,
|
|
31466
|
+
mutate,
|
|
31467
|
+
safeBody,
|
|
31468
|
+
deliverChannelMessage: deps.deliverChannelMessage
|
|
31469
|
+
});
|
|
29546
31470
|
registerWorkspaceStatusRoutes(app, {
|
|
29547
31471
|
boundWorkspace: primaryBoundWorkspace,
|
|
29548
31472
|
bridge: primaryBridge,
|
|
@@ -29608,6 +31532,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29608
31532
|
parseClientId: parseClientIdHeader,
|
|
29609
31533
|
safeBody
|
|
29610
31534
|
});
|
|
31535
|
+
mountWorkspaceGenerationRoutes(app, {
|
|
31536
|
+
bridge: primaryBridge,
|
|
31537
|
+
mutate,
|
|
31538
|
+
parseClientId: parseClientIdHeader,
|
|
31539
|
+
safeBody
|
|
31540
|
+
});
|
|
29611
31541
|
mountWorkspaceQualifiedAgentsRoutes(app, {
|
|
29612
31542
|
workspaceRegistry,
|
|
29613
31543
|
mutate,
|
|
@@ -29784,6 +31714,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29784
31714
|
allowPrivateAuthBaseUrl: opts.allowPrivateAuthBaseUrl === true,
|
|
29785
31715
|
installAuthProvider: deps.installAuthProvider
|
|
29786
31716
|
});
|
|
31717
|
+
const virtualSubagentSessions = new VirtualSubagentSessions();
|
|
29787
31718
|
registerSessionRoutes(app, {
|
|
29788
31719
|
boundWorkspace: primaryBoundWorkspace,
|
|
29789
31720
|
bridge: primaryBridge,
|
|
@@ -29792,9 +31723,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29792
31723
|
mutate,
|
|
29793
31724
|
sendBridgeError: sendBridgeError2,
|
|
29794
31725
|
daemonLog,
|
|
31726
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
|
|
29795
31727
|
promptDeadlineMs: opts.promptDeadlineMs,
|
|
29796
31728
|
sessionShellCommandEnabled,
|
|
29797
|
-
languageCodes
|
|
31729
|
+
languageCodes,
|
|
31730
|
+
virtualSubagentSessions
|
|
29798
31731
|
});
|
|
29799
31732
|
registerWorkspaceMcpControlRoutes(app, {
|
|
29800
31733
|
boundWorkspace: primaryBoundWorkspace,
|
|
@@ -29886,7 +31819,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29886
31819
|
boundWorkspace: primaryBoundWorkspace,
|
|
29887
31820
|
mutate,
|
|
29888
31821
|
safeBody,
|
|
29889
|
-
bridge: deps.manageScheduledTaskSessions ? bridge : void 0
|
|
31822
|
+
bridge: deps.manageScheduledTaskSessions ? bridge : void 0,
|
|
31823
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
29890
31824
|
});
|
|
29891
31825
|
registerGoalsRoutes(app, {
|
|
29892
31826
|
boundWorkspace: primaryBoundWorkspace,
|
|
@@ -29896,16 +31830,32 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29896
31830
|
workspaceRegistry,
|
|
29897
31831
|
mutate,
|
|
29898
31832
|
safeBody,
|
|
29899
|
-
manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true
|
|
31833
|
+
manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
|
|
31834
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
29900
31835
|
});
|
|
29901
31836
|
registerUsageStatsRoutes(app);
|
|
29902
31837
|
if (deps.manageScheduledTaskSessions) {
|
|
31838
|
+
const registerScheduledTaskAuthorizations = /* @__PURE__ */ __name((workspaceCwd, tasks) => {
|
|
31839
|
+
const authorizations = deps.channelDeliveryAuthorizations;
|
|
31840
|
+
if (!authorizations) return;
|
|
31841
|
+
for (const task of tasks) {
|
|
31842
|
+
if (!task.delivery || !task.sessionId) continue;
|
|
31843
|
+
authorizations.registerScheduledTask(workspaceCwd, {
|
|
31844
|
+
sessionId: task.sessionId,
|
|
31845
|
+
taskId: task.id,
|
|
31846
|
+
target: task.delivery.target,
|
|
31847
|
+
recurring: task.recurring,
|
|
31848
|
+
...typeof task.lastFiredAt === "number" ? { lastFiredAt: task.lastFiredAt } : {}
|
|
31849
|
+
});
|
|
31850
|
+
}
|
|
31851
|
+
}, "registerScheduledTaskAuthorizations");
|
|
29903
31852
|
const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
29904
31853
|
const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
|
|
29905
31854
|
const rehydrateWorkspace = /* @__PURE__ */ __name((taskBridge, workspaceCwd) => {
|
|
29906
31855
|
void rehydrateScheduledTaskSessions({
|
|
29907
31856
|
bridge: taskBridge,
|
|
29908
31857
|
boundWorkspace: workspaceCwd,
|
|
31858
|
+
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(workspaceCwd, tasks), "onTasksRead"),
|
|
29909
31859
|
onError: /* @__PURE__ */ __name((sessionId, err) => {
|
|
29910
31860
|
process.stderr.write(
|
|
29911
31861
|
`qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -29930,7 +31880,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29930
31880
|
const keepalive = startScheduledTaskKeepalive({
|
|
29931
31881
|
bridge: runtime.bridge,
|
|
29932
31882
|
boundWorkspace: runtime.workspaceCwd,
|
|
29933
|
-
intervalMs: keepaliveIntervalMs
|
|
31883
|
+
intervalMs: keepaliveIntervalMs,
|
|
31884
|
+
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
|
|
29934
31885
|
});
|
|
29935
31886
|
rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
|
|
29936
31887
|
keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
|
|
@@ -29960,7 +31911,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29960
31911
|
workspaceRegistry,
|
|
29961
31912
|
daemonLog,
|
|
29962
31913
|
writerIdleTimeoutMs: opts.writerIdleTimeoutMs,
|
|
29963
|
-
sendBridgeError: sendBridgeError2
|
|
31914
|
+
sendBridgeError: sendBridgeError2,
|
|
31915
|
+
virtualSubagentSessions
|
|
29964
31916
|
});
|
|
29965
31917
|
acpHandleRef.current = mountAcpHttp(app, primaryBridge, {
|
|
29966
31918
|
boundWorkspace: primaryBoundWorkspace,
|