@qwen-code/qwen-code 0.21.13 → 0.21.14-nightly.20260822.7a4566cb3b
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 +15 -7
- package/bundled/qc-helper/docs/extension/introduction.md +2 -0
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/dingtalk.md +1 -1
- package/bundled/qc-helper/docs/features/code-review.md +25 -3
- package/bundled/qc-helper/docs/features/commands.md +120 -8
- package/bundled/qc-helper/docs/features/markdown-rendering.md +6 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +3 -3
- package/bundled/qc-helper/docs/features/terminal-images.md +50 -0
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +21 -4
- package/bundled/review/SKILL.md +113 -62
- package/chunks/MaxSizedBox-NCWYES5B.js +98 -0
- package/chunks/{StandaloneSessionPicker-KEGXNUG6.js → StandaloneSessionPicker-A4V4F64Y.js} +80 -79
- package/chunks/{acp-startup-profiler-NMDXYGDN.js → acp-startup-profiler-DDVSJKJK.js} +2 -2
- package/chunks/{acpAgent-XPES32S7.js → acpAgent-YYRH7HTQ.js} +1094 -278
- package/chunks/{agent-DPTOZFEM.js → agent-NEM254CJ.js} +52 -51
- package/chunks/agent-headless-AVFYIRPV.js +88 -0
- package/chunks/{anthropicContentGenerator-G7BVXTKN.js → anthropicContentGenerator-IWFTSBSV.js} +25 -25
- package/chunks/{artifact-tool-GEXTOPVO.js → artifact-tool-SBXMTVCB.js} +3 -3
- package/chunks/{askUserQuestion-B33XRSB7.js → askUserQuestion-KEQJRFD6.js} +3 -3
- package/chunks/{bridge-YNQBAA4Z.js → bridge-2CGOUO25.js} +59 -57
- package/chunks/{ca-4CQ6MYNQ.js → ca-SLZJD6QH.js} +8 -0
- package/chunks/{channel-management-service-GWY2GAIC.js → channel-management-service-FUJ2EFTF.js} +1 -1
- package/chunks/channel-settings-store-AZKNHHDC.js +103 -0
- package/chunks/{channel-worker-group-7LXCMZ77.js → channel-worker-group-CTE54QL6.js} +8 -7
- package/chunks/{channel-worker-manager-RYEME4ZZ.js → channel-worker-manager-4EHTD3T4.js} +8 -7
- package/chunks/{channel-worker-supervisor-OEVWBHGT.js → channel-worker-supervisor-F6I6WSWW.js} +6 -5
- package/chunks/{chunk-KD5BOPLP.js → chunk-2G4QF4VI.js} +125 -31
- package/chunks/{chunk-BHILXOC3.js → chunk-2MTIAN5Z.js} +3 -3
- package/chunks/{chunk-A4QRWUDE.js → chunk-2NWPB6T4.js} +6 -6
- package/chunks/{chunk-KV27IEHM.js → chunk-2TRNCJK4.js} +1 -1
- package/chunks/{chunk-EL5SXY3T.js → chunk-32CHFLGV.js} +198 -23
- package/chunks/{chunk-5CVO7YES.js → chunk-36OF5PRW.js} +1 -1
- package/chunks/{chunk-X26JYGTD.js → chunk-37BZSWEV.js} +1 -1
- package/chunks/{chunk-WFSTRPRO.js → chunk-3CLIDIVQ.js} +3 -3
- package/chunks/{chunk-A267JX7H.js → chunk-3HWN4E7N.js} +18 -18
- package/chunks/{chunk-ZYYTZUI2.js → chunk-3LYGXZ2H.js} +3 -3
- package/chunks/chunk-3SIGAHUX.js +3969 -0
- package/chunks/{chunk-BVJS5BSP.js → chunk-3XD4PT3B.js} +1 -1
- package/chunks/{chunk-6QFDQMQX.js → chunk-3ZFJUBTP.js} +1 -1
- package/chunks/{chunk-HUTNYWBG.js → chunk-45UD2TU4.js} +19 -11
- package/chunks/{chunk-4W5U2TUT.js → chunk-4F5WV4RF.js} +4 -4
- package/chunks/{chunk-I3G5JWBV.js → chunk-4GP3MNQ2.js} +2695 -1524
- package/chunks/{chunk-V26NVGAU.js → chunk-4MIDDJLJ.js} +8 -3
- package/chunks/{chunk-TS6625XH.js → chunk-5MK45KZ3.js} +9 -5
- package/chunks/{chunk-V57QC6WW.js → chunk-5OTMZVPL.js} +11 -9
- package/chunks/{chunk-MC4TLKEI.js → chunk-5PHLBWBL.js} +3 -3
- package/chunks/chunk-64LXOKG4.js +367 -0
- package/chunks/{chunk-6HY6IF3Z.js → chunk-6NFAEG54.js} +22 -2
- package/chunks/{chunk-TIGA2IVL.js → chunk-6NJIPX6W.js} +10 -298
- package/chunks/{chunk-MRMJCLIY.js → chunk-6RB2S4QP.js} +3 -3
- package/chunks/chunk-6S2OXVJT.js +369 -0
- package/chunks/{chunk-O4D7SPJN.js → chunk-6U46RZ25.js} +3 -3
- package/chunks/{chunk-JOOFMXGF.js → chunk-6UDHEIUT.js} +6 -6
- package/chunks/{chunk-VOQXFAY5.js → chunk-74TONY4F.js} +286 -0
- package/chunks/{chunk-LJQAUZMR.js → chunk-7CPJMZVJ.js} +1627 -180
- package/chunks/{chunk-T3CHYWJZ.js → chunk-7E7UCJHS.js} +100 -4
- package/chunks/{chunk-YZHRN3CF.js → chunk-7IV52LTO.js} +2 -2
- package/chunks/{chunk-4PKCUT7F.js → chunk-7JDGSJQH.js} +7 -7
- package/chunks/{chunk-GO7STP6N.js → chunk-7VITNOH6.js} +4 -4
- package/chunks/{chunk-CU6GJD55.js → chunk-7WLFSDLG.js} +1 -1
- package/chunks/{chunk-4WKAA4KS.js → chunk-A4N4FTMH.js} +1 -11
- package/chunks/{chunk-BUQDLC2G.js → chunk-A5F2YNO6.js} +3 -3
- package/chunks/{chunk-OY5RNSV4.js → chunk-AGCLK4G7.js} +3 -3
- package/chunks/{chunk-IA2K2HJE.js → chunk-AP3B7LKD.js} +2 -2
- package/chunks/{chunk-Y3YCSWG5.js → chunk-AZF6SME3.js} +2 -2
- package/chunks/{chunk-QFJ5JHQR.js → chunk-C72BXMJ5.js} +1 -1
- package/chunks/chunk-CETB5XY4.js +3654 -0
- package/chunks/{chunk-AA2BEKV3.js → chunk-CTAP6PO3.js} +3 -3
- package/chunks/{chunk-MS7GNABG.js → chunk-CXJHQVEK.js} +8 -0
- package/chunks/{chunk-QF2NHSPB.js → chunk-D534POS2.js} +274 -225
- package/chunks/{chunk-UKMR3CKV.js → chunk-D7QQ6RUB.js} +24 -9
- package/chunks/{chunk-DXIBNLBZ.js → chunk-DB2OKNTU.js} +2 -2
- package/chunks/{chunk-DGZEMW5R.js → chunk-DJEHYM4H.js} +3 -3
- package/chunks/{chunk-O565M6A4.js → chunk-DRVS6K7A.js} +260 -16
- package/chunks/{chunk-U3VNBPUO.js → chunk-DV4375RD.js} +5 -5
- package/chunks/{chunk-OXCMMLED.js → chunk-E63A23D7.js} +3 -3
- package/chunks/{chunk-4NFY2S7N.js → chunk-E7REAOTN.js} +15 -0
- package/chunks/{chunk-6ORZ2EDC.js → chunk-EW2IQ3ID.js} +3 -3
- package/chunks/{chunk-DGK6P3BQ.js → chunk-EXVK5R7X.js} +13 -13
- package/chunks/{chunk-NWNEANAT.js → chunk-FOGQO4FG.js} +953 -660
- package/chunks/{chunk-3U3VAL47.js → chunk-FV6PXZRO.js} +1 -1
- package/chunks/{chunk-76J3IJ3M.js → chunk-FX5TGHDE.js} +8 -8
- package/chunks/{chunk-QIH2HAEN.js → chunk-GXG4PYQB.js} +1 -1
- package/chunks/{chunk-FDGGZIYW.js → chunk-HDKCKCYO.js} +3 -3
- package/chunks/{chunk-RIAABG2K.js → chunk-HERHU33B.js} +2 -2
- package/chunks/{chunk-ZYBBISBY.js → chunk-HETN3NE2.js} +18 -15
- package/chunks/{chunk-XIT3GURH.js → chunk-HGBACZGD.js} +3 -3
- package/chunks/{chunk-UZPM4XHR.js → chunk-HGH7DXNI.js} +29 -8
- package/chunks/{chunk-CHHABXPE.js → chunk-HIK2OF33.js} +1 -1
- package/chunks/{chunk-FC4KQFCS.js → chunk-HMJ2P3SV.js} +1 -1
- package/chunks/chunk-HRVMTN37.js +26 -0
- package/chunks/{chunk-PQ36L4F5.js → chunk-HZZGYJIP.js} +1 -1
- package/chunks/{chunk-PT4I7NBA.js → chunk-I432KXWD.js} +1 -1
- package/chunks/{chunk-3EZLLVDF.js → chunk-IBJ5S45N.js} +3 -3
- package/chunks/{chunk-A4MFR4C5.js → chunk-IO257NUD.js} +3 -5
- package/chunks/{chunk-MIPFDQAF.js → chunk-ISJMN3ML.js} +1 -1
- package/chunks/chunk-IWOWEENB.js +9169 -0
- package/chunks/{chunk-XHRY7BXD.js → chunk-J6SIP2IT.js} +4 -4
- package/chunks/{chunk-OD2WU5QY.js → chunk-J7JQXYVL.js} +1 -1
- package/chunks/{chunk-NEFOOD54.js → chunk-J7VPB2HF.js} +4 -4
- package/chunks/{chunk-P7MPQI75.js → chunk-JGUBDRBC.js} +2 -2
- package/chunks/{chunk-SXCOEJO4.js → chunk-JOLJTKIG.js} +1 -1
- package/chunks/{chunk-NTTBXH7U.js → chunk-JS73NNWF.js} +8 -0
- package/chunks/{chunk-QRCNA3SR.js → chunk-JXLPQTMW.js} +50 -70
- package/chunks/{chunk-NNHNLJ2X.js → chunk-K2MSGB3W.js} +317 -72
- package/chunks/{chunk-KBXKR5R2.js → chunk-K52PZNU4.js} +1 -1
- package/chunks/{chunk-OOQUVWIG.js → chunk-K5OIW3I7.js} +4 -4
- package/chunks/{chunk-SOORFWKY.js → chunk-KSPRQSB4.js} +1 -1
- package/chunks/{chunk-WSH6GRKG.js → chunk-KVGR4MCF.js} +3 -3
- package/chunks/{chunk-6YKYPVDV.js → chunk-LC5M7YVE.js} +4 -4
- package/chunks/{chunk-M6NDLY2T.js → chunk-LD5VIJ7S.js} +1 -1
- package/chunks/{chunk-OMLJNPBE.js → chunk-LDGWX737.js} +84 -4
- package/chunks/{chunk-FAAUPSY2.js → chunk-LI4YHTQK.js} +1 -1
- package/chunks/{chunk-CXAOG665.js → chunk-LIKIJAUH.js} +2 -2
- package/chunks/chunk-LJZSMWOH.js +18 -0
- package/chunks/{chunk-BKPPWD33.js → chunk-M2IL2RTA.js} +22 -2
- package/chunks/{chunk-N5YPT6PH.js → chunk-MHOY756Q.js} +25 -13
- package/chunks/{chunk-YP5KH5Y7.js → chunk-ND7NOI4P.js} +1 -1
- package/chunks/{chunk-AW4TRXOC.js → chunk-NP2LV67M.js} +1 -1
- package/chunks/{chunk-GGDBMYGZ.js → chunk-NQB52P65.js} +5 -5
- package/chunks/{chunk-E3DYKPYZ.js → chunk-NUGZAFR2.js} +3 -3
- package/chunks/{chunk-GMIEIY3Y.js → chunk-O5BDEWBC.js} +3 -3
- package/chunks/{chunk-GDXET5XU.js → chunk-O5Z7EB6Y.js} +3 -3
- package/chunks/{chunk-5EYKMUUY.js → chunk-OTXXOZKW.js} +1 -1
- package/chunks/{chunk-M732YJPW.js → chunk-PALTIYXB.js} +6 -6
- package/chunks/{chunk-7UXUJ5T3.js → chunk-PLECQWDB.js} +1 -1
- package/chunks/{chunk-MLPXSYXR.js → chunk-PMIKPGDF.js} +66 -32
- package/chunks/{chunk-IWPYVAO2.js → chunk-PSQJ24ZZ.js} +3 -3
- package/chunks/{chunk-CPHEPGAO.js → chunk-PZRUV52H.js} +2 -2
- package/chunks/{chunk-PP4FUZNV.js → chunk-Q7RPLE33.js} +2 -2
- package/chunks/{chunk-S5DWMTHO.js → chunk-QQUVPMMZ.js} +2 -0
- package/chunks/{chunk-JUEPY766.js → chunk-RNGTMHKN.js} +3 -3
- package/chunks/{chunk-TUGSVUJB.js → chunk-ROV6B34L.js} +6 -6
- package/chunks/{chunk-RVOJ2FBP.js → chunk-RPJOOK6N.js} +1576 -10633
- package/chunks/{chunk-AXN7UPYQ.js → chunk-RQJJZQOH.js} +2 -2
- package/chunks/{chunk-AFSG32D5.js → chunk-RRRCWDFO.js} +1 -1
- package/chunks/{chunk-2M55OBEB.js → chunk-S3G6YFQC.js} +1 -1
- package/chunks/{chunk-4S5337WV.js → chunk-SVU5KGR7.js} +6527 -3314
- package/chunks/chunk-TBVSALA3.js +1109 -0
- package/chunks/{chunk-QUGAUQGJ.js → chunk-TBWQLLFO.js} +2 -0
- package/chunks/{chunk-AS5IN4GK.js → chunk-THK3QUU6.js} +5 -5
- package/chunks/{chunk-JNDY2MDR.js → chunk-TLDZKNZP.js} +1 -1
- package/chunks/{chunk-ZZO74WKW.js → chunk-TNAIZBPQ.js} +115 -28
- package/chunks/{chunk-3Z43GZUQ.js → chunk-TXASDT2M.js} +1 -1
- package/chunks/{chunk-CZBYX5MY.js → chunk-U53XZHAE.js} +1 -1
- package/chunks/{chunk-HIBNSEJE.js → chunk-UDG5EZJI.js} +0 -2
- package/chunks/{chunk-QNQAPSN2.js → chunk-URN2JIAQ.js} +4 -1
- package/chunks/{chunk-EZ5RP345.js → chunk-UYQTX2P6.js} +44 -13
- package/chunks/{chunk-BZ263IKX.js → chunk-UZPYR3EV.js} +1 -1
- package/chunks/{chunk-YZOSNW4R.js → chunk-VFACN2CE.js} +1 -1
- package/chunks/{chunk-RWDNJBWN.js → chunk-VLRBJ24J.js} +2 -2
- package/chunks/{chunk-NHDR76JX.js → chunk-VMJL7RH6.js} +4 -4
- package/chunks/{chunk-E23IPNGS.js → chunk-VOTDAZR7.js} +35 -6
- package/chunks/{chunk-XLLKYULU.js → chunk-VSNPOSDN.js} +2 -2
- package/chunks/{chunk-25EYDK42.js → chunk-VUMLT7E5.js} +2 -2
- package/chunks/{chunk-H4A72DE5.js → chunk-W4CRPSC5.js} +1 -1
- package/chunks/{chunk-NM5V5OVW.js → chunk-WJJYJVQE.js} +3 -3
- package/chunks/{chunk-ROIYNTHJ.js → chunk-WRT324N6.js} +3 -3
- package/chunks/chunk-WZAD4ZNJ.js +59 -0
- package/chunks/{chunk-SG7ZP5PG.js → chunk-WZDM44SB.js} +4 -4
- package/chunks/{chunk-JE7KQ2UP.js → chunk-XIQ5HQ2F.js} +469 -77
- package/chunks/{chunk-QV5YN5YD.js → chunk-XJOHLP2A.js} +5 -5
- package/chunks/{chunk-XUJNK7Y6.js → chunk-XL5K4SVK.js} +1 -1
- package/chunks/{chunk-CKSJECTU.js → chunk-XZJKSETB.js} +9 -5
- package/chunks/{chunk-YEYY7TEP.js → chunk-Y2FEAXLP.js} +7 -7
- package/chunks/{chunk-2B2BF7P7.js → chunk-YDJRMQU4.js} +3 -3
- package/chunks/{chunk-46UV252V.js → chunk-YHC2EYYG.js} +35 -38
- package/chunks/{chunk-OVZPVYZB.js → chunk-YMVFIYHV.js} +96 -18
- package/chunks/{chunk-WGHHA7ZH.js → chunk-Z3JMO2CH.js} +1 -1
- package/chunks/{chunk-MA2HEDVP.js → chunk-ZRYQMWEP.js} +3 -3
- package/chunks/{chunk-IGGGG5CX.js → chunk-ZTAT23TL.js} +15948 -10201
- package/chunks/{computer-use-77C5FHMW.js → computer-use-H2T7IFYX.js} +55 -54
- package/chunks/{config-utils-IVHRSXWI.js → config-utils-3DY73VIJ.js} +2 -2
- package/chunks/contextCommand-5AAZFFFV.js +94 -0
- package/chunks/{core-runtime-7VMIKUTG.js → core-runtime-JWFNKO2S.js} +57 -55
- package/chunks/{create-sub-session-2L5MQRN4.js → create-sub-session-33HIYIJE.js} +58 -56
- package/chunks/{create-sub-session-KRQULJE6.js → create-sub-session-XBCVGNFU.js} +6 -4
- package/chunks/{cron-create-H7UEPDSN.js → cron-create-IKA56DAF.js} +5 -5
- package/chunks/{cron-delete-6SZK7YFM.js → cron-delete-K5Q62EGH.js} +5 -5
- package/chunks/{cron-list-H25JIHEZ.js → cron-list-QBFGAMP7.js} +5 -5
- package/chunks/{daemon-2KTG7ZBN.js → daemon-NNCQ3HWT.js} +806 -147
- package/chunks/{daemon-git-worktree-guard-DXYIMWFT.js → daemon-git-worktree-guard-6233JAPJ.js} +54 -53
- package/chunks/daemon-status-provider-3EI2KALQ.js +104 -0
- package/chunks/daemon-trust-policy-QWWU7CON.js +100 -0
- package/chunks/{daemon-trust-policy-monitor-RYYGCQ3J.js → daemon-trust-policy-monitor-FH7GBAKN.js} +60 -59
- package/chunks/{de-UBEBKG6V.js → de-AH4LGCF5.js} +8 -0
- package/chunks/{deferred-core-runtime-3SGXFXEQ.js → deferred-core-runtime-EDUZQRME.js} +52 -51
- package/chunks/{discovery-ORA5J7YP.js → discovery-X2NV535U.js} +1 -1
- package/chunks/{display-image-ON3EYFRD.js → display-image-OEJMJV3S.js} +5 -5
- package/chunks/{dist-YEPL4RAW.js → dist-5EV2G6MC.js} +2 -3
- package/chunks/{dist-MAQXAQ2Y.js → dist-EQ3Q5XHX.js} +45337 -32756
- package/chunks/{dist-WJ4BHIEW.js → dist-ESS34DHC.js} +72 -0
- package/chunks/{dist-JWMKPWT5.js → dist-EUOUPUFO.js} +3 -4
- package/chunks/{dist-IYYN3RUT.js → dist-UOFRXJT6.js} +2798 -1250
- package/chunks/{earlyInputCapture-KJMLFVQV.js → earlyInputCapture-VSP42LUR.js} +53 -52
- package/chunks/{edit-I4LQFAEC.js → edit-ZTLO5ASX.js} +60 -58
- package/chunks/{en-X6YV7GME.js → en-MD3GP5YL.js} +8 -0
- package/chunks/{enter-worktree-YNPOJSRH.js → enter-worktree-TMTPDS2S.js} +55 -54
- package/chunks/{enterPlanMode-XCPK62ER.js → enterPlanMode-UBAXFMYI.js} +55 -54
- package/chunks/{environment-S7CTIHMX.js → environment-C2CZN7CB.js} +55 -54
- package/chunks/{errors-7HB2AIDS.js → errors-ZUNFQINF.js} +54 -53
- package/chunks/{exit-worktree-AIIY7SR6.js → exit-worktree-572NWEPJ.js} +55 -54
- package/chunks/exitPlanMode-QTIXFGZT.js +86 -0
- package/chunks/{fast-path-NDJV3ZFJ.js → fast-path-CEEVHQL3.js} +3 -3
- package/chunks/{fast-path-settings-LNOFM2YP.js → fast-path-settings-WHX3J3ZI.js} +2 -2
- package/chunks/{fr-VENTC2BS.js → fr-ZEML2JWS.js} +8 -0
- package/chunks/{gemini-RSUFP5OE.js → gemini-I2YR6GMS.js} +114 -112
- package/chunks/{geminiContentGenerator-SQ5XBPZ7.js → geminiContentGenerator-GQWNDZQF.js} +7 -7
- package/chunks/getMachineId-bsd-FBOAYNSY.js +48 -0
- package/chunks/{getMachineId-bsd-FG7IUY6U.js → getMachineId-bsd-YH7RURBZ.js} +4 -4
- package/chunks/{getMachineId-darwin-GLCJI2RA.js → getMachineId-darwin-H6USQYNI.js} +4 -4
- package/chunks/getMachineId-darwin-RNJLJUXY.js +47 -0
- package/chunks/{getMachineId-linux-O6OPPAKO.js → getMachineId-linux-HF2N63ET.js} +3 -3
- package/chunks/getMachineId-linux-UEVRAIAB.js +41 -0
- package/chunks/getMachineId-unsupported-FWXYJ7HW.js +31 -0
- package/chunks/{getMachineId-unsupported-S6CKYVGC.js → getMachineId-unsupported-NYA5DXRB.js} +3 -3
- package/chunks/getMachineId-win-LRVGMHLW.js +50 -0
- package/chunks/{getMachineId-win-X5SRNEH7.js → getMachineId-win-SMEGY2DW.js} +4 -4
- package/chunks/{glob-J4RUJAHX.js → glob-XFBL2RVT.js} +58 -57
- package/chunks/{goal-tools-VHTNVOKK.js → goal-tools-TLJCE7YZ.js} +6 -6
- package/chunks/{grep-VJWPLFOT.js → grep-U675LEXE.js} +55 -54
- package/chunks/handleAutoUpdate-R6RUCIA2.js +97 -0
- package/chunks/{i18n-RM5YOICI.js → i18n-SJCZDZ4C.js} +53 -52
- package/chunks/{image-gen-EXECB5XM.js → image-gen-6VY7CA7C.js} +14 -14
- package/chunks/initializer-CRDZXJOG.js +101 -0
- package/chunks/installationInfo-EW3NEJDZ.js +95 -0
- package/chunks/{ja-QHT4EQTO.js → ja-UM5B2HMD.js} +8 -0
- package/chunks/{keychain-token-storage-3XFJ5ZB2.js → keychain-token-storage-MTFTAESK.js} +3 -3
- package/chunks/list-TZEMTXDH.js +104 -0
- package/chunks/{list-agents-OSVDFI6S.js → list-agents-43XUEXJV.js} +6 -6
- package/chunks/loadedSettingsAdapter-47DG424L.js +98 -0
- package/chunks/{loggingContentGenerator-WF4ZOJEZ.js → loggingContentGenerator-77C6O5VW.js} +31 -29
- package/chunks/{loop-wakeup-WQS6JYAG.js → loop-wakeup-E54KDUXC.js} +6 -6
- package/chunks/{ls-D3HUFHDP.js → ls-CGL2UC3H.js} +7 -7
- package/chunks/{lsp-3QDDJTCS.js → lsp-5IKUO5DX.js} +3 -3
- package/chunks/{managed-npm-update-E7IW6N7V.js → managed-npm-update-AJ5GZRUA.js} +53 -52
- package/chunks/mcp-AQK656Y4.js +98 -0
- package/chunks/{monitor-EE2UYMGE.js → monitor-UDZXKYT3.js} +55 -54
- package/chunks/nonInteractiveCli-6NC3NLZM.js +166 -0
- package/chunks/{notebook-edit-NTDY4QDU.js → notebook-edit-G6WZI2YT.js} +59 -57
- package/chunks/{openaiContentGenerator-YNFVJMRJ.js → openaiContentGenerator-IHVHP3VB.js} +32 -32
- package/chunks/{pidfile-4XSFLYBZ.js → pidfile-EBKS2HBK.js} +53 -52
- package/chunks/{processUtils-WDA2MJFD.js → processUtils-B7M35ZLR.js} +2 -2
- package/chunks/prompt-terminal-ledger-5JYOPOII.js +93 -0
- package/chunks/{pt-VL3I5RNY.js → pt-5BMJ3XYH.js} +8 -0
- package/chunks/{qwenContentGenerator-434M7QKY.js → qwenContentGenerator-WCJPPTED.js} +59 -58
- package/chunks/{qwenOAuth2-GMYZOO6A.js → qwenOAuth2-S2CLBSEZ.js} +10 -10
- package/chunks/read-file-WFM53FTW.js +33 -0
- package/chunks/{read-mcp-resource-XD54ZQMC.js → read-mcp-resource-XYES2B42.js} +3 -3
- package/chunks/{record-artifact-SEYFJEJF.js → record-artifact-W3IBTGL7.js} +10 -6
- package/chunks/{resumeHistoryUtils-EVG3WYK2.js → resumeHistoryUtils-CK4ZC6YO.js} +59 -58
- package/chunks/ripGrep-B3PBLEQ3.js +86 -0
- package/chunks/{ru-4RCKL4PY.js → ru-6GL66ORV.js} +8 -0
- package/chunks/{run-qwen-serve-3QSGRXAN.js → run-qwen-serve-DC5RXI6N.js} +537 -185
- package/chunks/{runtime-5MLLZ7DC.js → runtime-UVEETF54.js} +63 -62
- package/chunks/{scheduler-RPBJ63CH.js → scheduler-MWT3UMVN.js} +54 -53
- package/chunks/{sdk-exporters-grpc-54L4LS5L.js → sdk-exporters-grpc-6J5CKOMO.js} +194 -75
- package/chunks/{sdk-exporters-http-XUVP63H6.js → sdk-exporters-http-Q3YZ4752.js} +40 -45
- package/chunks/{sdk-impl-YXUEN2Z2.js → sdk-impl-BOMCAN2Z.js} +7211 -5454
- package/chunks/{send-message-VZENRWRH.js → send-message-J4VT46OI.js} +8 -8
- package/chunks/{serve-HS3XLPXU.js → serve-AKM75GTE.js} +60 -61
- package/chunks/{server-TC4A7AAZ.js → server-KU7XIDVT.js} +2221 -399
- package/chunks/{session-UBOFXVMN.js → session-DKVYIRWN.js} +108 -105
- package/chunks/{settings-D5644OM5.js → settings-NS3PXZDP.js} +63 -62
- package/chunks/{shell-3PZULQQV.js → shell-UXCNM2OK.js} +52 -51
- package/chunks/{skill-PEVVXQ3L.js → skill-KV7YCCTM.js} +30 -28
- package/chunks/{skill-settings-J65JKKES.js → skill-settings-EXW7ESWJ.js} +59 -58
- package/chunks/{spawnChannel-IYGXRHSQ.js → spawnChannel-FCP44P4V.js} +55 -54
- package/chunks/{standalone-update-IFM53PE7.js → standalone-update-RGW3B2DX.js} +55 -54
- package/chunks/{startInteractiveUI-3AVH7L6H.js → startInteractiveUI-UZMF2BIJ.js} +615 -392
- package/chunks/{syntheticOutput-7GWFIDXT.js → syntheticOutput-JAXMIMZP.js} +4 -4
- package/chunks/{task-create-FCBDX7UH.js → task-create-I2H322E4.js} +12 -12
- package/chunks/{task-list-YIYIUFUA.js → task-list-3OLIWFTQ.js} +21 -7
- package/chunks/{task-stop-X37KYTKB.js → task-stop-JAUY6MSY.js} +3 -3
- package/chunks/{task-update-MYPFVOVM.js → task-update-B3XO4CPI.js} +87 -16
- package/chunks/{team-create-ZAIA7KAV.js → team-create-77XY3KAE.js} +56 -56
- package/chunks/{team-delete-6UMU4XLS.js → team-delete-Q7GE7RRI.js} +6 -6
- package/chunks/{team-plan-approval-UNIUS7OD.js → team-plan-approval-TAQANDQG.js} +55 -54
- package/chunks/{terminal-image-renderer-G343P2RV.js → terminal-image-renderer-V4LIF5NS.js} +54 -53
- package/chunks/theme-manager-KKBAJ574.js +90 -0
- package/chunks/{todoWrite-U2R4NVF4.js → todoWrite-FJJTY2TI.js} +7 -7
- package/chunks/{tool-search-5R2OE4C7.js → tool-search-GZJYRK4I.js} +25 -24
- package/chunks/{total-session-admission-4KBHMQQ2.js → total-session-admission-NIBNWXHE.js} +59 -57
- package/chunks/{trustedFolders-LK6T4XC7.js → trustedFolders-7GEI2NYC.js} +53 -52
- package/chunks/{undici-PYHBDDPN.js → undici-S7WJSKGJ.js} +962 -391
- package/chunks/{update-relaunch-UBKROIC6.js → update-relaunch-OA3OEBMD.js} +5 -5
- package/chunks/{updateCheck-W4Y2GFSD.js → updateCheck-QVHQEVIY.js} +56 -55
- package/chunks/{useAutoAcceptIndicator-C7BEICBF.js → useAutoAcceptIndicator-WZ27J7NY.js} +64 -63
- package/chunks/{validateNonInterActiveAuth-LTEI2TB6.js → validateNonInterActiveAuth-OXJA2JWG.js} +99 -96
- package/chunks/{version-G5A5DGVS.js → version-KJO64WD7.js} +1 -1
- package/chunks/{web-fetch-RTEQTR5Z.js → web-fetch-CC5INI2R.js} +25 -23
- package/chunks/{web-search-5OXHEZPV.js → web-search-MOAUAN6N.js} +18 -18
- package/chunks/{web-shell-static-O73YPVVC.js → web-shell-static-3NUTRHAH.js} +4 -5
- package/chunks/{workflow-ISQJHPG2.js → workflow-BN2ZEJMK.js} +366 -105
- package/chunks/workspace-providers-status-R5QTZFK3.js +101 -0
- package/chunks/{workspace-registration-store-CYNY6IP6.js → workspace-registration-store-WMSLM36M.js} +1 -1
- package/chunks/{workspace-registry-34GTUUHB.js → workspace-registry-J3RUCXH6.js} +59 -57
- package/chunks/{workspace-service-XCDQLE2Y.js → workspace-service-JJZFPKM4.js} +66 -65
- package/chunks/workspace-skills-status-DRIOZRIA.js +101 -0
- package/chunks/{workspace-trust-reconciler-AYGXC7A3.js → workspace-trust-reconciler-YAYSN6CX.js} +69 -67
- package/chunks/write-file-7HXHFFOY.js +88 -0
- package/chunks/{zh-TW-SQ4HTSCW.js → zh-TW-LVLBK4KF.js} +8 -0
- package/chunks/{zh-LMSTK4WD.js → zh-UBMWS2BJ.js} +8 -0
- package/chunks/{zoom-image-4BFYJ3HG.js → zoom-image-EFMQMU4G.js} +24 -22
- package/cli.js +15 -15
- package/locales/ca.js +13 -0
- package/locales/de.js +12 -0
- package/locales/en.js +11 -0
- package/locales/fr.js +13 -0
- package/locales/ja.js +13 -0
- package/locales/pt.js +12 -0
- package/locales/ru.js +12 -0
- package/locales/zh-TW.js +11 -0
- package/locales/zh.js +11 -0
- package/package.json +3 -3
- package/web-shell/assets/{arc-CgOpDKvm.js → arc-BCP1f-bN.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-0Ag_m34F.js → architectureDiagram-3BPJPVTR-D-6ajMay.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-IwTwFau0.js → blockDiagram-GPEHLZMM-CcLlnVnf.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-DLa5GUv8.js → c4Diagram-AAUBKEIU-C_Sp9UwQ.js} +1 -1
- package/web-shell/assets/channel-BcImYzbA.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-DcYP-WFG.js → chunk-2J33WTMH-CG0ngvo9.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-C8MVPMiQ.js → chunk-4BX2VUAB-D43LsVdk.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-BUi4Yfv3.js → chunk-55IACEB6-BqNIn5rz.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-Cy3Su2YY.js → chunk-727SXJPM-BSHmO08Y.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-Dp8Teqv6.js → chunk-AQP2D5EJ-CMUbr5tQ.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-BDTDM-4j.js → chunk-FMBD7UC4-Cm6JflnZ.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-7HfDt0r2.js → chunk-ND2GUHAM-CBR39YQZ.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-BIBU0uCF.js → chunk-QZHKN3VN-CWnqaLb-.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-OWx0rDRW.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-OWx0rDRW.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-DRLdcg9p.js → cose-bilkent-S5V4N54A-DJlTdnfD.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-DCCgDwqW.js → dagre-BM42HDAG-1AFN1uVc.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-CsBTBmk3.js → diagram-2AECGRRQ-gC0GGNSW.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-C9qjH8Lt.js → diagram-5GNKFQAL-CPmRPT1s.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-Brjs_lj2.js → diagram-KO2AKTUF-atigp6Hr.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-DtiWCl_F.js → diagram-LMA3HP47-BJnJFSRQ.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DmfKLkBT.js → diagram-OG6HWLK6-CyvJ4fG2.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-Bve_4deH.js → erDiagram-TEJ5UH35-CZac_jT6.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-C2_kXCcV.js → flowDiagram-I6XJVG4X-pd-LQxWB.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-BSBIjiTF.js → ganttDiagram-6RSMTGT7-CvB1at7l.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-CyebwI55.js → gitGraphDiagram-PVQCEYII-B5Y6nkil.js} +1 -1
- package/web-shell/assets/index-Bg3DAn8Z.js +1788 -0
- package/web-shell/assets/{index-d0yfnV1M.js → index-Bj3ZSUHL.js} +1 -1
- package/web-shell/assets/index-mp32EO88.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-CSDGnWxU.js → infoDiagram-5YYISTIA-BdyWvU4P.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-BK4jU13p.js → ishikawaDiagram-YF4QCWOH-CaHbUdvN.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-D_W6j-oF.js → journeyDiagram-JHISSGLW-DR9F3FpG.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-C7xf-SdC.js → kanban-definition-UN3LZRKU-BoEUbkw2.js} +1 -1
- package/web-shell/assets/{linear-DQmzxpxd.js → linear-DUbfzV4T.js} +1 -1
- package/web-shell/assets/{mermaid.core-9P7AGOLG.js → mermaid.core-CLLkPcpD.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-DgcgMyPk.js → mindmap-definition-RKZ34NQL-FuKI3Stt.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-3wWGb9eG.js → pieDiagram-4H26LBE5-CVAHL7l5.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BeCXnQw9.js → quadrantDiagram-W4KKPZXB-BkGi5fRj.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-Bi1UOHDz.js → requirementDiagram-4Y6WPE33-B5ghV8-K.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-lrLUjjbb.js → sankeyDiagram-5OEKKPKP-CKFbVhkQ.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-BFuqKz6Q.js → sequenceDiagram-3UESZ5HK-C5P9ujPd.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-8DemQLhu.js → stateDiagram-AJRCARHV-CsDn-Rez.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DpGKD1ez.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-uzEuVQXg.js → timeline-definition-PNZ67QCA-B6oLBkTr.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-BQTeZ_-o.js → vennDiagram-CIIHVFJN-DvtBkYwp.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-B6yM5Im7.js → wardley-L42UT6IY-D2UwTX16.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-ChM8bmgn.js → wardleyDiagram-YWT4CUSO-FnnfCxYI.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-oNG6HyB1.js → xychartDiagram-2RQKCTM6-C1SaMQ7d.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/MaxSizedBox-UQALOVVT.js +0 -97
- package/chunks/agent-headless-GJCQMURW.js +0 -87
- package/chunks/channel-settings-store-WNWYFHG7.js +0 -102
- package/chunks/chunk-AZQ3DT76.js +0 -10017
- package/chunks/chunk-CR3C7WXL.js +0 -113
- package/chunks/chunk-K5IDV3PC.js +0 -519
- package/chunks/chunk-MPHPFVKK.js +0 -48
- package/chunks/chunk-RLKC46YT.js +0 -3582
- package/chunks/chunk-UPDOZBWO.js +0 -358
- package/chunks/contextCommand-PJ77GBWL.js +0 -93
- package/chunks/daemon-status-provider-ZDOYJCU6.js +0 -102
- package/chunks/daemon-trust-policy-E67OYUK2.js +0 -99
- package/chunks/exitPlanMode-R4JY7V2O.js +0 -85
- package/chunks/handleAutoUpdate-POCX2MNB.js +0 -94
- package/chunks/initializer-Z2AFGBNR.js +0 -100
- package/chunks/installationInfo-4I5FXNMH.js +0 -92
- package/chunks/list-ZMBFIGZA.js +0 -103
- package/chunks/loadedSettingsAdapter-T6TV4YJ7.js +0 -97
- package/chunks/mcp-6UNYX4HG.js +0 -97
- package/chunks/nonInteractiveCli-WAY237O4.js +0 -163
- package/chunks/read-file-TAFBKMNI.js +0 -32
- package/chunks/ripGrep-WOEK2PXS.js +0 -85
- package/chunks/theme-manager-Z3RIT7DB.js +0 -89
- package/chunks/undici-3FJYTMOF.js +0 -25914
- package/chunks/workspace-providers-status-2ZPZPUPZ.js +0 -100
- package/chunks/workspace-skills-status-RS4O7AIJ.js +0 -100
- package/chunks/write-file-EWXKVVXF.js +0 -87
- package/web-shell/assets/channel-BrGVBa2L.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-B5TUzJzI.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-B5TUzJzI.js +0 -1
- package/web-shell/assets/index-CIDsgxTe.js +0 -1792
- package/web-shell/assets/index-DiQnWi_E.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-DhM5ixYd.js +0 -1
- package/chunks/{dist-BROOP2EG.js → dist-LZO24N3E.js} +1 -1
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
formatWorkspaceMemoryForgetSummary,
|
|
11
11
|
isCompatibleLiveSessionSource,
|
|
12
12
|
isReservedLiveSessionSource,
|
|
13
|
+
isReservedStandaloneSessionSource,
|
|
13
14
|
isValidServerName,
|
|
14
15
|
normalizeChannelDelivery,
|
|
15
16
|
parseChannelDelivery,
|
|
@@ -20,13 +21,13 @@ import {
|
|
|
20
21
|
shouldSuppressRememberErrorDetails,
|
|
21
22
|
workspaceMemoryFailureCode,
|
|
22
23
|
workspaceMemoryFailureDiagnostics
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TNAIZBPQ.js";
|
|
24
25
|
import {
|
|
25
26
|
deriveWebSocketBase,
|
|
26
27
|
openQwenAsrRealtimeStream,
|
|
27
28
|
openVoiceStream,
|
|
28
29
|
openVoiceStreamWithRetry
|
|
29
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-RQJJZQOH.js";
|
|
30
31
|
import {
|
|
31
32
|
SetupGithubError,
|
|
32
33
|
collectSessionData,
|
|
@@ -38,18 +39,18 @@ import {
|
|
|
38
39
|
toJson,
|
|
39
40
|
toJsonl,
|
|
40
41
|
toMarkdown
|
|
41
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-3SIGAHUX.js";
|
|
42
43
|
import {
|
|
43
44
|
OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
|
|
44
45
|
ObservedChannelContactStore
|
|
45
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-UZPYR3EV.js";
|
|
47
|
+
import "./chunk-FV6PXZRO.js";
|
|
46
48
|
import {
|
|
47
49
|
escapeAnsiCtrlCodes
|
|
48
|
-
} from "./chunk-
|
|
49
|
-
import "./chunk-3U3VAL47.js";
|
|
50
|
+
} from "./chunk-E7REAOTN.js";
|
|
50
51
|
import "./chunk-2MIN6GRR.js";
|
|
51
52
|
import "./chunk-QHTIBUWB.js";
|
|
52
|
-
import "./chunk-
|
|
53
|
+
import "./chunk-TXASDT2M.js";
|
|
53
54
|
import {
|
|
54
55
|
ACP_PRE_ATTACH_MAX_FRAMES_GLOBAL,
|
|
55
56
|
ACP_PRE_ATTACH_MAX_FRAMES_PER_CONNECTION,
|
|
@@ -62,11 +63,13 @@ import {
|
|
|
62
63
|
CLIENT_ID_RE,
|
|
63
64
|
ClientMcpSenderRegistry,
|
|
64
65
|
ConversationRuntimeOwnershipError,
|
|
66
|
+
CredentialStore,
|
|
65
67
|
DeviceFlowRegistry,
|
|
66
68
|
MAX_CLIENT_ID_LENGTH,
|
|
67
69
|
MAX_CONCURRENT_VOICE_SESSIONS,
|
|
68
70
|
MAX_SERVER_NAME_LENGTH,
|
|
69
71
|
MAX_TOOL_NAME_LENGTH,
|
|
72
|
+
MutableOriginAllowlist,
|
|
70
73
|
PathMutexRegistry,
|
|
71
74
|
QWEN_CDP_MCP_COMMAND_ENV,
|
|
72
75
|
TooManyActiveDeviceFlowsError,
|
|
@@ -88,7 +91,8 @@ import {
|
|
|
88
91
|
createManagedScratchDirectory,
|
|
89
92
|
createMutationGate,
|
|
90
93
|
createRateLimiter,
|
|
91
|
-
|
|
94
|
+
daemonInboundTraceIdContext,
|
|
95
|
+
daemonTelemetryResponseContext,
|
|
92
96
|
detectFromLoopback,
|
|
93
97
|
getAdvertisedServeFeatures,
|
|
94
98
|
getDeferredRuntimeRequestTiming,
|
|
@@ -99,6 +103,8 @@ import {
|
|
|
99
103
|
isBrowserAutomationMcpAvailable,
|
|
100
104
|
isDeepHealthQuery,
|
|
101
105
|
isScratchRootCompatible,
|
|
106
|
+
listenerIdentityOf,
|
|
107
|
+
listenerIdentityOfSocket,
|
|
102
108
|
parseAllowOriginPatterns,
|
|
103
109
|
parseAndValidateWorkspaceClientId,
|
|
104
110
|
parseClientIdHeader,
|
|
@@ -107,6 +113,7 @@ import {
|
|
|
107
113
|
parseMaxQueuedQuery,
|
|
108
114
|
parseOptionalWorkspaceCwd,
|
|
109
115
|
parsePermissionVoteBody,
|
|
116
|
+
requestWasAuthenticated,
|
|
110
117
|
requireSessionId,
|
|
111
118
|
resolveAcpHttpEnabled,
|
|
112
119
|
resolveCdpMcpCommand,
|
|
@@ -116,9 +123,11 @@ import {
|
|
|
116
123
|
sendJsonBodyParserError,
|
|
117
124
|
setDeviceFlowRegistry,
|
|
118
125
|
setRateLimiter,
|
|
126
|
+
singleTokenCredentials,
|
|
127
|
+
tagListener,
|
|
119
128
|
unsafeRevealSecret,
|
|
120
129
|
validateMcpRuntimeServerName
|
|
121
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-DRVS6K7A.js";
|
|
122
131
|
import "./chunk-VGHZT6JR.js";
|
|
123
132
|
import {
|
|
124
133
|
isLoopbackBind,
|
|
@@ -126,10 +135,38 @@ import {
|
|
|
126
135
|
parseCallerSuppliedSessionId
|
|
127
136
|
} from "./chunk-TQOF5KBL.js";
|
|
128
137
|
import "./chunk-UXEO7E3V.js";
|
|
138
|
+
import {
|
|
139
|
+
WorkspaceGenerationClosedError,
|
|
140
|
+
createSingleWorkspaceRegistry,
|
|
141
|
+
createWorkspaceSessionOwnerIndex
|
|
142
|
+
} from "./chunk-K3LPAED5.js";
|
|
143
|
+
import {
|
|
144
|
+
isInternalWorkspaceRuntime
|
|
145
|
+
} from "./chunk-NYWWQ437.js";
|
|
146
|
+
import {
|
|
147
|
+
assertValidChannelSecretUpdates
|
|
148
|
+
} from "./chunk-Q7RPLE33.js";
|
|
149
|
+
import {
|
|
150
|
+
createWorkspaceSkillsStatusProvider
|
|
151
|
+
} from "./chunk-AGCLK4G7.js";
|
|
152
|
+
import "./chunk-BGXZBI5B.js";
|
|
153
|
+
import {
|
|
154
|
+
isServeDebugMode,
|
|
155
|
+
mountWebShellAssets,
|
|
156
|
+
mountWebShellSpaFallback
|
|
157
|
+
} from "./chunk-KSPRQSB4.js";
|
|
158
|
+
import {
|
|
159
|
+
require_express
|
|
160
|
+
} from "./chunk-O5Z7EB6Y.js";
|
|
129
161
|
import {
|
|
130
162
|
evaluateDaemonWorkspaceTrust,
|
|
131
163
|
readDaemonTrustPolicySnapshot
|
|
132
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-HGBACZGD.js";
|
|
165
|
+
import {
|
|
166
|
+
readRecentPromptTerminals,
|
|
167
|
+
reconcileDanglingPromptTerminals,
|
|
168
|
+
withPromptTerminals
|
|
169
|
+
} from "./chunk-64LXOKG4.js";
|
|
133
170
|
import {
|
|
134
171
|
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
135
172
|
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
@@ -143,14 +180,14 @@ import {
|
|
|
143
180
|
validateWorkspaceSkillName,
|
|
144
181
|
validateWorkspaceVoiceState,
|
|
145
182
|
voiceSettingsScopeToWire
|
|
146
|
-
} from "./chunk-
|
|
183
|
+
} from "./chunk-UYQTX2P6.js";
|
|
147
184
|
import {
|
|
148
185
|
PermissionRulesValidationError,
|
|
149
186
|
buildPermissionSettings,
|
|
150
187
|
isPermissionRuleType,
|
|
151
188
|
normalizePermissionRules,
|
|
152
189
|
readPermissionRuleSet
|
|
153
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-PLECQWDB.js";
|
|
154
191
|
import {
|
|
155
192
|
assertVoiceBaseUrlNetworkAllowed,
|
|
156
193
|
isStreamingVoiceModel,
|
|
@@ -158,24 +195,22 @@ import {
|
|
|
158
195
|
resolveVoiceTranscriptionConfig,
|
|
159
196
|
sanitizeVoiceErrorMessage,
|
|
160
197
|
transcribeVoiceAudio
|
|
161
|
-
} from "./chunk-
|
|
198
|
+
} from "./chunk-EW2IQ3ID.js";
|
|
162
199
|
import {
|
|
163
200
|
isVoiceEnabled,
|
|
164
201
|
isVoiceMode,
|
|
165
202
|
readVoiceModel
|
|
166
|
-
} from "./chunk-
|
|
167
|
-
import "./chunk-
|
|
203
|
+
} from "./chunk-GXG4PYQB.js";
|
|
204
|
+
import "./chunk-Z3JMO2CH.js";
|
|
205
|
+
import "./chunk-Z4X5MTRT.js";
|
|
206
|
+
import {
|
|
207
|
+
WorkspacePermissionRulesSessionRequiredError,
|
|
208
|
+
WorkspaceSettingsPartialPersistError,
|
|
209
|
+
mapWorkspaceSkillToggleError
|
|
210
|
+
} from "./chunk-Z7VOMGDC.js";
|
|
168
211
|
import {
|
|
169
212
|
createTotalSessionAdmissionController
|
|
170
213
|
} from "./chunk-X2UOOG5V.js";
|
|
171
|
-
import {
|
|
172
|
-
WorkspaceGenerationClosedError,
|
|
173
|
-
createSingleWorkspaceRegistry,
|
|
174
|
-
createWorkspaceSessionOwnerIndex
|
|
175
|
-
} from "./chunk-K3LPAED5.js";
|
|
176
|
-
import {
|
|
177
|
-
isInternalWorkspaceRuntime
|
|
178
|
-
} from "./chunk-NYWWQ437.js";
|
|
179
214
|
import "./chunk-OIBUG24X.js";
|
|
180
215
|
import {
|
|
181
216
|
MAX_SESSION_RESTORE_TIMEOUT_MS,
|
|
@@ -183,19 +218,24 @@ import {
|
|
|
183
218
|
restoreRetryAfterSeconds
|
|
184
219
|
} from "./chunk-4JRM2BSM.js";
|
|
185
220
|
import {
|
|
186
|
-
|
|
187
|
-
} from "./chunk-
|
|
221
|
+
getStableLiveDiscoveryBaseDir
|
|
222
|
+
} from "./chunk-5MK45KZ3.js";
|
|
223
|
+
import {
|
|
224
|
+
LIVE_HOST_BUNDLE_ID,
|
|
225
|
+
LIVE_HOST_PROTOCOL_VERSION,
|
|
226
|
+
LIVE_INPUT_AUDIO_EPOCH_BYTES
|
|
227
|
+
} from "./chunk-NKLP3DCK.js";
|
|
188
228
|
import {
|
|
189
229
|
createDaemonStatusProvider
|
|
190
|
-
} from "./chunk-
|
|
191
|
-
import "./chunk-
|
|
192
|
-
import "./chunk-
|
|
230
|
+
} from "./chunk-K5OIW3I7.js";
|
|
231
|
+
import "./chunk-JS73NNWF.js";
|
|
232
|
+
import "./chunk-J6SIP2IT.js";
|
|
193
233
|
import {
|
|
194
234
|
SessionArtifactAuthorizationError,
|
|
195
235
|
SessionArtifactValidationError,
|
|
196
236
|
createAcpSessionBridge,
|
|
197
237
|
parseSessionSource
|
|
198
|
-
} from "./chunk-
|
|
238
|
+
} from "./chunk-7CPJMZVJ.js";
|
|
199
239
|
import {
|
|
200
240
|
EVENT_SCHEMA_VERSION,
|
|
201
241
|
EventBus,
|
|
@@ -203,66 +243,38 @@ import {
|
|
|
203
243
|
} from "./chunk-7U5G6JXI.js";
|
|
204
244
|
import "./chunk-WCCLLK7X.js";
|
|
205
245
|
import "./chunk-OCPBI7J5.js";
|
|
246
|
+
import "./chunk-VMJL7RH6.js";
|
|
206
247
|
import {
|
|
207
248
|
createWorkspaceProvidersStatusProvider
|
|
208
|
-
} from "./chunk-
|
|
249
|
+
} from "./chunk-Y2FEAXLP.js";
|
|
209
250
|
import {
|
|
210
251
|
getAuthTypeFromEnv,
|
|
211
252
|
resolveCliGenerationConfig
|
|
212
|
-
} from "./chunk-
|
|
253
|
+
} from "./chunk-3LYGXZ2H.js";
|
|
213
254
|
import {
|
|
214
255
|
snapshotProcessEnv
|
|
215
|
-
} from "./chunk-
|
|
216
|
-
import {
|
|
217
|
-
createWorkspaceSkillsStatusProvider
|
|
218
|
-
} from "./chunk-OY5RNSV4.js";
|
|
219
|
-
import "./chunk-BGXZBI5B.js";
|
|
220
|
-
import "./chunk-Z4X5MTRT.js";
|
|
221
|
-
import {
|
|
222
|
-
WorkspacePermissionRulesSessionRequiredError,
|
|
223
|
-
WorkspaceSettingsPartialPersistError,
|
|
224
|
-
mapWorkspaceSkillToggleError
|
|
225
|
-
} from "./chunk-Z7VOMGDC.js";
|
|
226
|
-
import {
|
|
227
|
-
isServeDebugMode,
|
|
228
|
-
mountWebShellAssets,
|
|
229
|
-
mountWebShellSpaFallback
|
|
230
|
-
} from "./chunk-SOORFWKY.js";
|
|
256
|
+
} from "./chunk-WJJYJVQE.js";
|
|
231
257
|
import {
|
|
232
|
-
|
|
233
|
-
|
|
258
|
+
STATUS_SCHEMA_VERSION,
|
|
259
|
+
SessionRestoreTimeoutError,
|
|
260
|
+
createIdleWorkspaceMemoryStatus,
|
|
261
|
+
mapDomainErrorToErrorKind
|
|
262
|
+
} from "./chunk-URN2JIAQ.js";
|
|
263
|
+
import "./chunk-HMJ2P3SV.js";
|
|
234
264
|
import {
|
|
235
265
|
daemonObservedContactsPath,
|
|
236
266
|
loadChannelsConfig
|
|
237
|
-
} from "./chunk-
|
|
238
|
-
import "./chunk-
|
|
267
|
+
} from "./chunk-ROV6B34L.js";
|
|
268
|
+
import "./chunk-XJOHLP2A.js";
|
|
239
269
|
import "./chunk-57OAHC2Y.js";
|
|
240
270
|
import {
|
|
241
271
|
parseChannelWebhookConfigLenient
|
|
242
|
-
} from "./chunk-
|
|
272
|
+
} from "./chunk-J7JQXYVL.js";
|
|
243
273
|
import "./chunk-45NQKMYB.js";
|
|
244
274
|
import {
|
|
245
275
|
supportedChannelCatalog
|
|
246
|
-
} from "./chunk-
|
|
276
|
+
} from "./chunk-2NWPB6T4.js";
|
|
247
277
|
import "./chunk-V6WHFGST.js";
|
|
248
|
-
import {
|
|
249
|
-
getStableLiveDiscoveryBaseDir
|
|
250
|
-
} from "./chunk-TS6625XH.js";
|
|
251
|
-
import {
|
|
252
|
-
LIVE_HOST_BUNDLE_ID,
|
|
253
|
-
LIVE_HOST_PROTOCOL_VERSION,
|
|
254
|
-
LIVE_INPUT_AUDIO_EPOCH_BYTES
|
|
255
|
-
} from "./chunk-NKLP3DCK.js";
|
|
256
|
-
import "./chunk-NHDR76JX.js";
|
|
257
|
-
import {
|
|
258
|
-
STATUS_SCHEMA_VERSION,
|
|
259
|
-
SessionRestoreTimeoutError,
|
|
260
|
-
createIdleWorkspaceMemoryStatus,
|
|
261
|
-
mapDomainErrorToErrorKind
|
|
262
|
-
} from "./chunk-QNQAPSN2.js";
|
|
263
|
-
import "./chunk-K6KS3LTN.js";
|
|
264
|
-
import "./chunk-FC4KQFCS.js";
|
|
265
|
-
import "./chunk-T3CHYWJZ.js";
|
|
266
278
|
import {
|
|
267
279
|
MAX_REGISTERED_WORKSPACES,
|
|
268
280
|
WorkspaceDisplayNameValidationError,
|
|
@@ -270,13 +282,13 @@ import {
|
|
|
270
282
|
WorkspaceRegistrationStoreLimitError,
|
|
271
283
|
normalizeWorkspaceDisplayName,
|
|
272
284
|
workspaceRegistrationId
|
|
273
|
-
} from "./chunk-
|
|
285
|
+
} from "./chunk-TLDZKNZP.js";
|
|
274
286
|
import {
|
|
275
287
|
CHANNEL_PROMPT_META_KEY,
|
|
276
288
|
DAEMON_PROMPT_DISPLAY_TEXT_META_KEY,
|
|
277
289
|
REQUESTED_SESSION_ID_META_KEY,
|
|
278
290
|
gradeActiveWorkCoverage
|
|
279
|
-
} from "./chunk-
|
|
291
|
+
} from "./chunk-QQUVPMMZ.js";
|
|
280
292
|
import {
|
|
281
293
|
BranchWhilePromptActiveError,
|
|
282
294
|
BridgeChannelQuarantinedError,
|
|
@@ -330,23 +342,25 @@ import {
|
|
|
330
342
|
QWEN_SERVER_TOKEN_ENV,
|
|
331
343
|
isChannelDeliveryError,
|
|
332
344
|
isChannelWebhookEnqueueError
|
|
333
|
-
} from "./chunk-
|
|
345
|
+
} from "./chunk-ND7NOI4P.js";
|
|
334
346
|
import {
|
|
335
347
|
normalizeWorkerDiagnostic
|
|
336
348
|
} from "./chunk-A6NRNRKE.js";
|
|
337
349
|
import {
|
|
338
350
|
normalizeServeChannelSelection
|
|
339
351
|
} from "./chunk-ALMR3E6Q.js";
|
|
340
|
-
import "./chunk-
|
|
352
|
+
import "./chunk-UDG5EZJI.js";
|
|
353
|
+
import "./chunk-3VUENPWF.js";
|
|
341
354
|
import {
|
|
342
355
|
redactLogCredentials
|
|
343
356
|
} from "./chunk-M5GB774H.js";
|
|
344
|
-
import "./chunk-
|
|
357
|
+
import "./chunk-5HBA2Z7V.js";
|
|
358
|
+
import "./chunk-K6KS3LTN.js";
|
|
359
|
+
import "./chunk-7E7UCJHS.js";
|
|
345
360
|
import {
|
|
346
361
|
sanitizeLogText
|
|
347
362
|
} from "./chunk-AW27A43Y.js";
|
|
348
363
|
import "./chunk-IW6RQPQB.js";
|
|
349
|
-
import "./chunk-5HBA2Z7V.js";
|
|
350
364
|
import {
|
|
351
365
|
getDialogSettingKeys,
|
|
352
366
|
getModelProvidersOwnerScope,
|
|
@@ -356,30 +370,31 @@ import {
|
|
|
356
370
|
getWritableScopes,
|
|
357
371
|
loadSettings,
|
|
358
372
|
validateSettingValue
|
|
359
|
-
} from "./chunk-
|
|
373
|
+
} from "./chunk-3HWN4E7N.js";
|
|
374
|
+
import "./chunk-VOTDAZR7.js";
|
|
360
375
|
import "./chunk-RKUWKYED.js";
|
|
361
|
-
import "./chunk-E23IPNGS.js";
|
|
362
|
-
import "./chunk-GOXKNSDZ.js";
|
|
363
|
-
import "./chunk-IDS7MSUP.js";
|
|
364
376
|
import {
|
|
365
377
|
detectSystemLanguage,
|
|
366
378
|
resolveLanguageSetting
|
|
367
|
-
} from "./chunk-
|
|
379
|
+
} from "./chunk-45UD2TU4.js";
|
|
368
380
|
import {
|
|
369
381
|
SUPPORTED_LANGUAGES,
|
|
370
382
|
resolveSupportedLanguage
|
|
371
383
|
} from "./chunk-5EJZE3FP.js";
|
|
372
|
-
import "./chunk-
|
|
373
|
-
import "./chunk-
|
|
374
|
-
import "./chunk-
|
|
384
|
+
import "./chunk-5PHLBWBL.js";
|
|
385
|
+
import "./chunk-GOXKNSDZ.js";
|
|
386
|
+
import "./chunk-IDS7MSUP.js";
|
|
387
|
+
import "./chunk-CXJHQVEK.js";
|
|
388
|
+
import "./chunk-7WLFSDLG.js";
|
|
375
389
|
import "./chunk-WZMH7II3.js";
|
|
376
390
|
import {
|
|
377
391
|
getWorkspaceTrustStatus
|
|
378
|
-
} from "./chunk-
|
|
392
|
+
} from "./chunk-PSQJ24ZZ.js";
|
|
379
393
|
import "./chunk-NPQ5ZKRP.js";
|
|
380
394
|
import {
|
|
381
395
|
isWithinRoot as isWithinRoot2
|
|
382
396
|
} from "./chunk-MR3PXB6E.js";
|
|
397
|
+
import "./chunk-LJZSMWOH.js";
|
|
383
398
|
import {
|
|
384
399
|
ALL_PROVIDERS,
|
|
385
400
|
BTW_MAX_INPUT_LENGTH,
|
|
@@ -388,6 +403,7 @@ import {
|
|
|
388
403
|
ClientMcpRegistrar,
|
|
389
404
|
DEFAULT_LOG_LIMIT,
|
|
390
405
|
ExtensionManager,
|
|
406
|
+
ExtensionNotUpdatableError,
|
|
391
407
|
GITHUB_PR_ERROR_MESSAGE_MAX,
|
|
392
408
|
GROUP_COLOR_OPTIONS,
|
|
393
409
|
GitWorktreeService,
|
|
@@ -401,6 +417,7 @@ import {
|
|
|
401
417
|
SESSION_TRANSCRIPT_MAX_LIMIT,
|
|
402
418
|
SESSION_TRANSCRIPT_MAX_PAGE_BYTES,
|
|
403
419
|
SESSION_WRITER_RPC_CODES,
|
|
420
|
+
SessionIdCaseConflictError,
|
|
404
421
|
SessionOrganizationError,
|
|
405
422
|
SessionOrganizationService,
|
|
406
423
|
SessionService,
|
|
@@ -437,6 +454,7 @@ import {
|
|
|
437
454
|
gitPull,
|
|
438
455
|
gitPush,
|
|
439
456
|
glob,
|
|
457
|
+
isSupportedArchiveUrl,
|
|
440
458
|
isValidCheckoutRef,
|
|
441
459
|
isValidRefName,
|
|
442
460
|
loadIgnoreRules,
|
|
@@ -448,25 +466,26 @@ import {
|
|
|
448
466
|
resolveBranchName,
|
|
449
467
|
resolveProviderProtocol,
|
|
450
468
|
shouldShowStep,
|
|
469
|
+
sleepInhibitor,
|
|
451
470
|
stripTerminalControlSequences,
|
|
452
471
|
watchRepoBranch,
|
|
453
472
|
writeWorkspaceContextFile,
|
|
454
473
|
writeWorktreeSession,
|
|
455
474
|
writeWorktreeSessionMarker
|
|
456
|
-
} from "./chunk-
|
|
475
|
+
} from "./chunk-SVU5KGR7.js";
|
|
457
476
|
import "./chunk-GOFAQQZA.js";
|
|
458
|
-
import "./chunk-5M6IDOMF.js";
|
|
459
477
|
import "./chunk-TWPJO254.js";
|
|
460
478
|
import "./chunk-CQ35AJ4Z.js";
|
|
479
|
+
import "./chunk-5M6IDOMF.js";
|
|
480
|
+
import "./chunk-KVGR4MCF.js";
|
|
481
|
+
import "./chunk-XZJKSETB.js";
|
|
482
|
+
import "./chunk-YMVFIYHV.js";
|
|
483
|
+
import "./chunk-6PVPNMXU.js";
|
|
484
|
+
import "./chunk-OTXXOZKW.js";
|
|
461
485
|
import {
|
|
462
486
|
MAX_JOBS,
|
|
463
487
|
nextDurableFireMs
|
|
464
|
-
} from "./chunk-
|
|
465
|
-
import "./chunk-WSH6GRKG.js";
|
|
466
|
-
import "./chunk-CKSJECTU.js";
|
|
467
|
-
import "./chunk-OVZPVYZB.js";
|
|
468
|
-
import "./chunk-6PVPNMXU.js";
|
|
469
|
-
import "./chunk-5EYKMUUY.js";
|
|
488
|
+
} from "./chunk-DJEHYM4H.js";
|
|
470
489
|
import {
|
|
471
490
|
nextFireTime,
|
|
472
491
|
parseCron
|
|
@@ -479,71 +498,72 @@ import {
|
|
|
479
498
|
readCronTasks,
|
|
480
499
|
taskHasLegacyCondition,
|
|
481
500
|
updateCronTasks
|
|
482
|
-
} from "./chunk-
|
|
483
|
-
import "./chunk-
|
|
501
|
+
} from "./chunk-AZF6SME3.js";
|
|
502
|
+
import "./chunk-TBVSALA3.js";
|
|
484
503
|
import "./chunk-O6GEWCJA.js";
|
|
485
504
|
import "./chunk-T26EAKDL.js";
|
|
486
|
-
import "./chunk-ZPJWUGCS.js";
|
|
487
505
|
import "./chunk-CPBF7KYF.js";
|
|
506
|
+
import "./chunk-VUMLT7E5.js";
|
|
507
|
+
import "./chunk-ISJMN3ML.js";
|
|
508
|
+
import "./chunk-2TRNCJK4.js";
|
|
509
|
+
import "./chunk-NUGZAFR2.js";
|
|
510
|
+
import {
|
|
511
|
+
parseGoalControlRequest
|
|
512
|
+
} from "./chunk-LDGWX737.js";
|
|
488
513
|
import {
|
|
489
514
|
APPROVAL_MODES
|
|
490
|
-
} from "./chunk-
|
|
491
|
-
import "./chunk-
|
|
492
|
-
import "./chunk-MIPFDQAF.js";
|
|
515
|
+
} from "./chunk-VLRBJ24J.js";
|
|
516
|
+
import "./chunk-ZPJWUGCS.js";
|
|
493
517
|
import "./chunk-MLXTMF7H.js";
|
|
494
|
-
import
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
518
|
+
import {
|
|
519
|
+
QwenOAuth2Client,
|
|
520
|
+
QwenOAuthPollError,
|
|
521
|
+
cacheQwenCredentials,
|
|
522
|
+
generatePKCEPair,
|
|
523
|
+
isDeviceAuthorizationSuccess,
|
|
524
|
+
isDeviceTokenPending,
|
|
525
|
+
isDeviceTokenSuccess
|
|
526
|
+
} from "./chunk-O5BDEWBC.js";
|
|
527
|
+
import "./chunk-NAVJD2PQ.js";
|
|
528
|
+
import "./chunk-WRT324N6.js";
|
|
529
|
+
import "./chunk-YDJRMQU4.js";
|
|
530
|
+
import "./chunk-KM73TBQ4.js";
|
|
531
|
+
import "./chunk-E63A23D7.js";
|
|
532
|
+
import {
|
|
533
|
+
recordDaemonBridgeError,
|
|
534
|
+
recordDaemonHttpRequest
|
|
535
|
+
} from "./chunk-6NJIPX6W.js";
|
|
536
|
+
import "./chunk-P3QQPMQA.js";
|
|
498
537
|
import {
|
|
499
538
|
addDaemonRequestAttribute,
|
|
500
539
|
captureDaemonTelemetryContext,
|
|
501
540
|
emitDaemonLog,
|
|
541
|
+
extractDaemonHttpTraceContext,
|
|
542
|
+
extractInboundTraceId,
|
|
502
543
|
hashDaemonWorkspace,
|
|
503
|
-
recordDaemonBridgeError,
|
|
504
544
|
recordDaemonError,
|
|
505
|
-
recordDaemonHttpRequest,
|
|
506
545
|
recordDaemonHttpResponse,
|
|
507
546
|
runWithDaemonTelemetryContext,
|
|
508
547
|
withDaemonRequestSpan
|
|
509
|
-
} from "./chunk-
|
|
548
|
+
} from "./chunk-6S2OXVJT.js";
|
|
549
|
+
import "./chunk-XWRJCPHC.js";
|
|
510
550
|
import "./chunk-SAH4BD2J.js";
|
|
511
|
-
import "./chunk-
|
|
512
|
-
import "./chunk-
|
|
551
|
+
import "./chunk-VSNPOSDN.js";
|
|
552
|
+
import "./chunk-I432KXWD.js";
|
|
513
553
|
import "./chunk-S6LOFUVP.js";
|
|
514
|
-
import "./chunk-
|
|
515
|
-
import {
|
|
516
|
-
SubagentError,
|
|
517
|
-
SubagentErrorCode
|
|
518
|
-
} from "./chunk-SG7ZP5PG.js";
|
|
519
|
-
import "./chunk-K623ENWT.js";
|
|
520
|
-
import {
|
|
521
|
-
escapeXml
|
|
522
|
-
} from "./chunk-AQ37AY7B.js";
|
|
523
|
-
import "./chunk-KBXKR5R2.js";
|
|
524
|
-
import {
|
|
525
|
-
QwenOAuth2Client,
|
|
526
|
-
QwenOAuthPollError,
|
|
527
|
-
cacheQwenCredentials,
|
|
528
|
-
generatePKCEPair,
|
|
529
|
-
isDeviceAuthorizationSuccess,
|
|
530
|
-
isDeviceTokenPending,
|
|
531
|
-
isDeviceTokenSuccess
|
|
532
|
-
} from "./chunk-GMIEIY3Y.js";
|
|
533
|
-
import "./chunk-NAVJD2PQ.js";
|
|
534
|
-
import "./chunk-ROIYNTHJ.js";
|
|
535
|
-
import "./chunk-2B2BF7P7.js";
|
|
536
|
-
import "./chunk-P3QQPMQA.js";
|
|
537
|
-
import "./chunk-YZHRN3CF.js";
|
|
538
|
-
import "./chunk-FAAUPSY2.js";
|
|
539
|
-
import "./chunk-KM73TBQ4.js";
|
|
540
|
-
import "./chunk-MPHPFVKK.js";
|
|
554
|
+
import "./chunk-7IV52LTO.js";
|
|
541
555
|
import "./chunk-AXMWHKXA.js";
|
|
542
|
-
import "./chunk-GLCZKT5V.js";
|
|
543
556
|
import "./chunk-DJ2GSRLV.js";
|
|
544
|
-
import "./chunk-
|
|
545
|
-
import "./chunk-
|
|
546
|
-
import "./chunk-
|
|
557
|
+
import "./chunk-2J3OJGTL.js";
|
|
558
|
+
import "./chunk-LI4YHTQK.js";
|
|
559
|
+
import "./chunk-GLCZKT5V.js";
|
|
560
|
+
import "./chunk-C72BXMJ5.js";
|
|
561
|
+
import {
|
|
562
|
+
parseLineTolerant,
|
|
563
|
+
read
|
|
564
|
+
} from "./chunk-RPJOOK6N.js";
|
|
565
|
+
import "./chunk-YRLW2MSX.js";
|
|
566
|
+
import "./chunk-VGC4I5JJ.js";
|
|
547
567
|
import {
|
|
548
568
|
CursorNotAtLineBoundaryError,
|
|
549
569
|
LargeNonUtf8TextError,
|
|
@@ -551,40 +571,47 @@ import {
|
|
|
551
571
|
decodeBufferWithEncodingInfoAsync,
|
|
552
572
|
getAllGeminiMdFilenames,
|
|
553
573
|
isUtf8CompatibleEncoding,
|
|
554
|
-
isWithinRoot
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
import "./chunk-
|
|
559
|
-
import "./chunk-VGC4I5JJ.js";
|
|
560
|
-
import "./chunk-CHHABXPE.js";
|
|
561
|
-
import "./chunk-MA2HEDVP.js";
|
|
562
|
-
import "./chunk-XUJNK7Y6.js";
|
|
563
|
-
import "./chunk-6HY6IF3Z.js";
|
|
564
|
-
import "./chunk-4PKCUT7F.js";
|
|
574
|
+
isWithinRoot
|
|
575
|
+
} from "./chunk-IWOWEENB.js";
|
|
576
|
+
import "./chunk-HIK2OF33.js";
|
|
577
|
+
import "./chunk-ZRYQMWEP.js";
|
|
578
|
+
import "./chunk-7JDGSJQH.js";
|
|
565
579
|
import "./chunk-F6WFNA7U.js";
|
|
566
|
-
import "./chunk-
|
|
580
|
+
import "./chunk-WZAD4ZNJ.js";
|
|
567
581
|
import "./chunk-FPGTNKCP.js";
|
|
568
|
-
import "./chunk-
|
|
569
|
-
import "./chunk-
|
|
570
|
-
import "./chunk-
|
|
582
|
+
import "./chunk-YHC2EYYG.js";
|
|
583
|
+
import "./chunk-PZRUV52H.js";
|
|
584
|
+
import "./chunk-JGUBDRBC.js";
|
|
585
|
+
import "./chunk-HDKCKCYO.js";
|
|
586
|
+
import "./chunk-HHJLM3WQ.js";
|
|
571
587
|
import {
|
|
588
|
+
isTelemetrySdkInitialized,
|
|
572
589
|
redactUrlCredentials,
|
|
573
590
|
stripAnsiAndControl
|
|
574
|
-
} from "./chunk-
|
|
575
|
-
import "./chunk-
|
|
576
|
-
import "./chunk-
|
|
591
|
+
} from "./chunk-32CHFLGV.js";
|
|
592
|
+
import "./chunk-74TONY4F.js";
|
|
593
|
+
import "./chunk-XL5K4SVK.js";
|
|
594
|
+
import {
|
|
595
|
+
SubagentError,
|
|
596
|
+
SubagentErrorCode
|
|
597
|
+
} from "./chunk-WZDM44SB.js";
|
|
598
|
+
import "./chunk-K623ENWT.js";
|
|
599
|
+
import {
|
|
600
|
+
escapeXml
|
|
601
|
+
} from "./chunk-AQ37AY7B.js";
|
|
602
|
+
import "./chunk-K52PZNU4.js";
|
|
603
|
+
import "./chunk-6NFAEG54.js";
|
|
577
604
|
import {
|
|
578
605
|
FatalConfigError,
|
|
579
606
|
Storage,
|
|
580
607
|
createDebugLogger,
|
|
581
608
|
getErrorMessage,
|
|
582
609
|
runWithoutDebugLogSession
|
|
583
|
-
} from "./chunk-
|
|
584
|
-
import "./chunk-VOQXFAY5.js";
|
|
610
|
+
} from "./chunk-A5F2YNO6.js";
|
|
585
611
|
import {
|
|
586
612
|
writeStderrLine,
|
|
587
|
-
writeStderrLineSafe
|
|
613
|
+
writeStderrLineSafe,
|
|
614
|
+
writeStdoutLineSafe
|
|
588
615
|
} from "./chunk-KGJGEEVR.js";
|
|
589
616
|
import "./chunk-75DOP5OR.js";
|
|
590
617
|
import "./chunk-DMTGGOSA.js";
|
|
@@ -596,7 +623,7 @@ import {
|
|
|
596
623
|
} from "./chunk-TYAMGABM.js";
|
|
597
624
|
import "./chunk-FCMNKVXT.js";
|
|
598
625
|
import "./chunk-AMDSOFFV.js";
|
|
599
|
-
import "./chunk-
|
|
626
|
+
import "./chunk-TBWQLLFO.js";
|
|
600
627
|
import {
|
|
601
628
|
init_esbuild_shims
|
|
602
629
|
} from "./chunk-5O2XNYP6.js";
|
|
@@ -607,12 +634,435 @@ import {
|
|
|
607
634
|
|
|
608
635
|
// packages/cli/src/serve/server.ts
|
|
609
636
|
init_esbuild_shims();
|
|
610
|
-
var
|
|
637
|
+
var import_express7 = __toESM(require_express(), 1);
|
|
611
638
|
import * as path18 from "node:path";
|
|
612
639
|
|
|
640
|
+
// packages/cli/src/serve/local-control/index.ts
|
|
641
|
+
init_esbuild_shims();
|
|
642
|
+
|
|
643
|
+
// packages/cli/src/serve/local-control/lan-interfaces.ts
|
|
644
|
+
init_esbuild_shims();
|
|
645
|
+
import { networkInterfaces } from "node:os";
|
|
646
|
+
function isLanIpv4(address) {
|
|
647
|
+
const octets = address.split(".").map((part) => Number(part));
|
|
648
|
+
if (octets.length !== 4 || octets.some((o) => !Number.isInteger(o))) {
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
const [a, b] = octets;
|
|
652
|
+
if (a === 10) return true;
|
|
653
|
+
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
654
|
+
if (a === 192 && b === 168) return true;
|
|
655
|
+
if (a === 169 && b === 254) return true;
|
|
656
|
+
return false;
|
|
657
|
+
}
|
|
658
|
+
__name(isLanIpv4, "isLanIpv4");
|
|
659
|
+
function isSoftwareNetwork(interfaceName) {
|
|
660
|
+
if (/vpn/i.test(interfaceName)) return true;
|
|
661
|
+
return /(^|[\s_.-])(utun|tun|tap|ppp|ipsec|wg|wireguard|tailscale|zerotier|zt[a-z0-9]*|hamachi|nordlynx|proton|wintun|docker|veth[0-9a-f]+|vmnet|vboxnet|vethernet|virtualbox|host[- ]only|podman|cni|lxcbr|lxdbr|flannel|virbr|br-[0-9a-f]+|bridge\d|anyconnect|globalprotect|pulse[\s-]secure|forticlient|fortinet|ivanti|cisco[\s_-]secure|citrix|sonicwall|cloudflare)(\d|[\s_.-]|$)/i.test(
|
|
662
|
+
interfaceName
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
__name(isSoftwareNetwork, "isSoftwareNetwork");
|
|
666
|
+
function listLanCandidates(interfaces = networkInterfaces()) {
|
|
667
|
+
const candidates = [];
|
|
668
|
+
for (const [interfaceName, addresses] of Object.entries(interfaces).sort()) {
|
|
669
|
+
if (isSoftwareNetwork(interfaceName)) continue;
|
|
670
|
+
for (const address of addresses ?? []) {
|
|
671
|
+
if (address.family !== "IPv4" || address.internal) continue;
|
|
672
|
+
if (!isLanIpv4(address.address)) continue;
|
|
673
|
+
candidates.push({ interfaceName, address: address.address });
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return candidates;
|
|
677
|
+
}
|
|
678
|
+
__name(listLanCandidates, "listLanCandidates");
|
|
679
|
+
var NoLanInterfaceError = class extends Error {
|
|
680
|
+
static {
|
|
681
|
+
__name(this, "NoLanInterfaceError");
|
|
682
|
+
}
|
|
683
|
+
code = "no_lan_interface";
|
|
684
|
+
constructor() {
|
|
685
|
+
super(
|
|
686
|
+
"No private IPv4 address is available. Local Control needs the host to be on a local network (Wi-Fi or Ethernet)."
|
|
687
|
+
);
|
|
688
|
+
this.name = "NoLanInterfaceError";
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
var AmbiguousLanInterfaceError = class extends Error {
|
|
692
|
+
static {
|
|
693
|
+
__name(this, "AmbiguousLanInterfaceError");
|
|
694
|
+
}
|
|
695
|
+
code = "ambiguous_lan_interface";
|
|
696
|
+
candidates;
|
|
697
|
+
constructor(candidates) {
|
|
698
|
+
super(
|
|
699
|
+
"Multiple local networks are available; choose which one to expose: " + candidates.map((c) => `${c.interfaceName} (${c.address})`).join(", ")
|
|
700
|
+
);
|
|
701
|
+
this.name = "AmbiguousLanInterfaceError";
|
|
702
|
+
this.candidates = candidates;
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
var UnknownLanInterfaceError = class extends Error {
|
|
706
|
+
static {
|
|
707
|
+
__name(this, "UnknownLanInterfaceError");
|
|
708
|
+
}
|
|
709
|
+
code = "unknown_lan_interface";
|
|
710
|
+
constructor(requested) {
|
|
711
|
+
super(
|
|
712
|
+
`${requested} is not a private IPv4 address on this host right now. The network may have changed since the list was fetched.`
|
|
713
|
+
);
|
|
714
|
+
this.name = "UnknownLanInterfaceError";
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
function selectLanAddress(preferredAddress, interfaces = networkInterfaces()) {
|
|
718
|
+
const candidates = listLanCandidates(interfaces);
|
|
719
|
+
if (candidates.length === 0) throw new NoLanInterfaceError();
|
|
720
|
+
if (preferredAddress !== void 0) {
|
|
721
|
+
const match = candidates.find((c) => c.address === preferredAddress);
|
|
722
|
+
if (!match) throw new UnknownLanInterfaceError(preferredAddress);
|
|
723
|
+
return match;
|
|
724
|
+
}
|
|
725
|
+
if (candidates.length > 1) throw new AmbiguousLanInterfaceError(candidates);
|
|
726
|
+
return candidates[0];
|
|
727
|
+
}
|
|
728
|
+
__name(selectLanAddress, "selectLanAddress");
|
|
729
|
+
|
|
730
|
+
// packages/cli/src/serve/local-control/service.ts
|
|
731
|
+
init_esbuild_shims();
|
|
732
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
733
|
+
import { readFileSync } from "node:fs";
|
|
734
|
+
import { createServer } from "node:http";
|
|
735
|
+
import { createServer as createSecureServer } from "node:https";
|
|
736
|
+
var CORS_KEY = "local-control";
|
|
737
|
+
var MAX_CONNECTIONS = 64;
|
|
738
|
+
var HEADERS_TIMEOUT_MS = 1e4;
|
|
739
|
+
var KEEP_ALIVE_TIMEOUT_MS = 5e3;
|
|
740
|
+
var REQUEST_TIMEOUT_MS = 30 * 6e4;
|
|
741
|
+
var InvalidLocalControlTargetError = class extends Error {
|
|
742
|
+
static {
|
|
743
|
+
__name(this, "InvalidLocalControlTargetError");
|
|
744
|
+
}
|
|
745
|
+
code = "invalid_local_control_target";
|
|
746
|
+
constructor() {
|
|
747
|
+
super("Local Control target must be a valid URL target.");
|
|
748
|
+
this.name = "InvalidLocalControlTargetError";
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
var LocalControlService = class {
|
|
752
|
+
static {
|
|
753
|
+
__name(this, "LocalControlService");
|
|
754
|
+
}
|
|
755
|
+
#deps;
|
|
756
|
+
#server;
|
|
757
|
+
#token;
|
|
758
|
+
#selected;
|
|
759
|
+
#sleep;
|
|
760
|
+
#url;
|
|
761
|
+
#transition = Promise.resolve();
|
|
762
|
+
constructor(deps) {
|
|
763
|
+
this.#deps = deps;
|
|
764
|
+
}
|
|
765
|
+
get active() {
|
|
766
|
+
return this.#server !== void 0;
|
|
767
|
+
}
|
|
768
|
+
status() {
|
|
769
|
+
if (!this.#server || !this.#token || !this.#selected) {
|
|
770
|
+
return { active: false };
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
active: true,
|
|
774
|
+
url: this.#url,
|
|
775
|
+
interfaceName: this.#selected.interfaceName,
|
|
776
|
+
address: this.#selected.address,
|
|
777
|
+
port: this.#deps.getPort(),
|
|
778
|
+
sleepInhibited: this.#sleep !== void 0 && sleepInhibitor.isRunning(),
|
|
779
|
+
encrypted: this.#deps.tlsPaths !== void 0
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Bring the LAN listener up. Enabling while already active is a no-op that
|
|
784
|
+
* returns the existing status rather than re-minting: a second scan of the
|
|
785
|
+
* same QR must keep working, and silently invalidating the token the user is
|
|
786
|
+
* mid-pairing with would be indistinguishable from a bug.
|
|
787
|
+
*/
|
|
788
|
+
async enable(options = {}) {
|
|
789
|
+
return this.#serialize(() => this.#enable(options));
|
|
790
|
+
}
|
|
791
|
+
async #enable(options) {
|
|
792
|
+
if (this.active) return this.status();
|
|
793
|
+
const selected = selectLanAddress(options.address);
|
|
794
|
+
const port = this.#deps.getPort();
|
|
795
|
+
const authority = `${selected.address}:${port}`;
|
|
796
|
+
const token = mintPairingToken();
|
|
797
|
+
const tls = this.#deps.tlsPaths;
|
|
798
|
+
const scheme = tls ? "https" : "http";
|
|
799
|
+
const origin = new URL(`${scheme}://${authority}`).origin;
|
|
800
|
+
const url = buildPairedUrl(scheme, authority, token.secret, options.target);
|
|
801
|
+
const server = tls ? createSecureServer(
|
|
802
|
+
{ cert: readFileSync(tls.cert), key: readFileSync(tls.key) },
|
|
803
|
+
this.#deps.app
|
|
804
|
+
) : createServer(this.#deps.app);
|
|
805
|
+
server.maxConnections = MAX_CONNECTIONS;
|
|
806
|
+
server.headersTimeout = HEADERS_TIMEOUT_MS;
|
|
807
|
+
server.requestTimeout = REQUEST_TIMEOUT_MS;
|
|
808
|
+
server.keepAliveTimeout = KEEP_ALIVE_TIMEOUT_MS;
|
|
809
|
+
tagListener(server, { kind: "local-control", authority, origin });
|
|
810
|
+
this.#deps.credentials.addPairingToken(token.id, token.secret);
|
|
811
|
+
this.#deps.originAllowlist.add(CORS_KEY, origin);
|
|
812
|
+
try {
|
|
813
|
+
this.#deps.attachWebSocket(server);
|
|
814
|
+
await listen(server, port, selected.address);
|
|
815
|
+
} catch (error2) {
|
|
816
|
+
this.#deps.detachWebSocket(server);
|
|
817
|
+
this.#deps.credentials.revokePairingToken(token.id);
|
|
818
|
+
this.#deps.originAllowlist.remove(CORS_KEY);
|
|
819
|
+
throw error2;
|
|
820
|
+
}
|
|
821
|
+
server.on("error", (error2) => {
|
|
822
|
+
writeStderrLine(
|
|
823
|
+
`qwen serve: Local Control listener error: ${error2.message}`
|
|
824
|
+
);
|
|
825
|
+
});
|
|
826
|
+
this.#server = server;
|
|
827
|
+
this.#token = token;
|
|
828
|
+
this.#selected = selected;
|
|
829
|
+
this.#url = url;
|
|
830
|
+
this.#sleep = sleepInhibitor.acquire("Qwen Code Local Control is active");
|
|
831
|
+
return this.status();
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Take the LAN listener down and invalidate its credential.
|
|
835
|
+
*
|
|
836
|
+
* Revocation happens first and unconditionally. If closing the socket fails
|
|
837
|
+
* or hangs, the outcome is a listener that accepts connections no credential
|
|
838
|
+
* can authenticate — inert. The reverse order would leave a live, reachable
|
|
839
|
+
* listener with a valid token if teardown failed partway.
|
|
840
|
+
*/
|
|
841
|
+
async disable() {
|
|
842
|
+
return this.#serialize(() => this.#disable());
|
|
843
|
+
}
|
|
844
|
+
async #disable() {
|
|
845
|
+
const server = this.#server;
|
|
846
|
+
const token = this.#token;
|
|
847
|
+
this.#server = void 0;
|
|
848
|
+
this.#token = void 0;
|
|
849
|
+
this.#selected = void 0;
|
|
850
|
+
this.#url = void 0;
|
|
851
|
+
if (token) this.#deps.credentials.revokePairingToken(token.id);
|
|
852
|
+
this.#deps.originAllowlist.remove(CORS_KEY);
|
|
853
|
+
this.#sleep?.release();
|
|
854
|
+
this.#sleep = void 0;
|
|
855
|
+
if (server) {
|
|
856
|
+
this.#deps.detachWebSocket(server);
|
|
857
|
+
await close(server);
|
|
858
|
+
}
|
|
859
|
+
return { active: false };
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Called from the daemon's drain path. Local Control must not outlive the
|
|
863
|
+
* daemon that owns it: a listener surviving drain would hold the port and
|
|
864
|
+
* keep answering with a token nothing can revoke anymore.
|
|
865
|
+
*/
|
|
866
|
+
async dispose() {
|
|
867
|
+
await this.disable();
|
|
868
|
+
}
|
|
869
|
+
async #serialize(operation) {
|
|
870
|
+
const previous = this.#transition;
|
|
871
|
+
let release;
|
|
872
|
+
this.#transition = new Promise((resolve7) => {
|
|
873
|
+
release = resolve7;
|
|
874
|
+
});
|
|
875
|
+
await previous;
|
|
876
|
+
try {
|
|
877
|
+
return await operation();
|
|
878
|
+
} finally {
|
|
879
|
+
release();
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
function mintPairingToken() {
|
|
884
|
+
const secret = randomBytes(32).toString("base64url");
|
|
885
|
+
return { id: randomUUID(), secret };
|
|
886
|
+
}
|
|
887
|
+
__name(mintPairingToken, "mintPairingToken");
|
|
888
|
+
function buildPairedUrl(scheme, authority, secret, target) {
|
|
889
|
+
const url = new URL(`${scheme}://${authority}`);
|
|
890
|
+
if (target) {
|
|
891
|
+
let resolved;
|
|
892
|
+
try {
|
|
893
|
+
resolved = new URL(target, url);
|
|
894
|
+
} catch {
|
|
895
|
+
throw new InvalidLocalControlTargetError();
|
|
896
|
+
}
|
|
897
|
+
url.pathname = resolved.pathname;
|
|
898
|
+
url.search = resolved.search;
|
|
899
|
+
}
|
|
900
|
+
url.hash = `token=${encodeURIComponent(secret)}`;
|
|
901
|
+
return url.toString();
|
|
902
|
+
}
|
|
903
|
+
__name(buildPairedUrl, "buildPairedUrl");
|
|
904
|
+
function listen(server, port, host) {
|
|
905
|
+
return new Promise((resolve7, reject) => {
|
|
906
|
+
const onError = /* @__PURE__ */ __name((error2) => {
|
|
907
|
+
server.removeListener("listening", onListening);
|
|
908
|
+
reject(error2);
|
|
909
|
+
}, "onError");
|
|
910
|
+
const onListening = /* @__PURE__ */ __name(() => {
|
|
911
|
+
server.removeListener("error", onError);
|
|
912
|
+
resolve7();
|
|
913
|
+
}, "onListening");
|
|
914
|
+
server.once("error", onError);
|
|
915
|
+
server.once("listening", onListening);
|
|
916
|
+
server.listen(port, host);
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
__name(listen, "listen");
|
|
920
|
+
function close(server) {
|
|
921
|
+
return new Promise((resolve7) => {
|
|
922
|
+
server.closeAllConnections?.();
|
|
923
|
+
server.close(() => resolve7());
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
__name(close, "close");
|
|
927
|
+
|
|
928
|
+
// packages/cli/src/serve/routes/workspace-local-control.ts
|
|
929
|
+
init_esbuild_shims();
|
|
930
|
+
async function withUiData(status) {
|
|
931
|
+
let qrText;
|
|
932
|
+
if (status.url) {
|
|
933
|
+
try {
|
|
934
|
+
const { default: qrcode } = await import("./main-PXAUXNF2.js");
|
|
935
|
+
qrcode.setErrorLevel("Q");
|
|
936
|
+
qrcode.generate(status.url, { small: true }, (code) => {
|
|
937
|
+
qrText = code.trimEnd();
|
|
938
|
+
});
|
|
939
|
+
} catch {
|
|
940
|
+
qrText = void 0;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return { ...status, qrText, interfaces: listLanCandidates() };
|
|
944
|
+
}
|
|
945
|
+
__name(withUiData, "withUiData");
|
|
946
|
+
function presentStatus(req, ui) {
|
|
947
|
+
if (requestWasAuthenticated(req)) return ui;
|
|
948
|
+
const { url: _url, qrText: _qrText, ...rest } = ui;
|
|
949
|
+
return { ...rest, urlRedacted: ui.url !== void 0 };
|
|
950
|
+
}
|
|
951
|
+
__name(presentStatus, "presentStatus");
|
|
952
|
+
function requirePrimaryListener(req, res) {
|
|
953
|
+
if (listenerIdentityOf(req).kind === "primary") return true;
|
|
954
|
+
res.status(403).json({
|
|
955
|
+
error: "Local Control can only be enabled from the machine running the daemon.",
|
|
956
|
+
code: "local_control_remote_enable_denied"
|
|
957
|
+
});
|
|
958
|
+
return false;
|
|
959
|
+
}
|
|
960
|
+
__name(requirePrimaryListener, "requirePrimaryListener");
|
|
961
|
+
function registerWorkspaceLocalControlRoutes(app, deps) {
|
|
962
|
+
app.get("/workspace/local-control", async (req, res) => {
|
|
963
|
+
res.status(200).json(presentStatus(req, await withUiData(deps.service.status())));
|
|
964
|
+
});
|
|
965
|
+
app.post(
|
|
966
|
+
"/workspace/local-control/enable",
|
|
967
|
+
deps.mutate(),
|
|
968
|
+
async (req, res) => {
|
|
969
|
+
if (!requirePrimaryListener(req, res)) return;
|
|
970
|
+
if (deps.webShellAvailable === false) {
|
|
971
|
+
res.status(409).json({
|
|
972
|
+
error: "Local Control requires the Web Shell.",
|
|
973
|
+
code: "local_control_web_shell_unavailable"
|
|
974
|
+
});
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (deps.primaryBindHostname !== void 0 && !isLoopbackBind(deps.primaryBindHostname)) {
|
|
978
|
+
res.status(409).json({
|
|
979
|
+
error: "Local Control requires the daemon to be bound to loopback; restart it with --hostname 127.0.0.1.",
|
|
980
|
+
code: "local_control_non_loopback_bind"
|
|
981
|
+
});
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
if (deps.isDaemonDraining?.()) {
|
|
985
|
+
res.status(503).json({
|
|
986
|
+
error: "Daemon is shutting down.",
|
|
987
|
+
code: "daemon_draining"
|
|
988
|
+
});
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
const body = deps.safeBody(req) ?? {};
|
|
992
|
+
try {
|
|
993
|
+
const ui = await withUiData(
|
|
994
|
+
await deps.service.enable({
|
|
995
|
+
address: typeof body.address === "string" ? body.address : void 0,
|
|
996
|
+
target: typeof body.target === "string" ? body.target : void 0
|
|
997
|
+
})
|
|
998
|
+
);
|
|
999
|
+
if (!requestWasAuthenticated(req) && ui.url) {
|
|
1000
|
+
writeStdoutLineSafe(
|
|
1001
|
+
`qwen serve: Local Control pairing URL: ${ui.url}`
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
res.status(200).json(presentStatus(req, ui));
|
|
1005
|
+
} catch (error2) {
|
|
1006
|
+
sendEnableError(res, error2);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
);
|
|
1010
|
+
app.post(
|
|
1011
|
+
"/workspace/local-control/disable",
|
|
1012
|
+
deps.mutate(),
|
|
1013
|
+
async (req, res) => {
|
|
1014
|
+
if (listenerIdentityOf(req).kind === "local-control") {
|
|
1015
|
+
queueMicrotask(() => {
|
|
1016
|
+
void deps.service.disable().catch((error2) => {
|
|
1017
|
+
writeStderrLine(
|
|
1018
|
+
`qwen serve: Local Control disable failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
1019
|
+
);
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1022
|
+
res.status(200).json({ active: false });
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
res.status(200).json(
|
|
1026
|
+
presentStatus(req, await withUiData(await deps.service.disable()))
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
__name(registerWorkspaceLocalControlRoutes, "registerWorkspaceLocalControlRoutes");
|
|
1032
|
+
function sendEnableError(res, error2) {
|
|
1033
|
+
if (error2 instanceof AmbiguousLanInterfaceError) {
|
|
1034
|
+
res.status(409).json({
|
|
1035
|
+
error: error2.message,
|
|
1036
|
+
code: error2.code,
|
|
1037
|
+
interfaces: error2.candidates
|
|
1038
|
+
});
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
if (error2 instanceof NoLanInterfaceError) {
|
|
1042
|
+
res.status(409).json({ error: error2.message, code: error2.code });
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
if (error2 instanceof UnknownLanInterfaceError) {
|
|
1046
|
+
res.status(409).json({
|
|
1047
|
+
error: error2.message,
|
|
1048
|
+
code: error2.code,
|
|
1049
|
+
interfaces: listLanCandidates()
|
|
1050
|
+
});
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
if (error2 instanceof InvalidLocalControlTargetError) {
|
|
1054
|
+
res.status(400).json({ error: error2.message, code: error2.code });
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
res.status(500).json({
|
|
1058
|
+
error: error2 instanceof Error ? error2.message : String(error2),
|
|
1059
|
+
code: "local_control_enable_failed"
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
__name(sendEnableError, "sendEnableError");
|
|
1063
|
+
|
|
613
1064
|
// packages/cli/src/serve/acp-http/index.ts
|
|
614
1065
|
init_esbuild_shims();
|
|
615
|
-
import { createHash as createHash3, timingSafeEqual } from "node:crypto";
|
|
616
1066
|
|
|
617
1067
|
// packages/cli/src/serve/acp-http/dispatch.ts
|
|
618
1068
|
init_esbuild_shims();
|
|
@@ -1131,6 +1581,7 @@ function createAuditPublisher(deps) {
|
|
|
1131
1581
|
if (record.sizeBytes !== void 0) payload.sizeBytes = record.sizeBytes;
|
|
1132
1582
|
if (record.truncated) payload.truncated = true;
|
|
1133
1583
|
if (record.matchedIgnore) payload.matchedIgnore = record.matchedIgnore;
|
|
1584
|
+
if (record.operation !== void 0) payload.operation = record.operation;
|
|
1134
1585
|
if (record.pattern !== void 0 && includeRawPaths) {
|
|
1135
1586
|
payload.pattern = record.pattern;
|
|
1136
1587
|
}
|
|
@@ -1177,7 +1628,7 @@ __name(createAuditPublisher, "createAuditPublisher");
|
|
|
1177
1628
|
|
|
1178
1629
|
// packages/cli/src/serve/fs/workspace-file-system.ts
|
|
1179
1630
|
init_esbuild_shims();
|
|
1180
|
-
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
1631
|
+
import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
|
|
1181
1632
|
import { constants as fsConstants, promises as fsp2 } from "node:fs";
|
|
1182
1633
|
import * as path4 from "node:path";
|
|
1183
1634
|
|
|
@@ -1238,6 +1689,11 @@ function assertCursorMatchesFile(cursor, stats, path19) {
|
|
|
1238
1689
|
__name(assertCursorMatchesFile, "assertCursorMatchesFile");
|
|
1239
1690
|
|
|
1240
1691
|
// packages/cli/src/serve/fs/workspace-file-system.ts
|
|
1692
|
+
var OWNER_ONLY_NEW_FILE_MODE = 384;
|
|
1693
|
+
function resolveNewFileModeBits(policy, umask) {
|
|
1694
|
+
return policy === "system" ? 438 & ~(umask ?? process.umask()) : OWNER_ONLY_NEW_FILE_MODE;
|
|
1695
|
+
}
|
|
1696
|
+
__name(resolveNewFileModeBits, "resolveNewFileModeBits");
|
|
1241
1697
|
function createWorkspaceFileSystemFactory(deps) {
|
|
1242
1698
|
const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
|
|
1243
1699
|
if (boundWorkspaces.length === 0) {
|
|
@@ -1263,6 +1719,7 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1263
1719
|
});
|
|
1264
1720
|
const lowFs = new StandardFileSystemService();
|
|
1265
1721
|
const pathLocks = deps.pathLocks ?? new PathMutexRegistry();
|
|
1722
|
+
const newFileMode = deps.newFileMode ?? "owner";
|
|
1266
1723
|
const forRequest = /* @__PURE__ */ __name((ctx) => new WorkspaceFileSystemImpl({
|
|
1267
1724
|
primaryWorkspace,
|
|
1268
1725
|
workspaces,
|
|
@@ -1271,7 +1728,8 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1271
1728
|
ctx,
|
|
1272
1729
|
lowFs,
|
|
1273
1730
|
pathLocks,
|
|
1274
|
-
generationGuard: deps.generationGuard
|
|
1731
|
+
generationGuard: deps.generationGuard,
|
|
1732
|
+
newFileMode
|
|
1275
1733
|
}), "forRequest");
|
|
1276
1734
|
return {
|
|
1277
1735
|
assertCanWrite() {
|
|
@@ -1304,7 +1762,8 @@ function createWorkspaceFileSystemFactory(deps) {
|
|
|
1304
1762
|
audit,
|
|
1305
1763
|
ctx,
|
|
1306
1764
|
pathLocks,
|
|
1307
|
-
generationGuard: deps.generationGuard
|
|
1765
|
+
generationGuard: deps.generationGuard,
|
|
1766
|
+
newFileMode
|
|
1308
1767
|
});
|
|
1309
1768
|
return;
|
|
1310
1769
|
} catch (outsideErr) {
|
|
@@ -1343,6 +1802,7 @@ async function writeSameHostToolTextOutsideWorkspace(deps) {
|
|
|
1343
1802
|
content,
|
|
1344
1803
|
mode: "overwrite",
|
|
1345
1804
|
meta,
|
|
1805
|
+
newFileModeBits: resolveNewFileModeBits(deps.newFileMode),
|
|
1346
1806
|
assertGenerationOpen: /* @__PURE__ */ __name(() => deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1347
1807
|
});
|
|
1348
1808
|
deps.audit.recordAccess(deps.ctx, {
|
|
@@ -1862,6 +2322,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1862
2322
|
mode: opts.mode,
|
|
1863
2323
|
expectedHash: opts.expectedHash,
|
|
1864
2324
|
meta,
|
|
2325
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
1865
2326
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1866
2327
|
});
|
|
1867
2328
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -1924,6 +2385,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1924
2385
|
content,
|
|
1925
2386
|
mode: "overwrite",
|
|
1926
2387
|
meta,
|
|
2388
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
1927
2389
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1928
2390
|
});
|
|
1929
2391
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2035,6 +2497,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2035
2497
|
mode: "replace",
|
|
2036
2498
|
expectedHash: opts.expectedHash,
|
|
2037
2499
|
meta,
|
|
2500
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
2038
2501
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2039
2502
|
});
|
|
2040
2503
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2098,6 +2561,7 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2098
2561
|
content: next,
|
|
2099
2562
|
mode: "overwrite",
|
|
2100
2563
|
meta: mergeWriteMeta(snapshot.meta, {}),
|
|
2564
|
+
newFileModeBits: resolveNewFileModeBits(this.deps.newFileMode),
|
|
2101
2565
|
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2102
2566
|
});
|
|
2103
2567
|
const verdict = this.ignoreVerdict(p, "file");
|
|
@@ -2149,6 +2613,36 @@ var WorkspaceFileSystemImpl = class {
|
|
|
2149
2613
|
});
|
|
2150
2614
|
}
|
|
2151
2615
|
}
|
|
2616
|
+
async mkdir(p, opts) {
|
|
2617
|
+
const start = performance.now();
|
|
2618
|
+
try {
|
|
2619
|
+
this.deps.generationGuard?.assertOpen();
|
|
2620
|
+
assertTrustedForIntent(this.deps.trusted, "write");
|
|
2621
|
+
const out = await this.deps.pathLocks.runExclusive(
|
|
2622
|
+
p,
|
|
2623
|
+
async () => {
|
|
2624
|
+
await ensureResolvedDirectory(p, {
|
|
2625
|
+
recursive: opts?.recursive ?? false,
|
|
2626
|
+
assertGenerationOpen: /* @__PURE__ */ __name(() => this.deps.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
2627
|
+
});
|
|
2628
|
+
this.deps.generationGuard?.assertOpen();
|
|
2629
|
+
const verdict = this.ignoreVerdict(p, "directory");
|
|
2630
|
+
this.deps.audit.recordAccess(this.deps.ctx, {
|
|
2631
|
+
intent: "write",
|
|
2632
|
+
absolute: p,
|
|
2633
|
+
durationMs: performance.now() - start,
|
|
2634
|
+
sizeBytes: 0,
|
|
2635
|
+
operation: "mkdir",
|
|
2636
|
+
matchedIgnore: verdict.ignored ? verdict.category : void 0
|
|
2637
|
+
});
|
|
2638
|
+
return void 0;
|
|
2639
|
+
}
|
|
2640
|
+
);
|
|
2641
|
+
return out;
|
|
2642
|
+
} catch (err) {
|
|
2643
|
+
throw this.recordAndWrap(err, "write", p);
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2152
2646
|
/**
|
|
2153
2647
|
* Coerce an arbitrary thrown value into an `FsError`, emit the
|
|
2154
2648
|
* matching `fs.denied` audit event, and return the typed error
|
|
@@ -2632,10 +3126,82 @@ async function atomicWriteTextResolvedFile(input) {
|
|
|
2632
3126
|
buf,
|
|
2633
3127
|
mode: input.mode,
|
|
2634
3128
|
expectedHash: input.expectedHash,
|
|
3129
|
+
newFileModeBits: input.newFileModeBits,
|
|
2635
3130
|
assertGenerationOpen: input.assertGenerationOpen
|
|
2636
3131
|
});
|
|
2637
3132
|
}
|
|
2638
3133
|
__name(atomicWriteTextResolvedFile, "atomicWriteTextResolvedFile");
|
|
3134
|
+
async function ensureResolvedDirectory(target, opts) {
|
|
3135
|
+
const assertRealDirectory = /* @__PURE__ */ __name(async (p) => {
|
|
3136
|
+
const st = await fsp2.lstat(p);
|
|
3137
|
+
if (st.isSymbolicLink()) {
|
|
3138
|
+
throw new FsError("symlink_escape", `directory path is a symlink: ${p}`, {
|
|
3139
|
+
hint: "re-resolve the target after detecting symlink swaps"
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
if (!st.isDirectory()) {
|
|
3143
|
+
throw new FsError(
|
|
3144
|
+
"parse_error",
|
|
3145
|
+
`path exists and is not a directory: ${p}`
|
|
3146
|
+
);
|
|
3147
|
+
}
|
|
3148
|
+
}, "assertRealDirectory");
|
|
3149
|
+
const assertParentNotSymlink = /* @__PURE__ */ __name(async (p) => {
|
|
3150
|
+
const parent = path4.dirname(p);
|
|
3151
|
+
const st = await fsp2.lstat(parent);
|
|
3152
|
+
if (st.isSymbolicLink()) {
|
|
3153
|
+
throw new FsError(
|
|
3154
|
+
"symlink_escape",
|
|
3155
|
+
`directory parent is a symlink: ${parent}`,
|
|
3156
|
+
{ hint: "re-resolve the target after detecting symlink swaps" }
|
|
3157
|
+
);
|
|
3158
|
+
}
|
|
3159
|
+
}, "assertParentNotSymlink");
|
|
3160
|
+
try {
|
|
3161
|
+
await assertRealDirectory(target);
|
|
3162
|
+
return;
|
|
3163
|
+
} catch (err) {
|
|
3164
|
+
if (isFsError(err)) throw err;
|
|
3165
|
+
if (err.code !== "ENOENT") throw err;
|
|
3166
|
+
}
|
|
3167
|
+
if (!opts.recursive) {
|
|
3168
|
+
opts.assertGenerationOpen();
|
|
3169
|
+
await assertParentNotSymlink(target);
|
|
3170
|
+
try {
|
|
3171
|
+
await fsp2.mkdir(target, { mode: 493 });
|
|
3172
|
+
} catch (err) {
|
|
3173
|
+
if (err.code !== "EEXIST") throw err;
|
|
3174
|
+
}
|
|
3175
|
+
await assertRealDirectory(target);
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
const missing = [];
|
|
3179
|
+
let current = target;
|
|
3180
|
+
while (true) {
|
|
3181
|
+
try {
|
|
3182
|
+
await assertRealDirectory(current);
|
|
3183
|
+
break;
|
|
3184
|
+
} catch (err) {
|
|
3185
|
+
if (isFsError(err)) throw err;
|
|
3186
|
+
if (err.code !== "ENOENT") throw err;
|
|
3187
|
+
missing.push(current);
|
|
3188
|
+
const parent = path4.dirname(current);
|
|
3189
|
+
if (parent === current) throw err;
|
|
3190
|
+
current = parent;
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
for (const entry of missing.reverse()) {
|
|
3194
|
+
opts.assertGenerationOpen();
|
|
3195
|
+
await assertParentNotSymlink(entry);
|
|
3196
|
+
try {
|
|
3197
|
+
await fsp2.mkdir(entry, { mode: 493 });
|
|
3198
|
+
} catch (err) {
|
|
3199
|
+
if (err.code !== "EEXIST") throw err;
|
|
3200
|
+
}
|
|
3201
|
+
await assertRealDirectory(entry);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
__name(ensureResolvedDirectory, "ensureResolvedDirectory");
|
|
2639
3205
|
async function atomicPublishResolvedFile(input) {
|
|
2640
3206
|
const target = input.target;
|
|
2641
3207
|
const parent = path4.dirname(target);
|
|
@@ -2651,7 +3217,7 @@ async function atomicPublishResolvedFile(input) {
|
|
|
2651
3217
|
`parent path is not a directory: ${parent}`
|
|
2652
3218
|
);
|
|
2653
3219
|
}
|
|
2654
|
-
const tmpSuffix = `.${process.pid}.${
|
|
3220
|
+
const tmpSuffix = `.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
|
|
2655
3221
|
const tmpNameMaxBytes = 255;
|
|
2656
3222
|
const tmpBaseMaxBytes = tmpNameMaxBytes - 1 - Buffer.byteLength(tmpSuffix, "utf-8");
|
|
2657
3223
|
let tmpBase = path4.basename(target);
|
|
@@ -2679,7 +3245,10 @@ async function atomicPublishResolvedFile(input) {
|
|
|
2679
3245
|
mode: input.mode,
|
|
2680
3246
|
expectedHash: input.expectedHash
|
|
2681
3247
|
});
|
|
2682
|
-
await chmodHandleBestEffort(
|
|
3248
|
+
await chmodHandleBestEffort(
|
|
3249
|
+
tempHandle,
|
|
3250
|
+
targetState.mode ?? input.newFileModeBits ?? OWNER_ONLY_NEW_FILE_MODE
|
|
3251
|
+
);
|
|
2683
3252
|
await assertTempPathMatchesStat(tmpPath, tempStat);
|
|
2684
3253
|
await tempHandle.close();
|
|
2685
3254
|
tempHandle = void 0;
|
|
@@ -4658,7 +5227,7 @@ __name(registerWorkspaceQualifiedVoiceRoutes, "registerWorkspaceQualifiedVoiceRo
|
|
|
4658
5227
|
|
|
4659
5228
|
// packages/cli/src/serve/workspace-remember.ts
|
|
4660
5229
|
init_esbuild_shims();
|
|
4661
|
-
import { randomUUID } from "node:crypto";
|
|
5230
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
4662
5231
|
var debugLogger = createDebugLogger("WORKSPACE_REMEMBER");
|
|
4663
5232
|
function requireTrustedWorkspace(deps, res) {
|
|
4664
5233
|
if (deps.isWorkspaceTrusted?.() !== false) return true;
|
|
@@ -4688,7 +5257,7 @@ function nowIso() {
|
|
|
4688
5257
|
}
|
|
4689
5258
|
__name(nowIso, "nowIso");
|
|
4690
5259
|
function createMemoryTaskId(kind) {
|
|
4691
|
-
return `${kind}-${
|
|
5260
|
+
return `${kind}-${randomUUID2()}`;
|
|
4692
5261
|
}
|
|
4693
5262
|
__name(createMemoryTaskId, "createMemoryTaskId");
|
|
4694
5263
|
function touchedScopesFromTopics(topics) {
|
|
@@ -5446,11 +6015,13 @@ var RequestedSessionIdAdmissionError = class extends Error {
|
|
|
5446
6015
|
name = "RequestedSessionIdAdmissionError";
|
|
5447
6016
|
};
|
|
5448
6017
|
async function persistedSessionExists(sessionService, sessionId) {
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
6018
|
+
try {
|
|
6019
|
+
if (await sessionService.findSessionIdIgnoringCase(sessionId) !== void 0) {
|
|
6020
|
+
return true;
|
|
6021
|
+
}
|
|
6022
|
+
} catch (error2) {
|
|
6023
|
+
if (error2 instanceof SessionIdCaseConflictError) return true;
|
|
6024
|
+
throw error2;
|
|
5454
6025
|
}
|
|
5455
6026
|
for (const state of ["active", "archived"]) {
|
|
5456
6027
|
try {
|
|
@@ -7759,8 +8330,13 @@ var SessionArchiveCoordinator = class {
|
|
|
7759
8330
|
maintenanceSealed = false;
|
|
7760
8331
|
activeMaintenance = 0;
|
|
7761
8332
|
maintenanceDrain;
|
|
8333
|
+
// Lock keys are canonicalized like every other session-id lookup: batch
|
|
8334
|
+
// delete/archive/unarchive lock raw caller spellings while restore locks
|
|
8335
|
+
// the request spelling, and on a case-insensitive filesystem both reach
|
|
8336
|
+
// the same transcript file — uncanonicalized keys would let a differently
|
|
8337
|
+
// cased caller id slip past a held guard and unlink it mid-restore.
|
|
7762
8338
|
assertNotTransitioning(sessionId) {
|
|
7763
|
-
if (this.exclusive.has(sessionId)) {
|
|
8339
|
+
if (this.exclusive.has(normalizeSessionIdForLookup(sessionId))) {
|
|
7764
8340
|
throw new SessionArchivingError(sessionId);
|
|
7765
8341
|
}
|
|
7766
8342
|
}
|
|
@@ -7768,7 +8344,9 @@ var SessionArchiveCoordinator = class {
|
|
|
7768
8344
|
if (this.maintenanceSealed) {
|
|
7769
8345
|
throw new DaemonDrainingError();
|
|
7770
8346
|
}
|
|
7771
|
-
const uniqueSessionIds = [
|
|
8347
|
+
const uniqueSessionIds = [
|
|
8348
|
+
...new Set(sessionIds.map(normalizeSessionIdForLookup))
|
|
8349
|
+
];
|
|
7772
8350
|
for (const sessionId of uniqueSessionIds) {
|
|
7773
8351
|
this.assertNotTransitioning(sessionId);
|
|
7774
8352
|
if ((this.shared.get(sessionId) ?? 0) > 0) {
|
|
@@ -7810,7 +8388,9 @@ var SessionArchiveCoordinator = class {
|
|
|
7810
8388
|
if (this.maintenanceSealed) {
|
|
7811
8389
|
throw new DaemonDrainingError();
|
|
7812
8390
|
}
|
|
7813
|
-
const uniqueSessionIds = [
|
|
8391
|
+
const uniqueSessionIds = [
|
|
8392
|
+
...new Set(sessionIds.map(normalizeSessionIdForLookup))
|
|
8393
|
+
];
|
|
7814
8394
|
for (const sessionId of uniqueSessionIds) {
|
|
7815
8395
|
this.assertNotTransitioning(sessionId);
|
|
7816
8396
|
}
|
|
@@ -8004,7 +8584,9 @@ async function deleteDaemonSessions(params) {
|
|
|
8004
8584
|
coordinatorLockHeld = false,
|
|
8005
8585
|
onError
|
|
8006
8586
|
} = params;
|
|
8007
|
-
const uniqueSessionIds = [
|
|
8587
|
+
const uniqueSessionIds = [
|
|
8588
|
+
...new Set(sessionIds.map(normalizeSessionIdForLookup))
|
|
8589
|
+
];
|
|
8008
8590
|
if (!coordinatorLockHeld) {
|
|
8009
8591
|
for (const sessionId of uniqueSessionIds) {
|
|
8010
8592
|
coordinator.assertNotTransitioning(sessionId);
|
|
@@ -8014,22 +8596,40 @@ async function deleteDaemonSessions(params) {
|
|
|
8014
8596
|
uniqueSessionIds.map(async (sessionId) => {
|
|
8015
8597
|
try {
|
|
8016
8598
|
const mutateSession = /* @__PURE__ */ __name(async () => {
|
|
8599
|
+
const removePersistedSession = /* @__PURE__ */ __name(async () => {
|
|
8600
|
+
const result = await deletePersistedSessionWithLease(
|
|
8601
|
+
service,
|
|
8602
|
+
sessionId
|
|
8603
|
+
);
|
|
8604
|
+
if (result.kind === "error") {
|
|
8605
|
+
onError?.({
|
|
8606
|
+
phase: "remove",
|
|
8607
|
+
sessionId,
|
|
8608
|
+
error: errorMessage(result.error)
|
|
8609
|
+
});
|
|
8610
|
+
return result;
|
|
8611
|
+
}
|
|
8612
|
+
try {
|
|
8613
|
+
await bridge.deleteSessionAttachments(sessionId);
|
|
8614
|
+
return result;
|
|
8615
|
+
} catch (error2) {
|
|
8616
|
+
onError?.({
|
|
8617
|
+
phase: "delete",
|
|
8618
|
+
sessionId,
|
|
8619
|
+
error: errorMessage(error2)
|
|
8620
|
+
});
|
|
8621
|
+
return {
|
|
8622
|
+
kind: "error",
|
|
8623
|
+
error: error2,
|
|
8624
|
+
mutationApplied: result.mutationApplied
|
|
8625
|
+
};
|
|
8626
|
+
}
|
|
8627
|
+
}, "removePersistedSession");
|
|
8017
8628
|
try {
|
|
8018
8629
|
await bridge.closeSession(sessionId);
|
|
8019
8630
|
} catch (error2) {
|
|
8020
8631
|
if (isSessionNotFoundError(error2)) {
|
|
8021
|
-
|
|
8022
|
-
service,
|
|
8023
|
-
sessionId
|
|
8024
|
-
);
|
|
8025
|
-
if (result2.kind === "error") {
|
|
8026
|
-
onError?.({
|
|
8027
|
-
phase: "remove",
|
|
8028
|
-
sessionId,
|
|
8029
|
-
error: errorMessage(result2.error)
|
|
8030
|
-
});
|
|
8031
|
-
}
|
|
8032
|
-
return result2;
|
|
8632
|
+
return await removePersistedSession();
|
|
8033
8633
|
}
|
|
8034
8634
|
onError?.({
|
|
8035
8635
|
phase: "close",
|
|
@@ -8042,18 +8642,7 @@ async function deleteDaemonSessions(params) {
|
|
|
8042
8642
|
mutationApplied: false
|
|
8043
8643
|
};
|
|
8044
8644
|
}
|
|
8045
|
-
|
|
8046
|
-
service,
|
|
8047
|
-
sessionId
|
|
8048
|
-
);
|
|
8049
|
-
if (result.kind === "error") {
|
|
8050
|
-
onError?.({
|
|
8051
|
-
phase: "remove",
|
|
8052
|
-
sessionId,
|
|
8053
|
-
error: errorMessage(result.error)
|
|
8054
|
-
});
|
|
8055
|
-
}
|
|
8056
|
-
return result;
|
|
8645
|
+
return await removePersistedSession();
|
|
8057
8646
|
}, "mutateSession");
|
|
8058
8647
|
return await (coordinatorLockHeld ? mutateSession() : coordinator.runExclusiveMany([sessionId], mutateSession));
|
|
8059
8648
|
} catch (error2) {
|
|
@@ -8114,6 +8703,7 @@ async function deleteDaemonSessionIfOrphan(params) {
|
|
|
8114
8703
|
if (result.kind === "error") {
|
|
8115
8704
|
throw result.error;
|
|
8116
8705
|
}
|
|
8706
|
+
bridge.markSessionCatalogChanged();
|
|
8117
8707
|
return true;
|
|
8118
8708
|
}
|
|
8119
8709
|
__name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
|
|
@@ -8193,7 +8783,9 @@ async function archiveDaemonSessions(params) {
|
|
|
8193
8783
|
coordinator,
|
|
8194
8784
|
coordinatorLockHeld = false
|
|
8195
8785
|
} = params;
|
|
8196
|
-
const uniqueSessionIds = [
|
|
8786
|
+
const uniqueSessionIds = [
|
|
8787
|
+
...new Set(sessionIds.map(normalizeSessionIdForLookup))
|
|
8788
|
+
];
|
|
8197
8789
|
if (!coordinatorLockHeld) {
|
|
8198
8790
|
for (const sessionId of uniqueSessionIds) {
|
|
8199
8791
|
coordinator.assertNotTransitioning(sessionId);
|
|
@@ -8335,7 +8927,9 @@ async function unarchiveDaemonSessions(params) {
|
|
|
8335
8927
|
coordinator,
|
|
8336
8928
|
coordinatorLockHeld = false
|
|
8337
8929
|
} = params;
|
|
8338
|
-
const uniqueSessionIds = [
|
|
8930
|
+
const uniqueSessionIds = [
|
|
8931
|
+
...new Set(sessionIds.map(normalizeSessionIdForLookup))
|
|
8932
|
+
];
|
|
8339
8933
|
if (!coordinatorLockHeld) {
|
|
8340
8934
|
for (const sessionId of uniqueSessionIds) {
|
|
8341
8935
|
coordinator.assertNotTransitioning(sessionId);
|
|
@@ -9123,6 +9717,15 @@ function toRpcError(err) {
|
|
|
9123
9717
|
sessionId: err.sessionId
|
|
9124
9718
|
}
|
|
9125
9719
|
};
|
|
9720
|
+
case "SessionIdCaseConflictError":
|
|
9721
|
+
return {
|
|
9722
|
+
code: RPC.INTERNAL_ERROR,
|
|
9723
|
+
message: errMsg(err),
|
|
9724
|
+
data: {
|
|
9725
|
+
errorKind: "session_conflict",
|
|
9726
|
+
sessionId: err.sessionId
|
|
9727
|
+
}
|
|
9728
|
+
};
|
|
9126
9729
|
case "SessionArchivingError":
|
|
9127
9730
|
return {
|
|
9128
9731
|
code: RPC.INTERNAL_ERROR,
|
|
@@ -9231,11 +9834,20 @@ var AcpDispatcher = class {
|
|
|
9231
9834
|
archiveStates
|
|
9232
9835
|
});
|
|
9233
9836
|
}
|
|
9837
|
+
// Combined invalidate-and-mark for catalog mutations whose conservative
|
|
9838
|
+
// finally-semantics match (delete/archive/unarchive). The revision advance
|
|
9839
|
+
// always follows the cache invalidation so a newly exposed version never
|
|
9840
|
+
// precedes it. Exact no-op paths (e.g. metadata rename) gate the mark on
|
|
9841
|
+
// an actual change via the bridge instead of using this helper.
|
|
9842
|
+
invalidateSessionListsAndMarkCatalog(archiveStates) {
|
|
9843
|
+
this.invalidateSessionLists(archiveStates);
|
|
9844
|
+
this.bridge.markSessionCatalogChanged();
|
|
9845
|
+
}
|
|
9234
9846
|
async runWithSessionListInvalidation(archiveStates, mutation) {
|
|
9235
9847
|
try {
|
|
9236
9848
|
return await mutation();
|
|
9237
9849
|
} finally {
|
|
9238
|
-
this.
|
|
9850
|
+
this.invalidateSessionListsAndMarkCatalog(archiveStates);
|
|
9239
9851
|
}
|
|
9240
9852
|
}
|
|
9241
9853
|
removeOrphanSession(sessionId, removePersistedSession = false, runtime = this.getSessionRuntimeContext()) {
|
|
@@ -9710,6 +10322,19 @@ var AcpDispatcher = class {
|
|
|
9710
10322
|
return;
|
|
9711
10323
|
}
|
|
9712
10324
|
const sessionRuntime = this.getSessionRuntimeContext();
|
|
10325
|
+
if (isReservedStandaloneSessionSource({
|
|
10326
|
+
sourceType: typeof params["sourceType"] === "string" ? params["sourceType"] : void 0
|
|
10327
|
+
})) {
|
|
10328
|
+
conn.sendConn(
|
|
10329
|
+
error(
|
|
10330
|
+
id,
|
|
10331
|
+
RPC.INVALID_PARAMS,
|
|
10332
|
+
"The requested session source is reserved for daemon-owned standalone sessions.",
|
|
10333
|
+
{ errorKind: "reserved_session_source" }
|
|
10334
|
+
)
|
|
10335
|
+
);
|
|
10336
|
+
return;
|
|
10337
|
+
}
|
|
9713
10338
|
const source = parseSessionSource(
|
|
9714
10339
|
params["sourceType"],
|
|
9715
10340
|
params["sourceId"]
|
|
@@ -9843,23 +10468,54 @@ var AcpDispatcher = class {
|
|
|
9843
10468
|
}
|
|
9844
10469
|
);
|
|
9845
10470
|
try {
|
|
10471
|
+
const guardSessionService = new SessionService(cwd, {
|
|
10472
|
+
runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
|
|
10473
|
+
});
|
|
10474
|
+
let persistedGuardId;
|
|
10475
|
+
try {
|
|
10476
|
+
persistedGuardId = await guardSessionService.findSessionIdIgnoringCase(sessionId);
|
|
10477
|
+
} catch (error2) {
|
|
10478
|
+
if (error2 instanceof SessionIdCaseConflictError && await guardSessionService.getSessionLocation(
|
|
10479
|
+
error2.candidateSessionId ?? sessionId
|
|
10480
|
+
) === "conflict") {
|
|
10481
|
+
throw new SessionConflictError(sessionId);
|
|
10482
|
+
}
|
|
10483
|
+
throw error2;
|
|
10484
|
+
}
|
|
9846
10485
|
const restored = await this.archiveCoordinator.runSharedMany(
|
|
9847
10486
|
[sessionId],
|
|
9848
10487
|
async () => {
|
|
9849
10488
|
assertGenerationOpen?.();
|
|
10489
|
+
const sessionService = new SessionService(cwd, {
|
|
10490
|
+
runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
|
|
10491
|
+
});
|
|
10492
|
+
let storageSessionId = persistedGuardId ?? sessionId;
|
|
10493
|
+
let persistedSessionId;
|
|
10494
|
+
try {
|
|
10495
|
+
persistedSessionId = await sessionService.findSessionIdIgnoringCase(sessionId);
|
|
10496
|
+
} catch (error2) {
|
|
10497
|
+
if (error2 instanceof SessionIdCaseConflictError && await sessionService.getSessionLocation(
|
|
10498
|
+
error2.candidateSessionId ?? sessionId
|
|
10499
|
+
) === "conflict") {
|
|
10500
|
+
throw new SessionConflictError(sessionId);
|
|
10501
|
+
}
|
|
10502
|
+
throw error2;
|
|
10503
|
+
}
|
|
10504
|
+
if (persistedSessionId) {
|
|
10505
|
+
storageSessionId = persistedSessionId;
|
|
10506
|
+
} else if (this.liveSessionIsolation) {
|
|
10507
|
+
throw new SessionNotFoundError(sessionId);
|
|
10508
|
+
}
|
|
9850
10509
|
await assertSessionLoadable(
|
|
9851
10510
|
cwd,
|
|
9852
|
-
|
|
10511
|
+
storageSessionId,
|
|
9853
10512
|
sessionRuntime.sessionRuntimeBaseDir
|
|
9854
10513
|
);
|
|
9855
|
-
const sessionService = new SessionService(cwd, {
|
|
9856
|
-
runtimeBaseDir: sessionRuntime.sessionRuntimeBaseDir
|
|
9857
|
-
});
|
|
9858
10514
|
const metadata = this.liveSessionIsolation ? await readLoadableLiveConversationMetadata(
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
) : await sessionService.readCreationMetadata(
|
|
9862
|
-
if (metadata === void 0) {
|
|
10515
|
+
storageSessionId,
|
|
10516
|
+
sessionService
|
|
10517
|
+
) : await sessionService.readCreationMetadata(storageSessionId);
|
|
10518
|
+
if (metadata === void 0 || this.liveSessionIsolation !== void 0 && isReservedStandaloneSessionSource(metadata)) {
|
|
9863
10519
|
throw new SessionNotFoundError(sessionId);
|
|
9864
10520
|
}
|
|
9865
10521
|
const liveConversationCwd = this.liveSessionIsolation ? await this.liveSessionIsolation.materializeConversationDirectory(
|
|
@@ -10718,6 +11374,7 @@ var AcpDispatcher = class {
|
|
|
10718
11374
|
..."groupId" in params ? { groupId: params["groupId"] } : {},
|
|
10719
11375
|
..."color" in params ? { color: params["color"] } : {}
|
|
10720
11376
|
});
|
|
11377
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10721
11378
|
this.replyConn(conn, id, { sessionId, ...organization });
|
|
10722
11379
|
});
|
|
10723
11380
|
return;
|
|
@@ -10736,6 +11393,7 @@ var AcpDispatcher = class {
|
|
|
10736
11393
|
name: params["name"],
|
|
10737
11394
|
color: params["color"]
|
|
10738
11395
|
});
|
|
11396
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10739
11397
|
assertGenerationOpen?.();
|
|
10740
11398
|
this.replyConn(conn, id, { group });
|
|
10741
11399
|
return;
|
|
@@ -10753,6 +11411,7 @@ var AcpDispatcher = class {
|
|
|
10753
11411
|
..."color" in params ? { color: params["color"] } : {},
|
|
10754
11412
|
..."order" in params ? { order: params["order"] } : {}
|
|
10755
11413
|
});
|
|
11414
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
10756
11415
|
assertGenerationOpen?.();
|
|
10757
11416
|
this.replyConn(conn, id, { group });
|
|
10758
11417
|
return;
|
|
@@ -10766,6 +11425,9 @@ var AcpDispatcher = class {
|
|
|
10766
11425
|
const deleted = await createSessionOrganizationService(workspaceCwd).deleteGroup(
|
|
10767
11426
|
groupId
|
|
10768
11427
|
);
|
|
11428
|
+
if (deleted) {
|
|
11429
|
+
this.invalidateSessionListsAndMarkCatalog(["active", "archived"]);
|
|
11430
|
+
}
|
|
10769
11431
|
assertGenerationOpen?.();
|
|
10770
11432
|
this.replyConn(conn, id, { deleted });
|
|
10771
11433
|
return;
|
|
@@ -12869,7 +13531,7 @@ var AcpDispatcher = class {
|
|
|
12869
13531
|
|
|
12870
13532
|
// packages/cli/src/serve/acp-http/connection-registry.ts
|
|
12871
13533
|
init_esbuild_shims();
|
|
12872
|
-
import { randomUUID as
|
|
13534
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
12873
13535
|
var DEFAULT_MAX_CONNECTIONS = 64;
|
|
12874
13536
|
var AcpConnection = class {
|
|
12875
13537
|
constructor(connectionId, fromLoopback, onAbandonPending, onDetachSession, preAttachBudget = new AcpPreAttachBudget(), onFatalConnection, maxFramesPerConnection = ACP_PRE_ATTACH_MAX_FRAMES_PER_CONNECTION, maxPayloadBytesPerConnection = ACP_PRE_ATTACH_MAX_PAYLOAD_BYTES_PER_CONNECTION, onPreAttachGuardFailure) {
|
|
@@ -12880,8 +13542,8 @@ var AcpConnection = class {
|
|
|
12880
13542
|
this.maxFramesPerConnection = maxFramesPerConnection;
|
|
12881
13543
|
this.maxPayloadBytesPerConnection = maxPayloadBytesPerConnection;
|
|
12882
13544
|
this.onPreAttachGuardFailure = onPreAttachGuardFailure;
|
|
12883
|
-
this.connectionId = connectionId ??
|
|
12884
|
-
this.clientId =
|
|
13545
|
+
this.connectionId = connectionId ?? randomUUID3();
|
|
13546
|
+
this.clientId = randomUUID3();
|
|
12885
13547
|
this.fromLoopback = fromLoopback;
|
|
12886
13548
|
}
|
|
12887
13549
|
static {
|
|
@@ -15985,9 +16647,15 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
15985
16647
|
}
|
|
15986
16648
|
let wss;
|
|
15987
16649
|
let upgradeListener;
|
|
15988
|
-
|
|
16650
|
+
const upgradeServers = /* @__PURE__ */ new Set();
|
|
16651
|
+
const upgradeCredentials = opts.credentials ?? singleTokenCredentials(opts.token);
|
|
15989
16652
|
function setupWebSocket(httpServer) {
|
|
15990
|
-
if (disposed ||
|
|
16653
|
+
if (disposed || upgradeServers.has(httpServer)) return;
|
|
16654
|
+
if (wss) {
|
|
16655
|
+
upgradeServers.add(httpServer);
|
|
16656
|
+
httpServer.on("upgrade", upgradeListener);
|
|
16657
|
+
return;
|
|
16658
|
+
}
|
|
15991
16659
|
wss = new import_websocket_server.default({
|
|
15992
16660
|
noServer: true,
|
|
15993
16661
|
maxPayload: 10 * 1024 * 1024,
|
|
@@ -16007,8 +16675,7 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16007
16675
|
return false;
|
|
16008
16676
|
}, "handleProtocols")
|
|
16009
16677
|
});
|
|
16010
|
-
|
|
16011
|
-
const expectedTokenHash = opts.token ? createHash3("sha256").update(opts.token).digest() : void 0;
|
|
16678
|
+
upgradeServers.add(httpServer);
|
|
16012
16679
|
upgradeListener = /* @__PURE__ */ __name((req, socket, head) => {
|
|
16013
16680
|
if (disposed) {
|
|
16014
16681
|
socket.destroy();
|
|
@@ -16036,8 +16703,18 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16036
16703
|
return;
|
|
16037
16704
|
}
|
|
16038
16705
|
const fromLoopback = isLoopbackSocket(socket);
|
|
16039
|
-
|
|
16040
|
-
|
|
16706
|
+
const upgradeListenerIdentity = listenerIdentityOfSocket(socket);
|
|
16707
|
+
const host = (req.headers["host"] ?? "").toLowerCase();
|
|
16708
|
+
if (upgradeListenerIdentity.kind === "local-control") {
|
|
16709
|
+
const authority = upgradeListenerIdentity.authority;
|
|
16710
|
+
const browserHost = upgradeListenerIdentity.origin === void 0 ? void 0 : new URL(upgradeListenerIdentity.origin).host.toLowerCase();
|
|
16711
|
+
if (authority === void 0 || host !== authority && host !== browserHost) {
|
|
16712
|
+
logReject(`host-not-allowed ${host || "(missing)"}`);
|
|
16713
|
+
socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
16714
|
+
socket.destroy();
|
|
16715
|
+
return;
|
|
16716
|
+
}
|
|
16717
|
+
} else if (fromLoopback) {
|
|
16041
16718
|
const allowed = /* @__PURE__ */ new Set([
|
|
16042
16719
|
`localhost:${localPort}`,
|
|
16043
16720
|
`127.0.0.1:${localPort}`,
|
|
@@ -16062,7 +16739,8 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16062
16739
|
try {
|
|
16063
16740
|
const isLoopbackOrigin = isSameLoopbackOrigin(origin, localPort);
|
|
16064
16741
|
const isAllowlistedOrigin = opts.allowedOrigins !== void 0 && opts.allowedOrigins.origins.has(origin.toLowerCase());
|
|
16065
|
-
|
|
16742
|
+
const isListenerOrigin = upgradeListenerIdentity.kind === "local-control" && upgradeListenerIdentity.origin === origin.toLowerCase();
|
|
16743
|
+
if (!isLoopbackOrigin && !isAllowlistedOrigin && !isListenerOrigin) {
|
|
16066
16744
|
logReject(`origin-not-allowed ${origin}`);
|
|
16067
16745
|
socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
16068
16746
|
socket.destroy();
|
|
@@ -16075,10 +16753,9 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16075
16753
|
return;
|
|
16076
16754
|
}
|
|
16077
16755
|
}
|
|
16078
|
-
if (
|
|
16079
|
-
const
|
|
16080
|
-
|
|
16081
|
-
if (!actual || !expectedTokenHash || actual.length !== expectedTokenHash.length || !timingSafeEqual(expectedTokenHash, actual)) {
|
|
16756
|
+
if (!upgradeCredentials.isOpen(upgradeListenerIdentity)) {
|
|
16757
|
+
const presented = extractUpgradeBearer(req);
|
|
16758
|
+
if (!presented || !upgradeCredentials.verify(presented, upgradeListenerIdentity)) {
|
|
16082
16759
|
logReject("auth-mismatch");
|
|
16083
16760
|
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
16084
16761
|
socket.destroy();
|
|
@@ -16587,10 +17264,12 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16587
17264
|
dispose: /* @__PURE__ */ __name(() => {
|
|
16588
17265
|
if (disposed) return;
|
|
16589
17266
|
disposed = true;
|
|
16590
|
-
if (
|
|
16591
|
-
|
|
17267
|
+
if (upgradeListener) {
|
|
17268
|
+
for (const server of upgradeServers) {
|
|
17269
|
+
server.removeListener("upgrade", upgradeListener);
|
|
17270
|
+
}
|
|
17271
|
+
upgradeServers.clear();
|
|
16592
17272
|
upgradeListener = void 0;
|
|
16593
|
-
upgradeServer = void 0;
|
|
16594
17273
|
}
|
|
16595
17274
|
registry.dispose();
|
|
16596
17275
|
opts.workspaceRememberLane.dispose();
|
|
@@ -16730,6 +17409,17 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
16730
17409
|
}, "getSnapshot"),
|
|
16731
17410
|
attachServer(server) {
|
|
16732
17411
|
setupWebSocket(server);
|
|
17412
|
+
},
|
|
17413
|
+
detachServer(server) {
|
|
17414
|
+
if (!upgradeServers.delete(server)) return;
|
|
17415
|
+
if (upgradeListener) server.removeListener("upgrade", upgradeListener);
|
|
17416
|
+
if (!wss) return;
|
|
17417
|
+
for (const client of wss.clients) {
|
|
17418
|
+
const clientSocket = client._socket;
|
|
17419
|
+
if (clientSocket?.server === server) {
|
|
17420
|
+
client.terminate();
|
|
17421
|
+
}
|
|
17422
|
+
}
|
|
16733
17423
|
}
|
|
16734
17424
|
};
|
|
16735
17425
|
}
|
|
@@ -18752,7 +19442,7 @@ function createExtensionsController(deps) {
|
|
|
18752
19442
|
version: ext.version,
|
|
18753
19443
|
isActive: ext.isActive,
|
|
18754
19444
|
path: ext.path,
|
|
18755
|
-
...ext.installMetadata?.source ? {
|
|
19445
|
+
...ext.installMetadata?.source && ext.installMetadata.type !== "snapshot" ? {
|
|
18756
19446
|
source: redactExtensionDisplaySource(
|
|
18757
19447
|
ext.installMetadata.source
|
|
18758
19448
|
)
|
|
@@ -18761,7 +19451,8 @@ function createExtensionsController(deps) {
|
|
|
18761
19451
|
...ext.installMetadata?.originSource ? { originSource: ext.installMetadata.originSource } : {},
|
|
18762
19452
|
...ext.installMetadata?.ref ? { ref: ext.installMetadata.ref } : {},
|
|
18763
19453
|
...ext.installMetadata?.autoUpdate !== void 0 ? { autoUpdate: ext.installMetadata.autoUpdate } : {},
|
|
18764
|
-
|
|
19454
|
+
...ext.installMetadata?.type === "snapshot" ? { credentialPersistence: "one_time" } : ext.installMetadata?.credentialPersistence === "stored" ? { credentialPersistence: "stored" } : {},
|
|
19455
|
+
updateState: ext.installMetadata?.type === "snapshot" ? "not updatable" : ext.installMetadata ? "unknown" : "not updatable",
|
|
18765
19456
|
capabilities,
|
|
18766
19457
|
details: {
|
|
18767
19458
|
mcpServers: ext.mcpServers ? Object.keys(ext.mcpServers) : [],
|
|
@@ -18811,6 +19502,7 @@ var EXTENSION_INTERACTION_DEADLINE_MS = 10 * 6e4;
|
|
|
18811
19502
|
var EXTENSION_INTERACTIVE_PREPARE_DEADLINE_MS = EXTENSION_PREPARE_DEADLINE_MS + EXTENSION_INTERACTION_DEADLINE_MS;
|
|
18812
19503
|
var EXTENSION_UPDATE_CHECK_DEADLINE_MS = 2 * 6e4;
|
|
18813
19504
|
var EXTENSION_ARCHIVE_UPLOAD_LIMIT = "10mb";
|
|
19505
|
+
var MAX_EXTENSION_BATCH_SIZE = 100;
|
|
18814
19506
|
var extensionArchiveBodyParser = import_express2.default.raw({
|
|
18815
19507
|
type: "application/octet-stream",
|
|
18816
19508
|
limit: EXTENSION_ARCHIVE_UPLOAD_LIMIT
|
|
@@ -18851,6 +19543,32 @@ var parseExtensionScope = /* @__PURE__ */ __name((body, res) => {
|
|
|
18851
19543
|
}
|
|
18852
19544
|
return scope === "user" ? "User" /* User */ : "Workspace" /* Workspace */;
|
|
18853
19545
|
}, "parseExtensionScope");
|
|
19546
|
+
var parseExtensionBatchNames = /* @__PURE__ */ __name((req, res, safeBody2) => {
|
|
19547
|
+
const rawNames = safeBody2(req)["extensionNames"];
|
|
19548
|
+
if (!Array.isArray(rawNames) || rawNames.length === 0 || rawNames.length > MAX_EXTENSION_BATCH_SIZE || !rawNames.every((name) => typeof name === "string")) {
|
|
19549
|
+
res.status(400).json({
|
|
19550
|
+
error: `\`extensionNames\` must be a non-empty string array (max ${MAX_EXTENSION_BATCH_SIZE})`,
|
|
19551
|
+
code: "invalid_extension_names"
|
|
19552
|
+
});
|
|
19553
|
+
return void 0;
|
|
19554
|
+
}
|
|
19555
|
+
const names = [];
|
|
19556
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19557
|
+
for (const name of rawNames) {
|
|
19558
|
+
if (!/^[a-zA-Z0-9-_.]+$/.test(name)) {
|
|
19559
|
+
res.status(400).json({
|
|
19560
|
+
error: `Invalid extension name "${name}"`,
|
|
19561
|
+
code: "invalid_extension_name"
|
|
19562
|
+
});
|
|
19563
|
+
return void 0;
|
|
19564
|
+
}
|
|
19565
|
+
const normalizedName = name.toLowerCase();
|
|
19566
|
+
if (seen.has(normalizedName)) continue;
|
|
19567
|
+
seen.add(normalizedName);
|
|
19568
|
+
names.push(name);
|
|
19569
|
+
}
|
|
19570
|
+
return names;
|
|
19571
|
+
}, "parseExtensionBatchNames");
|
|
18854
19572
|
var parseExtensionRegistryUrl = /* @__PURE__ */ __name((value, res) => {
|
|
18855
19573
|
let parsed;
|
|
18856
19574
|
try {
|
|
@@ -18891,23 +19609,76 @@ var parsePotentialSourceUrl = /* @__PURE__ */ __name((source) => {
|
|
|
18891
19609
|
}
|
|
18892
19610
|
}
|
|
18893
19611
|
}, "parsePotentialSourceUrl");
|
|
18894
|
-
var
|
|
19612
|
+
var parseExtensionInstallSource = /* @__PURE__ */ __name((source, persistence, res) => {
|
|
19613
|
+
if (persistence !== void 0 && persistence !== "stored" && persistence !== "one_time") {
|
|
19614
|
+
res.status(400).json({
|
|
19615
|
+
error: '`credentialPersistence` must be "stored" or "one_time"'
|
|
19616
|
+
});
|
|
19617
|
+
return null;
|
|
19618
|
+
}
|
|
18895
19619
|
const parsed = parsePotentialSourceUrl(source);
|
|
18896
|
-
if (!parsed)
|
|
18897
|
-
|
|
18898
|
-
|
|
18899
|
-
|
|
19620
|
+
if (!parsed) {
|
|
19621
|
+
if (persistence !== void 0) {
|
|
19622
|
+
res.status(400).json({
|
|
19623
|
+
error: "`credentialPersistence` requires source URL credentials"
|
|
19624
|
+
});
|
|
19625
|
+
return null;
|
|
19626
|
+
}
|
|
19627
|
+
return { source };
|
|
18900
19628
|
}
|
|
18901
19629
|
if (isBlockedAuthProviderHost(parsed.hostname)) {
|
|
18902
19630
|
res.status(400).json({ error: "`source` host is not allowed" });
|
|
18903
|
-
return
|
|
19631
|
+
return null;
|
|
18904
19632
|
}
|
|
18905
19633
|
if (parsed.protocol !== "https:") {
|
|
18906
19634
|
res.status(400).json({ error: "`source` must use https" });
|
|
18907
|
-
return
|
|
19635
|
+
return null;
|
|
18908
19636
|
}
|
|
18909
|
-
|
|
18910
|
-
|
|
19637
|
+
const authority = /^[a-z][a-z\d+.-]*:\/\/([^/?#]*)/i.exec(source)?.[1];
|
|
19638
|
+
const hasUserInfo = !!parsed.username || !!parsed.password || authority?.includes("@") === true;
|
|
19639
|
+
if (!hasUserInfo) {
|
|
19640
|
+
if (persistence !== void 0) {
|
|
19641
|
+
res.status(400).json({
|
|
19642
|
+
error: "`credentialPersistence` requires source URL credentials"
|
|
19643
|
+
});
|
|
19644
|
+
return null;
|
|
19645
|
+
}
|
|
19646
|
+
return { source };
|
|
19647
|
+
}
|
|
19648
|
+
const hasControlCharacter = /* @__PURE__ */ __name((value) => Array.from(value).some((character) => {
|
|
19649
|
+
const code = character.charCodeAt(0);
|
|
19650
|
+
return code <= 31 || code >= 127 && code <= 159;
|
|
19651
|
+
}), "hasControlCharacter");
|
|
19652
|
+
if (hasControlCharacter(source)) {
|
|
19653
|
+
res.status(400).json({ error: "`source` credentials are invalid" });
|
|
19654
|
+
return null;
|
|
19655
|
+
}
|
|
19656
|
+
let username;
|
|
19657
|
+
let password;
|
|
19658
|
+
try {
|
|
19659
|
+
username = decodeURIComponent(parsed.username);
|
|
19660
|
+
password = decodeURIComponent(parsed.password);
|
|
19661
|
+
} catch {
|
|
19662
|
+
res.status(400).json({ error: "`source` credentials are invalid" });
|
|
19663
|
+
return null;
|
|
19664
|
+
}
|
|
19665
|
+
const invalidText = /* @__PURE__ */ __name((value, maxBytes) => Buffer.byteLength(value, "utf8") > maxBytes || hasControlCharacter(value), "invalidText");
|
|
19666
|
+
if (!username && !password || invalidText(username, 256) || invalidText(password, 4096)) {
|
|
19667
|
+
res.status(400).json({ error: "`source` credentials are invalid" });
|
|
19668
|
+
return null;
|
|
19669
|
+
}
|
|
19670
|
+
parsed.username = "";
|
|
19671
|
+
parsed.password = "";
|
|
19672
|
+
const credentialPersistence = persistence ?? "one_time";
|
|
19673
|
+
return {
|
|
19674
|
+
source: parsed.toString(),
|
|
19675
|
+
gitCredential: {
|
|
19676
|
+
username,
|
|
19677
|
+
password,
|
|
19678
|
+
persistence: credentialPersistence
|
|
19679
|
+
}
|
|
19680
|
+
};
|
|
19681
|
+
}, "parseExtensionInstallSource");
|
|
18911
19682
|
var validateExtensionSourceMetadata = /* @__PURE__ */ __name((installMetadata) => {
|
|
18912
19683
|
if (installMetadata.type !== "git") return true;
|
|
18913
19684
|
const parsed = parsePotentialSourceUrl(installMetadata.source);
|
|
@@ -19424,6 +20195,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19424
20195
|
const allowPreRelease = body["allowPreRelease"];
|
|
19425
20196
|
const registry = body["registry"];
|
|
19426
20197
|
const consent = body["consent"];
|
|
20198
|
+
const credentialPersistence = body["credentialPersistence"];
|
|
19427
20199
|
if (!source || typeof source !== "string") {
|
|
19428
20200
|
res.status(400).json({ error: "Missing or invalid source" });
|
|
19429
20201
|
return;
|
|
@@ -19448,7 +20220,6 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19448
20220
|
res.status(400).json({ error: "`registry` must be a string" });
|
|
19449
20221
|
return;
|
|
19450
20222
|
}
|
|
19451
|
-
const sourceValue = source;
|
|
19452
20223
|
const refValue = typeof ref === "string" ? ref : void 0;
|
|
19453
20224
|
const autoUpdateValue = typeof autoUpdate === "boolean" ? autoUpdate : void 0;
|
|
19454
20225
|
const allowPreReleaseValue = typeof allowPreRelease === "boolean" ? allowPreRelease : void 0;
|
|
@@ -19461,7 +20232,25 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19461
20232
|
});
|
|
19462
20233
|
return;
|
|
19463
20234
|
}
|
|
19464
|
-
|
|
20235
|
+
const parsedSource = parseExtensionInstallSource(
|
|
20236
|
+
source,
|
|
20237
|
+
credentialPersistence,
|
|
20238
|
+
res
|
|
20239
|
+
);
|
|
20240
|
+
if (!parsedSource) return;
|
|
20241
|
+
const sourceValue = parsedSource.source;
|
|
20242
|
+
body["source"] = sourceValue;
|
|
20243
|
+
const gitCredential = parsedSource.gitCredential;
|
|
20244
|
+
if (gitCredential?.persistence === "one_time" && autoUpdateValue) {
|
|
20245
|
+
res.status(400).json({
|
|
20246
|
+
error: "`autoUpdate` is not supported with one-time credentials"
|
|
20247
|
+
});
|
|
20248
|
+
return;
|
|
20249
|
+
}
|
|
20250
|
+
if (gitCredential && isSupportedArchiveUrl(sourceValue)) {
|
|
20251
|
+
res.status(400).json({
|
|
20252
|
+
error: "Git credentials require an HTTPS Git install source."
|
|
20253
|
+
});
|
|
19465
20254
|
return;
|
|
19466
20255
|
}
|
|
19467
20256
|
const localSource = /^[A-Za-z]:[\\/]/.test(sourceValue) || sourceValue.startsWith("/") || sourceValue.startsWith(".");
|
|
@@ -19511,7 +20300,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19511
20300
|
}
|
|
19512
20301
|
ctrl.runQueuedExtensionMutation(
|
|
19513
20302
|
"install",
|
|
19514
|
-
{ source: sourceValue },
|
|
20303
|
+
gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
|
|
19515
20304
|
res,
|
|
19516
20305
|
async (extensionManager, _signal, context, operationId) => {
|
|
19517
20306
|
const prepared = await context.prepare(async (signal) => {
|
|
@@ -19523,6 +20312,11 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19523
20312
|
"Only GitHub, Git, and npm extension installs are supported over the daemon endpoint."
|
|
19524
20313
|
);
|
|
19525
20314
|
}
|
|
20315
|
+
if (gitCredential && installMetadata.type !== "git" && installMetadata.type !== "github-release") {
|
|
20316
|
+
throw new Error(
|
|
20317
|
+
"Git credentials require an HTTPS Git install source."
|
|
20318
|
+
);
|
|
20319
|
+
}
|
|
19526
20320
|
if (installMetadata.type === "npm" && refValue) {
|
|
19527
20321
|
throw new Error("--ref is not applicable for npm extensions.");
|
|
19528
20322
|
}
|
|
@@ -19547,7 +20341,8 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19547
20341
|
},
|
|
19548
20342
|
initialActivation: { scope: "user" },
|
|
19549
20343
|
requestConsent: /* @__PURE__ */ __name(() => Promise.resolve(), "requestConsent"),
|
|
19550
|
-
signal
|
|
20344
|
+
signal,
|
|
20345
|
+
...gitCredential ? { gitCredential } : {}
|
|
19551
20346
|
});
|
|
19552
20347
|
});
|
|
19553
20348
|
try {
|
|
@@ -19559,9 +20354,13 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19559
20354
|
);
|
|
19560
20355
|
return {
|
|
19561
20356
|
status: "installed",
|
|
19562
|
-
source: sourceValue,
|
|
20357
|
+
...gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
|
|
19563
20358
|
name: committed.identity.name,
|
|
19564
|
-
version: committed.version
|
|
20359
|
+
version: committed.version,
|
|
20360
|
+
...gitCredential ? {
|
|
20361
|
+
credentialPersistence: gitCredential.persistence,
|
|
20362
|
+
...prepared.credentialStorage ? { credentialStorage: prepared.credentialStorage } : {}
|
|
20363
|
+
} : {}
|
|
19565
20364
|
};
|
|
19566
20365
|
} finally {
|
|
19567
20366
|
await extensionManager.disposePreparedExtension(prepared);
|
|
@@ -19934,6 +20733,17 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19934
20733
|
}
|
|
19935
20734
|
return state;
|
|
19936
20735
|
}, "parseActivationState");
|
|
20736
|
+
const parseWorkspaceBatchActivationState = /* @__PURE__ */ __name((req, res) => {
|
|
20737
|
+
const state = safeBody2(req)["state"];
|
|
20738
|
+
if (state !== "enabled" && state !== "disabled" && state !== "inherit") {
|
|
20739
|
+
res.status(400).json({
|
|
20740
|
+
error: '`state` must be "enabled", "disabled", or "inherit"',
|
|
20741
|
+
code: "invalid_extension_activation"
|
|
20742
|
+
});
|
|
20743
|
+
return null;
|
|
20744
|
+
}
|
|
20745
|
+
return state;
|
|
20746
|
+
}, "parseWorkspaceBatchActivationState");
|
|
19937
20747
|
const sendOperation = /* @__PURE__ */ __name((req, res, route, manager, operation, failureContext, run2, options = {}) => {
|
|
19938
20748
|
if (!primaryController.validateExtensionMutationClient(req, res, {
|
|
19939
20749
|
requireClientId: false,
|
|
@@ -19972,6 +20782,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19972
20782
|
name: extension.name,
|
|
19973
20783
|
version: extension.version,
|
|
19974
20784
|
...extension.installMetadata?.type ? { installType: extension.installMetadata.type } : {},
|
|
20785
|
+
...extension.installMetadata?.type === "snapshot" ? { credentialPersistence: "one_time" } : extension.installMetadata?.credentialPersistence === "stored" ? { credentialPersistence: "stored" } : {},
|
|
19975
20786
|
defaultActivation: policy?.defaultActivation ?? "enabled",
|
|
19976
20787
|
workspaceOverrideCount: Object.values(
|
|
19977
20788
|
policy?.workspaceOverrides ?? {}
|
|
@@ -19999,6 +20810,43 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
19999
20810
|
}
|
|
20000
20811
|
res.status(200).json(operation);
|
|
20001
20812
|
});
|
|
20813
|
+
app.put("/extensions/activation", mutate({ strict: true }), (req, res) => {
|
|
20814
|
+
const names = parseExtensionBatchNames(req, res, safeBody2);
|
|
20815
|
+
if (!names) return;
|
|
20816
|
+
const state = parseActivationState(req, res);
|
|
20817
|
+
if (!state) return;
|
|
20818
|
+
const manager = primaryController.createExtensionManager(
|
|
20819
|
+
boundWorkspace,
|
|
20820
|
+
true
|
|
20821
|
+
);
|
|
20822
|
+
sendOperation(
|
|
20823
|
+
req,
|
|
20824
|
+
res,
|
|
20825
|
+
"PUT /extensions/activation",
|
|
20826
|
+
manager,
|
|
20827
|
+
"set_default_activation_batch",
|
|
20828
|
+
{},
|
|
20829
|
+
async (extensionManager, _signal, context) => {
|
|
20830
|
+
await context.commit(
|
|
20831
|
+
async (onCommitted) => await extensionManager.setExtensionDefaultActivations(
|
|
20832
|
+
names,
|
|
20833
|
+
state,
|
|
20834
|
+
onCommitted
|
|
20835
|
+
)
|
|
20836
|
+
);
|
|
20837
|
+
return {
|
|
20838
|
+
status: "updated",
|
|
20839
|
+
results: names.map((name) => ({
|
|
20840
|
+
name,
|
|
20841
|
+
defaultActivation: state
|
|
20842
|
+
}))
|
|
20843
|
+
};
|
|
20844
|
+
},
|
|
20845
|
+
{
|
|
20846
|
+
...workspaceRegistry ? { refreshRuntimes: /* @__PURE__ */ __name(() => workspaceRegistry.listAll(), "refreshRuntimes") } : {}
|
|
20847
|
+
}
|
|
20848
|
+
);
|
|
20849
|
+
});
|
|
20002
20850
|
app.put(
|
|
20003
20851
|
"/extensions/:extensionId/activation",
|
|
20004
20852
|
mutate({ strict: true }),
|
|
@@ -20048,6 +20896,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20048
20896
|
const autoUpdate = body["autoUpdate"];
|
|
20049
20897
|
const allowPreRelease = body["allowPreRelease"];
|
|
20050
20898
|
const registry = body["registry"];
|
|
20899
|
+
const credentialPersistence = body["credentialPersistence"];
|
|
20051
20900
|
if (typeof source !== "string" || !source) {
|
|
20052
20901
|
res.status(400).json({ error: "Missing or invalid source" });
|
|
20053
20902
|
return;
|
|
@@ -20080,7 +20929,27 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20080
20929
|
});
|
|
20081
20930
|
return;
|
|
20082
20931
|
}
|
|
20083
|
-
|
|
20932
|
+
const parsedSource = parseExtensionInstallSource(
|
|
20933
|
+
source,
|
|
20934
|
+
credentialPersistence,
|
|
20935
|
+
res
|
|
20936
|
+
);
|
|
20937
|
+
if (!parsedSource) return;
|
|
20938
|
+
const sourceValue = parsedSource.source;
|
|
20939
|
+
body["source"] = sourceValue;
|
|
20940
|
+
const gitCredential = parsedSource.gitCredential;
|
|
20941
|
+
if (gitCredential?.persistence === "one_time" && autoUpdate === true) {
|
|
20942
|
+
res.status(400).json({
|
|
20943
|
+
error: "`autoUpdate` is not supported with one-time credentials"
|
|
20944
|
+
});
|
|
20945
|
+
return;
|
|
20946
|
+
}
|
|
20947
|
+
if (gitCredential && isSupportedArchiveUrl(sourceValue)) {
|
|
20948
|
+
res.status(400).json({
|
|
20949
|
+
error: "Git credentials require an HTTPS Git install source."
|
|
20950
|
+
});
|
|
20951
|
+
return;
|
|
20952
|
+
}
|
|
20084
20953
|
if (!activation || typeof activation !== "object") {
|
|
20085
20954
|
res.status(400).json({ error: "Missing initial activation" });
|
|
20086
20955
|
return;
|
|
@@ -20119,10 +20988,10 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20119
20988
|
"POST /extensions/install",
|
|
20120
20989
|
manager,
|
|
20121
20990
|
"install",
|
|
20122
|
-
{ source },
|
|
20991
|
+
gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
|
|
20123
20992
|
async (extensionManager, _signal, context) => {
|
|
20124
20993
|
const prepared = await context.prepare(async (signal) => {
|
|
20125
|
-
const metadata = await parseInstallSource(
|
|
20994
|
+
const metadata = await parseInstallSource(sourceValue, {
|
|
20126
20995
|
networkPolicy: "public"
|
|
20127
20996
|
});
|
|
20128
20997
|
if (metadata.type !== "git" && metadata.type !== "github-release" && metadata.type !== "npm") {
|
|
@@ -20130,6 +20999,11 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20130
20999
|
"Only GitHub, Git, and npm extension installs are supported over the daemon endpoint."
|
|
20131
21000
|
);
|
|
20132
21001
|
}
|
|
21002
|
+
if (gitCredential && metadata.type !== "git" && metadata.type !== "github-release") {
|
|
21003
|
+
throw new Error(
|
|
21004
|
+
"Git credentials require an HTTPS Git install source."
|
|
21005
|
+
);
|
|
21006
|
+
}
|
|
20133
21007
|
if (!validateExtensionSourceMetadata(metadata)) {
|
|
20134
21008
|
throw new Error("`source` host is not allowed");
|
|
20135
21009
|
}
|
|
@@ -20154,7 +21028,8 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20154
21028
|
requestConsent: /* @__PURE__ */ __name(() => Promise.resolve(), "requestConsent"),
|
|
20155
21029
|
cwd: boundWorkspace,
|
|
20156
21030
|
initialActivation,
|
|
20157
|
-
signal
|
|
21031
|
+
signal,
|
|
21032
|
+
...gitCredential ? { gitCredential } : {}
|
|
20158
21033
|
});
|
|
20159
21034
|
});
|
|
20160
21035
|
try {
|
|
@@ -20166,9 +21041,13 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20166
21041
|
);
|
|
20167
21042
|
return {
|
|
20168
21043
|
status: "installed",
|
|
20169
|
-
source,
|
|
21044
|
+
...gitCredential?.persistence === "one_time" ? {} : { source: sourceValue },
|
|
20170
21045
|
name: committed.identity.name,
|
|
20171
|
-
version: committed.version
|
|
21046
|
+
version: committed.version,
|
|
21047
|
+
...gitCredential ? {
|
|
21048
|
+
credentialPersistence: gitCredential.persistence,
|
|
21049
|
+
...prepared.credentialStorage ? { credentialStorage: prepared.credentialStorage } : {}
|
|
21050
|
+
} : {}
|
|
20172
21051
|
};
|
|
20173
21052
|
} finally {
|
|
20174
21053
|
await extensionManager.disposePreparedExtension(prepared);
|
|
@@ -20235,9 +21114,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20235
21114
|
if (!extension)
|
|
20236
21115
|
throw new Error(`Extension "${extensionId}" not found`);
|
|
20237
21116
|
if (extension.installMetadata?.type !== "git" && extension.installMetadata?.type !== "archive-url" && extension.installMetadata?.type !== "github-release" && extension.installMetadata?.type !== "npm") {
|
|
20238
|
-
throw new
|
|
20239
|
-
`Extension "${extension.name}" is not remotely updatable.`
|
|
20240
|
-
);
|
|
21117
|
+
throw new ExtensionNotUpdatableError(extension.name);
|
|
20241
21118
|
}
|
|
20242
21119
|
const preparedResult = await context.prepare(
|
|
20243
21120
|
async (signal) => await extensionManager.prepareExtensionUpdate({
|
|
@@ -20299,7 +21176,7 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20299
21176
|
);
|
|
20300
21177
|
const snapshot = await manager.getExtensionStoreSnapshot();
|
|
20301
21178
|
const policy = snapshot.extensions[extensionId];
|
|
20302
|
-
if (!policy) {
|
|
21179
|
+
if (!policy || policy.declarationOnly) {
|
|
20303
21180
|
res.status(204).end();
|
|
20304
21181
|
return;
|
|
20305
21182
|
}
|
|
@@ -20373,6 +21250,57 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
20373
21250
|
});
|
|
20374
21251
|
}
|
|
20375
21252
|
});
|
|
21253
|
+
app.put(
|
|
21254
|
+
"/workspaces/:workspace/extensions/activation",
|
|
21255
|
+
mutate({ strict: true }),
|
|
21256
|
+
(req, res) => {
|
|
21257
|
+
const runtime = resolveWorkspaceRuntimeFromParam(registry, req, res);
|
|
21258
|
+
if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res)) return;
|
|
21259
|
+
const names = parseExtensionBatchNames(req, res, safeBody2);
|
|
21260
|
+
if (!names) return;
|
|
21261
|
+
const state = parseWorkspaceBatchActivationState(req, res);
|
|
21262
|
+
if (!state) return;
|
|
21263
|
+
const manager = primaryController.createExtensionManager(
|
|
21264
|
+
runtime.workspaceCwd,
|
|
21265
|
+
true
|
|
21266
|
+
);
|
|
21267
|
+
sendOperation(
|
|
21268
|
+
req,
|
|
21269
|
+
res,
|
|
21270
|
+
"PUT /workspaces/:workspace/extensions/activation",
|
|
21271
|
+
manager,
|
|
21272
|
+
"set_workspace_activation_batch",
|
|
21273
|
+
{},
|
|
21274
|
+
async (extensionManager, _signal, context) => {
|
|
21275
|
+
const snapshot = await context.commit(
|
|
21276
|
+
async (onCommitted) => await extensionManager.setExtensionWorkspaceActivations(
|
|
21277
|
+
names,
|
|
21278
|
+
runtime.workspaceCwd,
|
|
21279
|
+
state,
|
|
21280
|
+
onCommitted
|
|
21281
|
+
)
|
|
21282
|
+
);
|
|
21283
|
+
return {
|
|
21284
|
+
status: "updated",
|
|
21285
|
+
updated: snapshot.updated,
|
|
21286
|
+
results: names.map((name) => ({
|
|
21287
|
+
name,
|
|
21288
|
+
workspaceActivation: state === "inherit" ? null : state,
|
|
21289
|
+
effectiveActivation: extensionManager.getExtensionActivationForNameFromSnapshot(
|
|
21290
|
+
name,
|
|
21291
|
+
snapshot,
|
|
21292
|
+
runtime.workspaceCwd
|
|
21293
|
+
).effective
|
|
21294
|
+
}))
|
|
21295
|
+
};
|
|
21296
|
+
},
|
|
21297
|
+
{
|
|
21298
|
+
refreshRuntimes: [runtime],
|
|
21299
|
+
assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
21300
|
+
}
|
|
21301
|
+
);
|
|
21302
|
+
}
|
|
21303
|
+
);
|
|
20376
21304
|
app.put(
|
|
20377
21305
|
"/workspaces/:workspace/extensions/:extensionId/activation",
|
|
20378
21306
|
mutate({ strict: true }),
|
|
@@ -20777,6 +21705,7 @@ __name(registerWorkspaceQualifiedFileWriteRoutes, "registerWorkspaceQualifiedFil
|
|
|
20777
21705
|
var MAX_CONCURRENT_UPLOADS = 4;
|
|
20778
21706
|
var MAX_UPLOAD_FILENAME_BYTES = 255;
|
|
20779
21707
|
var NUMBERED_CANDIDATE_CAP = 1e3;
|
|
21708
|
+
var MAX_UPLOAD_DIR_DEPTH = 64;
|
|
20780
21709
|
var uploadGateLeases = /* @__PURE__ */ new WeakMap();
|
|
20781
21710
|
function createUploadConcurrencyGate(max = MAX_CONCURRENT_UPLOADS) {
|
|
20782
21711
|
let active = 0;
|
|
@@ -20934,6 +21863,14 @@ function fileUploadAdmission(deps, opts) {
|
|
|
20934
21863
|
sendParseError(res, ROUTE2, "`path` must name a file");
|
|
20935
21864
|
return;
|
|
20936
21865
|
}
|
|
21866
|
+
if (dir.split("/").filter(Boolean).length > MAX_UPLOAD_DIR_DEPTH) {
|
|
21867
|
+
sendParseError(
|
|
21868
|
+
res,
|
|
21869
|
+
ROUTE2,
|
|
21870
|
+
`directory path exceeds ${MAX_UPLOAD_DIR_DEPTH} components`
|
|
21871
|
+
);
|
|
21872
|
+
return;
|
|
21873
|
+
}
|
|
20937
21874
|
if (queryPath.includes("\0")) {
|
|
20938
21875
|
sendParseError(res, ROUTE2, "path must not contain null bytes");
|
|
20939
21876
|
return;
|
|
@@ -20979,10 +21916,11 @@ function fileUploadAdmission(deps, opts) {
|
|
|
20979
21916
|
dirStat = await fs9.stat(resolvedDir);
|
|
20980
21917
|
} catch (err) {
|
|
20981
21918
|
if (isFsError(err) && err.kind === "path_not_found") {
|
|
20982
|
-
|
|
20983
|
-
|
|
21919
|
+
await fs9.mkdir(resolvedDir, { recursive: true });
|
|
21920
|
+
dirStat = await fs9.stat(resolvedDir);
|
|
21921
|
+
} else {
|
|
21922
|
+
throw err;
|
|
20984
21923
|
}
|
|
20985
|
-
throw err;
|
|
20986
21924
|
}
|
|
20987
21925
|
if (dirStat.kind !== "directory") {
|
|
20988
21926
|
sendParseError(res, ROUTE2, "parent path is not a directory");
|
|
@@ -21380,6 +22318,7 @@ init_esbuild_shims();
|
|
|
21380
22318
|
|
|
21381
22319
|
// packages/cli/src/serve/server/telemetry.ts
|
|
21382
22320
|
init_esbuild_shims();
|
|
22321
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
21383
22322
|
var legacySessionTelemetryRoutes = [
|
|
21384
22323
|
{
|
|
21385
22324
|
method: "POST",
|
|
@@ -21519,6 +22458,18 @@ var legacySessionTelemetryRoutes = [
|
|
|
21519
22458
|
attribution: "handler_resolved",
|
|
21520
22459
|
route: "POST /session/:id/tasks/:taskId/cancel"
|
|
21521
22460
|
},
|
|
22461
|
+
{
|
|
22462
|
+
method: "POST",
|
|
22463
|
+
path: "/session/:id/goal",
|
|
22464
|
+
attribution: "handler_resolved",
|
|
22465
|
+
route: "POST /session/:id/goal"
|
|
22466
|
+
},
|
|
22467
|
+
{
|
|
22468
|
+
method: "GET",
|
|
22469
|
+
path: "/session/:id/goal",
|
|
22470
|
+
attribution: "handler_resolved",
|
|
22471
|
+
route: "GET /session/:id/goal"
|
|
22472
|
+
},
|
|
21522
22473
|
{
|
|
21523
22474
|
method: "POST",
|
|
21524
22475
|
path: "/session/:id/goal/clear",
|
|
@@ -21531,6 +22482,24 @@ var legacySessionTelemetryRoutes = [
|
|
|
21531
22482
|
attribution: "handler_resolved",
|
|
21532
22483
|
route: "POST /session/:id/continue"
|
|
21533
22484
|
},
|
|
22485
|
+
{
|
|
22486
|
+
method: "POST",
|
|
22487
|
+
path: "/session/:id/attachments",
|
|
22488
|
+
attribution: "handler_resolved",
|
|
22489
|
+
route: "POST /session/:id/attachments"
|
|
22490
|
+
},
|
|
22491
|
+
{
|
|
22492
|
+
method: "GET",
|
|
22493
|
+
path: "/session/:id/attachments/:attachmentId",
|
|
22494
|
+
attribution: "handler_resolved",
|
|
22495
|
+
route: "GET /session/:id/attachments/:attachmentId"
|
|
22496
|
+
},
|
|
22497
|
+
{
|
|
22498
|
+
method: "DELETE",
|
|
22499
|
+
path: "/session/:id/attachments/:attachmentId",
|
|
22500
|
+
attribution: "handler_resolved",
|
|
22501
|
+
route: "DELETE /session/:id/attachments/:attachmentId"
|
|
22502
|
+
},
|
|
21534
22503
|
{
|
|
21535
22504
|
method: "POST",
|
|
21536
22505
|
path: "/session/:id/prompt",
|
|
@@ -21651,6 +22620,18 @@ var legacySessionTelemetryRoutes = [
|
|
|
21651
22620
|
attribution: "handler_resolved",
|
|
21652
22621
|
route: "DELETE /session/:id/pending-prompts/:promptId"
|
|
21653
22622
|
},
|
|
22623
|
+
{
|
|
22624
|
+
method: "GET",
|
|
22625
|
+
path: "/session/:id/turns/current",
|
|
22626
|
+
attribution: "handler_resolved",
|
|
22627
|
+
route: "GET /session/:id/turns/current"
|
|
22628
|
+
},
|
|
22629
|
+
{
|
|
22630
|
+
method: "GET",
|
|
22631
|
+
path: "/session/:id/turns/:promptId",
|
|
22632
|
+
attribution: "handler_resolved",
|
|
22633
|
+
route: "GET /session/:id/turns/:promptId"
|
|
22634
|
+
},
|
|
21654
22635
|
{
|
|
21655
22636
|
method: "POST",
|
|
21656
22637
|
path: "/session/:id/shell",
|
|
@@ -21706,7 +22687,6 @@ var legacySessionTelemetryRoutes = [
|
|
|
21706
22687
|
route: "POST /session/:id/a2ui-action"
|
|
21707
22688
|
}
|
|
21708
22689
|
];
|
|
21709
|
-
var daemonTelemetryResponseContext = Symbol("daemonTelemetryResponseContext");
|
|
21710
22690
|
function decodePathSegment(value) {
|
|
21711
22691
|
try {
|
|
21712
22692
|
return decodeURIComponent(value);
|
|
@@ -21779,6 +22759,9 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
21779
22759
|
if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions$/.test(path19)) {
|
|
21780
22760
|
return { route: "GET /workspace/:id/sessions" };
|
|
21781
22761
|
}
|
|
22762
|
+
if (req.method === "GET" && /^\/workspaces\/[^/]+\/sessions\/live-state$/.test(path19)) {
|
|
22763
|
+
return { route: "GET /workspaces/:workspace/sessions/live-state" };
|
|
22764
|
+
}
|
|
21782
22765
|
if (req.method === "GET" && /^\/workspace\/[^/]+\/session-info$/.test(path19)) {
|
|
21783
22766
|
return { route: "GET /workspace/:id/session-info" };
|
|
21784
22767
|
}
|
|
@@ -21930,8 +22913,34 @@ function resolveDaemonTelemetryRoute(req) {
|
|
|
21930
22913
|
return void 0;
|
|
21931
22914
|
}
|
|
21932
22915
|
__name(resolveDaemonTelemetryRoute, "resolveDaemonTelemetryRoute");
|
|
22916
|
+
var TRACEPARENT_BREADCRUMB_BURST = 60;
|
|
22917
|
+
var TRACEPARENT_BREADCRUMB_REFILL_PER_SECOND = 2;
|
|
22918
|
+
function daemonInboundTraceIdCaptureMiddleware(req, res, next) {
|
|
22919
|
+
try {
|
|
22920
|
+
const inboundTraceId = extractInboundTraceId(req.headers);
|
|
22921
|
+
if (inboundTraceId !== void 0) {
|
|
22922
|
+
res[daemonInboundTraceIdContext] = inboundTraceId;
|
|
22923
|
+
}
|
|
22924
|
+
} catch {
|
|
22925
|
+
}
|
|
22926
|
+
next();
|
|
22927
|
+
}
|
|
22928
|
+
__name(daemonInboundTraceIdCaptureMiddleware, "daemonInboundTraceIdCaptureMiddleware");
|
|
21933
22929
|
function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
|
|
21934
22930
|
const workspaceHashByCwd = /* @__PURE__ */ new Map();
|
|
22931
|
+
let breadcrumbTokens = TRACEPARENT_BREADCRUMB_BURST;
|
|
22932
|
+
let breadcrumbRefillBaseline = performance2.now();
|
|
22933
|
+
const acquireBreadcrumbToken = /* @__PURE__ */ __name(() => {
|
|
22934
|
+
const now = Math.max(performance2.now(), breadcrumbRefillBaseline);
|
|
22935
|
+
breadcrumbTokens = Math.min(
|
|
22936
|
+
TRACEPARENT_BREADCRUMB_BURST,
|
|
22937
|
+
breadcrumbTokens + (now - breadcrumbRefillBaseline) / 1e3 * TRACEPARENT_BREADCRUMB_REFILL_PER_SECOND
|
|
22938
|
+
);
|
|
22939
|
+
breadcrumbRefillBaseline = now;
|
|
22940
|
+
if (breadcrumbTokens < 1) return false;
|
|
22941
|
+
breadcrumbTokens -= 1;
|
|
22942
|
+
return true;
|
|
22943
|
+
}, "acquireBreadcrumbToken");
|
|
21935
22944
|
const resolveWorkspaceHash = /* @__PURE__ */ __name((workspaceCwd) => {
|
|
21936
22945
|
const existing = workspaceHashByCwd.get(workspaceCwd);
|
|
21937
22946
|
if (existing !== void 0) return existing;
|
|
@@ -21960,10 +22969,39 @@ function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
|
|
|
21960
22969
|
const clientId = rawClientId !== void 0 && rawClientId !== "" && rawClientId.length <= MAX_CLIENT_ID_LENGTH && CLIENT_ID_RE.test(rawClientId) ? rawClientId : void 0;
|
|
21961
22970
|
const deferredRuntime = getDeferredRuntimeRequestTiming(req);
|
|
21962
22971
|
const startMs = deferredRuntime?.startedAt.getTime() ?? Date.now();
|
|
22972
|
+
let parentContext;
|
|
22973
|
+
if (isTelemetrySdkInitialized()) {
|
|
22974
|
+
try {
|
|
22975
|
+
parentContext = extractDaemonHttpTraceContext(req.headers);
|
|
22976
|
+
} catch {
|
|
22977
|
+
parentContext = void 0;
|
|
22978
|
+
}
|
|
22979
|
+
try {
|
|
22980
|
+
const inboundTraceparent = req.headers?.["traceparent"];
|
|
22981
|
+
if (!parentContext && typeof inboundTraceparent === "string" && inboundTraceparent.length > 0 && acquireBreadcrumbToken()) {
|
|
22982
|
+
emitDaemonLog(
|
|
22983
|
+
"Rejected invalid inbound traceparent header.",
|
|
22984
|
+
{
|
|
22985
|
+
"http.route": route.route,
|
|
22986
|
+
"http.request.header.traceparent": sanitizeLogText(
|
|
22987
|
+
inboundTraceparent,
|
|
22988
|
+
128
|
|
22989
|
+
)
|
|
22990
|
+
},
|
|
22991
|
+
{
|
|
22992
|
+
eventName: "qwen-code.daemon.traceparent.invalid",
|
|
22993
|
+
severityNumber: 5
|
|
22994
|
+
// SeverityNumber.DEBUG
|
|
22995
|
+
}
|
|
22996
|
+
);
|
|
22997
|
+
}
|
|
22998
|
+
} catch {
|
|
22999
|
+
}
|
|
23000
|
+
}
|
|
21963
23001
|
const telemetryRes = res;
|
|
21964
23002
|
if (route.attribution === "handler_resolved") {
|
|
21965
23003
|
try {
|
|
21966
|
-
telemetryRes[daemonTelemetryResponseContext]
|
|
23004
|
+
telemetryRes[daemonTelemetryResponseContext] ??= {};
|
|
21967
23005
|
} catch {
|
|
21968
23006
|
}
|
|
21969
23007
|
}
|
|
@@ -21975,6 +23013,7 @@ function daemonTelemetryMiddleware(resolveWorkspaceCwd, recordRequest) {
|
|
|
21975
23013
|
...sessionId ? { sessionId } : {},
|
|
21976
23014
|
...route.permissionRequestId ? { permissionRequestId: route.permissionRequestId } : {},
|
|
21977
23015
|
...clientId ? { clientId } : {},
|
|
23016
|
+
...parentContext ? { parentContext } : {},
|
|
21978
23017
|
...deferredRuntime?.waitMs !== void 0 ? {
|
|
21979
23018
|
startTime: deferredRuntime.startedAt,
|
|
21980
23019
|
deferredRuntimeWaitMs: deferredRuntime.waitMs,
|
|
@@ -22212,6 +23251,7 @@ init_esbuild_shims();
|
|
|
22212
23251
|
import * as crypto3 from "node:crypto";
|
|
22213
23252
|
import * as fs6 from "node:fs";
|
|
22214
23253
|
import * as path12 from "node:path";
|
|
23254
|
+
var import_express4 = __toESM(require_express(), 1);
|
|
22215
23255
|
|
|
22216
23256
|
// packages/cli/src/serve/server/prompt-deadline.ts
|
|
22217
23257
|
init_esbuild_shims();
|
|
@@ -22409,10 +23449,27 @@ var PersistedSessionListCache = class {
|
|
|
22409
23449
|
}
|
|
22410
23450
|
};
|
|
22411
23451
|
|
|
23452
|
+
// packages/cli/src/serve/server/activity-timestamp.ts
|
|
23453
|
+
init_esbuild_shims();
|
|
23454
|
+
function laterActivityTimestamp(live, persisted) {
|
|
23455
|
+
const liveTime = live === void 0 ? Number.NaN : Date.parse(live);
|
|
23456
|
+
const persistedTime = persisted === void 0 ? Number.NaN : Date.parse(persisted);
|
|
23457
|
+
const liveValid = Number.isFinite(liveTime);
|
|
23458
|
+
const persistedValid = Number.isFinite(persistedTime);
|
|
23459
|
+
if (liveValid && persistedValid) {
|
|
23460
|
+
return liveTime >= persistedTime ? live : persisted;
|
|
23461
|
+
}
|
|
23462
|
+
if (liveValid) return live;
|
|
23463
|
+
if (persistedValid) return persisted;
|
|
23464
|
+
return live ?? persisted;
|
|
23465
|
+
}
|
|
23466
|
+
__name(laterActivityTimestamp, "laterActivityTimestamp");
|
|
23467
|
+
|
|
22412
23468
|
// packages/cli/src/serve/server/session-list.ts
|
|
22413
23469
|
var DEFAULT_SESSION_PAGE_SIZE = 20;
|
|
22414
23470
|
var MAX_SESSION_PAGE_SIZE = 100;
|
|
22415
23471
|
var MAX_ORGANIZED_SESSIONS = 5e4;
|
|
23472
|
+
var MAX_EMITTED_CURSOR_SESSION_IDS = 64;
|
|
22416
23473
|
var PERSISTED_SESSION_LIST_CACHE_TTL_MS = 2e3;
|
|
22417
23474
|
var persistedSessionListCache = new PersistedSessionListCache(
|
|
22418
23475
|
PERSISTED_SESSION_LIST_CACHE_TTL_MS,
|
|
@@ -22447,6 +23504,14 @@ function parseSessionCursor(cursor) {
|
|
|
22447
23504
|
return parsed;
|
|
22448
23505
|
}
|
|
22449
23506
|
__name(parseSessionCursor, "parseSessionCursor");
|
|
23507
|
+
function parseEmittedSessionIds(value) {
|
|
23508
|
+
if (value === void 0) return [];
|
|
23509
|
+
if (!Array.isArray(value) || value.some((id) => typeof id !== "string" || id.length === 0)) {
|
|
23510
|
+
return void 0;
|
|
23511
|
+
}
|
|
23512
|
+
return value;
|
|
23513
|
+
}
|
|
23514
|
+
__name(parseEmittedSessionIds, "parseEmittedSessionIds");
|
|
22450
23515
|
function parseOrganizedCursor(cursor, expected) {
|
|
22451
23516
|
if (cursor === "") return void 0;
|
|
22452
23517
|
try {
|
|
@@ -22456,15 +23521,26 @@ function parseOrganizedCursor(cursor, expected) {
|
|
|
22456
23521
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof last !== "object" || last === null || Array.isArray(last) || typeof last.isPinned !== "boolean" || typeof last.activityTime !== "number" || !Number.isFinite(last.activityTime) || typeof last.sessionId !== "string" || last.sessionId.length === 0 || parsed.group !== expected.group || parsed.archiveState !== expected.archiveState || parsed.sourceType !== expected.sourceType || parsed.sourceId !== expected.sourceId) {
|
|
22457
23522
|
throw new Error("invalid organized cursor");
|
|
22458
23523
|
}
|
|
22459
|
-
|
|
23524
|
+
const emitted = parseEmittedSessionIds(parsed.emitted);
|
|
23525
|
+
if (emitted === void 0) {
|
|
23526
|
+
throw new Error("invalid organized cursor");
|
|
23527
|
+
}
|
|
23528
|
+
return { last, emitted };
|
|
22460
23529
|
} catch {
|
|
22461
23530
|
throw new InvalidCursorError(cursor, "organized");
|
|
22462
23531
|
}
|
|
22463
23532
|
}
|
|
22464
23533
|
__name(parseOrganizedCursor, "parseOrganizedCursor");
|
|
22465
|
-
function encodeOrganizedCursor(last, group, archiveState, sourceType, sourceId) {
|
|
23534
|
+
function encodeOrganizedCursor(last, group, archiveState, sourceType, sourceId, emitted = []) {
|
|
22466
23535
|
return Buffer.from(
|
|
22467
|
-
JSON.stringify({
|
|
23536
|
+
JSON.stringify({
|
|
23537
|
+
group,
|
|
23538
|
+
archiveState,
|
|
23539
|
+
sourceType,
|
|
23540
|
+
sourceId,
|
|
23541
|
+
last,
|
|
23542
|
+
...emitted.length > 0 ? { emitted } : {}
|
|
23543
|
+
}),
|
|
22468
23544
|
"utf8"
|
|
22469
23545
|
).toString("base64url");
|
|
22470
23546
|
}
|
|
@@ -22505,7 +23581,16 @@ function parseMetadataSessionCursor(cursor, expected) {
|
|
|
22505
23581
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || typeof last !== "object" || last === null || Array.isArray(last) || typeof last.activityTime !== "number" || !Number.isFinite(last.activityTime) || typeof last.sessionId !== "string" || last.sessionId.length === 0 || parsed.parentSessionId !== expected.parentSessionId || parsed.sourceType !== expected.sourceType || parsed.sourceId !== expected.sourceId || parsed.archiveState !== expected.archiveState) {
|
|
22506
23582
|
throw new Error("invalid metadata cursor");
|
|
22507
23583
|
}
|
|
22508
|
-
|
|
23584
|
+
const emitted = parseEmittedSessionIds(
|
|
23585
|
+
parsed.emitted
|
|
23586
|
+
);
|
|
23587
|
+
if (emitted === void 0) {
|
|
23588
|
+
throw new Error("invalid metadata cursor");
|
|
23589
|
+
}
|
|
23590
|
+
return {
|
|
23591
|
+
last: { activityTime: last.activityTime, sessionId: last.sessionId },
|
|
23592
|
+
emitted
|
|
23593
|
+
};
|
|
22509
23594
|
} catch {
|
|
22510
23595
|
throw new InvalidCursorError(
|
|
22511
23596
|
cursor,
|
|
@@ -22514,9 +23599,14 @@ function parseMetadataSessionCursor(cursor, expected) {
|
|
|
22514
23599
|
}
|
|
22515
23600
|
}
|
|
22516
23601
|
__name(parseMetadataSessionCursor, "parseMetadataSessionCursor");
|
|
22517
|
-
function encodeMetadataSessionCursor(last, filter, archiveState) {
|
|
23602
|
+
function encodeMetadataSessionCursor(last, filter, archiveState, emitted = []) {
|
|
22518
23603
|
return Buffer.from(
|
|
22519
|
-
JSON.stringify({
|
|
23604
|
+
JSON.stringify({
|
|
23605
|
+
...filter,
|
|
23606
|
+
archiveState,
|
|
23607
|
+
last,
|
|
23608
|
+
...emitted.length > 0 ? { emitted } : {}
|
|
23609
|
+
}),
|
|
22520
23610
|
"utf8"
|
|
22521
23611
|
).toString("base64url");
|
|
22522
23612
|
}
|
|
@@ -22576,7 +23666,7 @@ function mergeLiveSessionSummary(existing, live) {
|
|
|
22576
23666
|
parentSessionId: existing.parentSessionId ?? live.parentSessionId,
|
|
22577
23667
|
sourceType: existing.sourceType ?? live.sourceType,
|
|
22578
23668
|
sourceId: existing.sourceType !== void 0 ? existing.sourceId : live.sourceId,
|
|
22579
|
-
updatedAt: live.updatedAt
|
|
23669
|
+
updatedAt: laterActivityTimestamp(live.updatedAt, existing.updatedAt),
|
|
22580
23670
|
clientCount: live.clientCount,
|
|
22581
23671
|
hasActivePrompt: live.hasActivePrompt,
|
|
22582
23672
|
isArchived: false
|
|
@@ -22726,6 +23816,36 @@ function compareOrganizedCursorKeys(a, b) {
|
|
|
22726
23816
|
return a.sessionId.localeCompare(b.sessionId);
|
|
22727
23817
|
}
|
|
22728
23818
|
__name(compareOrganizedCursorKeys, "compareOrganizedCursorKeys");
|
|
23819
|
+
function nextEmittedSessionIds(options) {
|
|
23820
|
+
const candidates = new Set(options.carried);
|
|
23821
|
+
for (const row of options.page) {
|
|
23822
|
+
if (options.liveSessionIds.has(row.sessionId)) {
|
|
23823
|
+
candidates.add(row.sessionId);
|
|
23824
|
+
}
|
|
23825
|
+
}
|
|
23826
|
+
const kept = [];
|
|
23827
|
+
for (const sessionId of candidates) {
|
|
23828
|
+
const row = options.listedById.get(sessionId);
|
|
23829
|
+
if (!row) {
|
|
23830
|
+
kept.push({ sessionId, persistedTime: Number.NEGATIVE_INFINITY });
|
|
23831
|
+
continue;
|
|
23832
|
+
}
|
|
23833
|
+
const persistedTime = options.persistedTimeById.get(sessionId);
|
|
23834
|
+
if (persistedTime === void 0) {
|
|
23835
|
+
kept.push({ sessionId, persistedTime: Number.NEGATIVE_INFINITY });
|
|
23836
|
+
continue;
|
|
23837
|
+
}
|
|
23838
|
+
if (options.reenters(row, persistedTime)) {
|
|
23839
|
+
kept.push({ sessionId, persistedTime });
|
|
23840
|
+
}
|
|
23841
|
+
}
|
|
23842
|
+
if (kept.length > MAX_EMITTED_CURSOR_SESSION_IDS) {
|
|
23843
|
+
kept.sort((a, b) => a.persistedTime - b.persistedTime);
|
|
23844
|
+
kept.length = MAX_EMITTED_CURSOR_SESSION_IDS;
|
|
23845
|
+
}
|
|
23846
|
+
return kept.map((entry) => entry.sessionId);
|
|
23847
|
+
}
|
|
23848
|
+
__name(nextEmittedSessionIds, "nextEmittedSessionIds");
|
|
22729
23849
|
function applyOrganization(session, organization) {
|
|
22730
23850
|
return {
|
|
22731
23851
|
...session,
|
|
@@ -22752,12 +23872,14 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
22752
23872
|
"group"
|
|
22753
23873
|
);
|
|
22754
23874
|
}
|
|
22755
|
-
const
|
|
23875
|
+
const cursor = options.cursor !== void 0 ? parseOrganizedCursor(options.cursor, {
|
|
22756
23876
|
group,
|
|
22757
23877
|
archiveState,
|
|
22758
23878
|
sourceType: options.sourceType,
|
|
22759
23879
|
sourceId: options.sourceId
|
|
22760
23880
|
}) : void 0;
|
|
23881
|
+
const cursorKey = cursor?.last;
|
|
23882
|
+
const emittedBeforePage = new Set(cursor?.emitted ?? []);
|
|
22761
23883
|
const isFirstPage = cursorKey === void 0;
|
|
22762
23884
|
let liveMergeFailed = false;
|
|
22763
23885
|
const bySessionId = /* @__PURE__ */ new Map();
|
|
@@ -22779,10 +23901,18 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
22779
23901
|
)
|
|
22780
23902
|
);
|
|
22781
23903
|
}
|
|
22782
|
-
|
|
23904
|
+
const persistedTimeById = new Map(
|
|
23905
|
+
persisted.sessions.map((session) => [
|
|
23906
|
+
session.sessionId,
|
|
23907
|
+
getSummaryActivityTime(session)
|
|
23908
|
+
])
|
|
23909
|
+
);
|
|
23910
|
+
const liveSessionIds = /* @__PURE__ */ new Set();
|
|
23911
|
+
if (readOptions.mergeLive !== false && archiveState !== "archived") {
|
|
22783
23912
|
try {
|
|
22784
23913
|
const liveSessions = bridge.listWorkspaceSessions(workspaceCwd);
|
|
22785
23914
|
for (const live of liveSessions) {
|
|
23915
|
+
liveSessionIds.add(live.sessionId);
|
|
22786
23916
|
const existing = bySessionId.get(live.sessionId);
|
|
22787
23917
|
const organization = snapshot.sessions.get(live.sessionId);
|
|
22788
23918
|
if (existing) {
|
|
@@ -22794,7 +23924,9 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
22794
23924
|
)
|
|
22795
23925
|
);
|
|
22796
23926
|
} else if (
|
|
22797
|
-
//
|
|
23927
|
+
// A live-only row has no persisted key to page by, so it stays a
|
|
23928
|
+
// first-page-only insertion as before.
|
|
23929
|
+
isFirstPage && // `listAllPersistedSummaries` already scanned every persisted
|
|
22798
23930
|
// session when the scan wasn't truncated, so a `sessionId` missing
|
|
22799
23931
|
// from `bySessionId` is definitively new — no disk re-check
|
|
22800
23932
|
// needed. Re-checking here raced a session that persists its
|
|
@@ -22802,9 +23934,9 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
22802
23934
|
// above and this point: `existing` stayed undefined but
|
|
22803
23935
|
// `sessionExists` flipped to true, silently dropping the live
|
|
22804
23936
|
// session from the response instead of merging it.
|
|
22805
|
-
!persisted.truncated || !await (readOptions.signal ? sessionService.sessionExists(live.sessionId, {
|
|
23937
|
+
(!persisted.truncated || !await (readOptions.signal ? sessionService.sessionExists(live.sessionId, {
|
|
22806
23938
|
signal: readOptions.signal
|
|
22807
|
-
}) : sessionService.sessionExists(live.sessionId))
|
|
23939
|
+
}) : sessionService.sessionExists(live.sessionId)))
|
|
22808
23940
|
) {
|
|
22809
23941
|
bySessionId.set(
|
|
22810
23942
|
live.sessionId,
|
|
@@ -22847,19 +23979,52 @@ async function listOrganizedWorkspaceSessionsForResponse(bridge, workspaceCwd, o
|
|
|
22847
23979
|
filtered.sort((a, b) => compareOrganizedSessions(activityTimeById, a, b));
|
|
22848
23980
|
readOptions.signal?.throwIfAborted();
|
|
22849
23981
|
const afterCursor = cursorKey === void 0 ? filtered : filtered.filter(
|
|
22850
|
-
(session) =>
|
|
22851
|
-
|
|
22852
|
-
|
|
22853
|
-
|
|
23982
|
+
(session) => (
|
|
23983
|
+
// A row already emitted at a live-derived key stays excluded even
|
|
23984
|
+
// if its key regressed behind the cursor (live retirement, or a
|
|
23985
|
+
// live-only row that persisted mid-pass).
|
|
23986
|
+
!emittedBeforePage.has(session.sessionId) && compareOrganizedCursorKeys(
|
|
23987
|
+
cursorKey,
|
|
23988
|
+
getOrganizedCursorKey(activityTimeById, session)
|
|
23989
|
+
) < 0
|
|
23990
|
+
)
|
|
22854
23991
|
);
|
|
22855
23992
|
const page = afterCursor.slice(0, pageSize);
|
|
22856
|
-
|
|
22857
|
-
|
|
22858
|
-
|
|
22859
|
-
|
|
22860
|
-
|
|
22861
|
-
|
|
22862
|
-
|
|
23993
|
+
let nextCursor;
|
|
23994
|
+
if (page.length < afterCursor.length) {
|
|
23995
|
+
const boundary = getOrganizedCursorKey(
|
|
23996
|
+
activityTimeById,
|
|
23997
|
+
page[page.length - 1]
|
|
23998
|
+
);
|
|
23999
|
+
const emitted = nextEmittedSessionIds({
|
|
24000
|
+
carried: emittedBeforePage,
|
|
24001
|
+
page,
|
|
24002
|
+
liveSessionIds,
|
|
24003
|
+
listedById: new Map(
|
|
24004
|
+
filtered.map((session) => [session.sessionId, session])
|
|
24005
|
+
),
|
|
24006
|
+
persistedTimeById,
|
|
24007
|
+
// `isPinned` is re-read from the organization snapshot on every page
|
|
24008
|
+
// request, so a pin flip between fetches can move the persisted key
|
|
24009
|
+
// across the pinned/unpinned blocks. Keep the identity while the key
|
|
24010
|
+
// could re-enter under either state.
|
|
24011
|
+
reenters: /* @__PURE__ */ __name((row, persistedTime) => [true, false].some(
|
|
24012
|
+
(isPinned) => compareOrganizedCursorKeys(boundary, {
|
|
24013
|
+
isPinned,
|
|
24014
|
+
activityTime: persistedTime,
|
|
24015
|
+
sessionId: row.sessionId
|
|
24016
|
+
}) < 0
|
|
24017
|
+
), "reenters")
|
|
24018
|
+
});
|
|
24019
|
+
nextCursor = encodeOrganizedCursor(
|
|
24020
|
+
boundary,
|
|
24021
|
+
group,
|
|
24022
|
+
archiveState,
|
|
24023
|
+
options.sourceType,
|
|
24024
|
+
options.sourceId,
|
|
24025
|
+
emitted
|
|
24026
|
+
);
|
|
24027
|
+
}
|
|
22863
24028
|
return {
|
|
22864
24029
|
sessions: page,
|
|
22865
24030
|
...nextCursor !== void 0 ? { nextCursor } : {},
|
|
@@ -22884,10 +24049,18 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
|
|
|
22884
24049
|
for (const session of persisted.sessions) {
|
|
22885
24050
|
bySessionId.set(session.sessionId, clonePersistedSummary(session));
|
|
22886
24051
|
}
|
|
24052
|
+
const persistedTimeById = new Map(
|
|
24053
|
+
persisted.sessions.map((session) => [
|
|
24054
|
+
session.sessionId,
|
|
24055
|
+
getSummaryActivityTime(session)
|
|
24056
|
+
])
|
|
24057
|
+
);
|
|
24058
|
+
const liveSessionIds = /* @__PURE__ */ new Set();
|
|
22887
24059
|
let liveMergeFailed = false;
|
|
22888
24060
|
if (readOptions.mergeLive !== false && archiveState !== "archived") {
|
|
22889
24061
|
try {
|
|
22890
24062
|
for (const live of bridge.listWorkspaceSessions(workspaceCwd)) {
|
|
24063
|
+
liveSessionIds.add(live.sessionId);
|
|
22891
24064
|
const existing = bySessionId.get(live.sessionId);
|
|
22892
24065
|
if (existing) {
|
|
22893
24066
|
bySessionId.set(
|
|
@@ -22929,22 +24102,46 @@ async function listWorkspaceSessionsByMetadataForResponse(bridge, workspaceCwd,
|
|
|
22929
24102
|
)
|
|
22930
24103
|
);
|
|
22931
24104
|
readOptions.signal?.throwIfAborted();
|
|
22932
|
-
const
|
|
24105
|
+
const cursor = options.cursor !== void 0 && options.cursor !== "" ? parseMetadataSessionCursor(options.cursor, {
|
|
22933
24106
|
...filter,
|
|
22934
24107
|
archiveState
|
|
22935
24108
|
}) : void 0;
|
|
24109
|
+
const cursorKey = cursor?.last;
|
|
24110
|
+
const emittedBeforePage = new Set(cursor?.emitted ?? []);
|
|
22936
24111
|
const afterCursor = cursorKey === void 0 ? matches : matches.filter(
|
|
22937
|
-
(session) =>
|
|
22938
|
-
|
|
22939
|
-
|
|
22940
|
-
|
|
24112
|
+
(session) => (
|
|
24113
|
+
// See the organized path: exclude rows already emitted at a
|
|
24114
|
+
// live-derived key whose key regressed behind the cursor.
|
|
24115
|
+
!emittedBeforePage.has(session.sessionId) && compareLiveSessionCursorKeys(
|
|
24116
|
+
cursorKey,
|
|
24117
|
+
getLiveSessionCursorKey(session)
|
|
24118
|
+
) < 0
|
|
24119
|
+
)
|
|
22941
24120
|
);
|
|
22942
24121
|
const page = afterCursor.slice(0, pageSize);
|
|
22943
|
-
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
22947
|
-
|
|
24122
|
+
let nextCursor;
|
|
24123
|
+
if (page.length < afterCursor.length) {
|
|
24124
|
+
const boundary = getLiveSessionCursorKey(page[page.length - 1]);
|
|
24125
|
+
const emitted = nextEmittedSessionIds({
|
|
24126
|
+
carried: emittedBeforePage,
|
|
24127
|
+
page,
|
|
24128
|
+
liveSessionIds,
|
|
24129
|
+
listedById: new Map(
|
|
24130
|
+
matches.map((session) => [session.sessionId, session])
|
|
24131
|
+
),
|
|
24132
|
+
persistedTimeById,
|
|
24133
|
+
reenters: /* @__PURE__ */ __name((row, persistedTime) => compareLiveSessionCursorKeys(boundary, {
|
|
24134
|
+
activityTime: persistedTime,
|
|
24135
|
+
sessionId: row.sessionId
|
|
24136
|
+
}) < 0, "reenters")
|
|
24137
|
+
});
|
|
24138
|
+
nextCursor = encodeMetadataSessionCursor(
|
|
24139
|
+
boundary,
|
|
24140
|
+
filter,
|
|
24141
|
+
archiveState,
|
|
24142
|
+
emitted
|
|
24143
|
+
);
|
|
24144
|
+
}
|
|
22948
24145
|
return {
|
|
22949
24146
|
sessions: page,
|
|
22950
24147
|
...nextCursor !== void 0 ? { nextCursor } : {},
|
|
@@ -24036,6 +25233,58 @@ var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 2 * SESSION_TRANSCRIPT_MAX_EXPANDE
|
|
|
24036
25233
|
var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
|
|
24037
25234
|
var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
|
|
24038
25235
|
var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
|
|
25236
|
+
var MEDIA_CONTENT_MAX_BLOCKS = 256;
|
|
25237
|
+
function isSvgMimeType(mimeType) {
|
|
25238
|
+
return mimeType?.split(";", 1)[0]?.trim().toLowerCase() === "image/svg+xml";
|
|
25239
|
+
}
|
|
25240
|
+
__name(isSvgMimeType, "isSvgMimeType");
|
|
25241
|
+
function parseMediaContentBlock(block) {
|
|
25242
|
+
if (typeof block !== "object" || block === null || Array.isArray(block)) {
|
|
25243
|
+
return { valid: false, code: "not-object" };
|
|
25244
|
+
}
|
|
25245
|
+
const record = block;
|
|
25246
|
+
const type = record["type"];
|
|
25247
|
+
const data = record["data"];
|
|
25248
|
+
const attachmentId = record["attachmentId"];
|
|
25249
|
+
const mimeType = record["mimeType"];
|
|
25250
|
+
const size = record["size"];
|
|
25251
|
+
const inline = typeof data === "string" && data.length > 0;
|
|
25252
|
+
const reference = typeof attachmentId === "string" && attachmentId.length > 0 && typeof size === "number" && Number.isSafeInteger(size) && size >= 0 && (type !== "image" || size > 0);
|
|
25253
|
+
if (type === "resource" && !reference) {
|
|
25254
|
+
const resource = record["resource"];
|
|
25255
|
+
if (typeof resource !== "object" || resource === null) {
|
|
25256
|
+
return { valid: false, code: "invalid-shape" };
|
|
25257
|
+
}
|
|
25258
|
+
const value = resource;
|
|
25259
|
+
const hasText = typeof value["text"] === "string";
|
|
25260
|
+
const hasBlob = typeof value["blob"] === "string";
|
|
25261
|
+
if (typeof value["uri"] !== "string" || value["uri"].length === 0 || hasText === hasBlob) {
|
|
25262
|
+
return { valid: false, code: "invalid-shape" };
|
|
25263
|
+
}
|
|
25264
|
+
return { valid: true, block };
|
|
25265
|
+
}
|
|
25266
|
+
if (type !== "image" && type !== "resource" || (type === "image" ? inline === reference : inline || !reference) || typeof mimeType !== "string" || type === "image" && !mimeType.startsWith("image/")) {
|
|
25267
|
+
return { valid: false, code: "invalid-shape" };
|
|
25268
|
+
}
|
|
25269
|
+
if (type === "image" && isSvgMimeType(mimeType)) {
|
|
25270
|
+
return { valid: false, code: "svg" };
|
|
25271
|
+
}
|
|
25272
|
+
return {
|
|
25273
|
+
valid: true,
|
|
25274
|
+
block: inline ? { type, data, mimeType } : { type, attachmentId, mimeType, size }
|
|
25275
|
+
};
|
|
25276
|
+
}
|
|
25277
|
+
__name(parseMediaContentBlock, "parseMediaContentBlock");
|
|
25278
|
+
function mediaBlockParseError(code, entryLabel) {
|
|
25279
|
+
if (code === "not-object") {
|
|
25280
|
+
return `each ${entryLabel} must be a media content block`;
|
|
25281
|
+
}
|
|
25282
|
+
if (code === "svg") {
|
|
25283
|
+
return "SVG images are not supported";
|
|
25284
|
+
}
|
|
25285
|
+
return `each ${entryLabel} must be an inline content block or carry \`attachmentId\`, \`size\`, and \`mimeType\``;
|
|
25286
|
+
}
|
|
25287
|
+
__name(mediaBlockParseError, "mediaBlockParseError");
|
|
24039
25288
|
var PRIMARY_ONLY_LIVE_SESSION_ROUTES = ["POST /session/:id/cd"];
|
|
24040
25289
|
var PRIMARY_OR_INTERNAL_LIVE_SESSION_ROUTES = [
|
|
24041
25290
|
"POST /session/:id/branch",
|
|
@@ -24243,11 +25492,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
24243
25492
|
archiveStates
|
|
24244
25493
|
});
|
|
24245
25494
|
}, "invalidateSessionLists");
|
|
25495
|
+
const invalidateSessionListsAndMarkCatalog = /* @__PURE__ */ __name((runtime, archiveStates) => {
|
|
25496
|
+
invalidateSessionLists(runtime, archiveStates);
|
|
25497
|
+
runtime.bridge.markSessionCatalogChanged();
|
|
25498
|
+
}, "invalidateSessionListsAndMarkCatalog");
|
|
24246
25499
|
const runWithSessionListInvalidation = /* @__PURE__ */ __name(async (runtime, archiveStates, mutation) => {
|
|
24247
25500
|
try {
|
|
24248
25501
|
return await mutation();
|
|
24249
25502
|
} finally {
|
|
24250
|
-
|
|
25503
|
+
invalidateSessionListsAndMarkCatalog(runtime, archiveStates);
|
|
24251
25504
|
}
|
|
24252
25505
|
}, "runWithSessionListInvalidation");
|
|
24253
25506
|
const requestedSessionIdAdmission = deps.requestedSessionIdAdmission ?? createRequestedSessionIdAdmission({
|
|
@@ -24617,7 +25870,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
24617
25870
|
}
|
|
24618
25871
|
const metadata = await readLoadableLiveConversationMetadata(
|
|
24619
25872
|
sessionId,
|
|
24620
|
-
|
|
25873
|
+
service
|
|
24621
25874
|
);
|
|
24622
25875
|
if (!metadata) throw new SessionNotFoundError(sessionId);
|
|
24623
25876
|
}
|
|
@@ -24941,10 +26194,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
24941
26194
|
if (location !== "active") return false;
|
|
24942
26195
|
if (!isInternalWorkspaceRuntime(runtime)) return true;
|
|
24943
26196
|
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
24944
|
-
return await readLoadableLiveConversationMetadata(
|
|
24945
|
-
sessionId,
|
|
24946
|
-
(candidateId) => service.readCreationMetadata(candidateId)
|
|
24947
|
-
) !== void 0;
|
|
26197
|
+
return await readLoadableLiveConversationMetadata(sessionId, service) !== void 0;
|
|
24948
26198
|
}, "activeInRuntime");
|
|
24949
26199
|
const throwMissingActiveTranscript = /* @__PURE__ */ __name(() => {
|
|
24950
26200
|
if (hasCursor) {
|
|
@@ -25140,7 +26390,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
25140
26390
|
if (!exists) continue;
|
|
25141
26391
|
const metadata = await readLoadableLiveConversationMetadata(
|
|
25142
26392
|
sessionId,
|
|
25143
|
-
|
|
26393
|
+
service
|
|
25144
26394
|
);
|
|
25145
26395
|
if (!assertCurrentInternalGeneration(entry, generation, res)) {
|
|
25146
26396
|
return void 0;
|
|
@@ -25227,7 +26477,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
25227
26477
|
if (!exists) continue;
|
|
25228
26478
|
const metadata = await readLoadableLiveConversationMetadata(
|
|
25229
26479
|
sessionId,
|
|
25230
|
-
|
|
26480
|
+
service
|
|
25231
26481
|
);
|
|
25232
26482
|
if (!assertCurrentInternalGeneration(entry, generation2, res)) {
|
|
25233
26483
|
return void 0;
|
|
@@ -25281,7 +26531,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
25281
26531
|
}
|
|
25282
26532
|
const metadata = await readLoadableLiveConversationMetadata(
|
|
25283
26533
|
sessionId,
|
|
25284
|
-
|
|
26534
|
+
service
|
|
25285
26535
|
);
|
|
25286
26536
|
if (!metadata) {
|
|
25287
26537
|
throw new SessionNotFoundError(sessionId);
|
|
@@ -25481,6 +26731,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
25481
26731
|
}
|
|
25482
26732
|
const approvalMode = parseOptionalApprovalMode(body, res);
|
|
25483
26733
|
if (approvalMode === null) return;
|
|
26734
|
+
if (isReservedStandaloneSessionSource({
|
|
26735
|
+
sourceType: typeof body["sourceType"] === "string" ? body["sourceType"] : void 0
|
|
26736
|
+
})) {
|
|
26737
|
+
res.status(400).json({
|
|
26738
|
+
error: "The requested session source is reserved for daemon-owned standalone sessions.",
|
|
26739
|
+
code: "reserved_session_source"
|
|
26740
|
+
});
|
|
26741
|
+
return;
|
|
26742
|
+
}
|
|
25484
26743
|
const source = parseSessionSource(body["sourceType"], body["sourceId"]);
|
|
25485
26744
|
if ("error" in source) {
|
|
25486
26745
|
res.status(400).json({
|
|
@@ -26051,24 +27310,54 @@ function registerSessionRoutes(app, deps) {
|
|
|
26051
27310
|
throw error2;
|
|
26052
27311
|
}
|
|
26053
27312
|
}
|
|
27313
|
+
let restoredStorageSessionId = sessionId;
|
|
26054
27314
|
try {
|
|
27315
|
+
const guardSessionService = createWorkspaceRuntimeSessionService(runtime);
|
|
27316
|
+
try {
|
|
27317
|
+
await guardSessionService.findSessionIdIgnoringCase(sessionId);
|
|
27318
|
+
} catch (error2) {
|
|
27319
|
+
if (error2 instanceof SessionIdCaseConflictError && await guardSessionService.getSessionLocation(
|
|
27320
|
+
error2.candidateSessionId ?? sessionId
|
|
27321
|
+
) === "conflict") {
|
|
27322
|
+
throw new SessionConflictError(sessionId);
|
|
27323
|
+
}
|
|
27324
|
+
throw error2;
|
|
27325
|
+
}
|
|
26055
27326
|
const session = await archiveCoordinator.runSharedMany(
|
|
26056
27327
|
[sessionId],
|
|
26057
27328
|
async () => {
|
|
27329
|
+
const sessionService = createWorkspaceRuntimeSessionService(runtime);
|
|
27330
|
+
let persistedSessionId;
|
|
27331
|
+
try {
|
|
27332
|
+
persistedSessionId = await sessionService.findSessionIdIgnoringCase(sessionId);
|
|
27333
|
+
} catch (error2) {
|
|
27334
|
+
if (error2 instanceof SessionIdCaseConflictError && await sessionService.getSessionLocation(
|
|
27335
|
+
error2.candidateSessionId ?? sessionId
|
|
27336
|
+
) === "conflict") {
|
|
27337
|
+
throw new SessionConflictError(sessionId);
|
|
27338
|
+
}
|
|
27339
|
+
throw error2;
|
|
27340
|
+
}
|
|
27341
|
+
if (persistedSessionId) {
|
|
27342
|
+
restoredStorageSessionId = persistedSessionId;
|
|
27343
|
+
} else if (isInternalWorkspaceRuntime(runtime)) {
|
|
27344
|
+
throw new SessionNotFoundError(sessionId);
|
|
27345
|
+
}
|
|
26058
27346
|
const location = await assertSessionLoadable(
|
|
26059
27347
|
workspaceCwd,
|
|
26060
|
-
|
|
27348
|
+
restoredStorageSessionId,
|
|
26061
27349
|
runtime.sessionRuntimeBaseDir
|
|
26062
27350
|
);
|
|
26063
27351
|
if (location === void 0 && isInternalWorkspaceRuntime(runtime)) {
|
|
26064
27352
|
throw new SessionNotFoundError(sessionId);
|
|
26065
27353
|
}
|
|
26066
|
-
const sessionService = createWorkspaceRuntimeSessionService(runtime);
|
|
26067
27354
|
const metadata = runtime.provenance === "live-conversation" ? await readLoadableLiveConversationMetadata(
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
) : await sessionService.readCreationMetadata(
|
|
26071
|
-
|
|
27355
|
+
restoredStorageSessionId,
|
|
27356
|
+
sessionService
|
|
27357
|
+
) : await sessionService.readCreationMetadata(
|
|
27358
|
+
restoredStorageSessionId
|
|
27359
|
+
);
|
|
27360
|
+
if (metadata === void 0 || isInternalWorkspaceRuntime(runtime) && isReservedStandaloneSessionSource(metadata)) {
|
|
26072
27361
|
throw new SessionNotFoundError(sessionId);
|
|
26073
27362
|
}
|
|
26074
27363
|
assertRuntimeGenerationOpen?.();
|
|
@@ -26160,7 +27449,19 @@ function registerSessionRoutes(app, deps) {
|
|
|
26160
27449
|
throw error2;
|
|
26161
27450
|
}
|
|
26162
27451
|
}
|
|
26163
|
-
|
|
27452
|
+
if (action === "load" && !restored.attached && !restored.hasActivePrompt && runtime.provenance !== "live-conversation") {
|
|
27453
|
+
try {
|
|
27454
|
+
await reconcileDanglingPromptTerminals(
|
|
27455
|
+
sessionService,
|
|
27456
|
+
sessionId
|
|
27457
|
+
);
|
|
27458
|
+
} catch {
|
|
27459
|
+
}
|
|
27460
|
+
}
|
|
27461
|
+
return withPromptTerminals(
|
|
27462
|
+
restored,
|
|
27463
|
+
action === "load" ? readRecentPromptTerminals(sessionService, sessionId) : void 0
|
|
27464
|
+
);
|
|
26164
27465
|
}
|
|
26165
27466
|
);
|
|
26166
27467
|
try {
|
|
@@ -26195,7 +27496,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
26195
27496
|
const sidecar = await readWorktreeSession(
|
|
26196
27497
|
createWorkspaceRuntimeSessionService(
|
|
26197
27498
|
runtime
|
|
26198
|
-
).getWorktreeSessionPath(
|
|
27499
|
+
).getWorktreeSessionPath(restoredStorageSessionId)
|
|
26199
27500
|
).catch(() => null);
|
|
26200
27501
|
if (sidecar) {
|
|
26201
27502
|
let realTarget;
|
|
@@ -26459,8 +27760,10 @@ function registerSessionRoutes(app, deps) {
|
|
|
26459
27760
|
if (!result.attached) {
|
|
26460
27761
|
const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
|
|
26461
27762
|
if (killed) {
|
|
26462
|
-
await createWorkspaceRuntimeSessionService(
|
|
26463
|
-
|
|
27763
|
+
const removed = await createWorkspaceRuntimeSessionService(
|
|
27764
|
+
runtime
|
|
27765
|
+
).removeSession(result.sessionId).catch(() => false);
|
|
27766
|
+
if (removed) runtime.bridge.markSessionCatalogChanged();
|
|
26464
27767
|
}
|
|
26465
27768
|
} else {
|
|
26466
27769
|
await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
|
|
@@ -26470,11 +27773,12 @@ function registerSessionRoutes(app, deps) {
|
|
|
26470
27773
|
}
|
|
26471
27774
|
if (!res.writable) {
|
|
26472
27775
|
if (!result.attached) {
|
|
26473
|
-
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
|
|
26474
|
-
if (!killed) return
|
|
26475
|
-
|
|
27776
|
+
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then(async (killed) => {
|
|
27777
|
+
if (!killed) return;
|
|
27778
|
+
const removed = await createWorkspaceRuntimeSessionService(
|
|
26476
27779
|
runtime
|
|
26477
27780
|
).removeSession(result.sessionId);
|
|
27781
|
+
if (removed) runtime.bridge.markSessionCatalogChanged();
|
|
26478
27782
|
}).catch(() => {
|
|
26479
27783
|
});
|
|
26480
27784
|
} else {
|
|
@@ -27027,6 +28331,42 @@ function registerSessionRoutes(app, deps) {
|
|
|
27027
28331
|
}
|
|
27028
28332
|
)
|
|
27029
28333
|
);
|
|
28334
|
+
app.post(
|
|
28335
|
+
"/session/:id/goal",
|
|
28336
|
+
mutate({ strict: true }),
|
|
28337
|
+
withOwnerMutableSession(
|
|
28338
|
+
"POST /session/:id/goal",
|
|
28339
|
+
async (req, res, sessionId, runtime) => {
|
|
28340
|
+
const request2 = parseGoalControlRequest(safeBody(req));
|
|
28341
|
+
if (!request2) {
|
|
28342
|
+
res.status(400).json({
|
|
28343
|
+
error: "Invalid Goal control request",
|
|
28344
|
+
code: "invalid_goal_control_request"
|
|
28345
|
+
});
|
|
28346
|
+
return;
|
|
28347
|
+
}
|
|
28348
|
+
const clientId = parseClientIdHeader(req, res);
|
|
28349
|
+
if (clientId === null) return;
|
|
28350
|
+
res.status(200).json(
|
|
28351
|
+
await runtime.bridge.controlSessionGoal(
|
|
28352
|
+
sessionId,
|
|
28353
|
+
request2,
|
|
28354
|
+
clientId === void 0 ? void 0 : { clientId }
|
|
28355
|
+
)
|
|
28356
|
+
);
|
|
28357
|
+
}
|
|
28358
|
+
)
|
|
28359
|
+
);
|
|
28360
|
+
app.get(
|
|
28361
|
+
"/session/:id/goal",
|
|
28362
|
+
withOwnerReadSession(
|
|
28363
|
+
"GET /session/:id/goal",
|
|
28364
|
+
async (_req, res, sessionId, runtime) => {
|
|
28365
|
+
const goal = await runtime.bridge.getSessionGoal(sessionId);
|
|
28366
|
+
res.status(200).json({ snapshot: goal.snapshot });
|
|
28367
|
+
}
|
|
28368
|
+
)
|
|
28369
|
+
);
|
|
27030
28370
|
app.post(
|
|
27031
28371
|
"/session/:id/goal/clear",
|
|
27032
28372
|
mutate({ strict: true }),
|
|
@@ -27061,6 +28401,115 @@ function registerSessionRoutes(app, deps) {
|
|
|
27061
28401
|
}
|
|
27062
28402
|
)
|
|
27063
28403
|
);
|
|
28404
|
+
app.post(
|
|
28405
|
+
"/session/:id/attachments",
|
|
28406
|
+
mutate(),
|
|
28407
|
+
import_express4.default.raw({ type: "*/*", limit: "8mb" }),
|
|
28408
|
+
(error2, _req, res, next) => {
|
|
28409
|
+
if (error2 && typeof error2 === "object" && "status" in error2 && error2.status === 413) {
|
|
28410
|
+
res.status(413).json({ error: "Request body too large (max 8 MiB)" });
|
|
28411
|
+
return;
|
|
28412
|
+
}
|
|
28413
|
+
next(error2);
|
|
28414
|
+
},
|
|
28415
|
+
withOwnerMutableSession(
|
|
28416
|
+
"POST /session/:id/attachments",
|
|
28417
|
+
async (req, res, sessionId, runtime) => {
|
|
28418
|
+
const name = req.query["name"];
|
|
28419
|
+
const contentType = req.headers["content-type"]?.split(";", 1)[0]?.trim().toLowerCase();
|
|
28420
|
+
if (typeof name !== "string" || !contentType || !Buffer.isBuffer(req.body)) {
|
|
28421
|
+
res.status(400).json({
|
|
28422
|
+
error: "request body, Content-Type, and name query parameter are required"
|
|
28423
|
+
});
|
|
28424
|
+
return;
|
|
28425
|
+
}
|
|
28426
|
+
const clientId = parseClientIdHeader(req, res);
|
|
28427
|
+
if (clientId === null) return;
|
|
28428
|
+
if (req.body.length === 0 && [
|
|
28429
|
+
"image/bmp",
|
|
28430
|
+
"image/gif",
|
|
28431
|
+
"image/jpeg",
|
|
28432
|
+
"image/png",
|
|
28433
|
+
"image/webp"
|
|
28434
|
+
].includes(contentType)) {
|
|
28435
|
+
res.status(400).json({ error: "Image attachments cannot be empty" });
|
|
28436
|
+
return;
|
|
28437
|
+
}
|
|
28438
|
+
try {
|
|
28439
|
+
const reference = await runtime.bridge.storeSessionAttachment(
|
|
28440
|
+
sessionId,
|
|
28441
|
+
req.body,
|
|
28442
|
+
contentType,
|
|
28443
|
+
clientId !== void 0 ? { clientId } : void 0,
|
|
28444
|
+
name
|
|
28445
|
+
);
|
|
28446
|
+
res.status(201).json(reference);
|
|
28447
|
+
} catch (error2) {
|
|
28448
|
+
if (error2 instanceof RangeError) {
|
|
28449
|
+
res.status(413).json({ error: error2.message });
|
|
28450
|
+
return;
|
|
28451
|
+
}
|
|
28452
|
+
if (error2 instanceof TypeError) {
|
|
28453
|
+
res.status(400).json({ error: error2.message });
|
|
28454
|
+
return;
|
|
28455
|
+
}
|
|
28456
|
+
throw error2;
|
|
28457
|
+
}
|
|
28458
|
+
}
|
|
28459
|
+
)
|
|
28460
|
+
);
|
|
28461
|
+
app.get(
|
|
28462
|
+
"/session/:id/attachments/:attachmentId",
|
|
28463
|
+
withOwnerReadSession(
|
|
28464
|
+
"GET /session/:id/attachments/:attachmentId",
|
|
28465
|
+
async (req, res, sessionId, runtime) => {
|
|
28466
|
+
const attachmentId = req.params["attachmentId"];
|
|
28467
|
+
if (!attachmentId) {
|
|
28468
|
+
res.status(400).json({ error: "`attachmentId` is required" });
|
|
28469
|
+
return;
|
|
28470
|
+
}
|
|
28471
|
+
const clientId = parseClientIdHeader(req, res);
|
|
28472
|
+
if (clientId === null) return;
|
|
28473
|
+
const attachment = await runtime.bridge.readSessionAttachment(
|
|
28474
|
+
sessionId,
|
|
28475
|
+
attachmentId,
|
|
28476
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
28477
|
+
);
|
|
28478
|
+
if (!attachment) {
|
|
28479
|
+
res.status(404).json({ error: "session attachment not found" });
|
|
28480
|
+
return;
|
|
28481
|
+
}
|
|
28482
|
+
res.setHeader("Content-Type", attachment.mimeType);
|
|
28483
|
+
res.setHeader("Content-Length", String(attachment.data.byteLength));
|
|
28484
|
+
res.setHeader("Cache-Control", "private, max-age=300");
|
|
28485
|
+
res.setHeader("Content-Disposition", "attachment");
|
|
28486
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
28487
|
+
res.status(200).send(attachment.data);
|
|
28488
|
+
}
|
|
28489
|
+
)
|
|
28490
|
+
);
|
|
28491
|
+
app.delete(
|
|
28492
|
+
"/session/:id/attachments/:attachmentId",
|
|
28493
|
+
mutate(),
|
|
28494
|
+
withOwnerMutableSession(
|
|
28495
|
+
"DELETE /session/:id/attachments/:attachmentId",
|
|
28496
|
+
async (req, res, sessionId, runtime) => {
|
|
28497
|
+
const attachmentId = req.params["attachmentId"];
|
|
28498
|
+
if (!attachmentId) {
|
|
28499
|
+
res.status(400).json({ error: "`attachmentId` is required" });
|
|
28500
|
+
return;
|
|
28501
|
+
}
|
|
28502
|
+
const clientId = parseClientIdHeader(req, res);
|
|
28503
|
+
if (clientId === null) return;
|
|
28504
|
+
const removed = await runtime.bridge.removeSessionAttachment(
|
|
28505
|
+
sessionId,
|
|
28506
|
+
attachmentId,
|
|
28507
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
28508
|
+
);
|
|
28509
|
+
res.status(200).json({ removed });
|
|
28510
|
+
}
|
|
28511
|
+
)
|
|
28512
|
+
);
|
|
27064
28513
|
app.post(
|
|
27065
28514
|
"/session/:id/prompt",
|
|
27066
28515
|
mutate(),
|
|
@@ -27084,6 +28533,25 @@ function registerSessionRoutes(app, deps) {
|
|
|
27084
28533
|
});
|
|
27085
28534
|
return;
|
|
27086
28535
|
}
|
|
28536
|
+
const mediaBlockCount = prompt.filter(
|
|
28537
|
+
(item) => item["type"] !== "text"
|
|
28538
|
+
).length;
|
|
28539
|
+
if (mediaBlockCount > MEDIA_CONTENT_MAX_BLOCKS) {
|
|
28540
|
+
res.status(400).json({
|
|
28541
|
+
error: `\`prompt\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
|
|
28542
|
+
});
|
|
28543
|
+
return;
|
|
28544
|
+
}
|
|
28545
|
+
for (const item of prompt) {
|
|
28546
|
+
if (item["type"] !== "image") continue;
|
|
28547
|
+
const parsed = parseMediaContentBlock(item);
|
|
28548
|
+
if (!parsed.valid) {
|
|
28549
|
+
res.status(400).json({
|
|
28550
|
+
error: mediaBlockParseError(parsed.code, "`prompt` image block")
|
|
28551
|
+
});
|
|
28552
|
+
return;
|
|
28553
|
+
}
|
|
28554
|
+
}
|
|
27087
28555
|
const rawRequestDeadline = body["deadlineMs"];
|
|
27088
28556
|
let requestDeadlineMs;
|
|
27089
28557
|
if (rawRequestDeadline !== void 0 && rawRequestDeadline !== null) {
|
|
@@ -27638,6 +29106,113 @@ function registerSessionRoutes(app, deps) {
|
|
|
27638
29106
|
}
|
|
27639
29107
|
)
|
|
27640
29108
|
);
|
|
29109
|
+
app.patch(
|
|
29110
|
+
"/workspaces/:workspace/session/:id/metadata",
|
|
29111
|
+
mutate({ strict: true }),
|
|
29112
|
+
async (req, res) => {
|
|
29113
|
+
const route = "PATCH /workspaces/:workspace/session/:id/metadata";
|
|
29114
|
+
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
29115
|
+
if (!runtime) return;
|
|
29116
|
+
const sessionId = requireSessionId(req, res);
|
|
29117
|
+
if (sessionId === null) return;
|
|
29118
|
+
const clientId = parseClientIdHeader(req, res);
|
|
29119
|
+
if (clientId === null) return;
|
|
29120
|
+
const rawDisplayName = safeBody(req)["displayName"];
|
|
29121
|
+
if (typeof rawDisplayName !== "string") {
|
|
29122
|
+
res.status(400).json({
|
|
29123
|
+
error: "`displayName` must be a string",
|
|
29124
|
+
code: "invalid_metadata",
|
|
29125
|
+
field: "displayName"
|
|
29126
|
+
});
|
|
29127
|
+
return;
|
|
29128
|
+
}
|
|
29129
|
+
try {
|
|
29130
|
+
const displayName = rawDisplayName.slice(0, 256);
|
|
29131
|
+
if (displayName.trim() === "") {
|
|
29132
|
+
throw new InvalidSessionMetadataError(
|
|
29133
|
+
"displayName",
|
|
29134
|
+
"must not be empty"
|
|
29135
|
+
);
|
|
29136
|
+
}
|
|
29137
|
+
if (Array.from(displayName).some((character) => {
|
|
29138
|
+
const code = character.charCodeAt(0);
|
|
29139
|
+
return code <= 31 || code === 127;
|
|
29140
|
+
})) {
|
|
29141
|
+
throw new InvalidSessionMetadataError(
|
|
29142
|
+
"displayName",
|
|
29143
|
+
"must not contain control characters"
|
|
29144
|
+
);
|
|
29145
|
+
}
|
|
29146
|
+
await archiveCoordinator.runExclusiveMany([sessionId], async () => {
|
|
29147
|
+
const assertRuntimeGenerationOpen = captureRuntimeGenerationAssertion(runtime);
|
|
29148
|
+
assertRuntimeGenerationOpen?.();
|
|
29149
|
+
const liveOwner = workspaceRegistry.resolveLiveSessionOwner(sessionId);
|
|
29150
|
+
if (liveOwner.kind === "unavailable") {
|
|
29151
|
+
sendWorkspaceRuntimeUnavailable(res);
|
|
29152
|
+
return;
|
|
29153
|
+
}
|
|
29154
|
+
if (liveOwner.kind === "ambiguous") {
|
|
29155
|
+
sendAmbiguousSessionOwner(
|
|
29156
|
+
res,
|
|
29157
|
+
route,
|
|
29158
|
+
sessionId,
|
|
29159
|
+
liveOwner.runtimes
|
|
29160
|
+
);
|
|
29161
|
+
return;
|
|
29162
|
+
}
|
|
29163
|
+
if (liveOwner.kind === "found" && liveOwner.runtime.workspaceCwd !== runtime.workspaceCwd) {
|
|
29164
|
+
sendSessionWorkspaceConflict(
|
|
29165
|
+
res,
|
|
29166
|
+
route,
|
|
29167
|
+
sessionId,
|
|
29168
|
+
runtime,
|
|
29169
|
+
liveOwner.runtime
|
|
29170
|
+
);
|
|
29171
|
+
return;
|
|
29172
|
+
}
|
|
29173
|
+
await runWithWorkspaceRuntimeStorage(runtime, async () => {
|
|
29174
|
+
let effective;
|
|
29175
|
+
try {
|
|
29176
|
+
effective = runtime.bridge.updateSessionMetadata(
|
|
29177
|
+
sessionId,
|
|
29178
|
+
{ displayName },
|
|
29179
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
29180
|
+
);
|
|
29181
|
+
assertRuntimeGenerationOpen?.();
|
|
29182
|
+
} catch (err) {
|
|
29183
|
+
if (!(err instanceof SessionNotFoundError)) throw err;
|
|
29184
|
+
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
29185
|
+
const location = await service.getSessionLocation(sessionId);
|
|
29186
|
+
assertRuntimeGenerationOpen?.();
|
|
29187
|
+
if (location === "conflict") {
|
|
29188
|
+
throw new SessionConflictError(sessionId);
|
|
29189
|
+
}
|
|
29190
|
+
const renamed = location ? await service.renameSession(
|
|
29191
|
+
sessionId,
|
|
29192
|
+
displayName,
|
|
29193
|
+
"manual",
|
|
29194
|
+
location
|
|
29195
|
+
) : false;
|
|
29196
|
+
assertRuntimeGenerationOpen?.();
|
|
29197
|
+
if (!renamed) {
|
|
29198
|
+
throw new SessionNotFoundError(sessionId);
|
|
29199
|
+
}
|
|
29200
|
+
runtime.bridge.markSessionCatalogChanged();
|
|
29201
|
+
effective = { displayName: displayName || void 0 };
|
|
29202
|
+
}
|
|
29203
|
+
invalidateSessionLists(runtime, ["active", "archived"]);
|
|
29204
|
+
res.status(200).json({ sessionId, ...effective });
|
|
29205
|
+
});
|
|
29206
|
+
});
|
|
29207
|
+
} catch (err) {
|
|
29208
|
+
sendBridgeError2(res, err, {
|
|
29209
|
+
route,
|
|
29210
|
+
sessionId,
|
|
29211
|
+
workspaceCwd: runtime.workspaceCwd
|
|
29212
|
+
});
|
|
29213
|
+
}
|
|
29214
|
+
}
|
|
29215
|
+
);
|
|
27641
29216
|
const handleSessionOrganizationUpdate = /* @__PURE__ */ __name(async (req, res, target) => {
|
|
27642
29217
|
const sessionId = requireSessionId(req, res);
|
|
27643
29218
|
if (sessionId === null) return;
|
|
@@ -27705,6 +29280,10 @@ function registerSessionRoutes(app, deps) {
|
|
|
27705
29280
|
...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
|
|
27706
29281
|
...rawColor !== void 0 ? { color: rawColor } : {}
|
|
27707
29282
|
});
|
|
29283
|
+
invalidateSessionListsAndMarkCatalog(runtime, [
|
|
29284
|
+
"active",
|
|
29285
|
+
"archived"
|
|
29286
|
+
]);
|
|
27708
29287
|
res.status(200).json({ sessionId, ...organization });
|
|
27709
29288
|
});
|
|
27710
29289
|
})()
|
|
@@ -27767,6 +29346,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27767
29346
|
color: body["color"]
|
|
27768
29347
|
})
|
|
27769
29348
|
);
|
|
29349
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27770
29350
|
res.status(201).json({ group });
|
|
27771
29351
|
} catch (err) {
|
|
27772
29352
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27794,6 +29374,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27794
29374
|
}
|
|
27795
29375
|
)
|
|
27796
29376
|
);
|
|
29377
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27797
29378
|
res.status(200).json({ group });
|
|
27798
29379
|
} catch (err) {
|
|
27799
29380
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27816,6 +29397,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
27816
29397
|
req.params["groupId"] ?? ""
|
|
27817
29398
|
)
|
|
27818
29399
|
);
|
|
29400
|
+
if (deleted) {
|
|
29401
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
29402
|
+
}
|
|
27819
29403
|
res.status(200).json({ deleted });
|
|
27820
29404
|
} catch (err) {
|
|
27821
29405
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27856,6 +29440,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27856
29440
|
color: body["color"]
|
|
27857
29441
|
})
|
|
27858
29442
|
);
|
|
29443
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27859
29444
|
res.status(201).json({ group });
|
|
27860
29445
|
} catch (err) {
|
|
27861
29446
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27883,6 +29468,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
27883
29468
|
}
|
|
27884
29469
|
)
|
|
27885
29470
|
);
|
|
29471
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
27886
29472
|
res.status(200).json({ group });
|
|
27887
29473
|
} catch (err) {
|
|
27888
29474
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -27904,6 +29490,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
27904
29490
|
req.params["groupId"] ?? ""
|
|
27905
29491
|
)
|
|
27906
29492
|
);
|
|
29493
|
+
if (deleted) {
|
|
29494
|
+
invalidateSessionListsAndMarkCatalog(runtime, ["active", "archived"]);
|
|
29495
|
+
}
|
|
27907
29496
|
res.status(200).json({ deleted });
|
|
27908
29497
|
} catch (err) {
|
|
27909
29498
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -28089,6 +29678,39 @@ function registerSessionRoutes(app, deps) {
|
|
|
28089
29678
|
"/workspaces/:workspace/sessions",
|
|
28090
29679
|
listWorkspaceSessionsHandler("workspace")
|
|
28091
29680
|
);
|
|
29681
|
+
const lastExposedCatalogVersions = /* @__PURE__ */ new WeakMap();
|
|
29682
|
+
app.get("/workspaces/:workspace/sessions/live-state", async (req, res) => {
|
|
29683
|
+
const route = "GET /workspaces/:workspace/sessions/live-state";
|
|
29684
|
+
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
29685
|
+
if (runtime === null) return;
|
|
29686
|
+
const assertRuntimeOpen = captureRuntimeGenerationAssertion(runtime);
|
|
29687
|
+
const bridge = runtime.bridge;
|
|
29688
|
+
try {
|
|
29689
|
+
assertRuntimeOpen?.();
|
|
29690
|
+
const catalogVersion = bridge.getSessionCatalogVersion();
|
|
29691
|
+
const lastExposed = lastExposedCatalogVersions.get(bridge);
|
|
29692
|
+
if (lastExposed === void 0 || lastExposed.generation !== catalogVersion.generation || lastExposed.revision !== catalogVersion.revision) {
|
|
29693
|
+
invalidateSessionLists(runtime, ["active", "archived"]);
|
|
29694
|
+
}
|
|
29695
|
+
const sessions = bridge.listWorkspaceSessions(runtime.workspaceCwd).map((session) => ({
|
|
29696
|
+
sessionId: session.sessionId,
|
|
29697
|
+
clientCount: session.clientCount,
|
|
29698
|
+
hasActivePrompt: session.hasActivePrompt,
|
|
29699
|
+
isWaitingForPermission: session.isWaitingForPermission ?? false,
|
|
29700
|
+
isWaitingForUserQuestion: session.isWaitingForUserQuestion ?? false,
|
|
29701
|
+
// Bridge-local activity watermark, absent until a running prompt in
|
|
29702
|
+
// this bridge publishes its first terminal. Reading it costs nothing
|
|
29703
|
+
// extra: the summary is already in memory.
|
|
29704
|
+
...session.updatedAt !== void 0 ? { updatedAt: session.updatedAt } : {}
|
|
29705
|
+
}));
|
|
29706
|
+
assertRuntimeOpen?.();
|
|
29707
|
+
lastExposedCatalogVersions.set(bridge, catalogVersion);
|
|
29708
|
+
res.setHeader("Cache-Control", "no-store");
|
|
29709
|
+
res.status(200).json({ v: 1, catalogVersion, sessions });
|
|
29710
|
+
} catch (err) {
|
|
29711
|
+
sendBridgeError2(res, err, { route });
|
|
29712
|
+
}
|
|
29713
|
+
});
|
|
28092
29714
|
const workspaceSessionInfoHandler = /* @__PURE__ */ __name((paramName) => async (req, res) => {
|
|
28093
29715
|
const route = paramName === "workspace" ? "GET /workspaces/:workspace/session-info" : "GET /workspace/:id/session-info";
|
|
28094
29716
|
const runtime = resolveRuntimeForCatalogRoute(req, res, paramName, route);
|
|
@@ -28257,9 +29879,36 @@ function registerSessionRoutes(app, deps) {
|
|
|
28257
29879
|
const message = body["message"];
|
|
28258
29880
|
const messageId = body["messageId"];
|
|
28259
29881
|
const trimmed = typeof message === "string" ? message.trim() : "";
|
|
28260
|
-
|
|
29882
|
+
const rawContent = body["content"];
|
|
29883
|
+
let mediaBlocks;
|
|
29884
|
+
if (rawContent !== void 0) {
|
|
29885
|
+
if (!Array.isArray(rawContent) || rawContent.length === 0) {
|
|
29886
|
+
res.status(400).json({
|
|
29887
|
+
error: "`content` must be a non-empty array of media blocks"
|
|
29888
|
+
});
|
|
29889
|
+
return;
|
|
29890
|
+
}
|
|
29891
|
+
if (rawContent.length > MEDIA_CONTENT_MAX_BLOCKS) {
|
|
29892
|
+
res.status(400).json({
|
|
29893
|
+
error: `\`content\` must carry at most ${MEDIA_CONTENT_MAX_BLOCKS} media blocks`
|
|
29894
|
+
});
|
|
29895
|
+
return;
|
|
29896
|
+
}
|
|
29897
|
+
mediaBlocks = [];
|
|
29898
|
+
for (const block of rawContent) {
|
|
29899
|
+
const parsed = parseMediaContentBlock(block);
|
|
29900
|
+
if (!parsed.valid) {
|
|
29901
|
+
res.status(400).json({
|
|
29902
|
+
error: mediaBlockParseError(parsed.code, "`content` entry")
|
|
29903
|
+
});
|
|
29904
|
+
return;
|
|
29905
|
+
}
|
|
29906
|
+
mediaBlocks.push(parsed.block);
|
|
29907
|
+
}
|
|
29908
|
+
}
|
|
29909
|
+
if (trimmed.length === 0 && mediaBlocks === void 0) {
|
|
28261
29910
|
res.status(400).json({
|
|
28262
|
-
error: "`message`
|
|
29911
|
+
error: "`message` must be a non-empty string, or `content` must carry at least one media block"
|
|
28263
29912
|
});
|
|
28264
29913
|
return;
|
|
28265
29914
|
}
|
|
@@ -28281,7 +29930,11 @@ function registerSessionRoutes(app, deps) {
|
|
|
28281
29930
|
sessionId,
|
|
28282
29931
|
trimmed,
|
|
28283
29932
|
clientId !== void 0 ? { clientId } : void 0,
|
|
28284
|
-
typeof messageId === "string" ? messageId : void 0
|
|
29933
|
+
typeof messageId === "string" ? messageId : void 0,
|
|
29934
|
+
{
|
|
29935
|
+
rejectIfIdle: true,
|
|
29936
|
+
...mediaBlocks ? { content: mediaBlocks } : {}
|
|
29937
|
+
}
|
|
28285
29938
|
);
|
|
28286
29939
|
res.status(200).json(result);
|
|
28287
29940
|
}
|
|
@@ -28373,6 +30026,73 @@ function registerSessionRoutes(app, deps) {
|
|
|
28373
30026
|
}
|
|
28374
30027
|
)
|
|
28375
30028
|
);
|
|
30029
|
+
app.get("/session/:id/turns/current", (req, res) => {
|
|
30030
|
+
const sessionId = requireSessionId(req, res);
|
|
30031
|
+
if (sessionId === null) return;
|
|
30032
|
+
const runtime = resolveLiveSessionRuntime(
|
|
30033
|
+
sessionId,
|
|
30034
|
+
res,
|
|
30035
|
+
"GET /session/:id/turns/current"
|
|
30036
|
+
);
|
|
30037
|
+
if (!runtime) return;
|
|
30038
|
+
const clientId = parseClientIdHeader(req, res);
|
|
30039
|
+
if (clientId === null) return;
|
|
30040
|
+
void (async () => {
|
|
30041
|
+
try {
|
|
30042
|
+
const status = await runtime.bridge.getSessionTurnStatus(
|
|
30043
|
+
sessionId,
|
|
30044
|
+
clientId !== void 0 ? { clientId } : void 0
|
|
30045
|
+
);
|
|
30046
|
+
res.status(200).json(status);
|
|
30047
|
+
} catch (err) {
|
|
30048
|
+
sendBridgeError2(res, err, {
|
|
30049
|
+
route: "GET /session/:id/turns/current",
|
|
30050
|
+
sessionId
|
|
30051
|
+
});
|
|
30052
|
+
}
|
|
30053
|
+
})();
|
|
30054
|
+
});
|
|
30055
|
+
app.get("/session/:id/turns/:promptId", (req, res) => {
|
|
30056
|
+
const sessionId = requireSessionId(req, res);
|
|
30057
|
+
if (sessionId === null) return;
|
|
30058
|
+
const runtime = resolveLiveSessionRuntime(
|
|
30059
|
+
sessionId,
|
|
30060
|
+
res,
|
|
30061
|
+
"GET /session/:id/turns/:promptId"
|
|
30062
|
+
);
|
|
30063
|
+
if (!runtime) return;
|
|
30064
|
+
const promptId = req.params["promptId"];
|
|
30065
|
+
if (!promptId) {
|
|
30066
|
+
res.status(400).json({ error: "`promptId` route parameter is required" });
|
|
30067
|
+
return;
|
|
30068
|
+
}
|
|
30069
|
+
const clientId = parseClientIdHeader(req, res);
|
|
30070
|
+
if (clientId === null) return;
|
|
30071
|
+
void (async () => {
|
|
30072
|
+
try {
|
|
30073
|
+
const status = await runtime.bridge.getSessionTurnStatus(
|
|
30074
|
+
sessionId,
|
|
30075
|
+
clientId !== void 0 ? { clientId } : void 0,
|
|
30076
|
+
promptId
|
|
30077
|
+
);
|
|
30078
|
+
if (!status) {
|
|
30079
|
+
res.status(404).json({
|
|
30080
|
+
error: `Prompt ${promptId} not found in session ${sessionId}`,
|
|
30081
|
+
code: "prompt_not_found",
|
|
30082
|
+
sessionId,
|
|
30083
|
+
promptId
|
|
30084
|
+
});
|
|
30085
|
+
return;
|
|
30086
|
+
}
|
|
30087
|
+
res.status(200).json(status);
|
|
30088
|
+
} catch (err) {
|
|
30089
|
+
sendBridgeError2(res, err, {
|
|
30090
|
+
route: "GET /session/:id/turns/:promptId",
|
|
30091
|
+
sessionId
|
|
30092
|
+
});
|
|
30093
|
+
}
|
|
30094
|
+
})();
|
|
30095
|
+
});
|
|
28376
30096
|
app.post(
|
|
28377
30097
|
"/session/:id/shell",
|
|
28378
30098
|
mutate({ strict: true }),
|
|
@@ -28634,10 +30354,10 @@ async function teardownBoundSession(target, sessionId) {
|
|
|
28634
30354
|
} else if (target.bridge) {
|
|
28635
30355
|
await target.bridge.closeSession(sessionId).catch(() => {
|
|
28636
30356
|
});
|
|
28637
|
-
await new SessionService(target.workspaceCwd, {
|
|
30357
|
+
const removed = await new SessionService(target.workspaceCwd, {
|
|
28638
30358
|
runtimeBaseDir: target.runtimeBaseDir
|
|
28639
|
-
}).removeSession(sessionId).catch(() =>
|
|
28640
|
-
|
|
30359
|
+
}).removeSession(sessionId).catch(() => false);
|
|
30360
|
+
if (removed) target.bridge.markSessionCatalogChanged?.();
|
|
28641
30361
|
}
|
|
28642
30362
|
}
|
|
28643
30363
|
__name(teardownBoundSession, "teardownBoundSession");
|
|
@@ -29523,7 +31243,7 @@ __name(parseNameField, "parseNameField");
|
|
|
29523
31243
|
|
|
29524
31244
|
// packages/cli/src/serve/routes/channel-notify.ts
|
|
29525
31245
|
init_esbuild_shims();
|
|
29526
|
-
import { randomUUID as
|
|
31246
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
29527
31247
|
function sendDeliveryError(res, error2) {
|
|
29528
31248
|
if (!isChannelDeliveryError(error2)) {
|
|
29529
31249
|
res.status(502).json({
|
|
@@ -29544,7 +31264,7 @@ function parseNotifyBody(body) {
|
|
|
29544
31264
|
);
|
|
29545
31265
|
}
|
|
29546
31266
|
return normalizeChannelDelivery(
|
|
29547
|
-
|
|
31267
|
+
randomUUID7(),
|
|
29548
31268
|
parseChannelDelivery(body["delivery"]),
|
|
29549
31269
|
body["text"]
|
|
29550
31270
|
);
|
|
@@ -29649,15 +31369,17 @@ function registerGoalsRoutes(app, deps) {
|
|
|
29649
31369
|
continue;
|
|
29650
31370
|
}
|
|
29651
31371
|
const { session, goal } = outcome.value;
|
|
29652
|
-
|
|
31372
|
+
const record = goal.snapshot.goal;
|
|
31373
|
+
if (!record || record.status === "complete") continue;
|
|
29653
31374
|
goals.push({
|
|
29654
31375
|
sessionId: session.sessionId,
|
|
29655
31376
|
displayName: session.displayName ?? null,
|
|
29656
|
-
condition:
|
|
29657
|
-
iterations:
|
|
29658
|
-
setAt:
|
|
29659
|
-
...
|
|
29660
|
-
hasActivePrompt: session.hasActivePrompt
|
|
31377
|
+
condition: record.objective,
|
|
31378
|
+
iterations: record.turnCount,
|
|
31379
|
+
setAt: record.createdAt,
|
|
31380
|
+
...record.lastReason !== void 0 ? { lastReason: record.lastReason } : {},
|
|
31381
|
+
hasActivePrompt: session.hasActivePrompt,
|
|
31382
|
+
snapshot: goal.snapshot
|
|
29661
31383
|
});
|
|
29662
31384
|
}
|
|
29663
31385
|
if (dropped.length > 0) {
|
|
@@ -29863,9 +31585,10 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
29863
31585
|
const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
|
|
29864
31586
|
const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
|
|
29865
31587
|
await bridge.closeSession(sessionId);
|
|
29866
|
-
await new SessionService(boundWorkspace, {
|
|
31588
|
+
const removed = await new SessionService(boundWorkspace, {
|
|
29867
31589
|
runtimeBaseDir: opts.runtimeBaseDir
|
|
29868
31590
|
}).removeSession(sessionId);
|
|
31591
|
+
if (removed) bridge.markSessionCatalogChanged?.();
|
|
29869
31592
|
});
|
|
29870
31593
|
const reviveState = /* @__PURE__ */ new Map();
|
|
29871
31594
|
const reviving = /* @__PURE__ */ new Set();
|
|
@@ -31443,8 +33166,8 @@ __name(registerWorkspaceQualifiedSettingsRoutes, "registerWorkspaceQualifiedSett
|
|
|
31443
33166
|
|
|
31444
33167
|
// packages/cli/src/serve/routes/sse-events.ts
|
|
31445
33168
|
init_esbuild_shims();
|
|
31446
|
-
import { randomUUID as
|
|
31447
|
-
import { performance as
|
|
33169
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
33170
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
31448
33171
|
|
|
31449
33172
|
// packages/cli/src/serve/server/error-response.ts
|
|
31450
33173
|
init_esbuild_shims();
|
|
@@ -31561,6 +33284,10 @@ function sendBridgeError(res, err, ctx, daemonLog) {
|
|
|
31561
33284
|
return;
|
|
31562
33285
|
}
|
|
31563
33286
|
if (sendGenerationClosedError(res, err)) return;
|
|
33287
|
+
if (err instanceof Error && "code" in err && (err.code === "session_attachment_gone" || err.code === "invalid_session_attachment_reference")) {
|
|
33288
|
+
res.status(err.code === "session_attachment_gone" ? 410 : 400).json({ error: err.message, code: err.code });
|
|
33289
|
+
return;
|
|
33290
|
+
}
|
|
31564
33291
|
if (err instanceof SessionWriterError) {
|
|
31565
33292
|
res.status(err.httpStatus).json({
|
|
31566
33293
|
error: err.message,
|
|
@@ -31725,6 +33452,14 @@ function sendBridgeError(res, err, ctx, daemonLog) {
|
|
|
31725
33452
|
});
|
|
31726
33453
|
return;
|
|
31727
33454
|
}
|
|
33455
|
+
if (err instanceof SessionIdCaseConflictError) {
|
|
33456
|
+
res.status(409).json({
|
|
33457
|
+
error: err.message,
|
|
33458
|
+
code: "session_conflict",
|
|
33459
|
+
sessionId: err.sessionId
|
|
33460
|
+
});
|
|
33461
|
+
return;
|
|
33462
|
+
}
|
|
31728
33463
|
if (err instanceof SessionArchivingError) {
|
|
31729
33464
|
res.set("Retry-After", "5");
|
|
31730
33465
|
res.status(409).json({
|
|
@@ -31886,6 +33621,22 @@ function sendBridgeError(res, err, ctx, daemonLog) {
|
|
|
31886
33621
|
});
|
|
31887
33622
|
return;
|
|
31888
33623
|
}
|
|
33624
|
+
if (kind === "untrusted_workspace") {
|
|
33625
|
+
res.status(403).json({
|
|
33626
|
+
error: errorMessage2(err),
|
|
33627
|
+
code: kind
|
|
33628
|
+
});
|
|
33629
|
+
return;
|
|
33630
|
+
}
|
|
33631
|
+
if (kind === "goal_conflict" || kind === "goal_invalid_transition" || kind === "goal_persist_failed") {
|
|
33632
|
+
const d = data;
|
|
33633
|
+
res.status(kind === "goal_persist_failed" ? 500 : 409).json({
|
|
33634
|
+
error: errorMessage2(err),
|
|
33635
|
+
code: kind,
|
|
33636
|
+
...d.current !== void 0 ? { current: d.current } : {}
|
|
33637
|
+
});
|
|
33638
|
+
return;
|
|
33639
|
+
}
|
|
31889
33640
|
if (kind === "branch_point_invalid") {
|
|
31890
33641
|
res.status(409).json({
|
|
31891
33642
|
error: errorMessage2(err),
|
|
@@ -32132,7 +33883,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32132
33883
|
app.get("/session/:id/events", async (req, res) => {
|
|
32133
33884
|
const sessionId = req.params["id"];
|
|
32134
33885
|
const diagnosticSessionId = boundedDiagnosticString(sessionId);
|
|
32135
|
-
const streamId =
|
|
33886
|
+
const streamId = randomUUID8();
|
|
32136
33887
|
const clientId = parseSseClientId(req.headers["x-qwen-client-id"]);
|
|
32137
33888
|
const connectReason = parseSseConnectReason(req.query["connectReason"]);
|
|
32138
33889
|
const previousStreamId = parsePreviousSseStreamId(
|
|
@@ -32325,7 +34076,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32325
34076
|
});
|
|
32326
34077
|
return;
|
|
32327
34078
|
}
|
|
32328
|
-
const openedAt =
|
|
34079
|
+
const openedAt = performance3.now();
|
|
32329
34080
|
let closeReason;
|
|
32330
34081
|
let terminalCandidate;
|
|
32331
34082
|
let terminalEventType;
|
|
@@ -32344,10 +34095,10 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32344
34095
|
if (activeDrainStartedAt !== void 0) {
|
|
32345
34096
|
maxDrainWaitMs = Math.max(
|
|
32346
34097
|
maxDrainWaitMs,
|
|
32347
|
-
|
|
34098
|
+
performance3.now() - activeDrainStartedAt
|
|
32348
34099
|
);
|
|
32349
34100
|
}
|
|
32350
|
-
const durationMs = Math.max(0,
|
|
34101
|
+
const durationMs = Math.max(0, performance3.now() - openedAt);
|
|
32351
34102
|
const resolvedCloseReason = closeReason ?? terminalCandidate ?? "client_disconnect";
|
|
32352
34103
|
const closeAttributes = {
|
|
32353
34104
|
"qwen-code.daemon.sse.duration_ms": durationMs,
|
|
@@ -32456,7 +34207,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32456
34207
|
if (activeDrainStartedAt === void 0) return;
|
|
32457
34208
|
maxDrainWaitMs = Math.max(
|
|
32458
34209
|
maxDrainWaitMs,
|
|
32459
|
-
|
|
34210
|
+
performance3.now() - activeDrainStartedAt
|
|
32460
34211
|
);
|
|
32461
34212
|
activeDrainStartedAt = void 0;
|
|
32462
34213
|
}, "settleDrainMeasurement");
|
|
@@ -32479,7 +34230,7 @@ function registerSseEventsRoutes(app, deps) {
|
|
|
32479
34230
|
return;
|
|
32480
34231
|
}
|
|
32481
34232
|
backpressureCount += 1;
|
|
32482
|
-
activeDrainStartedAt =
|
|
34233
|
+
activeDrainStartedAt = performance3.now();
|
|
32483
34234
|
const onDrain = /* @__PURE__ */ __name(() => {
|
|
32484
34235
|
res.off("close", onClose);
|
|
32485
34236
|
res.off("error", onError);
|
|
@@ -33154,6 +34905,19 @@ __name(registerA2uiActionRoutes, "registerA2uiActionRoutes");
|
|
|
33154
34905
|
init_esbuild_shims();
|
|
33155
34906
|
import * as path15 from "node:path";
|
|
33156
34907
|
var IDE_WORKSPACE_PATH_ENV_VAR = "QWEN_CODE_IDE_WORKSPACE_PATH";
|
|
34908
|
+
var NEW_FILE_MODE_ENV_VAR = "QWEN_SERVE_NEW_FILE_MODE";
|
|
34909
|
+
function parseNewFileModePolicy(env = process.env) {
|
|
34910
|
+
const raw = env[NEW_FILE_MODE_ENV_VAR];
|
|
34911
|
+
if (raw === void 0 || raw.trim() === "") return "owner";
|
|
34912
|
+
const normalized = raw.trim().toLowerCase();
|
|
34913
|
+
if (normalized === "system") return "system";
|
|
34914
|
+
if (normalized === "owner" || normalized === "0600") return "owner";
|
|
34915
|
+
writeStderrLine(
|
|
34916
|
+
`qwen serve: ignoring invalid ${NEW_FILE_MODE_ENV_VAR}=${raw} (expected 'system' or 'owner'); new files keep the 0600 default`
|
|
34917
|
+
);
|
|
34918
|
+
return "owner";
|
|
34919
|
+
}
|
|
34920
|
+
__name(parseNewFileModePolicy, "parseNewFileModePolicy");
|
|
33157
34921
|
function createDefaultFsAuditEmit() {
|
|
33158
34922
|
const WARN_EVERY = 100;
|
|
33159
34923
|
let droppedCount = 0;
|
|
@@ -33181,6 +34945,7 @@ function resolveBridgeFsFactory(input) {
|
|
|
33181
34945
|
emit: input.emit ?? createDefaultFsAuditEmit(),
|
|
33182
34946
|
pathLocks: input.pathLocks,
|
|
33183
34947
|
generationGuard: input.generationGuard,
|
|
34948
|
+
newFileMode: input.newFileMode ?? parseNewFileModePolicy(),
|
|
33184
34949
|
...input.customIgnoreFiles !== void 0 ? { customIgnoreFiles: input.customIgnoreFiles } : {}
|
|
33185
34950
|
});
|
|
33186
34951
|
}
|
|
@@ -33503,9 +35268,16 @@ __name(setupDeviceFlowRegistry, "setupDeviceFlowRegistry");
|
|
|
33503
35268
|
|
|
33504
35269
|
// packages/cli/src/serve/server/error-handlers.ts
|
|
33505
35270
|
init_esbuild_shims();
|
|
33506
|
-
var
|
|
35271
|
+
var import_express5 = __toESM(require_express(), 1);
|
|
33507
35272
|
function installJsonBodyParser(app) {
|
|
33508
|
-
|
|
35273
|
+
const parseJson = import_express5.default.json({ limit: "10mb" });
|
|
35274
|
+
app.use((req, res, next) => {
|
|
35275
|
+
if (req.method === "POST" && /^\/session\/[^/]+\/attachments\/?$/i.test(req.path)) {
|
|
35276
|
+
next();
|
|
35277
|
+
return;
|
|
35278
|
+
}
|
|
35279
|
+
parseJson(req, res, next);
|
|
35280
|
+
});
|
|
33509
35281
|
app.use((err, _req, res, next) => {
|
|
33510
35282
|
if (sendJsonBodyParserError(res, err)) return;
|
|
33511
35283
|
next(err);
|
|
@@ -38355,8 +40127,8 @@ __name(registerWorkspaceQualifiedSkillsRoutes, "registerWorkspaceQualifiedSkills
|
|
|
38355
40127
|
|
|
38356
40128
|
// packages/cli/src/serve/routes/channel-webhooks.ts
|
|
38357
40129
|
init_esbuild_shims();
|
|
38358
|
-
var
|
|
38359
|
-
import { createHash as
|
|
40130
|
+
var import_express6 = __toESM(require_express(), 1);
|
|
40131
|
+
import { createHash as createHash3, timingSafeEqual } from "node:crypto";
|
|
38360
40132
|
var PROTOTYPE_POLLUTION_KEYS = /* @__PURE__ */ new Set([
|
|
38361
40133
|
"__proto__",
|
|
38362
40134
|
"constructor",
|
|
@@ -38404,7 +40176,7 @@ function registerChannelWebhookRoutes(app, deps) {
|
|
|
38404
40176
|
locals.channelWebhook = { channelName, source, sourceConfig };
|
|
38405
40177
|
next();
|
|
38406
40178
|
},
|
|
38407
|
-
|
|
40179
|
+
import_express6.default.json({ limit: "1mb" }),
|
|
38408
40180
|
async (req, res) => {
|
|
38409
40181
|
const locals = res.locals;
|
|
38410
40182
|
const webhook = locals.channelWebhook;
|
|
@@ -38518,9 +40290,9 @@ function matchesWebhookSecret(candidate, expected) {
|
|
|
38518
40290
|
if (typeof candidate !== "string") {
|
|
38519
40291
|
return false;
|
|
38520
40292
|
}
|
|
38521
|
-
const expectedDigest =
|
|
38522
|
-
const candidateDigest =
|
|
38523
|
-
return
|
|
40293
|
+
const expectedDigest = createHash3("sha256").update(expected).digest();
|
|
40294
|
+
const candidateDigest = createHash3("sha256").update(candidate).digest();
|
|
40295
|
+
return timingSafeEqual(expectedDigest, candidateDigest);
|
|
38524
40296
|
}
|
|
38525
40297
|
__name(matchesWebhookSecret, "matchesWebhookSecret");
|
|
38526
40298
|
function readPayload(body, res) {
|
|
@@ -38599,7 +40371,7 @@ init_esbuild_shims();
|
|
|
38599
40371
|
|
|
38600
40372
|
// packages/cli/src/serve/live/live-host-coordinator.ts
|
|
38601
40373
|
init_esbuild_shims();
|
|
38602
|
-
import { randomUUID as
|
|
40374
|
+
import { randomUUID as randomUUID9, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
38603
40375
|
var DEFAULT_HELLO_TIMEOUT_MS = 5e3;
|
|
38604
40376
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 5e3;
|
|
38605
40377
|
var DEFAULT_HEARTBEAT_TIMEOUT_MS = 15e3;
|
|
@@ -38776,7 +40548,7 @@ __name(projectStatusForHost, "projectStatusForHost");
|
|
|
38776
40548
|
var LiveHostCoordinator = class {
|
|
38777
40549
|
constructor(options) {
|
|
38778
40550
|
this.options = options;
|
|
38779
|
-
this.daemonInstanceNonce = options.daemonInstanceNonce ??
|
|
40551
|
+
this.daemonInstanceNonce = options.daemonInstanceNonce ?? randomUUID9();
|
|
38780
40552
|
this.handlers = options.handlers ?? {};
|
|
38781
40553
|
this.now = options.now ?? Date.now;
|
|
38782
40554
|
this.helloTimeoutMs = options.helloTimeoutMs ?? DEFAULT_HELLO_TIMEOUT_MS;
|
|
@@ -38845,7 +40617,7 @@ var LiveHostCoordinator = class {
|
|
|
38845
40617
|
attachHost(socket, daemonNonce) {
|
|
38846
40618
|
const expectedNonce = Buffer.from(this.daemonInstanceNonce);
|
|
38847
40619
|
const presentedNonce = Buffer.from(daemonNonce ?? "");
|
|
38848
|
-
if (expectedNonce.byteLength !== presentedNonce.byteLength || !
|
|
40620
|
+
if (expectedNonce.byteLength !== presentedNonce.byteLength || !timingSafeEqual2(expectedNonce, presentedNonce)) {
|
|
38849
40621
|
socket.close(4003, "Invalid daemon instance nonce.");
|
|
38850
40622
|
return;
|
|
38851
40623
|
}
|
|
@@ -38968,7 +40740,7 @@ var LiveHostCoordinator = class {
|
|
|
38968
40740
|
startCall(mode) {
|
|
38969
40741
|
const call = {
|
|
38970
40742
|
epoch: ++this.nextEpoch,
|
|
38971
|
-
callId:
|
|
40743
|
+
callId: randomUUID9(),
|
|
38972
40744
|
mode,
|
|
38973
40745
|
state: "starting",
|
|
38974
40746
|
pendingPermission: false,
|
|
@@ -39027,7 +40799,7 @@ var LiveHostCoordinator = class {
|
|
|
39027
40799
|
new Error("Qwen Live Host must be connected to change the shortcut.")
|
|
39028
40800
|
);
|
|
39029
40801
|
}
|
|
39030
|
-
const requestId =
|
|
40802
|
+
const requestId = randomUUID9();
|
|
39031
40803
|
return new Promise((resolve7, reject) => {
|
|
39032
40804
|
const timer = setTimeout(() => {
|
|
39033
40805
|
this.rejectPendingShortcut(
|
|
@@ -39117,7 +40889,7 @@ var LiveHostCoordinator = class {
|
|
|
39117
40889
|
)
|
|
39118
40890
|
);
|
|
39119
40891
|
}
|
|
39120
|
-
const requestId =
|
|
40892
|
+
const requestId = randomUUID9();
|
|
39121
40893
|
return new Promise((resolve7, reject) => {
|
|
39122
40894
|
const timer = setTimeout(() => {
|
|
39123
40895
|
this.pendingAppshots.delete(requestId);
|
|
@@ -39457,7 +41229,7 @@ var LiveHostCoordinator = class {
|
|
|
39457
41229
|
this.disconnectHost(lease, 4008, "Live Host heartbeat timed out.");
|
|
39458
41230
|
return;
|
|
39459
41231
|
}
|
|
39460
|
-
const pingId =
|
|
41232
|
+
const pingId = randomUUID9();
|
|
39461
41233
|
lease.pingId = pingId;
|
|
39462
41234
|
this.sendHost({ type: "host.ping", pingId });
|
|
39463
41235
|
}
|
|
@@ -39725,7 +41497,7 @@ init_esbuild_shims();
|
|
|
39725
41497
|
|
|
39726
41498
|
// packages/cli/src/serve/live/live-setup-controller.ts
|
|
39727
41499
|
init_esbuild_shims();
|
|
39728
|
-
import { randomUUID as
|
|
41500
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
39729
41501
|
|
|
39730
41502
|
// packages/cli/src/serve/live/provider-credentials.ts
|
|
39731
41503
|
init_esbuild_shims();
|
|
@@ -39823,7 +41595,7 @@ __name(resolveLiveProviderCredential, "resolveLiveProviderCredential");
|
|
|
39823
41595
|
|
|
39824
41596
|
// packages/cli/src/serve/live/qwen-realtime-session.ts
|
|
39825
41597
|
init_esbuild_shims();
|
|
39826
|
-
import { randomUUID as
|
|
41598
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
39827
41599
|
var QWEN_REALTIME_LIMITS = {
|
|
39828
41600
|
maxInputAudioFrameBytes: 64 * 1024,
|
|
39829
41601
|
maxOutputAudioFrameBytes: 256 * 1024,
|
|
@@ -40238,7 +42010,7 @@ function openQwenRealtimeSession(config, callbacks = {}, deps = {}) {
|
|
|
40238
42010
|
const sendJson = /* @__PURE__ */ __name((body) => {
|
|
40239
42011
|
if (terminal || closedByClient || ws.readyState !== ws.OPEN) return false;
|
|
40240
42012
|
try {
|
|
40241
|
-
ws.send(JSON.stringify({ event_id:
|
|
42013
|
+
ws.send(JSON.stringify({ event_id: randomUUID10(), ...body }));
|
|
40242
42014
|
return true;
|
|
40243
42015
|
} catch (error2) {
|
|
40244
42016
|
fail(
|
|
@@ -41601,7 +43373,7 @@ async function validateCredential(credential) {
|
|
|
41601
43373
|
apiKey: credential.apiKey,
|
|
41602
43374
|
model: credential.realtimeModel,
|
|
41603
43375
|
voice: credential.voice,
|
|
41604
|
-
callEpoch: `setup-${
|
|
43376
|
+
callEpoch: `setup-${randomUUID11()}`
|
|
41605
43377
|
});
|
|
41606
43378
|
session.close({ discardPendingInput: true });
|
|
41607
43379
|
}
|
|
@@ -41908,7 +43680,7 @@ __name(registerLiveSetupRoutes, "registerLiveSetupRoutes");
|
|
|
41908
43680
|
// packages/cli/src/serve/live/live-host-installer.ts
|
|
41909
43681
|
init_esbuild_shims();
|
|
41910
43682
|
import { execFile as execFile3 } from "node:child_process";
|
|
41911
|
-
import { createHash as
|
|
43683
|
+
import { createHash as createHash4, randomUUID as randomUUID12 } from "node:crypto";
|
|
41912
43684
|
import * as fs7 from "node:fs";
|
|
41913
43685
|
import * as fsp5 from "node:fs/promises";
|
|
41914
43686
|
import * as os2 from "node:os";
|
|
@@ -42083,7 +43855,7 @@ async function downloadAsset(asset, url, destination, onProgress, fetchImpl) {
|
|
|
42083
43855
|
});
|
|
42084
43856
|
throw new Error("Live Host download size does not match its manifest.");
|
|
42085
43857
|
}
|
|
42086
|
-
const hash =
|
|
43858
|
+
const hash = createHash4("sha256");
|
|
42087
43859
|
let received = 0;
|
|
42088
43860
|
const guard = new Transform({
|
|
42089
43861
|
transform(chunk, _encoding, callback) {
|
|
@@ -42139,8 +43911,8 @@ async function installLatestHost(currentArchitecture, onStatus) {
|
|
|
42139
43911
|
const archivePath = path16.join(temporaryDirectory, "Qwen-Live-Host.zip");
|
|
42140
43912
|
const extractedPath = path16.join(temporaryDirectory, "extracted");
|
|
42141
43913
|
const candidatePath = path16.join(extractedPath, LIVE_HOST_APP_NAME);
|
|
42142
|
-
const stagingPath = `/Applications/.Qwen Live Host.install-${
|
|
42143
|
-
const backupPath = `/Applications/.Qwen Live Host.backup-${
|
|
43914
|
+
const stagingPath = `/Applications/.Qwen Live Host.install-${randomUUID12()}.app`;
|
|
43915
|
+
const backupPath = `/Applications/.Qwen Live Host.backup-${randomUUID12()}.app`;
|
|
42144
43916
|
let movedExisting = false;
|
|
42145
43917
|
let installedCandidate = false;
|
|
42146
43918
|
try {
|
|
@@ -42288,7 +44060,7 @@ var LiveHostInstaller = class {
|
|
|
42288
44060
|
|
|
42289
44061
|
// packages/cli/src/serve/live/live-session-coordinator.ts
|
|
42290
44062
|
init_esbuild_shims();
|
|
42291
|
-
import { createHash as
|
|
44063
|
+
import { createHash as createHash5, randomUUID as randomUUID13 } from "node:crypto";
|
|
42292
44064
|
import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
42293
44065
|
import { join as join12 } from "node:path";
|
|
42294
44066
|
|
|
@@ -42663,7 +44435,7 @@ function openLiveAudioCapture(source, identifier) {
|
|
|
42663
44435
|
);
|
|
42664
44436
|
const stream = createWriteStream2(path19, { flags: "wx", mode: 384 });
|
|
42665
44437
|
stream.on("error", () => void 0);
|
|
42666
|
-
return { source, path: path19, stream, hash:
|
|
44438
|
+
return { source, path: path19, stream, hash: createHash5("sha256"), bytes: 0 };
|
|
42667
44439
|
} catch {
|
|
42668
44440
|
return void 0;
|
|
42669
44441
|
}
|
|
@@ -43018,7 +44790,7 @@ var LiveSessionCoordinator = class {
|
|
|
43018
44790
|
context.speechInProgress = true;
|
|
43019
44791
|
context.inputCommitPending = true;
|
|
43020
44792
|
context.inputAwaitingResponse = false;
|
|
43021
|
-
const partialItemId = itemId ?? `partial:${
|
|
44793
|
+
const partialItemId = itemId ?? `partial:${randomUUID13()}`;
|
|
43022
44794
|
context.activePartialInputItemId = partialItemId;
|
|
43023
44795
|
if (!context.partialInputTranscripts.has(partialItemId)) {
|
|
43024
44796
|
context.partialInputTranscripts.set(partialItemId, "");
|
|
@@ -43048,7 +44820,7 @@ var LiveSessionCoordinator = class {
|
|
|
43048
44820
|
}, "onInputCommitted"),
|
|
43049
44821
|
onInputTranscriptDelta: /* @__PURE__ */ __name(({ itemId, text }) => {
|
|
43050
44822
|
if (this.isCurrentSocket(context, generation)) {
|
|
43051
|
-
const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${
|
|
44823
|
+
const partialItemId = itemId ?? context.activePartialInputItemId ?? `partial:${randomUUID13()}`;
|
|
43052
44824
|
context.activePartialInputItemId = partialItemId;
|
|
43053
44825
|
context.partialInputTranscripts.set(partialItemId, text);
|
|
43054
44826
|
this.options.host.setTranscript?.(context.epoch, text);
|
|
@@ -43058,7 +44830,7 @@ var LiveSessionCoordinator = class {
|
|
|
43058
44830
|
if (this.isCurrentSocket(context, generation)) {
|
|
43059
44831
|
context.speechInProgress = false;
|
|
43060
44832
|
context.inputCommitPending = false;
|
|
43061
|
-
const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${
|
|
44833
|
+
const completedItemId = itemId ?? context.activePartialInputItemId ?? `unattributed:${randomUUID13()}`;
|
|
43062
44834
|
context.partialInputTranscripts.delete(completedItemId);
|
|
43063
44835
|
if (context.activePartialInputItemId === completedItemId) {
|
|
43064
44836
|
context.activePartialInputItemId = void 0;
|
|
@@ -43774,9 +45546,10 @@ var LiveSessionCoordinator = class {
|
|
|
43774
45546
|
if (!sessionClosed) return;
|
|
43775
45547
|
if (removeFreshTranscript) {
|
|
43776
45548
|
try {
|
|
43777
|
-
await new SessionService(
|
|
43778
|
-
|
|
43779
|
-
);
|
|
45549
|
+
const transcriptRemoved = await new SessionService(
|
|
45550
|
+
runtime.workspaceCwd
|
|
45551
|
+
).removeSession(session.sessionId);
|
|
45552
|
+
if (transcriptRemoved) bridge.markSessionCatalogChanged();
|
|
43780
45553
|
} catch {
|
|
43781
45554
|
}
|
|
43782
45555
|
}
|
|
@@ -43789,7 +45562,7 @@ var LiveSessionCoordinator = class {
|
|
|
43789
45562
|
const runtime = context.runtime;
|
|
43790
45563
|
if (!runtime) throw new Error("Conversation workspace is unavailable.");
|
|
43791
45564
|
const bridge = runtime.bridge;
|
|
43792
|
-
const promptId =
|
|
45565
|
+
const promptId = randomUUID13();
|
|
43793
45566
|
const lastEventId = bridge.getSessionLastEventId(locator.sessionId);
|
|
43794
45567
|
const turnAbort = new AbortController();
|
|
43795
45568
|
this.inFlightTurnAborts.add(turnAbort);
|
|
@@ -44106,7 +45879,7 @@ var LiveSessionCoordinator = class {
|
|
|
44106
45879
|
|
|
44107
45880
|
// packages/cli/src/serve/live/live-task-service.ts
|
|
44108
45881
|
init_esbuild_shims();
|
|
44109
|
-
import { randomUUID as
|
|
45882
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
44110
45883
|
var DEFAULT_LIST_LIMIT = 20;
|
|
44111
45884
|
var DEFAULT_READ_TURN_LIMIT = 3;
|
|
44112
45885
|
var DEFAULT_WAIT_TIMEOUT_MS = 12e4;
|
|
@@ -44538,7 +46311,10 @@ var LiveTaskService = class {
|
|
|
44538
46311
|
cwd: located.summary.workspaceCwd,
|
|
44539
46312
|
createdAt: epochSeconds(located.summary.createdAt),
|
|
44540
46313
|
updatedAt: epochSeconds(
|
|
44541
|
-
|
|
46314
|
+
laterActivityTimestamp(
|
|
46315
|
+
located.summary.updatedAt,
|
|
46316
|
+
located.persisted?.conversation.lastUpdated
|
|
46317
|
+
)
|
|
44542
46318
|
)
|
|
44543
46319
|
},
|
|
44544
46320
|
page: {
|
|
@@ -44677,7 +46453,10 @@ var LiveTaskService = class {
|
|
|
44677
46453
|
),
|
|
44678
46454
|
eventId: task.runtime.bridge.getSessionLastEventId(target.threadId)
|
|
44679
46455
|
} : {},
|
|
44680
|
-
updatedAt:
|
|
46456
|
+
updatedAt: laterActivityTimestamp(
|
|
46457
|
+
task.summary.updatedAt,
|
|
46458
|
+
task.persisted?.conversation.lastUpdated
|
|
46459
|
+
)
|
|
44681
46460
|
});
|
|
44682
46461
|
const { reset: cursorReset } = decodeCursor(
|
|
44683
46462
|
target.afterCursor,
|
|
@@ -44691,7 +46470,10 @@ var LiveTaskService = class {
|
|
|
44691
46470
|
const completedAt = latestTurnRecords.at(-1)?.timestamp ?? task.persisted?.conversation.lastUpdated;
|
|
44692
46471
|
const failed = task.summary.hasTurnError === true;
|
|
44693
46472
|
const revision = task.summary.clientCount > 0 ? task.runtime.bridge.getSessionLastEventId(target.threadId) : epochSeconds(
|
|
44694
|
-
|
|
46473
|
+
laterActivityTimestamp(
|
|
46474
|
+
task.summary.updatedAt,
|
|
46475
|
+
task.persisted?.conversation.lastUpdated
|
|
46476
|
+
) ?? task.summary.createdAt
|
|
44695
46477
|
);
|
|
44696
46478
|
return {
|
|
44697
46479
|
schemaVersion: 1,
|
|
@@ -44823,7 +46605,7 @@ var LiveTaskService = class {
|
|
|
44823
46605
|
{ sessionId, prompt: [{ type: "text", text: prompt }] },
|
|
44824
46606
|
void 0,
|
|
44825
46607
|
{
|
|
44826
|
-
promptId:
|
|
46608
|
+
promptId: randomUUID14(),
|
|
44827
46609
|
onPromptAdmitted: /* @__PURE__ */ __name(() => {
|
|
44828
46610
|
admitted = true;
|
|
44829
46611
|
onAdmitted?.();
|
|
@@ -44843,7 +46625,7 @@ var LiveTaskService = class {
|
|
|
44843
46625
|
const service = createWorkspaceRuntimeSessionService(task.runtime);
|
|
44844
46626
|
const metadata = task.runtime.provenance === "live-conversation" ? await readLoadableLiveConversationMetadata(
|
|
44845
46627
|
task.summary.sessionId,
|
|
44846
|
-
|
|
46628
|
+
service
|
|
44847
46629
|
) : await service.readCreationMetadata(task.summary.sessionId);
|
|
44848
46630
|
if (metadata === void 0) {
|
|
44849
46631
|
throw new SessionNotFoundError(task.summary.sessionId);
|
|
@@ -44889,10 +46671,11 @@ var LiveTaskService = class {
|
|
|
44889
46671
|
removed = false;
|
|
44890
46672
|
}
|
|
44891
46673
|
if (removed) {
|
|
44892
|
-
await runWithWorkspaceRuntimeStorage(
|
|
46674
|
+
const persistedRemoved = await runWithWorkspaceRuntimeStorage(
|
|
44893
46675
|
runtime,
|
|
44894
|
-
() => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() =>
|
|
46676
|
+
() => createWorkspaceRuntimeSessionService(runtime).removeSession(session.sessionId).catch(() => false)
|
|
44895
46677
|
);
|
|
46678
|
+
if (persistedRemoved) runtime.bridge.markSessionCatalogChanged();
|
|
44896
46679
|
}
|
|
44897
46680
|
if (projectless && removed) {
|
|
44898
46681
|
await this.options.discardEmptyConversationDirectory(session.sessionId).catch(() => void 0);
|
|
@@ -45078,7 +46861,7 @@ var ConversationRuntimeManager = class {
|
|
|
45078
46861
|
|
|
45079
46862
|
// packages/cli/src/serve/conversations/conversation-runtime-ownership.ts
|
|
45080
46863
|
init_esbuild_shims();
|
|
45081
|
-
import { randomUUID as
|
|
46864
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
45082
46865
|
import { constants as fsConstants2 } from "node:fs";
|
|
45083
46866
|
import * as fs8 from "node:fs/promises";
|
|
45084
46867
|
import * as path17 from "node:path";
|
|
@@ -45214,16 +46997,20 @@ async function readOwnerRecord(ownerPath) {
|
|
|
45214
46997
|
process.platform === "win32" ? fsConstants2.O_RDONLY : fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW
|
|
45215
46998
|
);
|
|
45216
46999
|
} catch (error2) {
|
|
45217
|
-
|
|
47000
|
+
if (error2.code === "ELOOP") {
|
|
47001
|
+
throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
|
|
47002
|
+
}
|
|
47003
|
+
throw error2;
|
|
45218
47004
|
}
|
|
45219
47005
|
try {
|
|
45220
47006
|
const handleStat = await handle.stat();
|
|
45221
47007
|
if (!handleStat.isFile() || handleStat.nlink !== 1 || handleStat.dev !== pathStat.dev || handleStat.ino !== pathStat.ino || handleStat.size !== pathStat.size || process.platform !== "win32" && ((handleStat.mode & 511) !== 384 || typeof process.getuid === "function" && handleStat.uid !== process.getuid())) {
|
|
45222
47008
|
throw new UnsafeOwnershipStateError();
|
|
45223
47009
|
}
|
|
47010
|
+
const serialized = await handle.readFile("utf8");
|
|
45224
47011
|
let parsed;
|
|
45225
47012
|
try {
|
|
45226
|
-
parsed = JSON.parse(
|
|
47013
|
+
parsed = JSON.parse(serialized);
|
|
45227
47014
|
} catch (error2) {
|
|
45228
47015
|
throw new UnsafeOwnershipStateError(void 0, { cause: error2 });
|
|
45229
47016
|
}
|
|
@@ -45349,7 +47136,7 @@ var FileConversationRuntimeOwnership = class {
|
|
|
45349
47136
|
await this.commitRecord(identity, void 0);
|
|
45350
47137
|
}
|
|
45351
47138
|
}, "commitOwner");
|
|
45352
|
-
const liveDiscovery = await import("./discovery-
|
|
47139
|
+
const liveDiscovery = await import("./discovery-X2NV535U.js");
|
|
45353
47140
|
const handoff = await liveDiscovery.handoffLiveDiscoveryOwner(
|
|
45354
47141
|
this.stableBaseDir,
|
|
45355
47142
|
this.current,
|
|
@@ -45466,7 +47253,7 @@ var FileConversationRuntimeOwnership = class {
|
|
|
45466
47253
|
async commitRecord(identity, expected) {
|
|
45467
47254
|
const temporaryPath = path17.join(
|
|
45468
47255
|
this.ownerDirectory,
|
|
45469
|
-
`.runtime-owner.${this.current.pid}.${
|
|
47256
|
+
`.runtime-owner.${this.current.pid}.${randomUUID15()}.tmp`
|
|
45470
47257
|
);
|
|
45471
47258
|
let handle;
|
|
45472
47259
|
let renamed = false;
|
|
@@ -45646,7 +47433,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
45646
47433
|
"createServeApp: runtime replacement/removal requires deps.getSessionBridges so session-id admission can inspect draining generations."
|
|
45647
47434
|
);
|
|
45648
47435
|
}
|
|
45649
|
-
const app = (0,
|
|
47436
|
+
const app = (0, import_express7.default)();
|
|
45650
47437
|
const serveAppLifecycle = installServeAppLifecycle(
|
|
45651
47438
|
app,
|
|
45652
47439
|
deps.serveAppLifecycle
|
|
@@ -45810,6 +47597,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
45810
47597
|
}) : void 0;
|
|
45811
47598
|
const defaultSessionOwnerIndex = !injectedWorkspaceRegistry ? createWorkspaceSessionOwnerIndex() : void 0;
|
|
45812
47599
|
const bridge = injectedWorkspaceRegistry?.primary.bridge ?? deps.bridge ?? createAcpSessionBridge({
|
|
47600
|
+
sessionAttachmentsRoot: path18.join(
|
|
47601
|
+
new Storage(boundWorkspace).getProjectTempDir(),
|
|
47602
|
+
"attachments"
|
|
47603
|
+
),
|
|
45813
47604
|
maxSessions: opts.maxSessions,
|
|
45814
47605
|
...totalSessionAdmission ? { freshSessionAdmission: totalSessionAdmission.admit } : {},
|
|
45815
47606
|
...defaultSessionOwnerIndex ? {
|
|
@@ -46307,18 +48098,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46307
48098
|
app.locals.stopWorkspaceGitState = () => workspaceGitState.dispose();
|
|
46308
48099
|
app.locals.stopWorkspaceGitStateForWorkspace = (workspaceCwd) => workspaceGitState.disposeWorkspace(workspaceCwd);
|
|
46309
48100
|
const workspaceQualifiedAcpEnabled = acpHttpEnabledAtBoot;
|
|
46310
|
-
|
|
46311
|
-
|
|
46312
|
-
|
|
46313
|
-
|
|
46314
|
-
|
|
46315
|
-
);
|
|
46316
|
-
}
|
|
46317
|
-
app.use(allowOriginCors(parsedAllowOrigins));
|
|
46318
|
-
} else {
|
|
46319
|
-
app.use(denyBrowserOriginCors);
|
|
48101
|
+
const parsedAllowOrigins = parseAllowOriginPatterns(opts.allowOrigins ?? []);
|
|
48102
|
+
if (parsedAllowOrigins.allowAny && !opts.token) {
|
|
48103
|
+
throw new Error(
|
|
48104
|
+
`Refusing to start with --allow-origin '*' but no bearer token configured. '*' admits any cross-origin browser to the API; without a token, any local page can drive the daemon. Set a token or list specific origins instead of '*'.`
|
|
48105
|
+
);
|
|
46320
48106
|
}
|
|
48107
|
+
const originAllowlist = new MutableOriginAllowlist(parsedAllowOrigins);
|
|
48108
|
+
app.use(allowOriginCors(originAllowlist));
|
|
46321
48109
|
app.use(hostAllowlist(opts.hostname, getPort));
|
|
48110
|
+
const credentials = new CredentialStore(opts.token);
|
|
48111
|
+
const authenticate = bearerAuth(credentials);
|
|
46322
48112
|
const rateLimiter = installRateLimiter(app, opts, daemonLog, {
|
|
46323
48113
|
mount: false,
|
|
46324
48114
|
workspaceQualifiedAcpEnabled
|
|
@@ -46330,9 +48120,17 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46330
48120
|
getRateLimiter: /* @__PURE__ */ __name(() => rateLimiter, "getRateLimiter")
|
|
46331
48121
|
});
|
|
46332
48122
|
if (healthRoutes.exposeHealthPreAuth) {
|
|
48123
|
+
app.use("/health", (req, res, next) => {
|
|
48124
|
+
if (listenerIdentityOf(req).kind === "local-control") {
|
|
48125
|
+
authenticate(req, res, next);
|
|
48126
|
+
return;
|
|
48127
|
+
}
|
|
48128
|
+
next();
|
|
48129
|
+
});
|
|
46333
48130
|
healthRoutes.register(app);
|
|
46334
48131
|
}
|
|
46335
48132
|
installAccessLogMiddleware(app, daemonLog);
|
|
48133
|
+
app.use(daemonInboundTraceIdCaptureMiddleware);
|
|
46336
48134
|
const webShellDir = opts.serveWebShell !== false ? deps.webShellDir : void 0;
|
|
46337
48135
|
const webShellFrameAncestors = opts.allowOrigins && opts.allowOrigins.length > 0 ? [...parseAllowOriginPatterns(opts.allowOrigins).origins].filter(
|
|
46338
48136
|
(o) => o.startsWith("chrome-extension://") || o.startsWith("moz-extension://")
|
|
@@ -46373,7 +48171,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
46373
48171
|
daemonLog
|
|
46374
48172
|
});
|
|
46375
48173
|
}
|
|
46376
|
-
app.use(
|
|
48174
|
+
app.use(authenticate);
|
|
46377
48175
|
if (rateLimiter) {
|
|
46378
48176
|
app.use(rateLimiter.middleware);
|
|
46379
48177
|
}
|
|
@@ -47151,6 +48949,10 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
47151
48949
|
fsFactory: primaryRouteFileSystemFactory,
|
|
47152
48950
|
deviceFlowRegistry,
|
|
47153
48951
|
token: opts.token,
|
|
48952
|
+
// The WS upgrade bypasses Express middleware, so it needs the same
|
|
48953
|
+
// listener-scoped credentials the REST gate uses — otherwise the
|
|
48954
|
+
// `qwen-bearer.*` subprotocol would be a way around the scoping.
|
|
48955
|
+
credentials,
|
|
47154
48956
|
// Mirror the REST CORS allowlist onto the WS CSRF wall so an
|
|
47155
48957
|
// explicitly permitted origin (e.g. the extension's
|
|
47156
48958
|
// `chrome-extension://<id>`) can open the reverse tool channel.
|
|
@@ -47222,6 +49024,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
47222
49024
|
if (acpHandleRef.current) {
|
|
47223
49025
|
app.locals["acpHandle"] = acpHandleRef.current;
|
|
47224
49026
|
}
|
|
49027
|
+
const localControlService = new LocalControlService({
|
|
49028
|
+
app,
|
|
49029
|
+
credentials,
|
|
49030
|
+
originAllowlist,
|
|
49031
|
+
// Resolved through the ref on each call rather than captured so Local
|
|
49032
|
+
// Control cannot attach to a stale ACP mount.
|
|
49033
|
+
attachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.attachServer(server), "attachWebSocket"),
|
|
49034
|
+
detachWebSocket: /* @__PURE__ */ __name((server) => acpHandleRef.current?.detachServer(server), "detachWebSocket"),
|
|
49035
|
+
getPort,
|
|
49036
|
+
tlsPaths: opts.tlsCert && opts.tlsKey ? { cert: opts.tlsCert, key: opts.tlsKey } : void 0
|
|
49037
|
+
});
|
|
49038
|
+
app.locals["localControlService"] = localControlService;
|
|
49039
|
+
registerWorkspaceLocalControlRoutes(app, {
|
|
49040
|
+
service: localControlService,
|
|
49041
|
+
mutate,
|
|
49042
|
+
safeBody,
|
|
49043
|
+
isDaemonDraining: deps.isChannelControlDraining,
|
|
49044
|
+
webShellAvailable: Boolean(webShellDir),
|
|
49045
|
+
primaryBindHostname: opts.hostname
|
|
49046
|
+
});
|
|
47225
49047
|
if (webShellDir) {
|
|
47226
49048
|
mountWebShellSpaFallback(app, webShellDir, webShellFrameAncestors);
|
|
47227
49049
|
}
|