@qwen-code/qwen-code 0.20.2-headless-image-routing.1 → 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-PLQQB22E.js → StandaloneSessionPicker-BIRMPLRD.js} +66 -59
- package/chunks/{acp-startup-profiler-N3RHHXJ3.js → acp-startup-profiler-RV3IV562.js} +2 -2
- package/chunks/{acpAgent-AIVK2EM5.js → acpAgent-6J2U72PQ.js} +705 -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-GHIZ4MSZ.js → build-RV63TIRH.js} +2 -3
- package/chunks/{ca-N6VVUFVB.js → ca-25EDXPFZ.js} +2 -0
- package/chunks/{channel-worker-group-QZV2SP5U.js → channel-worker-group-2ZD7TVAT.js} +8 -7
- package/chunks/{channel-worker-manager-3GMAU45H.js → channel-worker-manager-4OA4BCGB.js} +190 -30
- package/chunks/{channel-worker-supervisor-QCXSXCRY.js → channel-worker-supervisor-V7KCFJTS.js} +7 -6
- 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-4DWTDZGS.js → chunk-2NH6DYI4.js} +12 -12
- package/chunks/chunk-2SCDWPXI.js +246 -0
- package/chunks/{chunk-QE4KFTBS.js → chunk-2X55UKQE.js} +3 -3
- package/chunks/{chunk-QBUDF33N.js → chunk-3QMGYBFN.js} +1 -1
- package/chunks/{chunk-3OAKYHRG.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-GHRSKGHF.js → chunk-4WIZGAH3.js} +7 -7
- package/chunks/{chunk-CAS7CB3T.js → chunk-55DJUCI2.js} +87 -29
- package/chunks/{chunk-QNLNLENL.js → chunk-5I2IWRSH.js} +2 -2
- package/chunks/{chunk-H24SOJIQ.js → chunk-5NBDS5S6.js} +147 -7
- package/chunks/{chunk-E4IMU4Y5.js → chunk-63P4EL5V.js} +1 -1
- package/chunks/chunk-6FGBXPWM.js +293 -0
- package/chunks/{chunk-FFFM6NJV.js → chunk-6GMVPFB2.js} +155 -73
- package/chunks/{chunk-KWK7UE6L.js → chunk-6OUGMXDC.js} +6 -6
- package/chunks/{chunk-QRUIS3DN.js → chunk-6PEXNQTX.js} +22 -1
- package/chunks/{chunk-FZPTCQY7.js → chunk-7JURR4JT.js} +1 -1
- package/chunks/{chunk-Q6NAKZTA.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-YO2XRXY6.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-FRPDJNK3.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-ZDP2Y2AL.js → chunk-CIKQ7KKO.js} +4625 -8645
- package/chunks/{chunk-PEJWA3QQ.js → chunk-D3UEZIQH.js} +4 -2
- 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-JC26SJ5Y.js → chunk-EBJQ6AXW.js} +13 -12
- package/chunks/{chunk-RCWKCN2Z.js → chunk-EPDRMGT4.js} +164 -17
- package/chunks/{chunk-FUFCALSJ.js → chunk-ETSW4KLJ.js} +2 -2
- package/chunks/{chunk-KHOVYUHX.js → chunk-FNQ6T3CV.js} +20 -3
- package/chunks/{chunk-SP5WRGVG.js → chunk-FQK6JAFG.js} +72 -23
- package/chunks/{chunk-NWZY2SPY.js → chunk-FSITMZJH.js} +8 -8
- package/chunks/{chunk-6RLROE6G.js → chunk-GLWP3FDB.js} +80 -15
- package/chunks/{chunk-KPBVP6SL.js → chunk-GSN55ZRI.js} +5 -5
- package/chunks/{chunk-MLYGPZGU.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-5G3ZVADU.js → chunk-IJTOWOD7.js} +17 -6
- package/chunks/chunk-IKCX4CCL.js +469 -0
- package/chunks/{chunk-LPEONXNV.js → chunk-IKYJHJNF.js} +3 -3
- package/chunks/{chunk-DTZY2SH2.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-46DK772E.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-RKWX4CMO.js → chunk-JVPM2ULZ.js} +6 -6
- package/chunks/{chunk-ENPCQK44.js → chunk-JXJFVC6E.js} +37 -18
- package/chunks/{chunk-NABLFI57.js → chunk-JZA3JUDJ.js} +1 -1
- package/chunks/{chunk-CGLQAVZE.js → chunk-K36B6G2O.js} +5 -5
- package/chunks/{chunk-GPSKDNEE.js → chunk-K4XWPEWB.js} +4 -4
- package/chunks/{chunk-QOZOIPSF.js → chunk-KIM5GUMA.js} +650 -113
- package/chunks/{chunk-JZSM2IZ3.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-O2XSCRCS.js → chunk-LB6DUZ26.js} +259 -67
- package/chunks/chunk-LEH5C7FV.js +232 -0
- package/chunks/{chunk-RWV32G2M.js → chunk-LH2BYDQ5.js} +6 -4
- package/chunks/{chunk-QKTHJXCS.js → chunk-LK7CHLVP.js} +79 -2
- package/chunks/{chunk-VRRF3GW5.js → chunk-LKEJ26GS.js} +11 -11
- package/chunks/{chunk-SQFXI7VK.js → chunk-LQIW3YFY.js} +227 -41
- package/chunks/chunk-LS77BEZP.js +405 -0
- package/chunks/{chunk-BSHD62QJ.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-3HFNGB2O.js → chunk-MVSUYZDT.js} +4 -4
- package/chunks/{chunk-T5IO6FZ4.js → chunk-MZAXJAUM.js} +1 -1
- package/chunks/{chunk-QKNXKTZX.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-CS2FSS7W.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-7THPNISK.js → chunk-PC6JANNU.js} +5 -5
- package/chunks/{chunk-OTQ6PSZC.js → chunk-PHOF65IG.js} +3498 -1030
- 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-RECUEJ7B.js → chunk-PSOO6YXD.js} +18 -15
- package/chunks/{chunk-X6N25LXS.js → chunk-PWTZEM3C.js} +2 -2
- package/chunks/{chunk-5NJTNQUW.js → chunk-PWVFN2LF.js} +1 -1
- package/chunks/{chunk-7AUH6A4T.js → chunk-Q4M4MDQ4.js} +2 -2
- package/chunks/{chunk-EZPB6S2I.js → chunk-QAF7NMK7.js} +1 -1
- package/chunks/{chunk-5GI55PF5.js → chunk-R5AFZNQW.js} +5 -5
- package/chunks/{chunk-T5B5NQZX.js → chunk-RF3EXIHJ.js} +47 -60
- package/chunks/{chunk-4K7VDKAD.js → chunk-RHLZR4E5.js} +1 -1
- package/chunks/{chunk-TJDW42MV.js → chunk-RIBKPMRP.js} +220 -141
- package/chunks/{chunk-RVLZCXEE.js → chunk-RWTEFFPU.js} +82 -3
- package/chunks/{chunk-L5QZGCRH.js → chunk-RZIX2G32.js} +1 -1
- package/chunks/{chunk-LLKWRXSS.js → chunk-SQCQ4KO2.js} +350 -418
- package/chunks/{chunk-THJNPLI4.js → chunk-TARRHLLG.js} +1 -0
- package/chunks/{chunk-XCXYRDHB.js → chunk-TEHGS6UP.js} +47 -18
- package/chunks/{chunk-PQIVAWXN.js → chunk-TGILQ3YH.js} +8 -8
- package/chunks/{chunk-Q2YKNMLS.js → chunk-TOFQCPDC.js} +43 -10
- package/chunks/{chunk-L3KUB6XM.js → chunk-TPRQ7RZH.js} +586 -242
- package/chunks/{chunk-T4TZQJ7W.js → chunk-TWPJO254.js} +5 -16
- package/chunks/{chunk-HIP6TVWA.js → chunk-U7M2DMGW.js} +3 -3
- package/chunks/{chunk-ACW3VNUE.js → chunk-UDX5OBWR.js} +41 -9
- package/chunks/{chunk-LW2FUYBN.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-O4BHWVUD.js → chunk-VIA5XA4U.js} +5 -2
- package/chunks/{chunk-EBXZ2YGV.js → chunk-VRYUBFMC.js} +1 -1
- package/chunks/{chunk-TWVE5ZS5.js → chunk-VULLI6WQ.js} +172 -6
- package/chunks/{chunk-LNDD3IML.js → chunk-WCXCRJYB.js} +1 -1
- package/chunks/{chunk-2LI23QA6.js → chunk-X5XDDSSH.js} +1 -1
- package/chunks/{chunk-Q35QUZDQ.js → chunk-Y34KJKDC.js} +1 -1
- package/chunks/{chunk-7NR2AIK6.js → chunk-YBL3QUDD.js} +2 -2
- package/chunks/{chunk-H4AR2JQF.js → chunk-YH6G52F2.js} +3 -3
- package/chunks/{chunk-MBOJHHPI.js → chunk-YPE6A4GC.js} +2 -2
- package/chunks/{chunk-3EK5ZOUQ.js → chunk-YX324OPW.js} +1 -1
- package/chunks/{chunk-4PTLZ3NX.js → chunk-Z2BC6UJ5.js} +3 -3
- package/chunks/{chunk-QLJUC7TG.js → chunk-ZD6UTE4A.js} +1 -1
- package/chunks/{chunk-LX3COOXF.js → chunk-ZFDTEDCF.js} +6 -6
- package/chunks/chunk-ZJHVAS7M.js +289 -0
- package/chunks/{chunk-4OWXOUYF.js → chunk-ZNAUOR2I.js} +15 -12
- package/chunks/{chunk-T2L47JJK.js → chunk-ZOIFNCKL.js} +4 -4
- package/chunks/{computer-use-2VIV73WK.js → computer-use-SOQ4E3VX.js} +43 -35
- package/chunks/{config-utils-FYTBZLCJ.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-XDHHC2P4.js → create-sub-session-QRJLW5BV.js} +43 -35
- 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-CS6SFEXC.js → edit-OBDSQURM.js} +43 -35
- package/chunks/{en-USMCCJAJ.js → en-MTWBNGDO.js} +15 -0
- package/chunks/{enter-worktree-LMAL75DY.js → enter-worktree-U6MRPQ2P.js} +43 -35
- package/chunks/{enterPlanMode-WVJB4DSS.js → enterPlanMode-BC5QUZZ2.js} +43 -35
- package/chunks/{environment-6YHC4JAJ.js → environment-W5UFC2CH.js} +46 -38
- package/chunks/errors-M7CLORXH.js +88 -0
- package/chunks/{exit-worktree-KPFD742L.js → exit-worktree-DGNYMECB.js} +43 -35
- package/chunks/{exitPlanMode-UEJS6CDY.js → exitPlanMode-GXTBWQAR.js} +43 -35
- package/chunks/{fast-path-G2N4NRCA.js → fast-path-JJZFJANL.js} +6 -6
- package/chunks/{fast-path-settings-DAOVFADC.js → fast-path-settings-WQJU2LAT.js} +2 -2
- package/chunks/{fr-WVHEBDDB.js → fr-45RLL55O.js} +1 -0
- package/chunks/{gemini-2MDVIOVT.js → gemini-QS36EBZV.js} +132 -102
- package/chunks/{geminiContentGenerator-ZXTDBMFR.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-562XFLIZ.js → glob-V7R3PSK3.js} +43 -35
- package/chunks/{grep-MGEFBDQK.js → grep-QYPSK7OP.js} +43 -35
- package/chunks/handleAutoUpdate-6DBEZYPV.js +81 -0
- package/chunks/{i18n-R6HJENXA.js → i18n-VUJJZIMU.js} +44 -36
- 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-4KNYSOYC.js → managed-npm-update-JYEMMXA3.js} +94 -38
- package/chunks/mcp-6DBDJPFU.js +83 -0
- package/chunks/{monitor-DMHKE4SW.js → monitor-R3ODH5U6.js} +45 -36
- package/chunks/node-UUDY34IG.js +305 -0
- package/chunks/nonInteractiveCli-MOYCYBBU.js +141 -0
- package/chunks/{notebook-edit-35SJGEOR.js → notebook-edit-BNOK452R.js} +43 -35
- package/chunks/{openaiContentGenerator-5LPAFXPF.js → openaiContentGenerator-WMCU3O2H.js} +27 -17
- package/chunks/pidfile-TFRZZZIO.js +86 -0
- package/chunks/{processUtils-GM2I55KF.js → processUtils-RT7UNCC2.js} +2 -2
- package/chunks/{pt-OK455PLH.js → pt-22Q3FP73.js} +1 -0
- package/chunks/{qwenContentGenerator-HKOYNP7H.js → qwenContentGenerator-HHCRK4SX.js} +56 -42
- package/chunks/{qwenOAuth2-NUUYC3V5.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-5VH3F4NW.js → run-qwen-serve-FU6HEM4J.js} +271 -57
- package/chunks/{runtime-OH77YH7W.js → runtime-XXRRTNP6.js} +55 -45
- package/chunks/{scheduler-WJQSLCSV.js → scheduler-G2ZS2Z7E.js} +43 -35
- 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-E4N4AI6Z.js → server-4UMH7OIZ.js} +2362 -411
- package/chunks/{session-5YUWIOQE.js → session-K3O3Q2SV.js} +105 -87
- package/chunks/{settings-YY7ZSFO7.js → settings-CR2EWTBA.js} +53 -45
- package/chunks/shell-HH3PF3A2.js +83 -0
- package/chunks/{skill-PAIDX3EU.js → skill-I3SDA4MB.js} +17 -16
- package/chunks/spawnChannel-RWNDBXGA.js +82 -0
- package/chunks/{src-IZXLJI5M.js → src-GE4TTTML.js} +302 -184
- package/chunks/{standalone-update-X675JVBL.js → standalone-update-Q6WFRZZQ.js} +45 -37
- package/chunks/{startInteractiveUI-ND2IVBU3.js → startInteractiveUI-SLZGHRPH.js} +747 -310
- 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-2DEYNMMN.js → team-create-YJALH5D2.js} +46 -38
- package/chunks/{team-delete-BB3CG3QF.js → team-delete-QE2UXJL7.js} +7 -7
- package/chunks/{team-plan-approval-65AVAOCT.js → team-plan-approval-34QFYKGN.js} +43 -35
- package/chunks/theme-manager-SWRILQHI.js +77 -0
- package/chunks/{todoWrite-KRAUN54W.js → todoWrite-VQ7FKOHL.js} +5 -5
- package/chunks/{tool-search-ZQP3SMTV.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-LURI52LP.js → trustedFolders-KHXHY6PY.js} +44 -36
- package/chunks/{update-relaunch-BPWFIDLM.js → update-relaunch-WBUZJC5O.js} +5 -5
- package/chunks/updateCheck-RKL6M5XN.js +92 -0
- package/chunks/useAutoAcceptIndicator-CFQ5BUJL.js +93 -0
- package/chunks/{validateNonInterActiveAuth-HWD6Y22I.js → validateNonInterActiveAuth-3R223G3R.js} +89 -80
- package/chunks/{version-OD4JAFG7.js → version-HS7YSFHV.js} +1 -1
- package/chunks/{web-fetch-RFBKNU24.js → web-fetch-NKCSG7ZE.js} +18 -16
- package/chunks/{web-search-AKTVS5YZ.js → web-search-S62WAP4S.js} +13 -27
- package/chunks/{workflow-VZVCOSZN.js → workflow-QAGU5RU4.js} +44 -36
- package/chunks/workspace-providers-status-QSVZUETE.js +86 -0
- package/chunks/{workspace-registration-store-Q5SFJSX4.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-3XQIBACV.js +0 -78
- package/chunks/agent-QXD5NSKA.js +0 -73
- package/chunks/agent-headless-4VXR2TBK.js +0 -67
- package/chunks/bridge-GIBRSPE6.js +0 -81
- package/chunks/chunk-CBOQ3HY7.js +0 -2019
- package/chunks/chunk-MA6GYKK7.js +0 -6928
- package/chunks/contextCommand-XQU7KLIH.js +0 -72
- package/chunks/daemon-status-provider-KQVNB4VA.js +0 -80
- package/chunks/earlyInputCapture-WP5SA3KH.js +0 -74
- package/chunks/errors-JEYPXX4S.js +0 -80
- package/chunks/handleAutoUpdate-2VJPAW43.js +0 -73
- package/chunks/initializer-UOX67ZFQ.js +0 -78
- package/chunks/installationInfo-NQNY34X3.js +0 -72
- package/chunks/list-2Z7KS7ZF.js +0 -81
- package/chunks/loadedSettingsAdapter-LIYY3LE4.js +0 -75
- package/chunks/mcp-AJ4QW3JA.js +0 -75
- package/chunks/nonInteractiveCli-PUSO5QF6.js +0 -134
- package/chunks/pidfile-EH2JW2PB.js +0 -78
- package/chunks/read-file-JZ5VXILQ.js +0 -31
- package/chunks/resumeHistoryUtils-Z3HG4WKM.js +0 -84
- package/chunks/ripGrep-JNLJCT2B.js +0 -65
- package/chunks/serve-NN5FXWR6.js +0 -81
- package/chunks/shell-FXT3NVC6.js +0 -75
- package/chunks/spawnChannel-XAWLXNOD.js +0 -74
- package/chunks/theme-manager-2WZHPK2M.js +0 -69
- package/chunks/total-session-admission-HULB2TEQ.js +0 -75
- package/chunks/updateCheck-D4ESCHBJ.js +0 -88
- package/chunks/useAutoAcceptIndicator-CBNLOF2P.js +0 -86
- package/chunks/workspace-providers-status-TJTVHORI.js +0 -78
- package/chunks/workspace-registry-H6VM5WXK.js +0 -79
- package/chunks/workspace-service-ZNKD3I2J.js +0 -90
- package/chunks/workspace-skills-status-OOBIXADG.js +0 -77
- package/chunks/write-file-CAKK5IAO.js +0 -65
- 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,21 +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";
|
|
44
91
|
import {
|
|
45
92
|
createSingleWorkspaceRegistry,
|
|
46
93
|
createWorkspaceSessionOwnerIndex
|
|
47
94
|
} from "./chunk-UGYMA4EI.js";
|
|
95
|
+
import "./chunk-GRC5HGPI.js";
|
|
48
96
|
import {
|
|
49
97
|
CAPABILITIES_SCHEMA_VERSION,
|
|
50
98
|
CLIENT_ID_HEADER,
|
|
@@ -102,87 +150,33 @@ import {
|
|
|
102
150
|
setRateLimiter,
|
|
103
151
|
unsafeRevealSecret,
|
|
104
152
|
validateMcpRuntimeServerName
|
|
105
|
-
} from "./chunk-
|
|
153
|
+
} from "./chunk-IJTOWOD7.js";
|
|
106
154
|
import {
|
|
107
155
|
isLoopbackBind
|
|
108
156
|
} from "./chunk-RXFQM6FQ.js";
|
|
157
|
+
import {
|
|
158
|
+
daemonObservedContactsPath,
|
|
159
|
+
loadChannelsConfig
|
|
160
|
+
} from "./chunk-PSOO6YXD.js";
|
|
161
|
+
import "./chunk-PC6JANNU.js";
|
|
162
|
+
import "./chunk-57OAHC2Y.js";
|
|
109
163
|
import {
|
|
110
164
|
createDaemonStatusProvider
|
|
111
|
-
} from "./chunk-
|
|
165
|
+
} from "./chunk-J24WCGIN.js";
|
|
112
166
|
import "./chunk-LXXMOYPL.js";
|
|
113
|
-
import "./chunk-
|
|
167
|
+
import "./chunk-MVSUYZDT.js";
|
|
114
168
|
import "./chunk-E5Z2AVNV.js";
|
|
115
|
-
import {
|
|
116
|
-
createWorkspaceProvidersStatusProvider
|
|
117
|
-
} from "./chunk-NWZY2SPY.js";
|
|
118
|
-
import {
|
|
119
|
-
getAuthTypeFromEnv,
|
|
120
|
-
resolveCliGenerationConfig
|
|
121
|
-
} from "./chunk-JZSM2IZ3.js";
|
|
122
|
-
import {
|
|
123
|
-
snapshotProcessEnv
|
|
124
|
-
} from "./chunk-FUFCALSJ.js";
|
|
125
|
-
import {
|
|
126
|
-
createWorkspaceSkillsStatusProvider
|
|
127
|
-
} from "./chunk-YO2XRXY6.js";
|
|
128
|
-
import "./chunk-2W3OOD4W.js";
|
|
129
|
-
import {
|
|
130
|
-
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
131
|
-
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
132
|
-
WorkspaceSkillManagementError,
|
|
133
|
-
WorkspaceVoiceError,
|
|
134
|
-
buildWorkspaceVoiceSettingsWrites,
|
|
135
|
-
buildWorkspaceVoiceStatus,
|
|
136
|
-
createDaemonWorkspaceService,
|
|
137
|
-
hasConfiguredBatchVoiceTranscriptionModel,
|
|
138
|
-
transcribeWorkspaceVoiceAudio,
|
|
139
|
-
validateWorkspaceSkillName,
|
|
140
|
-
validateWorkspaceVoiceState,
|
|
141
|
-
voiceSettingsScopeToWire
|
|
142
|
-
} from "./chunk-PQIVAWXN.js";
|
|
143
|
-
import {
|
|
144
|
-
PermissionRulesValidationError,
|
|
145
|
-
buildPermissionSettings,
|
|
146
|
-
isPermissionRuleType,
|
|
147
|
-
normalizePermissionRules,
|
|
148
|
-
readPermissionRuleSet
|
|
149
|
-
} from "./chunk-EBXZ2YGV.js";
|
|
150
|
-
import {
|
|
151
|
-
assertVoiceBaseUrlNetworkAllowed,
|
|
152
|
-
isStreamingVoiceModel,
|
|
153
|
-
resolveVoiceStreamConfig,
|
|
154
|
-
resolveVoiceTranscriptionConfig,
|
|
155
|
-
sanitizeVoiceErrorMessage,
|
|
156
|
-
transcribeVoiceAudio
|
|
157
|
-
} from "./chunk-MLYGPZGU.js";
|
|
158
|
-
import {
|
|
159
|
-
isVoiceEnabled,
|
|
160
|
-
isVoiceMode,
|
|
161
|
-
readVoiceModel
|
|
162
|
-
} from "./chunk-7NR2AIK6.js";
|
|
163
|
-
import "./chunk-QLJUC7TG.js";
|
|
164
|
-
import {
|
|
165
|
-
WorkspacePermissionRulesSessionRequiredError,
|
|
166
|
-
WorkspaceSettingsPartialPersistError,
|
|
167
|
-
WorkspaceSkillNotFoundError,
|
|
168
|
-
WorkspaceSkillNotToggleableError
|
|
169
|
-
} from "./chunk-OA4JVLSA.js";
|
|
170
|
-
import {
|
|
171
|
-
createTotalSessionAdmissionController
|
|
172
|
-
} from "./chunk-VYPFXUCB.js";
|
|
173
|
-
import "./chunk-GRC5HGPI.js";
|
|
174
169
|
import {
|
|
175
170
|
SessionArtifactAuthorizationError,
|
|
176
171
|
SessionArtifactValidationError,
|
|
177
172
|
createAcpSessionBridge,
|
|
178
173
|
parseSessionSource
|
|
179
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-KIM5GUMA.js";
|
|
180
175
|
import {
|
|
181
176
|
EVENT_SCHEMA_VERSION,
|
|
177
|
+
EventBus,
|
|
182
178
|
SubscriberLimitExceededError
|
|
183
|
-
} from "./chunk-
|
|
184
|
-
import "./chunk-COH43MRJ.js";
|
|
185
|
-
import "./chunk-QR6U5QPP.js";
|
|
179
|
+
} from "./chunk-GLWP3FDB.js";
|
|
186
180
|
import {
|
|
187
181
|
BranchWhilePromptActiveError,
|
|
188
182
|
CancelSentinelCollisionError,
|
|
@@ -216,24 +210,35 @@ import {
|
|
|
216
210
|
WorkspaceInitSymlinkError,
|
|
217
211
|
WorkspaceMismatchError
|
|
218
212
|
} from "./chunk-UH3WSE5L.js";
|
|
219
|
-
import "./chunk-
|
|
213
|
+
import "./chunk-COH43MRJ.js";
|
|
214
|
+
import "./chunk-3SJ43L4W.js";
|
|
215
|
+
import "./chunk-7JURR4JT.js";
|
|
220
216
|
import {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
} from "./chunk-RECUEJ7B.js";
|
|
224
|
-
import "./chunk-7THPNISK.js";
|
|
225
|
-
import "./chunk-57OAHC2Y.js";
|
|
217
|
+
createWorkspaceProvidersStatusProvider
|
|
218
|
+
} from "./chunk-FSITMZJH.js";
|
|
226
219
|
import {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
import
|
|
231
|
-
|
|
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";
|
|
232
230
|
import {
|
|
233
231
|
STATUS_SCHEMA_VERSION,
|
|
234
232
|
createIdleWorkspaceMemoryStatus,
|
|
235
233
|
mapDomainErrorToErrorKind
|
|
236
|
-
} 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";
|
|
237
242
|
import {
|
|
238
243
|
MAX_REGISTERED_WORKSPACES,
|
|
239
244
|
WorkspaceDisplayNameValidationError,
|
|
@@ -241,7 +246,7 @@ import {
|
|
|
241
246
|
WorkspaceRegistrationStoreLimitError,
|
|
242
247
|
normalizeWorkspaceDisplayName,
|
|
243
248
|
workspaceRegistrationId
|
|
244
|
-
} from "./chunk-
|
|
249
|
+
} from "./chunk-Q4M4MDQ4.js";
|
|
245
250
|
import {
|
|
246
251
|
MAX_WORKSPACE_PATH_LENGTH,
|
|
247
252
|
canonicalizeWorkspace,
|
|
@@ -249,26 +254,28 @@ import {
|
|
|
249
254
|
translateAndCheckAbsoluteWorkspacePath
|
|
250
255
|
} from "./chunk-2RFKHEXL.js";
|
|
251
256
|
import {
|
|
257
|
+
ChannelDeliveryError,
|
|
252
258
|
MAX_CHANNEL_STARTUP_FAILURES,
|
|
253
259
|
MAX_CHANNEL_STARTUP_FAILURE_CHANNEL_LENGTH,
|
|
254
260
|
MAX_CHANNEL_STARTUP_FAILURE_CODE_LENGTH,
|
|
255
261
|
MAX_CHANNEL_STARTUP_FAILURE_MESSAGE_LENGTH,
|
|
256
262
|
QWEN_SERVER_TOKEN_ENV,
|
|
263
|
+
isChannelDeliveryError,
|
|
257
264
|
isChannelWebhookEnqueueError,
|
|
258
265
|
normalizeWorkerDiagnostic
|
|
259
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-LK7CHLVP.js";
|
|
260
267
|
import {
|
|
261
268
|
normalizeServeChannelSelection
|
|
262
|
-
} from "./chunk-
|
|
269
|
+
} from "./chunk-JLU636DO.js";
|
|
270
|
+
import "./chunk-BK2UNYWD.js";
|
|
263
271
|
import {
|
|
264
272
|
redactLogCredentials
|
|
265
273
|
} from "./chunk-M5GB774H.js";
|
|
266
|
-
import "./chunk-5HBA2Z7V.js";
|
|
267
|
-
import "./chunk-T2NCM2ET.js";
|
|
268
274
|
import {
|
|
269
275
|
sanitizeLogText
|
|
270
|
-
} from "./chunk-
|
|
276
|
+
} from "./chunk-RWTEFFPU.js";
|
|
271
277
|
import "./chunk-UDXSXLER.js";
|
|
278
|
+
import "./chunk-5HBA2Z7V.js";
|
|
272
279
|
import {
|
|
273
280
|
getDialogSettingKeys,
|
|
274
281
|
getModelProvidersOwnerScope,
|
|
@@ -278,23 +285,23 @@ import {
|
|
|
278
285
|
getWritableScopes,
|
|
279
286
|
loadSettings,
|
|
280
287
|
validateSettingValue
|
|
281
|
-
} from "./chunk-
|
|
288
|
+
} from "./chunk-TEHGS6UP.js";
|
|
282
289
|
import "./chunk-RKUWKYED.js";
|
|
290
|
+
import "./chunk-GOXKNSDZ.js";
|
|
291
|
+
import "./chunk-IDS7MSUP.js";
|
|
283
292
|
import {
|
|
284
293
|
SUPPORTED_LANGUAGES,
|
|
285
294
|
detectSystemLanguage,
|
|
286
295
|
resolveLanguageSetting,
|
|
287
296
|
resolveSupportedLanguage
|
|
288
|
-
} from "./chunk-
|
|
289
|
-
import "./chunk-
|
|
290
|
-
import "./chunk-
|
|
291
|
-
import "./chunk-
|
|
292
|
-
import "./chunk-QRUIS3DN.js";
|
|
293
|
-
import "./chunk-3EK5ZOUQ.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,23 +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";
|
|
371
|
-
import "./chunk-T5IO6FZ4.js";
|
|
374
|
+
import "./chunk-TWPJO254.js";
|
|
375
|
+
import "./chunk-H6XPXXMH.js";
|
|
376
|
+
import "./chunk-K4XWPEWB.js";
|
|
372
377
|
import {
|
|
373
378
|
MAX_JOBS,
|
|
374
379
|
nextDurableFireMs
|
|
375
|
-
} from "./chunk-
|
|
380
|
+
} from "./chunk-TOFQCPDC.js";
|
|
376
381
|
import {
|
|
377
382
|
nextFireTime,
|
|
378
383
|
parseCron
|
|
379
|
-
} from "./chunk-
|
|
384
|
+
} from "./chunk-IRH27ZC2.js";
|
|
380
385
|
import "./chunk-VDDGDZMA.js";
|
|
381
386
|
import {
|
|
382
387
|
appendCronRun,
|
|
@@ -385,22 +390,27 @@ import {
|
|
|
385
390
|
readCronTasks,
|
|
386
391
|
taskHasLegacyCondition,
|
|
387
392
|
updateCronTasks
|
|
388
|
-
} from "./chunk-
|
|
389
|
-
import "./chunk-
|
|
393
|
+
} from "./chunk-FNQ6T3CV.js";
|
|
394
|
+
import "./chunk-ZOIFNCKL.js";
|
|
395
|
+
import "./chunk-PWTZEM3C.js";
|
|
396
|
+
import "./chunk-KRXPRVGL.js";
|
|
390
397
|
import "./chunk-6PVPNMXU.js";
|
|
398
|
+
import "./chunk-MZAXJAUM.js";
|
|
399
|
+
import "./chunk-SZRN75WQ.js";
|
|
400
|
+
import "./chunk-HTO4JFDZ.js";
|
|
391
401
|
import "./chunk-CPBF7KYF.js";
|
|
392
|
-
import "./chunk-NABLFI57.js";
|
|
393
|
-
import "./chunk-QBUDF33N.js";
|
|
394
|
-
import "./chunk-LIZRAKPB.js";
|
|
395
402
|
import {
|
|
396
403
|
APPROVAL_MODES,
|
|
397
404
|
SubagentError,
|
|
398
405
|
SubagentErrorCode
|
|
399
|
-
} from "./chunk-
|
|
406
|
+
} from "./chunk-L26JL52R.js";
|
|
400
407
|
import "./chunk-6AM5D4ME.js";
|
|
408
|
+
import "./chunk-JZA3JUDJ.js";
|
|
409
|
+
import "./chunk-3QMGYBFN.js";
|
|
401
410
|
import "./chunk-JCW2R7WC.js";
|
|
402
|
-
import "./chunk-
|
|
403
|
-
import "./chunk-
|
|
411
|
+
import "./chunk-M5JM7OSF.js";
|
|
412
|
+
import "./chunk-OHNBB4XR.js";
|
|
413
|
+
import "./chunk-E5TUC6CA.js";
|
|
404
414
|
import {
|
|
405
415
|
QwenOAuth2Client,
|
|
406
416
|
QwenOAuthPollError,
|
|
@@ -409,57 +419,69 @@ import {
|
|
|
409
419
|
isDeviceAuthorizationSuccess,
|
|
410
420
|
isDeviceTokenPending,
|
|
411
421
|
isDeviceTokenSuccess
|
|
412
|
-
} from "./chunk-
|
|
422
|
+
} from "./chunk-EPDRMGT4.js";
|
|
413
423
|
import "./chunk-JESCGQM3.js";
|
|
414
|
-
import "./chunk-
|
|
415
|
-
import "./chunk-
|
|
424
|
+
import "./chunk-NH6KE4JX.js";
|
|
425
|
+
import "./chunk-USTWD7QV.js";
|
|
416
426
|
import "./chunk-XVNQMZ2I.js";
|
|
417
|
-
import "./chunk-CR3C7WXL.js";
|
|
418
427
|
import "./chunk-FODK6UMO.js";
|
|
419
428
|
import "./chunk-GLNBDYUX.js";
|
|
420
429
|
import "./chunk-DJ2GSRLV.js";
|
|
430
|
+
import "./chunk-ZJHVAS7M.js";
|
|
421
431
|
import {
|
|
422
432
|
addDaemonRequestAttribute,
|
|
423
|
-
decodeBufferWithEncodingInfo,
|
|
424
433
|
emitDaemonLog,
|
|
425
|
-
getAllGeminiMdFilenames,
|
|
426
434
|
hashDaemonWorkspace,
|
|
427
|
-
isBinaryFile,
|
|
428
|
-
isWithinRoot,
|
|
429
435
|
recordDaemonBridgeError,
|
|
430
436
|
recordDaemonError,
|
|
431
437
|
recordDaemonHttpRequest,
|
|
432
438
|
recordDaemonHttpResponse,
|
|
433
439
|
withDaemonRequestSpan
|
|
434
|
-
} 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";
|
|
435
454
|
import "./chunk-VGC4I5JJ.js";
|
|
436
|
-
import "./chunk-
|
|
437
|
-
import "./chunk-
|
|
455
|
+
import "./chunk-MUP3T3AD.js";
|
|
456
|
+
import "./chunk-IKCX4CCL.js";
|
|
457
|
+
import "./chunk-46UV252V.js";
|
|
438
458
|
import "./chunk-A4UCTEB5.js";
|
|
439
459
|
import "./chunk-XWRJCPHC.js";
|
|
440
|
-
import "./chunk-
|
|
441
|
-
import "./chunk-
|
|
442
|
-
import "./chunk-
|
|
443
|
-
import
|
|
444
|
-
|
|
445
|
-
} from "./chunk-TYAMGABM.js";
|
|
446
|
-
import "./chunk-FCMNKVXT.js";
|
|
447
|
-
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";
|
|
448
465
|
import "./chunk-HTR4WV6U.js";
|
|
449
|
-
import "./chunk-
|
|
466
|
+
import "./chunk-BULDBTYC.js";
|
|
450
467
|
import "./chunk-U7ZFW55U.js";
|
|
451
|
-
import "./chunk-
|
|
452
|
-
import "./chunk-
|
|
468
|
+
import "./chunk-UUUTRMI2.js";
|
|
469
|
+
import "./chunk-PR75REBZ.js";
|
|
453
470
|
import {
|
|
454
471
|
FatalConfigError,
|
|
455
472
|
Storage,
|
|
456
473
|
createDebugLogger,
|
|
457
474
|
runWithoutDebugLogSession
|
|
458
|
-
} from "./chunk-
|
|
475
|
+
} from "./chunk-NL7LTRLR.js";
|
|
459
476
|
import "./chunk-75DOP5OR.js";
|
|
460
477
|
import "./chunk-DMTGGOSA.js";
|
|
461
478
|
import "./chunk-YQ3U5MUC.js";
|
|
462
|
-
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";
|
|
463
485
|
import {
|
|
464
486
|
init_esbuild_shims
|
|
465
487
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -651,9 +673,9 @@ async function findExistingAncestor(absolute) {
|
|
|
651
673
|
let current = absolute;
|
|
652
674
|
const tailParts = [];
|
|
653
675
|
for (let i = 0; i < MAX_ANCESTOR_HOPS; i++) {
|
|
654
|
-
let
|
|
676
|
+
let stat3 = null;
|
|
655
677
|
try {
|
|
656
|
-
|
|
678
|
+
stat3 = await fsp.stat(current);
|
|
657
679
|
} catch (err) {
|
|
658
680
|
const code = err?.code;
|
|
659
681
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -661,8 +683,8 @@ async function findExistingAncestor(absolute) {
|
|
|
661
683
|
throw err;
|
|
662
684
|
}
|
|
663
685
|
}
|
|
664
|
-
if (
|
|
665
|
-
if (tailParts.length > 0 && !
|
|
686
|
+
if (stat3) {
|
|
687
|
+
if (tailParts.length > 0 && !stat3.isDirectory()) {
|
|
666
688
|
throw new FsError(
|
|
667
689
|
"parse_error",
|
|
668
690
|
`path component is not a directory: ${absolute}`,
|
|
@@ -735,7 +757,7 @@ async function resolveWithinWorkspace(input, boundWorkspaces, intent) {
|
|
|
735
757
|
boundCanonicals
|
|
736
758
|
);
|
|
737
759
|
if (boundCanonical !== void 0) {
|
|
738
|
-
const finalPathIsSymlink = await fsp.lstat(absolute).then((
|
|
760
|
+
const finalPathIsSymlink = await fsp.lstat(absolute).then((stat3) => stat3.isSymbolicLink()).catch((lstatErr) => {
|
|
739
761
|
if (lstatErr.code === "ENOENT" || lstatErr.code === "ENOTDIR") {
|
|
740
762
|
return false;
|
|
741
763
|
}
|
|
@@ -1226,8 +1248,8 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1226
1248
|
const toRead = Math.min(maxBytes, available);
|
|
1227
1249
|
buf = Buffer.allocUnsafe(toRead);
|
|
1228
1250
|
if (toRead > 0) {
|
|
1229
|
-
const
|
|
1230
|
-
buf =
|
|
1251
|
+
const read2 = await fh.read(buf, 0, toRead, offset);
|
|
1252
|
+
buf = read2.bytesRead === toRead ? buf : buf.subarray(0, read2.bytesRead);
|
|
1231
1253
|
}
|
|
1232
1254
|
const afterRead = await fh.stat();
|
|
1233
1255
|
assertSameFile(st, afterRead, p, "read");
|
|
@@ -1768,17 +1790,17 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1768
1790
|
* for their `sendFsError` serializer.
|
|
1769
1791
|
*/
|
|
1770
1792
|
recordAndWrap(err, intent, input) {
|
|
1771
|
-
const
|
|
1793
|
+
const fs6 = wrapAsFsError(err);
|
|
1772
1794
|
this.deps.audit.recordDenied(this.deps.ctx, {
|
|
1773
1795
|
intent,
|
|
1774
1796
|
input,
|
|
1775
|
-
errorKind:
|
|
1776
|
-
hint:
|
|
1797
|
+
errorKind: fs6.kind,
|
|
1798
|
+
hint: fs6.hint,
|
|
1777
1799
|
// Quote the underlying OS / FsError message so audit
|
|
1778
1800
|
// consumers debugging a production incident can see the
|
|
1779
1801
|
// actual cause (errno text, byte counts, glob pattern,
|
|
1780
1802
|
// etc.) rather than just `errorKind` + `hint`.
|
|
1781
|
-
message:
|
|
1803
|
+
message: fs6.message,
|
|
1782
1804
|
// For glob denials (parse_error pattern rejection,
|
|
1783
1805
|
// catastrophic walk failures) the input IS the pattern
|
|
1784
1806
|
// already; surfacing it on the dedicated `pattern` field
|
|
@@ -1787,7 +1809,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1787
1809
|
// branching on intent.
|
|
1788
1810
|
pattern: intent === "glob" ? input : void 0
|
|
1789
1811
|
});
|
|
1790
|
-
return
|
|
1812
|
+
return fs6;
|
|
1791
1813
|
}
|
|
1792
1814
|
};
|
|
1793
1815
|
var CONTENT_HASH_RE = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -1895,9 +1917,9 @@ async function readStableRegularFileBuffer(p, pre) {
|
|
|
1895
1917
|
const out = Buffer.alloc(opened.size);
|
|
1896
1918
|
let offset = 0;
|
|
1897
1919
|
while (offset < opened.size) {
|
|
1898
|
-
const
|
|
1899
|
-
if (
|
|
1900
|
-
offset +=
|
|
1920
|
+
const read2 = await fh.read(out, offset, opened.size - offset, offset);
|
|
1921
|
+
if (read2.bytesRead === 0) break;
|
|
1922
|
+
offset += read2.bytesRead;
|
|
1901
1923
|
}
|
|
1902
1924
|
const afterRead = await fh.stat();
|
|
1903
1925
|
assertSameFile(opened, afterRead, p, "read");
|
|
@@ -2152,15 +2174,15 @@ async function hashRegularFileAtPath(p, pre) {
|
|
|
2152
2174
|
const buf = Buffer.allocUnsafe(64 * 1024);
|
|
2153
2175
|
let offset = 0;
|
|
2154
2176
|
while (offset < opened.size) {
|
|
2155
|
-
const
|
|
2177
|
+
const read2 = await fh.read(
|
|
2156
2178
|
buf,
|
|
2157
2179
|
0,
|
|
2158
2180
|
Math.min(buf.length, opened.size - offset),
|
|
2159
2181
|
offset
|
|
2160
2182
|
);
|
|
2161
|
-
if (
|
|
2162
|
-
hash.update(buf.subarray(0,
|
|
2163
|
-
offset +=
|
|
2183
|
+
if (read2.bytesRead === 0) break;
|
|
2184
|
+
hash.update(buf.subarray(0, read2.bytesRead));
|
|
2185
|
+
offset += read2.bytesRead;
|
|
2164
2186
|
}
|
|
2165
2187
|
} finally {
|
|
2166
2188
|
await fh.close();
|
|
@@ -2524,12 +2546,12 @@ __name(applyReadHeaders, "applyReadHeaders");
|
|
|
2524
2546
|
function sendFsError(res, err, route) {
|
|
2525
2547
|
applyReadHeaders(res);
|
|
2526
2548
|
if (isFsError(err)) {
|
|
2527
|
-
const
|
|
2528
|
-
res.status(
|
|
2529
|
-
errorKind:
|
|
2530
|
-
error:
|
|
2531
|
-
hint:
|
|
2532
|
-
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
|
|
2533
2555
|
});
|
|
2534
2556
|
return;
|
|
2535
2557
|
}
|
|
@@ -2631,13 +2653,13 @@ async function handleGetFile(req, res, deps) {
|
|
|
2631
2653
|
});
|
|
2632
2654
|
return;
|
|
2633
2655
|
}
|
|
2634
|
-
const
|
|
2656
|
+
const fs6 = factory.forRequest({
|
|
2635
2657
|
originatorClientId: clientId ?? void 0,
|
|
2636
2658
|
route: ROUTE2
|
|
2637
2659
|
});
|
|
2638
2660
|
try {
|
|
2639
|
-
const resolved = await
|
|
2640
|
-
const out = await
|
|
2661
|
+
const resolved = await fs6.resolve(queryPath, "read");
|
|
2662
|
+
const out = await fs6.readText(resolved, { maxBytes, line, limit });
|
|
2641
2663
|
const returnedBytes = Buffer.byteLength(out.content, "utf-8");
|
|
2642
2664
|
applyReadHeaders(res);
|
|
2643
2665
|
res.status(200).json({
|
|
@@ -2691,13 +2713,13 @@ async function handleGetFileBytes(req, res, deps) {
|
|
|
2691
2713
|
});
|
|
2692
2714
|
return;
|
|
2693
2715
|
}
|
|
2694
|
-
const
|
|
2716
|
+
const fs6 = factory.forRequest({
|
|
2695
2717
|
originatorClientId: clientId ?? void 0,
|
|
2696
2718
|
route: ROUTE2
|
|
2697
2719
|
});
|
|
2698
2720
|
try {
|
|
2699
|
-
const resolved = await
|
|
2700
|
-
const out = await
|
|
2721
|
+
const resolved = await fs6.resolve(queryPath, "read");
|
|
2722
|
+
const out = await fs6.readBytesWindow(resolved, {
|
|
2701
2723
|
offset: offset ?? 0,
|
|
2702
2724
|
maxBytes: maxBytes ?? DEFAULT_FILE_BYTES_MAX_BYTES
|
|
2703
2725
|
});
|
|
@@ -2725,13 +2747,13 @@ async function handleGetStat(req, res, deps) {
|
|
|
2725
2747
|
if (clientId === null) return;
|
|
2726
2748
|
const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
|
|
2727
2749
|
if (queryPath === null) return;
|
|
2728
|
-
const
|
|
2750
|
+
const fs6 = factory.forRequest({
|
|
2729
2751
|
originatorClientId: clientId ?? void 0,
|
|
2730
2752
|
route: ROUTE2
|
|
2731
2753
|
});
|
|
2732
2754
|
try {
|
|
2733
|
-
const resolved = await
|
|
2734
|
-
const st = await
|
|
2755
|
+
const resolved = await fs6.resolve(queryPath, "stat");
|
|
2756
|
+
const st = await fs6.stat(resolved);
|
|
2735
2757
|
applyReadHeaders(res);
|
|
2736
2758
|
res.status(200).json({
|
|
2737
2759
|
kind: "stat",
|
|
@@ -2754,13 +2776,13 @@ async function handleGetList(req, res, deps) {
|
|
|
2754
2776
|
const queryPath = requireStringQuery(res, req.query["path"], "path", ROUTE2);
|
|
2755
2777
|
if (queryPath === null) return;
|
|
2756
2778
|
const includeIgnored = parseBoolFlag(req.query["includeIgnored"]);
|
|
2757
|
-
const
|
|
2779
|
+
const fs6 = factory.forRequest({
|
|
2758
2780
|
originatorClientId: clientId ?? void 0,
|
|
2759
2781
|
route: ROUTE2
|
|
2760
2782
|
});
|
|
2761
2783
|
try {
|
|
2762
|
-
const resolved = await
|
|
2763
|
-
const entries = await
|
|
2784
|
+
const resolved = await fs6.resolve(queryPath, "list");
|
|
2785
|
+
const entries = await fs6.list(resolved, {
|
|
2764
2786
|
includeIgnored,
|
|
2765
2787
|
maxEntries: MAX_LIST_ENTRIES + 1
|
|
2766
2788
|
});
|
|
@@ -2813,15 +2835,15 @@ async function handleGetGlob(req, res, deps) {
|
|
|
2813
2835
|
}
|
|
2814
2836
|
const cwdRaw = req.query["cwd"];
|
|
2815
2837
|
const cwdString = typeof cwdRaw === "string" && cwdRaw.length > 0 ? cwdRaw : void 0;
|
|
2816
|
-
const
|
|
2838
|
+
const fs6 = factory.forRequest({
|
|
2817
2839
|
originatorClientId: clientId ?? void 0,
|
|
2818
2840
|
route: ROUTE2
|
|
2819
2841
|
});
|
|
2820
2842
|
const start = performance.now();
|
|
2821
2843
|
try {
|
|
2822
|
-
const cwdResolved = cwdString ? await
|
|
2844
|
+
const cwdResolved = cwdString ? await fs6.resolve(cwdString, "list") : void 0;
|
|
2823
2845
|
const cap = maxResults ?? DEFAULT_GLOB_MAX_RESULTS;
|
|
2824
|
-
const probe = await
|
|
2846
|
+
const probe = await fs6.glob(pattern, {
|
|
2825
2847
|
cwd: cwdResolved,
|
|
2826
2848
|
includeIgnored,
|
|
2827
2849
|
maxResults: cap + 1
|
|
@@ -2995,7 +3017,7 @@ function validateClientId(clientId, deps, res) {
|
|
|
2995
3017
|
}
|
|
2996
3018
|
__name(validateClientId, "validateClientId");
|
|
2997
3019
|
function createSetupGithubFileOps(factory, route, originatorClientId) {
|
|
2998
|
-
const
|
|
3020
|
+
const fs6 = factory.forRequest({
|
|
2999
3021
|
route,
|
|
3000
3022
|
...originatorClientId ? { originatorClientId } : {}
|
|
3001
3023
|
});
|
|
@@ -3018,14 +3040,14 @@ function createSetupGithubFileOps(factory, route, originatorClientId) {
|
|
|
3018
3040
|
]);
|
|
3019
3041
|
},
|
|
3020
3042
|
async writeTextFile(_gitRepoRoot, relativePath, content) {
|
|
3021
|
-
const resolved = await
|
|
3022
|
-
const out = await
|
|
3043
|
+
const resolved = await fs6.resolve(relativePath, "write");
|
|
3044
|
+
const out = await fs6.writeTextOverwrite(resolved, content);
|
|
3023
3045
|
return { sizeBytes: out.sizeBytes };
|
|
3024
3046
|
},
|
|
3025
3047
|
async readTextFile(_gitRepoRoot, relativePath) {
|
|
3026
3048
|
try {
|
|
3027
|
-
const resolved = await
|
|
3028
|
-
const out = await
|
|
3049
|
+
const resolved = await fs6.resolve(relativePath, "read");
|
|
3050
|
+
const out = await fs6.readText(resolved);
|
|
3029
3051
|
return out.content;
|
|
3030
3052
|
} catch (error2) {
|
|
3031
3053
|
if (isFsError(error2) && error2.kind === "path_not_found") {
|
|
@@ -3046,15 +3068,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
|
|
|
3046
3068
|
checkedSegments.push(segment);
|
|
3047
3069
|
const label = `Workspace path "${checkedSegments.join("/")}"`;
|
|
3048
3070
|
try {
|
|
3049
|
-
const
|
|
3050
|
-
if (
|
|
3071
|
+
const stat3 = await fsp3.lstat(current);
|
|
3072
|
+
if (stat3.isSymbolicLink()) {
|
|
3051
3073
|
throw new SetupGithubError(
|
|
3052
3074
|
"github_setup_invalid_workspace",
|
|
3053
3075
|
`${label} must not be a symlink.`,
|
|
3054
3076
|
400
|
|
3055
3077
|
);
|
|
3056
3078
|
}
|
|
3057
|
-
if (!
|
|
3079
|
+
if (!stat3.isDirectory()) {
|
|
3058
3080
|
throw new SetupGithubError(
|
|
3059
3081
|
"github_setup_invalid_workspace",
|
|
3060
3082
|
`${label} must be a directory.`,
|
|
@@ -3091,15 +3113,15 @@ async function ensureDirectoryWithoutSymlink(root, segments) {
|
|
|
3091
3113
|
}
|
|
3092
3114
|
__name(ensureDirectoryWithoutSymlink, "ensureDirectoryWithoutSymlink");
|
|
3093
3115
|
async function assertDirectoryWithoutSymlink(target, label) {
|
|
3094
|
-
const
|
|
3095
|
-
if (
|
|
3116
|
+
const stat3 = await fsp3.lstat(target);
|
|
3117
|
+
if (stat3.isSymbolicLink()) {
|
|
3096
3118
|
throw new SetupGithubError(
|
|
3097
3119
|
"github_setup_invalid_workspace",
|
|
3098
3120
|
`${label} must not be a symlink.`,
|
|
3099
3121
|
400
|
|
3100
3122
|
);
|
|
3101
3123
|
}
|
|
3102
|
-
if (!
|
|
3124
|
+
if (!stat3.isDirectory()) {
|
|
3103
3125
|
throw new SetupGithubError(
|
|
3104
3126
|
"github_setup_invalid_workspace",
|
|
3105
3127
|
`${label} must be a directory.`,
|
|
@@ -4740,12 +4762,12 @@ async function collectWorkspaceMemoryStatus(boundWorkspace) {
|
|
|
4740
4762
|
for (const filename of filenames) {
|
|
4741
4763
|
const candidate = path8.join(globalDir, filename);
|
|
4742
4764
|
try {
|
|
4743
|
-
const
|
|
4744
|
-
if (
|
|
4765
|
+
const stat3 = await fs.stat(candidate);
|
|
4766
|
+
if (stat3.isFile()) {
|
|
4745
4767
|
files.push({
|
|
4746
4768
|
absolutePath: candidate,
|
|
4747
4769
|
scope: "global",
|
|
4748
|
-
bytes:
|
|
4770
|
+
bytes: stat3.size
|
|
4749
4771
|
});
|
|
4750
4772
|
}
|
|
4751
4773
|
} catch (err) {
|
|
@@ -4789,12 +4811,12 @@ async function walkWorkspaceForMemory(start, filenames, errors) {
|
|
|
4789
4811
|
for (const filename of filenames) {
|
|
4790
4812
|
const candidate = path8.join(start, filename);
|
|
4791
4813
|
try {
|
|
4792
|
-
const
|
|
4793
|
-
if (
|
|
4814
|
+
const stat3 = await fs.stat(candidate);
|
|
4815
|
+
if (stat3.isFile()) {
|
|
4794
4816
|
out.push({
|
|
4795
4817
|
absolutePath: candidate,
|
|
4796
4818
|
scope: "workspace",
|
|
4797
|
-
bytes:
|
|
4819
|
+
bytes: stat3.size
|
|
4798
4820
|
});
|
|
4799
4821
|
}
|
|
4800
4822
|
} catch (err) {
|
|
@@ -4820,6 +4842,7 @@ __name(isEnoent, "isEnoent");
|
|
|
4820
4842
|
// packages/cli/src/serve/workspace-agents.ts
|
|
4821
4843
|
init_esbuild_shims();
|
|
4822
4844
|
import { promises as fs2 } from "node:fs";
|
|
4845
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4823
4846
|
var AGENT_TYPE_PATTERN = /^[\p{L}\p{N}_-]+$/u;
|
|
4824
4847
|
var AGENT_TYPE_MAX_LENGTH = 64;
|
|
4825
4848
|
var AGENT_TYPE_MIN_LENGTH = 2;
|
|
@@ -4827,6 +4850,27 @@ var MAX_DESCRIPTION_BYTES = 256 * 1024;
|
|
|
4827
4850
|
var MAX_SYSTEM_PROMPT_BYTES = 256 * 1024;
|
|
4828
4851
|
var MAX_TOOLS_ENTRIES = 256;
|
|
4829
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
|
+
];
|
|
4830
4874
|
function mountWorkspaceAgentsRoutes(app, deps) {
|
|
4831
4875
|
const manager = createDaemonSubagentManager(deps.boundWorkspace);
|
|
4832
4876
|
app.get("/workspace/agents", async (_req, res) => {
|
|
@@ -4865,7 +4909,11 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
4865
4909
|
return;
|
|
4866
4910
|
}
|
|
4867
4911
|
const level = scope === "workspace" ? "project" : "user";
|
|
4868
|
-
const config = parseAgentConfig(
|
|
4912
|
+
const config = parseAgentConfig(
|
|
4913
|
+
restoreAgentMcpServerSecrets(body, deps.boundWorkspace, level),
|
|
4914
|
+
level,
|
|
4915
|
+
res
|
|
4916
|
+
);
|
|
4869
4917
|
if (!config) return;
|
|
4870
4918
|
const collision = await manager.loadSubagent(config.name, level);
|
|
4871
4919
|
if (collision) {
|
|
@@ -4981,7 +5029,9 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
4981
5029
|
const agentType = validateAgentType(req, res);
|
|
4982
5030
|
if (agentType === null) return;
|
|
4983
5031
|
try {
|
|
4984
|
-
const
|
|
5032
|
+
const scopedLevel = parseScopeQuery(req, res);
|
|
5033
|
+
if (scopedLevel === null) return;
|
|
5034
|
+
const config = await manager.loadSubagent(agentType, scopedLevel);
|
|
4985
5035
|
if (!config) {
|
|
4986
5036
|
res.status(404).json({
|
|
4987
5037
|
error: `Subagent "${agentType}" not found`,
|
|
@@ -5010,9 +5060,6 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
5010
5060
|
const clientIdResult = resolveOriginatorClientId(deps, req, res);
|
|
5011
5061
|
if (clientIdResult === null) return;
|
|
5012
5062
|
const originatorClientId = clientIdResult;
|
|
5013
|
-
const body = deps.safeBody(req);
|
|
5014
|
-
const updates = parseAgentUpdates(body, res);
|
|
5015
|
-
if (!updates) return;
|
|
5016
5063
|
const preferredLevel = parseScopeQuery(req, res);
|
|
5017
5064
|
if (preferredLevel === null) return;
|
|
5018
5065
|
const existing = await manager.loadSubagent(agentType, preferredLevel);
|
|
@@ -5027,6 +5074,14 @@ function mountWorkspaceAgentsRoutes(app, deps) {
|
|
|
5027
5074
|
if (assertMutableLevel(existing, agentType, res)) {
|
|
5028
5075
|
return;
|
|
5029
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;
|
|
5030
5085
|
if (Object.keys(updates).length === 0) {
|
|
5031
5086
|
res.status(400).json({
|
|
5032
5087
|
error: "`POST /workspace/agents/:agentType` requires at least one updatable field in the body",
|
|
@@ -5270,7 +5325,11 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5270
5325
|
const level = parseWorkspaceOnlyAgentBodyScope(body, res);
|
|
5271
5326
|
if (level === null) return;
|
|
5272
5327
|
const manager = createDaemonSubagentManager(runtime.workspaceCwd);
|
|
5273
|
-
const config = parseAgentConfig(
|
|
5328
|
+
const config = parseAgentConfig(
|
|
5329
|
+
restoreAgentMcpServerSecrets(body, runtime.workspaceCwd, level),
|
|
5330
|
+
level,
|
|
5331
|
+
res
|
|
5332
|
+
);
|
|
5274
5333
|
if (!config) return;
|
|
5275
5334
|
const collision = await manager.loadSubagent(config.name, level);
|
|
5276
5335
|
if (collision) {
|
|
@@ -5359,9 +5418,6 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5359
5418
|
const clientIdResult = resolveOriginatorClientId(routeDeps, req, res);
|
|
5360
5419
|
if (clientIdResult === null) return;
|
|
5361
5420
|
const originatorClientId = clientIdResult;
|
|
5362
|
-
const body = deps.safeBody(req);
|
|
5363
|
-
const updates = parseAgentUpdates(body, res);
|
|
5364
|
-
if (!updates) return;
|
|
5365
5421
|
const manager = createDaemonSubagentManager(runtime.workspaceCwd);
|
|
5366
5422
|
const existing = await manager.loadSubagent(agentType, scopedLevel);
|
|
5367
5423
|
if (!existing) {
|
|
@@ -5373,6 +5429,14 @@ function mountWorkspaceQualifiedAgentsRoutes(app, deps) {
|
|
|
5373
5429
|
return;
|
|
5374
5430
|
}
|
|
5375
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;
|
|
5376
5440
|
if (Object.keys(updates).length === 0) {
|
|
5377
5441
|
res.status(400).json({
|
|
5378
5442
|
error: "`POST /workspaces/:workspace/agents/:agentType` requires at least one updatable field in the body",
|
|
@@ -5628,6 +5692,22 @@ function rejectWorkspaceQualifiedAgentScope(scope, res) {
|
|
|
5628
5692
|
return null;
|
|
5629
5693
|
}
|
|
5630
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");
|
|
5631
5711
|
function sendCreateAgentError(res, err, name) {
|
|
5632
5712
|
if (!(err instanceof SubagentError)) return false;
|
|
5633
5713
|
if (err.code === SubagentErrorCode.ALREADY_EXISTS) {
|
|
@@ -5769,22 +5849,73 @@ function parseAgentConfig(body, level, res) {
|
|
|
5769
5849
|
if (tools !== void 0) config.tools = tools;
|
|
5770
5850
|
if (disallowedTools !== void 0) config.disallowedTools = disallowedTools;
|
|
5771
5851
|
if (rejectIfPresentWrongType(body, "model", "string", res)) return void 0;
|
|
5772
|
-
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
|
+
}
|
|
5773
5858
|
if (rejectIfPresentWrongType(body, "color", "string", res)) return void 0;
|
|
5774
|
-
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
|
+
}
|
|
5775
5868
|
if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
|
|
5776
5869
|
return void 0;
|
|
5777
5870
|
}
|
|
5778
5871
|
if (typeof body["approvalMode"] === "string") {
|
|
5779
|
-
if (!
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
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
|
+
);
|
|
5785
5877
|
}
|
|
5786
5878
|
config.approvalMode = body["approvalMode"];
|
|
5787
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
|
+
}
|
|
5788
5919
|
if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
|
|
5789
5920
|
return void 0;
|
|
5790
5921
|
}
|
|
@@ -5854,23 +5985,86 @@ function parseAgentUpdates(body, res) {
|
|
|
5854
5985
|
updates.disallowedTools = disallowedTools;
|
|
5855
5986
|
}
|
|
5856
5987
|
}
|
|
5857
|
-
if (
|
|
5858
|
-
|
|
5859
|
-
if (rejectIfPresentWrongType(body, "
|
|
5860
|
-
if (typeof body["color"] === "string") updates.color = body["color"];
|
|
5861
|
-
if (rejectIfPresentWrongType(body, "approvalMode", "string", res)) {
|
|
5988
|
+
if (body["model"] === null) {
|
|
5989
|
+
updates.model = void 0;
|
|
5990
|
+
} else if (rejectIfPresentWrongType(body, "model", "string", res)) {
|
|
5862
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();
|
|
5863
5997
|
}
|
|
5864
|
-
if (
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
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
|
+
);
|
|
5871
6021
|
}
|
|
5872
6022
|
updates.approvalMode = body["approvalMode"];
|
|
5873
6023
|
}
|
|
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
|
+
}
|
|
5874
6068
|
if (rejectIfPresentWrongType(body, "background", "boolean", res)) {
|
|
5875
6069
|
return void 0;
|
|
5876
6070
|
}
|
|
@@ -5911,6 +6105,43 @@ function parseStringArray(value, field, res) {
|
|
|
5911
6105
|
return value;
|
|
5912
6106
|
}
|
|
5913
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");
|
|
5914
6145
|
function rejectIfPresentWrongType(body, key, expected, res) {
|
|
5915
6146
|
if (!(key in body)) return false;
|
|
5916
6147
|
if (typeof body[key] === expected) return false;
|
|
@@ -5934,13 +6165,31 @@ function isNoOpUpdate(existing, updates) {
|
|
|
5934
6165
|
if (updates.disallowedTools !== void 0 && !shallowArrayEqual(updates.disallowedTools, existing.disallowedTools)) {
|
|
5935
6166
|
return false;
|
|
5936
6167
|
}
|
|
5937
|
-
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) {
|
|
5938
6181
|
return false;
|
|
5939
6182
|
}
|
|
5940
|
-
if (updates.
|
|
6183
|
+
if (updates.mcpServers !== void 0 && !isDeepStrictEqual(
|
|
6184
|
+
normalizedRecord(updates.mcpServers),
|
|
6185
|
+
normalizedRecord(existing.mcpServers)
|
|
6186
|
+
)) {
|
|
5941
6187
|
return false;
|
|
5942
6188
|
}
|
|
5943
|
-
if (updates.
|
|
6189
|
+
if (updates.hooks !== void 0 && !isDeepStrictEqual(
|
|
6190
|
+
normalizedRecord(updates.hooks),
|
|
6191
|
+
normalizedRecord(existing.hooks)
|
|
6192
|
+
)) {
|
|
5944
6193
|
return false;
|
|
5945
6194
|
}
|
|
5946
6195
|
if (updates.background !== void 0 && updates.background !== existing.background) {
|
|
@@ -5959,7 +6208,20 @@ function isNoOpUpdate(existing, updates) {
|
|
|
5959
6208
|
return true;
|
|
5960
6209
|
}
|
|
5961
6210
|
__name(isNoOpUpdate, "isNoOpUpdate");
|
|
5962
|
-
function
|
|
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");
|
|
6224
|
+
function shallowArrayEqual(a, b) {
|
|
5963
6225
|
if (a === b) return true;
|
|
5964
6226
|
if (!a || !b) return false;
|
|
5965
6227
|
if (a.length !== b.length) return false;
|
|
@@ -6011,10 +6273,30 @@ function toSummary(config) {
|
|
|
6011
6273
|
isBuiltin: config.isBuiltin === true || config.level === "builtin",
|
|
6012
6274
|
hasTools: Array.isArray(config.tools) && config.tools.length > 0
|
|
6013
6275
|
};
|
|
6276
|
+
if (config.tools) summary.tools = [...config.tools];
|
|
6277
|
+
if (config.disallowedTools) {
|
|
6278
|
+
summary.disallowedTools = [...config.disallowedTools];
|
|
6279
|
+
}
|
|
6014
6280
|
if (config.model) summary.model = config.model;
|
|
6015
6281
|
if (config.color) summary.color = config.color;
|
|
6016
6282
|
if (config.background !== void 0) summary.background = config.background;
|
|
6017
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
|
+
}
|
|
6018
6300
|
if (config.extensionName) summary.extensionName = config.extensionName;
|
|
6019
6301
|
if (config.filePath) summary.filePath = config.filePath;
|
|
6020
6302
|
return summary;
|
|
@@ -6025,20 +6307,10 @@ function toDetail(config) {
|
|
|
6025
6307
|
...toSummary(config),
|
|
6026
6308
|
systemPrompt: config.systemPrompt
|
|
6027
6309
|
};
|
|
6028
|
-
if (config.
|
|
6029
|
-
|
|
6030
|
-
detail.disallowedTools = [...config.disallowedTools];
|
|
6031
|
-
}
|
|
6032
|
-
if (config.runConfig) {
|
|
6033
|
-
const runConfig = {};
|
|
6034
|
-
if (typeof config.runConfig.max_time_minutes === "number") {
|
|
6035
|
-
runConfig.max_time_minutes = config.runConfig.max_time_minutes;
|
|
6036
|
-
}
|
|
6037
|
-
if (typeof config.runConfig.max_turns === "number") {
|
|
6038
|
-
runConfig.max_turns = config.runConfig.max_turns;
|
|
6039
|
-
}
|
|
6040
|
-
detail.runConfig = runConfig;
|
|
6310
|
+
if (config.mcpServers) {
|
|
6311
|
+
detail.mcpServers = redactMcpServersSetting(config.mcpServers);
|
|
6041
6312
|
}
|
|
6313
|
+
if (config.hooks) detail.hooks = config.hooks;
|
|
6042
6314
|
return detail;
|
|
6043
6315
|
}
|
|
6044
6316
|
__name(toDetail, "toDetail");
|
|
@@ -9046,7 +9318,7 @@ var AcpDispatcher = class {
|
|
|
9046
9318
|
);
|
|
9047
9319
|
return;
|
|
9048
9320
|
}
|
|
9049
|
-
const
|
|
9321
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9050
9322
|
originatorClientId: conn.clientId,
|
|
9051
9323
|
route: `ACP ${method}`
|
|
9052
9324
|
});
|
|
@@ -9098,8 +9370,8 @@ var AcpDispatcher = class {
|
|
|
9098
9370
|
);
|
|
9099
9371
|
return;
|
|
9100
9372
|
}
|
|
9101
|
-
const resolved = await
|
|
9102
|
-
const out = await
|
|
9373
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9374
|
+
const out = await fs6.readText(resolved, { maxBytes, line, limit });
|
|
9103
9375
|
this.replyConn(conn, id, {
|
|
9104
9376
|
path: p,
|
|
9105
9377
|
content: out.content,
|
|
@@ -9121,7 +9393,7 @@ var AcpDispatcher = class {
|
|
|
9121
9393
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9122
9394
|
return;
|
|
9123
9395
|
}
|
|
9124
|
-
const
|
|
9396
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9125
9397
|
originatorClientId: conn.clientId,
|
|
9126
9398
|
route: `ACP ${method}`
|
|
9127
9399
|
});
|
|
@@ -9157,8 +9429,8 @@ var AcpDispatcher = class {
|
|
|
9157
9429
|
);
|
|
9158
9430
|
return;
|
|
9159
9431
|
}
|
|
9160
|
-
const resolved = await
|
|
9161
|
-
const buf = await
|
|
9432
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9433
|
+
const buf = await fs6.readBytesWindow(resolved, { offset, maxBytes });
|
|
9162
9434
|
this.replyConn(conn, id, { path: p, ...buf });
|
|
9163
9435
|
return;
|
|
9164
9436
|
}
|
|
@@ -9176,12 +9448,12 @@ var AcpDispatcher = class {
|
|
|
9176
9448
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9177
9449
|
return;
|
|
9178
9450
|
}
|
|
9179
|
-
const
|
|
9451
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9180
9452
|
originatorClientId: conn.clientId,
|
|
9181
9453
|
route: `ACP ${method}`
|
|
9182
9454
|
});
|
|
9183
|
-
const resolved = await
|
|
9184
|
-
const result = await
|
|
9455
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9456
|
+
const result = await fs6.stat(resolved);
|
|
9185
9457
|
this.replyConn(conn, id, { path: p, ...result });
|
|
9186
9458
|
return;
|
|
9187
9459
|
}
|
|
@@ -9199,13 +9471,13 @@ var AcpDispatcher = class {
|
|
|
9199
9471
|
conn.sendConn(error(id, RPC.INVALID_PARAMS, "`path` required"));
|
|
9200
9472
|
return;
|
|
9201
9473
|
}
|
|
9202
|
-
const
|
|
9474
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9203
9475
|
originatorClientId: conn.clientId,
|
|
9204
9476
|
route: `ACP ${method}`
|
|
9205
9477
|
});
|
|
9206
|
-
const resolved = await
|
|
9478
|
+
const resolved = await fs6.resolve(p, "read");
|
|
9207
9479
|
const MAX_LIST = 2e3;
|
|
9208
|
-
const entries = await
|
|
9480
|
+
const entries = await fs6.list(resolved, { maxEntries: MAX_LIST + 1 });
|
|
9209
9481
|
const truncated = entries.length > MAX_LIST;
|
|
9210
9482
|
this.replyConn(conn, id, {
|
|
9211
9483
|
path: p,
|
|
@@ -9230,7 +9502,7 @@ var AcpDispatcher = class {
|
|
|
9230
9502
|
);
|
|
9231
9503
|
return;
|
|
9232
9504
|
}
|
|
9233
|
-
const
|
|
9505
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9234
9506
|
originatorClientId: conn.clientId,
|
|
9235
9507
|
route: `ACP ${method}`
|
|
9236
9508
|
});
|
|
@@ -9250,7 +9522,7 @@ var AcpDispatcher = class {
|
|
|
9250
9522
|
);
|
|
9251
9523
|
return;
|
|
9252
9524
|
}
|
|
9253
|
-
const matches = await
|
|
9525
|
+
const matches = await fs6.glob(pattern, {
|
|
9254
9526
|
maxResults: maxResults + 1
|
|
9255
9527
|
});
|
|
9256
9528
|
const truncated = matches.length > maxResults;
|
|
@@ -9282,11 +9554,11 @@ var AcpDispatcher = class {
|
|
|
9282
9554
|
);
|
|
9283
9555
|
return;
|
|
9284
9556
|
}
|
|
9285
|
-
const
|
|
9557
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9286
9558
|
originatorClientId: conn.clientId,
|
|
9287
9559
|
route: `ACP ${method}`
|
|
9288
9560
|
});
|
|
9289
|
-
const resolved = await
|
|
9561
|
+
const resolved = await fs6.resolve(p, "write");
|
|
9290
9562
|
if (Buffer.byteLength(params["content"], "utf8") > 10 * 1024 * 1024) {
|
|
9291
9563
|
if (id !== void 0)
|
|
9292
9564
|
conn.sendConn(
|
|
@@ -9294,7 +9566,7 @@ var AcpDispatcher = class {
|
|
|
9294
9566
|
);
|
|
9295
9567
|
return;
|
|
9296
9568
|
}
|
|
9297
|
-
await
|
|
9569
|
+
await fs6.writeTextOverwrite(resolved, params["content"]);
|
|
9298
9570
|
this.replyConn(conn, id, { ok: true, path: p });
|
|
9299
9571
|
return;
|
|
9300
9572
|
}
|
|
@@ -9323,12 +9595,12 @@ var AcpDispatcher = class {
|
|
|
9323
9595
|
);
|
|
9324
9596
|
return;
|
|
9325
9597
|
}
|
|
9326
|
-
const
|
|
9598
|
+
const fs6 = this.fsFactory.forRequest({
|
|
9327
9599
|
originatorClientId: conn.clientId,
|
|
9328
9600
|
route: `ACP ${method}`
|
|
9329
9601
|
});
|
|
9330
|
-
const resolved = await
|
|
9331
|
-
const result = await
|
|
9602
|
+
const resolved = await fs6.resolve(p, "write");
|
|
9603
|
+
const result = await fs6.edit(
|
|
9332
9604
|
resolved,
|
|
9333
9605
|
params["oldText"],
|
|
9334
9606
|
params["newText"]
|
|
@@ -9872,11 +10144,24 @@ var AcpDispatcher = class {
|
|
|
9872
10144
|
}
|
|
9873
10145
|
}
|
|
9874
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
|
+
}
|
|
9875
10160
|
/**
|
|
9876
10161
|
* Bind a session-scoped SSE stream to the bridge's event stream,
|
|
9877
10162
|
* translating each `BridgeEvent` into a JSON-RPC frame (design §4.2).
|
|
9878
10163
|
*/
|
|
9879
|
-
async pumpSessionEvents(conn, sessionId, signal, lastEventId) {
|
|
10164
|
+
async pumpSessionEvents(conn, sessionId, signal, lastEventId, epoch) {
|
|
9880
10165
|
try {
|
|
9881
10166
|
let lastDeliveredId = lastEventId ?? 0;
|
|
9882
10167
|
let sawEviction = false;
|
|
@@ -9884,6 +10169,11 @@ var AcpDispatcher = class {
|
|
|
9884
10169
|
if (conn.hasInitialReplayPending(sessionId)) {
|
|
9885
10170
|
const snapshot = this.bridge.getSessionReplaySnapshot(sessionId);
|
|
9886
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
|
+
}
|
|
9887
10177
|
const snapshotEvents = [
|
|
9888
10178
|
...snapshot.compactedTurns,
|
|
9889
10179
|
...snapshot.liveJournal
|
|
@@ -9916,7 +10206,8 @@ var AcpDispatcher = class {
|
|
|
9916
10206
|
}
|
|
9917
10207
|
const iterable = this.bridge.subscribeEvents(sessionId, {
|
|
9918
10208
|
signal,
|
|
9919
|
-
...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {}
|
|
10209
|
+
...subscribeFromEventId !== void 0 ? { lastEventId: subscribeFromEventId } : {},
|
|
10210
|
+
...epoch !== void 0 ? { epoch } : {}
|
|
9920
10211
|
});
|
|
9921
10212
|
for await (const event of iterable) {
|
|
9922
10213
|
if (signal.aborted) break;
|
|
@@ -11029,6 +11320,17 @@ function parseLastEventId2(raw, logPrefix = "") {
|
|
|
11029
11320
|
return n;
|
|
11030
11321
|
}
|
|
11031
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");
|
|
11032
11334
|
|
|
11033
11335
|
// packages/cli/src/serve/acp-http/client-mcp-ws.ts
|
|
11034
11336
|
init_esbuild_shims();
|
|
@@ -12392,11 +12694,19 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
12392
12694
|
},
|
|
12393
12695
|
() => conn.touch()
|
|
12394
12696
|
);
|
|
12395
|
-
stream.open();
|
|
12396
12697
|
const lastEventId = parseLastEventId2(
|
|
12397
12698
|
headerOf(req, "last-event-id"),
|
|
12398
12699
|
"/acp "
|
|
12399
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();
|
|
12400
12710
|
conn.attachSessionStream(sessionId, stream, ac, lastEventId);
|
|
12401
12711
|
const onPumpSettled = /* @__PURE__ */ __name(() => {
|
|
12402
12712
|
if (stream.isClosed) {
|
|
@@ -12412,7 +12722,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
12412
12722
|
);
|
|
12413
12723
|
}
|
|
12414
12724
|
}, "onPumpSettled");
|
|
12415
|
-
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) => {
|
|
12416
12726
|
writeStderrLine(
|
|
12417
12727
|
`qwen serve: ${mount.routeLabel} event pump error (${logSafe(sessionId)}, lastEventId=${lastEventId ?? "none"}): ${logSafe(err instanceof Error ? err.message : String(err))}`
|
|
12418
12728
|
);
|
|
@@ -13865,6 +14175,130 @@ function mountWebShellSpaFallback(app, webShellDir, frameAncestors = []) {
|
|
|
13865
14175
|
}
|
|
13866
14176
|
__name(mountWebShellSpaFallback, "mountWebShellSpaFallback");
|
|
13867
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
|
+
|
|
13868
14302
|
// packages/cli/src/serve/routes/daemon-status.ts
|
|
13869
14303
|
init_esbuild_shims();
|
|
13870
14304
|
function registerDaemonStatusRoutes(app, deps) {
|
|
@@ -17519,13 +17953,13 @@ async function handlePostFileWrite(req, res, deps) {
|
|
|
17519
17953
|
req
|
|
17520
17954
|
);
|
|
17521
17955
|
if (originatorClientId === null) return;
|
|
17522
|
-
const
|
|
17956
|
+
const fs6 = factory.forRequest({
|
|
17523
17957
|
originatorClientId,
|
|
17524
17958
|
route: ROUTE2
|
|
17525
17959
|
});
|
|
17526
17960
|
try {
|
|
17527
|
-
const resolved = await
|
|
17528
|
-
const out = await
|
|
17961
|
+
const resolved = await fs6.resolve(queryPath, "write");
|
|
17962
|
+
const out = await fs6.writeTextAtomic(resolved, content, {
|
|
17529
17963
|
mode,
|
|
17530
17964
|
...expectedHash ? { expectedHash } : {},
|
|
17531
17965
|
...bom !== void 0 ? { bom } : {},
|
|
@@ -17578,13 +18012,13 @@ async function handlePostFileEdit(req, res, deps) {
|
|
|
17578
18012
|
req
|
|
17579
18013
|
);
|
|
17580
18014
|
if (originatorClientId === null) return;
|
|
17581
|
-
const
|
|
18015
|
+
const fs6 = factory.forRequest({
|
|
17582
18016
|
originatorClientId,
|
|
17583
18017
|
route: ROUTE2
|
|
17584
18018
|
});
|
|
17585
18019
|
try {
|
|
17586
|
-
const resolved = await
|
|
17587
|
-
const out = await
|
|
18020
|
+
const resolved = await fs6.resolve(queryPath, "edit");
|
|
18021
|
+
const out = await fs6.editAtomic(resolved, oldText, newText, {
|
|
17588
18022
|
expectedHash
|
|
17589
18023
|
});
|
|
17590
18024
|
applyReadHeaders(res);
|
|
@@ -17912,6 +18346,18 @@ var legacySessionTelemetryRoutes = [
|
|
|
17912
18346
|
attribution: "handler_resolved",
|
|
17913
18347
|
route: "GET /session/:id/tasks"
|
|
17914
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
|
+
},
|
|
17915
18361
|
{
|
|
17916
18362
|
method: "GET",
|
|
17917
18363
|
path: "/session/:id/lsp",
|
|
@@ -18594,7 +19040,7 @@ __name(registerPermissionRoutes, "registerPermissionRoutes");
|
|
|
18594
19040
|
// packages/cli/src/serve/routes/session.ts
|
|
18595
19041
|
init_esbuild_shims();
|
|
18596
19042
|
import * as crypto3 from "node:crypto";
|
|
18597
|
-
import * as
|
|
19043
|
+
import * as fs4 from "node:fs";
|
|
18598
19044
|
import * as path10 from "node:path";
|
|
18599
19045
|
|
|
18600
19046
|
// packages/cli/src/serve/server/prompt-deadline.ts
|
|
@@ -18887,7 +19333,17 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
18887
19333
|
organization
|
|
18888
19334
|
)
|
|
18889
19335
|
);
|
|
18890
|
-
} 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
|
+
) {
|
|
18891
19347
|
bySessionId.set(
|
|
18892
19348
|
live.sessionId,
|
|
18893
19349
|
applyOrganization(
|
|
@@ -18969,7 +19425,13 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
|
|
|
18969
19425
|
live.sessionId,
|
|
18970
19426
|
mergeLiveSessionSummary(existing, live)
|
|
18971
19427
|
);
|
|
18972
|
-
} 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
|
+
) {
|
|
18973
19435
|
bySessionId.set(live.sessionId, {
|
|
18974
19436
|
...live,
|
|
18975
19437
|
createdAt: live.createdAt,
|
|
@@ -19072,7 +19534,14 @@ async function listWorkspaceSessionsForResponse(bridge, workspaceCwd, options, r
|
|
|
19072
19534
|
const existing = bySessionId.get(live.sessionId);
|
|
19073
19535
|
if (existing) {
|
|
19074
19536
|
bySessionId.set(live.sessionId, mergeLiveSessionSummary(existing, live));
|
|
19075
|
-
} 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))) {
|
|
19076
19545
|
bySessionId.set(live.sessionId, {
|
|
19077
19546
|
...live,
|
|
19078
19547
|
createdAt: live.createdAt,
|
|
@@ -19200,108 +19669,846 @@ async function exportSessionTranscript(params) {
|
|
|
19200
19669
|
}
|
|
19201
19670
|
__name(exportSessionTranscript, "exportSessionTranscript");
|
|
19202
19671
|
|
|
19203
|
-
// packages/cli/src/serve/
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
var
|
|
19208
|
-
var
|
|
19209
|
-
|
|
19210
|
-
|
|
19211
|
-
|
|
19212
|
-
|
|
19213
|
-
|
|
19214
|
-
|
|
19215
|
-
|
|
19216
|
-
|
|
19217
|
-
}
|
|
19218
|
-
|
|
19219
|
-
function formatGenerationSse(event, data) {
|
|
19220
|
-
return `event: ${event}
|
|
19221
|
-
data: ${JSON.stringify({ v: 1, ...data })}
|
|
19222
|
-
|
|
19223
|
-
`;
|
|
19224
|
-
}
|
|
19225
|
-
__name(formatGenerationSse, "formatGenerationSse");
|
|
19226
|
-
function writeGenerationSseChunk(res, chunk) {
|
|
19227
|
-
if (res.destroyed) {
|
|
19228
|
-
return Promise.reject(new Error("Generation SSE connection destroyed"));
|
|
19229
|
-
}
|
|
19230
|
-
const writable = res.write(chunk);
|
|
19231
|
-
const flush = res.flush;
|
|
19232
|
-
flush?.call(res);
|
|
19233
|
-
if (writable) {
|
|
19234
|
-
return res.destroyed ? Promise.reject(new Error("Generation SSE connection destroyed")) : Promise.resolve();
|
|
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;
|
|
19235
19688
|
}
|
|
19236
|
-
|
|
19237
|
-
|
|
19238
|
-
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19246
|
-
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19252
|
-
|
|
19253
|
-
|
|
19254
|
-
|
|
19255
|
-
|
|
19256
|
-
|
|
19257
|
-
|
|
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
|
+
}
|
|
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
|
|
19258
19715
|
});
|
|
19259
19716
|
}
|
|
19260
|
-
__name(
|
|
19261
|
-
function
|
|
19262
|
-
|
|
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
|
+
});
|
|
19263
19723
|
}
|
|
19264
|
-
__name(
|
|
19265
|
-
function
|
|
19266
|
-
|
|
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
|
|
19729
|
+
});
|
|
19267
19730
|
}
|
|
19268
|
-
__name(
|
|
19269
|
-
|
|
19270
|
-
|
|
19271
|
-
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
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
|
|
19275
19746
|
});
|
|
19276
|
-
|
|
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
|
+
};
|
|
19277
19813
|
}
|
|
19278
|
-
__name(
|
|
19279
|
-
function
|
|
19280
|
-
|
|
19281
|
-
|
|
19814
|
+
__name(findToolCallMetrics, "findToolCallMetrics");
|
|
19815
|
+
function encodePart(value) {
|
|
19816
|
+
return Buffer.from(value, "utf8").toString("base64url");
|
|
19817
|
+
}
|
|
19818
|
+
__name(encodePart, "encodePart");
|
|
19819
|
+
function decodePart(value) {
|
|
19820
|
+
try {
|
|
19821
|
+
return Buffer.from(value, "base64url").toString("utf8");
|
|
19822
|
+
} catch {
|
|
19823
|
+
return void 0;
|
|
19282
19824
|
}
|
|
19283
|
-
res.status(400).json({
|
|
19284
|
-
v: 1,
|
|
19285
|
-
error: {
|
|
19286
|
-
code: err.code,
|
|
19287
|
-
message: err.message,
|
|
19288
|
-
...err.field ? { field: err.field } : {}
|
|
19289
|
-
}
|
|
19290
|
-
});
|
|
19291
|
-
return true;
|
|
19292
19825
|
}
|
|
19293
|
-
__name(
|
|
19294
|
-
function
|
|
19295
|
-
|
|
19296
|
-
|
|
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");
|
|
19297
19834
|
}
|
|
19298
|
-
|
|
19299
|
-
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19303
|
-
|
|
19304
|
-
|
|
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) {
|
|
20477
|
+
if (clientId !== void 0) return true;
|
|
20478
|
+
res.status(403).json({
|
|
20479
|
+
error: "Session artifact access requires a session-bound client id",
|
|
20480
|
+
code: "client_id_required",
|
|
20481
|
+
errorKind: "client_id_required"
|
|
20482
|
+
});
|
|
20483
|
+
return false;
|
|
20484
|
+
}
|
|
20485
|
+
__name(requireSessionArtifactClientId, "requireSessionArtifactClientId");
|
|
20486
|
+
function sendArtifactValidationError(res, err) {
|
|
20487
|
+
if (!(err instanceof SessionArtifactValidationError)) {
|
|
20488
|
+
return false;
|
|
20489
|
+
}
|
|
20490
|
+
res.status(400).json({
|
|
20491
|
+
v: 1,
|
|
20492
|
+
error: {
|
|
20493
|
+
code: err.code,
|
|
20494
|
+
message: err.message,
|
|
20495
|
+
...err.field ? { field: err.field } : {}
|
|
20496
|
+
}
|
|
20497
|
+
});
|
|
20498
|
+
return true;
|
|
20499
|
+
}
|
|
20500
|
+
__name(sendArtifactValidationError, "sendArtifactValidationError");
|
|
20501
|
+
function sendSessionOrganizationError(res, err) {
|
|
20502
|
+
if (!(err instanceof SessionOrganizationError)) {
|
|
20503
|
+
return false;
|
|
20504
|
+
}
|
|
20505
|
+
const status = err.code === "group_name_conflict" ? 409 : err.code === "group_not_found" ? 404 : err.code === "session_organization_store_unreadable" ? 500 : 400;
|
|
20506
|
+
res.status(status).json({
|
|
20507
|
+
error: err.message,
|
|
20508
|
+
code: err.code,
|
|
20509
|
+
...err.field !== void 0 ? { field: err.field } : {}
|
|
20510
|
+
});
|
|
20511
|
+
return true;
|
|
19305
20512
|
}
|
|
19306
20513
|
__name(sendSessionOrganizationError, "sendSessionOrganizationError");
|
|
19307
20514
|
function parseTranscriptLimitQuery(rawLimit, res) {
|
|
@@ -19426,11 +20633,40 @@ function registerSessionRoutes(app, deps) {
|
|
|
19426
20633
|
sendBridgeError: sendBridgeError2,
|
|
19427
20634
|
daemonLog,
|
|
19428
20635
|
promptDeadlineMs,
|
|
19429
|
-
sessionShellCommandEnabled
|
|
20636
|
+
sessionShellCommandEnabled,
|
|
20637
|
+
virtualSubagentSessions
|
|
19430
20638
|
} = deps;
|
|
19431
20639
|
const LANGUAGE_CODES = deps.languageCodes;
|
|
19432
20640
|
const transcriptCursorMasterKey = crypto3.randomBytes(32);
|
|
19433
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");
|
|
19434
20670
|
const getTranscriptCursorCodec = /* @__PURE__ */ __name((runtime) => {
|
|
19435
20671
|
const canonicalCwd = canonicalizeWorkspace(runtime.workspaceCwd);
|
|
19436
20672
|
const cacheKey = `${runtime.workspaceId}\0${canonicalCwd}`;
|
|
@@ -20011,6 +21247,138 @@ function registerSessionRoutes(app, deps) {
|
|
|
20011
21247
|
}
|
|
20012
21248
|
const clientId = parseClientIdHeader(req, res);
|
|
20013
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
|
+
}
|
|
20014
21382
|
let worktreeMeta;
|
|
20015
21383
|
const rawWorktree = body["worktree"];
|
|
20016
21384
|
if (rawWorktree !== void 0 && rawWorktree !== null) {
|
|
@@ -20082,7 +21450,8 @@ function registerSessionRoutes(app, deps) {
|
|
|
20082
21450
|
...approvalMode !== void 0 ? { approvalMode } : {},
|
|
20083
21451
|
...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
|
|
20084
21452
|
...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
|
|
20085
|
-
...worktreeMeta ? { worktree: worktreeMeta } : {}
|
|
21453
|
+
...worktreeMeta ? { worktree: worktreeMeta } : {},
|
|
21454
|
+
...branchMeta ? { branch: branchMeta } : {}
|
|
20086
21455
|
});
|
|
20087
21456
|
if (daemonLog) {
|
|
20088
21457
|
daemonLog.info(
|
|
@@ -20113,12 +21482,30 @@ function registerSessionRoutes(app, deps) {
|
|
|
20113
21482
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
20114
21483
|
});
|
|
20115
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);
|
|
20116
21496
|
}
|
|
20117
21497
|
} catch {
|
|
21498
|
+
if (branchMeta) {
|
|
21499
|
+
activeBranchSessions.set(workspaceCwd, session.sessionId);
|
|
21500
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21501
|
+
}
|
|
20118
21502
|
}
|
|
20119
21503
|
} else {
|
|
20120
21504
|
runtime.bridge.detachClient(session.sessionId, session.clientId).catch(() => {
|
|
20121
21505
|
});
|
|
21506
|
+
if (branchMeta) {
|
|
21507
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21508
|
+
}
|
|
20122
21509
|
}
|
|
20123
21510
|
return;
|
|
20124
21511
|
}
|
|
@@ -20183,18 +21570,79 @@ function registerSessionRoutes(app, deps) {
|
|
|
20183
21570
|
return;
|
|
20184
21571
|
}
|
|
20185
21572
|
}
|
|
21573
|
+
if (branchMeta) {
|
|
21574
|
+
activeBranchSessions.set(workspaceCwd, session.sessionId);
|
|
21575
|
+
inFlightBranchWorkspaces.delete(workspaceCwd);
|
|
21576
|
+
}
|
|
20186
21577
|
res.status(200).json(session);
|
|
20187
21578
|
} catch (err) {
|
|
20188
21579
|
if (worktreeMeta) {
|
|
20189
21580
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
20190
21581
|
});
|
|
20191
21582
|
}
|
|
21583
|
+
if (branchMeta) {
|
|
21584
|
+
await rollbackBranchCreation(
|
|
21585
|
+
workspaceCwd,
|
|
21586
|
+
branchMeta,
|
|
21587
|
+
branchBaseCommit,
|
|
21588
|
+
daemonLog
|
|
21589
|
+
);
|
|
21590
|
+
}
|
|
20192
21591
|
sendBridgeError2(res, err, { route: "POST /session" });
|
|
20193
21592
|
}
|
|
20194
21593
|
});
|
|
20195
21594
|
const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
|
|
20196
21595
|
const sessionId = requireSessionId(req, res);
|
|
20197
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
|
+
}
|
|
20198
21646
|
const body = safeBody(req);
|
|
20199
21647
|
const route = `POST /session/:id/${action}`;
|
|
20200
21648
|
let resolvedRuntime;
|
|
@@ -20284,7 +21732,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
20284
21732
|
path10.join(workspaceCwd, ".qwen", "worktrees")
|
|
20285
21733
|
];
|
|
20286
21734
|
try {
|
|
20287
|
-
realTarget =
|
|
21735
|
+
realTarget = fs4.realpathSync(sidecar.worktreePath);
|
|
20288
21736
|
let repoTop = null;
|
|
20289
21737
|
try {
|
|
20290
21738
|
repoTop = await new GitWorktreeService(
|
|
@@ -20297,7 +21745,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
20297
21745
|
}
|
|
20298
21746
|
const contained = candidateRoots.some((root) => {
|
|
20299
21747
|
try {
|
|
20300
|
-
const realRoot =
|
|
21748
|
+
const realRoot = fs4.realpathSync(root);
|
|
20301
21749
|
const rel = path10.relative(realRoot, realTarget);
|
|
20302
21750
|
return !rel.startsWith("..") && !path10.isAbsolute(rel);
|
|
20303
21751
|
} catch {
|
|
@@ -20340,18 +21788,124 @@ function registerSessionRoutes(app, deps) {
|
|
|
20340
21788
|
}
|
|
20341
21789
|
}
|
|
20342
21790
|
}
|
|
20343
|
-
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);
|
|
20344
21847
|
} catch (err) {
|
|
20345
|
-
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,
|
|
20346
21876
|
route,
|
|
20347
|
-
|
|
21877
|
+
res,
|
|
21878
|
+
workspaceRegistry,
|
|
21879
|
+
daemonLog
|
|
20348
21880
|
});
|
|
20349
|
-
|
|
20350
|
-
|
|
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
|
+
}
|
|
20351
21907
|
}
|
|
20352
|
-
|
|
20353
|
-
app.post("/session/:id/load", mutate(), restoreSessionHandler("load"));
|
|
20354
|
-
app.post("/session/:id/resume", mutate(), restoreSessionHandler("resume"));
|
|
21908
|
+
);
|
|
20355
21909
|
app.post(
|
|
20356
21910
|
"/session/:id/branch",
|
|
20357
21911
|
mutate(),
|
|
@@ -20651,6 +22205,28 @@ function registerSessionRoutes(app, deps) {
|
|
|
20651
22205
|
});
|
|
20652
22206
|
app.get(
|
|
20653
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
|
+
},
|
|
20654
22230
|
withOwnerReadSession(
|
|
20655
22231
|
"GET /session/:id/context",
|
|
20656
22232
|
async (_req, res, sessionId, runtime) => {
|
|
@@ -20682,6 +22258,28 @@ function registerSessionRoutes(app, deps) {
|
|
|
20682
22258
|
);
|
|
20683
22259
|
app.get(
|
|
20684
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
|
+
},
|
|
20685
22283
|
withOwnerReadSession(
|
|
20686
22284
|
"GET /session/:id/supported-commands",
|
|
20687
22285
|
async (_req, res, sessionId, runtime) => {
|
|
@@ -20903,10 +22501,32 @@ function registerSessionRoutes(app, deps) {
|
|
|
20903
22501
|
}
|
|
20904
22502
|
const clientId = parseClientIdHeader(req, res);
|
|
20905
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
|
+
}
|
|
20906
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
|
+
}
|
|
20907
22525
|
const forwardedBody = { ...body };
|
|
20908
22526
|
delete forwardedBody["deadlineMs"];
|
|
22527
|
+
delete forwardedBody["delivery"];
|
|
20909
22528
|
const lastEventId = ownerBridge.getSessionLastEventId(sessionId);
|
|
22529
|
+
const eventEpoch = ownerBridge.getSessionEventEpoch(sessionId);
|
|
20910
22530
|
addDaemonRequestAttribute("qwen-code.prompt_id", promptId);
|
|
20911
22531
|
const abort = new AbortController();
|
|
20912
22532
|
let responseFinished = false;
|
|
@@ -20936,10 +22556,21 @@ function registerSessionRoutes(app, deps) {
|
|
|
20936
22556
|
{
|
|
20937
22557
|
...clientId !== void 0 ? { clientId } : {},
|
|
20938
22558
|
promptId,
|
|
20939
|
-
...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
|
+
} : {}
|
|
20940
22566
|
}
|
|
20941
22567
|
);
|
|
20942
22568
|
} catch (err) {
|
|
22569
|
+
deps.channelDeliveryAuthorizations?.revokePrompt(
|
|
22570
|
+
runtime.workspaceCwd,
|
|
22571
|
+
sessionId,
|
|
22572
|
+
promptId
|
|
22573
|
+
);
|
|
20943
22574
|
res.off("close", onResClose);
|
|
20944
22575
|
res.off("finish", onResFinish);
|
|
20945
22576
|
if (daemonLog && err instanceof PromptQueueFullError) {
|
|
@@ -20984,12 +22615,23 @@ function registerSessionRoutes(app, deps) {
|
|
|
20984
22615
|
);
|
|
20985
22616
|
}
|
|
20986
22617
|
}
|
|
20987
|
-
).
|
|
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(() => {
|
|
20988
22630
|
});
|
|
20989
22631
|
if (daemonLog) {
|
|
20990
22632
|
daemonLog.info("prompt enqueued", { sessionId, promptId, clientId });
|
|
20991
22633
|
}
|
|
20992
|
-
res.status(202).json({ promptId, lastEventId });
|
|
22634
|
+
res.status(202).json({ promptId, lastEventId, eventEpoch });
|
|
20993
22635
|
}
|
|
20994
22636
|
)
|
|
20995
22637
|
);
|
|
@@ -21078,6 +22720,29 @@ function registerSessionRoutes(app, deps) {
|
|
|
21078
22720
|
app.post(
|
|
21079
22721
|
"/session/:id/heartbeat",
|
|
21080
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
|
+
},
|
|
21081
22746
|
withOwnerMutableSession(
|
|
21082
22747
|
"POST /session/:id/heartbeat",
|
|
21083
22748
|
(req, res, sessionId, runtime) => {
|
|
@@ -21094,6 +22759,25 @@ function registerSessionRoutes(app, deps) {
|
|
|
21094
22759
|
app.post(
|
|
21095
22760
|
"/session/:id/detach",
|
|
21096
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
|
+
},
|
|
21097
22781
|
withOwnerMutableSession(
|
|
21098
22782
|
"POST /session/:id/detach",
|
|
21099
22783
|
async (req, res, sessionId, runtime) => {
|
|
@@ -21146,6 +22830,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
21146
22830
|
clientId !== void 0 ? { clientId } : void 0
|
|
21147
22831
|
)
|
|
21148
22832
|
);
|
|
22833
|
+
clearBranchSessionEntry(sessionId);
|
|
21149
22834
|
res.status(204).end();
|
|
21150
22835
|
} catch (err) {
|
|
21151
22836
|
sendBridgeError2(res, err, {
|
|
@@ -21172,6 +22857,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
21172
22857
|
);
|
|
21173
22858
|
}, "onError")
|
|
21174
22859
|
});
|
|
22860
|
+
for (const removedId of result.removed) {
|
|
22861
|
+
clearBranchSessionEntry(removedId);
|
|
22862
|
+
}
|
|
21175
22863
|
res.status(200).json(result);
|
|
21176
22864
|
} catch (err) {
|
|
21177
22865
|
sendBridgeError2(res, err, { route: "POST /sessions/delete" });
|
|
@@ -21246,6 +22934,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
21246
22934
|
);
|
|
21247
22935
|
}, "onError")
|
|
21248
22936
|
});
|
|
22937
|
+
for (const removedId of result.removed) {
|
|
22938
|
+
clearBranchSessionEntry(removedId);
|
|
22939
|
+
}
|
|
21249
22940
|
res.status(200).json(result);
|
|
21250
22941
|
} catch (err) {
|
|
21251
22942
|
sendBridgeError2(res, err, { route });
|
|
@@ -22176,7 +23867,8 @@ function toView(task) {
|
|
|
22176
23867
|
sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
|
|
22177
23868
|
// Absent runs (tool-created / never-fired) normalizes to [] so the client
|
|
22178
23869
|
// never special-cases undefined.
|
|
22179
|
-
runs: Array.isArray(task.runs) ? task.runs : []
|
|
23870
|
+
runs: Array.isArray(task.runs) ? task.runs : [],
|
|
23871
|
+
...task.delivery !== void 0 ? { delivery: task.delivery } : {}
|
|
22180
23872
|
};
|
|
22181
23873
|
}
|
|
22182
23874
|
__name(toView, "toView");
|
|
@@ -22209,7 +23901,13 @@ function canonicalCron(cron) {
|
|
|
22209
23901
|
}
|
|
22210
23902
|
__name(canonicalCron, "canonicalCron");
|
|
22211
23903
|
function registerScheduledTaskCrudRoutes(app, deps) {
|
|
22212
|
-
const {
|
|
23904
|
+
const {
|
|
23905
|
+
prefix,
|
|
23906
|
+
resolveTarget,
|
|
23907
|
+
mutate,
|
|
23908
|
+
safeBody: safeBody2,
|
|
23909
|
+
channelDeliveryAuthorizations
|
|
23910
|
+
} = deps;
|
|
22213
23911
|
const base = `${prefix}/scheduled-tasks`;
|
|
22214
23912
|
app.get(base, async (req, res) => {
|
|
22215
23913
|
const target = resolveTarget(req, res);
|
|
@@ -22286,6 +23984,16 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22286
23984
|
});
|
|
22287
23985
|
return;
|
|
22288
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
|
+
}
|
|
22289
23997
|
const removedField = findRemovedTaskField(body);
|
|
22290
23998
|
if (removedField) {
|
|
22291
23999
|
res.status(400).json(removedFieldError(removedField));
|
|
@@ -22342,6 +24050,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22342
24050
|
// minute the task was created — same guard cronScheduler.create uses.
|
|
22343
24051
|
lastFiredAt: now - now % 6e4,
|
|
22344
24052
|
enabled,
|
|
24053
|
+
...delivery !== void 0 ? { delivery } : {},
|
|
22345
24054
|
...boundSessionId !== void 0 ? { sessionId: boundSessionId } : {},
|
|
22346
24055
|
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
22347
24056
|
};
|
|
@@ -22381,6 +24090,15 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22381
24090
|
});
|
|
22382
24091
|
return;
|
|
22383
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
|
+
}
|
|
22384
24102
|
res.status(201).json(toView(task));
|
|
22385
24103
|
});
|
|
22386
24104
|
app.patch(`${base}/:id`, mutate(), async (req, res) => {
|
|
@@ -22395,6 +24113,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22395
24113
|
const body = safeBody2(req);
|
|
22396
24114
|
const patch = {};
|
|
22397
24115
|
let clearName = false;
|
|
24116
|
+
let clearDelivery = false;
|
|
22398
24117
|
const removedPatchField = findRemovedTaskField(body);
|
|
22399
24118
|
if (removedPatchField) {
|
|
22400
24119
|
res.status(400).json(removedFieldError(removedPatchField));
|
|
@@ -22459,7 +24178,20 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22459
24178
|
}
|
|
22460
24179
|
patch.enabled = body["enabled"];
|
|
22461
24180
|
}
|
|
22462
|
-
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) {
|
|
22463
24195
|
res.status(400).json({
|
|
22464
24196
|
error: "No updatable fields provided",
|
|
22465
24197
|
code: "empty_patch"
|
|
@@ -22486,6 +24218,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22486
24218
|
}
|
|
22487
24219
|
const next = { ...current, ...patch };
|
|
22488
24220
|
if (clearName) delete next.name;
|
|
24221
|
+
if (clearDelivery) delete next.delivery;
|
|
22489
24222
|
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
22490
24223
|
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
22491
24224
|
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
@@ -22540,6 +24273,22 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22540
24273
|
} catch {
|
|
22541
24274
|
}
|
|
22542
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
|
+
}
|
|
22543
24292
|
res.status(200).json(toView(updated));
|
|
22544
24293
|
});
|
|
22545
24294
|
app.delete(`${base}/:id`, mutate(), async (req, res) => {
|
|
@@ -22582,6 +24331,13 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22582
24331
|
await bridge.closeSession(boundSessionId).catch(() => {
|
|
22583
24332
|
});
|
|
22584
24333
|
}
|
|
24334
|
+
if (boundSessionId) {
|
|
24335
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
24336
|
+
workspaceCwd,
|
|
24337
|
+
boundSessionId,
|
|
24338
|
+
id
|
|
24339
|
+
);
|
|
24340
|
+
}
|
|
22585
24341
|
res.status(200).json({ deleted: true, id });
|
|
22586
24342
|
});
|
|
22587
24343
|
app.post(`${base}/:id/run`, mutate(), async (req, res) => {
|
|
@@ -22662,17 +24418,30 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
22662
24418
|
}
|
|
22663
24419
|
__name(registerScheduledTaskCrudRoutes, "registerScheduledTaskCrudRoutes");
|
|
22664
24420
|
function registerScheduledTasksRoutes(app, deps) {
|
|
22665
|
-
const {
|
|
24421
|
+
const {
|
|
24422
|
+
boundWorkspace,
|
|
24423
|
+
mutate,
|
|
24424
|
+
safeBody: safeBody2,
|
|
24425
|
+
bridge,
|
|
24426
|
+
channelDeliveryAuthorizations
|
|
24427
|
+
} = deps;
|
|
22666
24428
|
registerScheduledTaskCrudRoutes(app, {
|
|
22667
24429
|
prefix: "",
|
|
22668
24430
|
resolveTarget: /* @__PURE__ */ __name(() => ({ workspaceCwd: boundWorkspace, bridge }), "resolveTarget"),
|
|
22669
24431
|
mutate,
|
|
22670
|
-
safeBody: safeBody2
|
|
24432
|
+
safeBody: safeBody2,
|
|
24433
|
+
channelDeliveryAuthorizations
|
|
22671
24434
|
});
|
|
22672
24435
|
}
|
|
22673
24436
|
__name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
|
|
22674
24437
|
function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
22675
|
-
const {
|
|
24438
|
+
const {
|
|
24439
|
+
workspaceRegistry,
|
|
24440
|
+
mutate,
|
|
24441
|
+
safeBody: safeBody2,
|
|
24442
|
+
manageScheduledTaskSessions,
|
|
24443
|
+
channelDeliveryAuthorizations
|
|
24444
|
+
} = deps;
|
|
22676
24445
|
registerScheduledTaskCrudRoutes(app, {
|
|
22677
24446
|
prefix: "/workspaces/:workspace",
|
|
22678
24447
|
resolveTarget: /* @__PURE__ */ __name((req, res) => {
|
|
@@ -22691,7 +24460,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
|
22691
24460
|
};
|
|
22692
24461
|
}, "resolveTarget"),
|
|
22693
24462
|
mutate,
|
|
22694
|
-
safeBody: safeBody2
|
|
24463
|
+
safeBody: safeBody2,
|
|
24464
|
+
channelDeliveryAuthorizations
|
|
22695
24465
|
});
|
|
22696
24466
|
}
|
|
22697
24467
|
__name(registerWorkspaceQualifiedScheduledTasksRoutes, "registerWorkspaceQualifiedScheduledTasksRoutes");
|
|
@@ -22721,6 +24491,77 @@ function parseNameField(raw) {
|
|
|
22721
24491
|
}
|
|
22722
24492
|
__name(parseNameField, "parseNameField");
|
|
22723
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
|
+
|
|
22724
24565
|
// packages/cli/src/serve/routes/goals.ts
|
|
22725
24566
|
init_esbuild_shims();
|
|
22726
24567
|
var PROBE_CONCURRENCY = 10;
|
|
@@ -22989,6 +24830,11 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
22989
24830
|
log.debug("keepalive: readCronTasks failed, skipping this pass", err);
|
|
22990
24831
|
return;
|
|
22991
24832
|
}
|
|
24833
|
+
try {
|
|
24834
|
+
opts.onTasksRead?.(tasks);
|
|
24835
|
+
} catch (err) {
|
|
24836
|
+
log.debug("keepalive: onTasksRead failed", err);
|
|
24837
|
+
}
|
|
22992
24838
|
for (const sessionId of collectBoundSessionIds(tasks)) {
|
|
22993
24839
|
try {
|
|
22994
24840
|
bridge.recordHeartbeat(sessionId);
|
|
@@ -23118,6 +24964,11 @@ async function rehydrateScheduledTaskSessions(deps) {
|
|
|
23118
24964
|
log.debug("rehydrate: readCronTasks failed", err);
|
|
23119
24965
|
return { loaded: [], failed: [] };
|
|
23120
24966
|
}
|
|
24967
|
+
try {
|
|
24968
|
+
deps.onTasksRead?.(tasks);
|
|
24969
|
+
} catch (err) {
|
|
24970
|
+
log.debug("rehydrate: onTasksRead failed", err);
|
|
24971
|
+
}
|
|
23121
24972
|
const sessionIds = collectBoundSessionIds(tasks);
|
|
23122
24973
|
const loaded = [];
|
|
23123
24974
|
const failed = [];
|
|
@@ -23477,6 +25328,7 @@ function createServeFeatures(deps) {
|
|
|
23477
25328
|
persistSettingAvailable,
|
|
23478
25329
|
sessionArtifactsPersistenceAvailable,
|
|
23479
25330
|
sessionGenerationAvailable,
|
|
25331
|
+
workspaceGenerationAvailable,
|
|
23480
25332
|
reloadAvailable,
|
|
23481
25333
|
channelReloadAvailable,
|
|
23482
25334
|
channelControlAvailable,
|
|
@@ -23513,6 +25365,7 @@ function createServeFeatures(deps) {
|
|
|
23513
25365
|
sessionShellCommandEnabled,
|
|
23514
25366
|
sessionArtifactsPersistenceAvailable,
|
|
23515
25367
|
sessionGenerationAvailable: sessionGenerationAvailable(),
|
|
25368
|
+
workspaceGenerationAvailable: workspaceGenerationAvailable(),
|
|
23516
25369
|
rateLimit: opts.rateLimit === true,
|
|
23517
25370
|
reloadAvailable,
|
|
23518
25371
|
channelReloadAvailable: channelReloadAvailable(),
|
|
@@ -24858,16 +26711,19 @@ data: ${dataJson}
|
|
|
24858
26711
|
__name(formatSseFrame, "formatSseFrame");
|
|
24859
26712
|
function registerSseEventsRoutes(app, deps) {
|
|
24860
26713
|
const { workspaceRegistry, daemonLog, sendBridgeError: sendBridgeError2, writerIdleTimeoutMs } = deps;
|
|
24861
|
-
app.get("/session/:id/events", (req, res) => {
|
|
26714
|
+
app.get("/session/:id/events", async (req, res) => {
|
|
24862
26715
|
const sessionId = req.params["id"];
|
|
24863
26716
|
const lastEventId = parseLastEventId(req.headers["last-event-id"]);
|
|
26717
|
+
const eventEpoch = parseEventEpochHeader(req.headers["x-qwen-event-epoch"]);
|
|
24864
26718
|
const maxQueued = parseMaxQueuedQuery(req.query["maxQueued"], res);
|
|
24865
26719
|
if (maxQueued === null) return;
|
|
24866
26720
|
let iter;
|
|
26721
|
+
let busEpoch;
|
|
24867
26722
|
const abort = new AbortController();
|
|
24868
26723
|
try {
|
|
26724
|
+
const virtualKey = parseVirtualSubagentSessionId(sessionId);
|
|
24869
26725
|
const runtime = requireSessionRuntime({
|
|
24870
|
-
sessionId,
|
|
26726
|
+
sessionId: virtualKey?.parentSessionId ?? sessionId,
|
|
24871
26727
|
route: "GET /session/:id/events",
|
|
24872
26728
|
res,
|
|
24873
26729
|
workspaceRegistry,
|
|
@@ -24875,13 +26731,33 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
24875
26731
|
});
|
|
24876
26732
|
if (!runtime) return;
|
|
24877
26733
|
const snapshot = req.query["snapshot"] === "1";
|
|
24878
|
-
const iterable =
|
|
26734
|
+
const iterable = virtualKey ? await deps.virtualSubagentSessions?.subscribe(runtime, sessionId, {
|
|
24879
26735
|
signal: abort.signal,
|
|
24880
26736
|
lastEventId,
|
|
26737
|
+
...maxQueued !== void 0 ? { maxQueued } : {}
|
|
26738
|
+
}) : runtime.bridge.subscribeEvents(sessionId, {
|
|
26739
|
+
signal: abort.signal,
|
|
26740
|
+
lastEventId,
|
|
26741
|
+
...eventEpoch !== void 0 ? { epoch: eventEpoch } : {},
|
|
24881
26742
|
...maxQueued !== void 0 ? { maxQueued } : {},
|
|
24882
26743
|
...snapshot ? { snapshot: true } : {}
|
|
24883
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
|
+
}
|
|
24884
26753
|
iter = iterable[Symbol.asyncIterator]();
|
|
26754
|
+
if (!virtualKey) {
|
|
26755
|
+
try {
|
|
26756
|
+
busEpoch = runtime.bridge.getSessionEventEpoch(sessionId);
|
|
26757
|
+
} catch {
|
|
26758
|
+
busEpoch = void 0;
|
|
26759
|
+
}
|
|
26760
|
+
}
|
|
24885
26761
|
} catch (err) {
|
|
24886
26762
|
if (err instanceof SubscriberLimitExceededError) {
|
|
24887
26763
|
writeStderrLine(
|
|
@@ -24921,6 +26797,9 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
24921
26797
|
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
24922
26798
|
res.setHeader("Connection", "keep-alive");
|
|
24923
26799
|
res.setHeader("X-Accel-Buffering", "no");
|
|
26800
|
+
if (busEpoch !== void 0) {
|
|
26801
|
+
res.setHeader("X-Qwen-Event-Epoch", busEpoch);
|
|
26802
|
+
}
|
|
24924
26803
|
res.flushHeaders();
|
|
24925
26804
|
activeSseCount++;
|
|
24926
26805
|
let sseCounted = true;
|
|
@@ -25046,7 +26925,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
25046
26925
|
const data = next.value.data;
|
|
25047
26926
|
const gap = typeof data.earliestAvailableId === "number" && typeof data.lastDeliveredId === "number" ? data.earliestAvailableId - data.lastDeliveredId - 1 : void 0;
|
|
25048
26927
|
writeStderrLine(
|
|
25049
|
-
`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.`
|
|
25050
26929
|
);
|
|
25051
26930
|
}
|
|
25052
26931
|
await writeWithBackpressure(formatSseFrame(next.value));
|
|
@@ -26034,7 +27913,7 @@ __name(registerWorkspaceQualifiedLifecycleRoutes, "registerWorkspaceQualifiedLif
|
|
|
26034
27913
|
|
|
26035
27914
|
// packages/cli/src/serve/routes/workspace-management.ts
|
|
26036
27915
|
init_esbuild_shims();
|
|
26037
|
-
import { readdir, stat } from "node:fs/promises";
|
|
27916
|
+
import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
26038
27917
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
26039
27918
|
import { basename as basename4, dirname as dirname4, isAbsolute as isAbsolute7, join as join8, resolve as resolve4, sep as sep3 } from "node:path";
|
|
26040
27919
|
var MAX_PATH_SUGGESTIONS = 50;
|
|
@@ -26256,7 +28135,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26256
28135
|
const suggestions = [];
|
|
26257
28136
|
let truncated = false;
|
|
26258
28137
|
try {
|
|
26259
|
-
const entries = await
|
|
28138
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
26260
28139
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
26261
28140
|
for (const entry of entries) {
|
|
26262
28141
|
if (entry.name.startsWith(".") && !filter.startsWith(".")) continue;
|
|
@@ -26266,7 +28145,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26266
28145
|
let isDir = entry.isDirectory();
|
|
26267
28146
|
if (!isDir && entry.isSymbolicLink()) {
|
|
26268
28147
|
try {
|
|
26269
|
-
isDir = (await
|
|
28148
|
+
isDir = (await stat2(join8(dir, entry.name))).isDirectory();
|
|
26270
28149
|
} catch {
|
|
26271
28150
|
continue;
|
|
26272
28151
|
}
|
|
@@ -26386,7 +28265,7 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
26386
28265
|
return;
|
|
26387
28266
|
}
|
|
26388
28267
|
try {
|
|
26389
|
-
const s = await
|
|
28268
|
+
const s = await stat2(canonical);
|
|
26390
28269
|
if (!s.isDirectory()) {
|
|
26391
28270
|
res.status(400).json({
|
|
26392
28271
|
error: "Path is not a directory",
|
|
@@ -27189,7 +29068,7 @@ __name(registerWorkspaceManagementRoutes, "registerWorkspaceManagementRoutes");
|
|
|
27189
29068
|
|
|
27190
29069
|
// packages/cli/src/serve/routes/workspace-git.ts
|
|
27191
29070
|
init_esbuild_shims();
|
|
27192
|
-
import * as
|
|
29071
|
+
import * as fs5 from "node:fs";
|
|
27193
29072
|
import * as path14 from "node:path";
|
|
27194
29073
|
function registerWorkspaceGitRoutes(app, deps) {
|
|
27195
29074
|
app.get("/workspace/git", async (_req, res) => {
|
|
@@ -27216,8 +29095,8 @@ function registerWorkspaceQualifiedGitRoutes(app, deps) {
|
|
|
27216
29095
|
let gitCwd = runtime.workspaceCwd;
|
|
27217
29096
|
if (typeof rawCwd === "string" && rawCwd.length > 0) {
|
|
27218
29097
|
try {
|
|
27219
|
-
const resolved =
|
|
27220
|
-
const root =
|
|
29098
|
+
const resolved = fs5.realpathSync(path14.resolve(rawCwd));
|
|
29099
|
+
const root = fs5.realpathSync(runtime.workspaceCwd);
|
|
27221
29100
|
const rel = path14.relative(root, resolved);
|
|
27222
29101
|
if (!rel.startsWith("..") && !path14.isAbsolute(rel)) {
|
|
27223
29102
|
gitCwd = resolved;
|
|
@@ -27641,6 +29520,38 @@ var WorkspaceGitState = class {
|
|
|
27641
29520
|
|
|
27642
29521
|
// packages/cli/src/serve/routes/workspace-mcp-control.ts
|
|
27643
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");
|
|
27644
29555
|
function registerWorkspaceMcpControlRoutes(app, deps) {
|
|
27645
29556
|
const {
|
|
27646
29557
|
boundWorkspace,
|
|
@@ -27667,9 +29578,11 @@ function registerWorkspaceMcpControlRoutes(app, deps) {
|
|
|
27667
29578
|
app.post(
|
|
27668
29579
|
"/workspace/mcp/reload",
|
|
27669
29580
|
mutate({ strict: true }),
|
|
27670
|
-
async (
|
|
29581
|
+
async (req, res) => {
|
|
29582
|
+
const options = parseMcpReloadOptions(safeBody2(req), res);
|
|
29583
|
+
if (!options) return;
|
|
27671
29584
|
try {
|
|
27672
|
-
const result = await bridge.reloadWorkspaceMcp();
|
|
29585
|
+
const result = await bridge.reloadWorkspaceMcp(options);
|
|
27673
29586
|
res.status(202).json(result);
|
|
27674
29587
|
} catch (err) {
|
|
27675
29588
|
sendBridgeError2(res, err, { route: "POST /workspace/mcp/reload" });
|
|
@@ -27874,9 +29787,11 @@ function registerWorkspaceQualifiedMcpControlRoutes(app, deps) {
|
|
|
27874
29787
|
res
|
|
27875
29788
|
);
|
|
27876
29789
|
if (!runtime) return;
|
|
29790
|
+
const options = parseMcpReloadOptions(deps.safeBody(req), res);
|
|
29791
|
+
if (!options) return;
|
|
27877
29792
|
const route = "POST /workspaces/:workspace/mcp/reload";
|
|
27878
29793
|
try {
|
|
27879
|
-
const result = await runtime.bridge.reloadWorkspaceMcp();
|
|
29794
|
+
const result = await runtime.bridge.reloadWorkspaceMcp(options);
|
|
27880
29795
|
res.status(202).json(result);
|
|
27881
29796
|
} catch (err) {
|
|
27882
29797
|
deps.sendBridgeError(res, err, { route });
|
|
@@ -29251,6 +31166,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29251
31166
|
(runtime) => runtime.bridge.generateSessionContent !== void 0
|
|
29252
31167
|
);
|
|
29253
31168
|
}, "sessionGenerationAvailable"),
|
|
31169
|
+
workspaceGenerationAvailable: /* @__PURE__ */ __name(() => primaryBridge.generateWorkspaceContent !== void 0, "workspaceGenerationAvailable"),
|
|
29254
31170
|
// Registry injection supplies the primary workspace service through the
|
|
29255
31171
|
// runtime, so it has the same reload surface as legacy deps.workspace.
|
|
29256
31172
|
reloadAvailable: deps.workspace !== void 0 || injectedWorkspaceRegistry !== void 0,
|
|
@@ -29544,6 +31460,13 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29544
31460
|
maxPendingPromptsPerSession: opts.maxPendingPromptsPerSession,
|
|
29545
31461
|
languageCodes
|
|
29546
31462
|
});
|
|
31463
|
+
registerChannelNotifyRoutes(app, {
|
|
31464
|
+
boundWorkspace: primaryBoundWorkspace,
|
|
31465
|
+
workspaceRegistry,
|
|
31466
|
+
mutate,
|
|
31467
|
+
safeBody,
|
|
31468
|
+
deliverChannelMessage: deps.deliverChannelMessage
|
|
31469
|
+
});
|
|
29547
31470
|
registerWorkspaceStatusRoutes(app, {
|
|
29548
31471
|
boundWorkspace: primaryBoundWorkspace,
|
|
29549
31472
|
bridge: primaryBridge,
|
|
@@ -29609,6 +31532,12 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29609
31532
|
parseClientId: parseClientIdHeader,
|
|
29610
31533
|
safeBody
|
|
29611
31534
|
});
|
|
31535
|
+
mountWorkspaceGenerationRoutes(app, {
|
|
31536
|
+
bridge: primaryBridge,
|
|
31537
|
+
mutate,
|
|
31538
|
+
parseClientId: parseClientIdHeader,
|
|
31539
|
+
safeBody
|
|
31540
|
+
});
|
|
29612
31541
|
mountWorkspaceQualifiedAgentsRoutes(app, {
|
|
29613
31542
|
workspaceRegistry,
|
|
29614
31543
|
mutate,
|
|
@@ -29785,6 +31714,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29785
31714
|
allowPrivateAuthBaseUrl: opts.allowPrivateAuthBaseUrl === true,
|
|
29786
31715
|
installAuthProvider: deps.installAuthProvider
|
|
29787
31716
|
});
|
|
31717
|
+
const virtualSubagentSessions = new VirtualSubagentSessions();
|
|
29788
31718
|
registerSessionRoutes(app, {
|
|
29789
31719
|
boundWorkspace: primaryBoundWorkspace,
|
|
29790
31720
|
bridge: primaryBridge,
|
|
@@ -29793,9 +31723,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29793
31723
|
mutate,
|
|
29794
31724
|
sendBridgeError: sendBridgeError2,
|
|
29795
31725
|
daemonLog,
|
|
31726
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
|
|
29796
31727
|
promptDeadlineMs: opts.promptDeadlineMs,
|
|
29797
31728
|
sessionShellCommandEnabled,
|
|
29798
|
-
languageCodes
|
|
31729
|
+
languageCodes,
|
|
31730
|
+
virtualSubagentSessions
|
|
29799
31731
|
});
|
|
29800
31732
|
registerWorkspaceMcpControlRoutes(app, {
|
|
29801
31733
|
boundWorkspace: primaryBoundWorkspace,
|
|
@@ -29887,7 +31819,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29887
31819
|
boundWorkspace: primaryBoundWorkspace,
|
|
29888
31820
|
mutate,
|
|
29889
31821
|
safeBody,
|
|
29890
|
-
bridge: deps.manageScheduledTaskSessions ? bridge : void 0
|
|
31822
|
+
bridge: deps.manageScheduledTaskSessions ? bridge : void 0,
|
|
31823
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
29891
31824
|
});
|
|
29892
31825
|
registerGoalsRoutes(app, {
|
|
29893
31826
|
boundWorkspace: primaryBoundWorkspace,
|
|
@@ -29897,16 +31830,32 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29897
31830
|
workspaceRegistry,
|
|
29898
31831
|
mutate,
|
|
29899
31832
|
safeBody,
|
|
29900
|
-
manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true
|
|
31833
|
+
manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
|
|
31834
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
29901
31835
|
});
|
|
29902
31836
|
registerUsageStatsRoutes(app);
|
|
29903
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");
|
|
29904
31852
|
const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
29905
31853
|
const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
|
|
29906
31854
|
const rehydrateWorkspace = /* @__PURE__ */ __name((taskBridge, workspaceCwd) => {
|
|
29907
31855
|
void rehydrateScheduledTaskSessions({
|
|
29908
31856
|
bridge: taskBridge,
|
|
29909
31857
|
boundWorkspace: workspaceCwd,
|
|
31858
|
+
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(workspaceCwd, tasks), "onTasksRead"),
|
|
29910
31859
|
onError: /* @__PURE__ */ __name((sessionId, err) => {
|
|
29911
31860
|
process.stderr.write(
|
|
29912
31861
|
`qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -29931,7 +31880,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29931
31880
|
const keepalive = startScheduledTaskKeepalive({
|
|
29932
31881
|
bridge: runtime.bridge,
|
|
29933
31882
|
boundWorkspace: runtime.workspaceCwd,
|
|
29934
|
-
intervalMs: keepaliveIntervalMs
|
|
31883
|
+
intervalMs: keepaliveIntervalMs,
|
|
31884
|
+
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
|
|
29935
31885
|
});
|
|
29936
31886
|
rehydrateWorkspace(runtime.bridge, runtime.workspaceCwd);
|
|
29937
31887
|
keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
|
|
@@ -29961,7 +31911,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
29961
31911
|
workspaceRegistry,
|
|
29962
31912
|
daemonLog,
|
|
29963
31913
|
writerIdleTimeoutMs: opts.writerIdleTimeoutMs,
|
|
29964
|
-
sendBridgeError: sendBridgeError2
|
|
31914
|
+
sendBridgeError: sendBridgeError2,
|
|
31915
|
+
virtualSubagentSessions
|
|
29965
31916
|
});
|
|
29966
31917
|
acpHandleRef.current = mountAcpHttp(app, primaryBridge, {
|
|
29967
31918
|
boundWorkspace: primaryBoundWorkspace,
|