@qwen-code/qwen-code 0.21.1 → 0.21.2-nightly.20260801.bc382c3ff
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 +9 -7
- package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/github.md +49 -10
- package/bundled/qc-helper/docs/features/channels/gitlab.md +177 -0
- package/bundled/qc-helper/docs/features/code-review.md +20 -0
- package/bundled/qc-helper/docs/features/commands.md +1 -0
- package/bundled/qc-helper/docs/features/hooks.md +135 -18
- package/bundled/qc-helper/docs/features/memory.md +27 -0
- package/bundled/qc-helper/docs/features/skills.md +14 -0
- package/bundled/qc-helper/docs/features/sub-agents.md +55 -8
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +7 -7
- package/bundled/qc-helper/docs/qwen-serve.md +28 -6
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +2 -2
- package/bundled/review/SKILL.md +1 -1
- package/chunks/{MaxSizedBox-VI3ROJJA.js → MaxSizedBox-CDHTDITS.js} +45 -40
- package/chunks/{StandaloneSessionPicker-LYXKD2EV.js → StandaloneSessionPicker-L63HUAHP.js} +65 -60
- package/chunks/{acp-startup-profiler-DFVPFQ6C.js → acp-startup-profiler-3RICG2YW.js} +2 -2
- package/chunks/{acpAgent-WN5SRDQO.js → acpAgent-6WVVT2P3.js} +962 -599
- package/chunks/{agent-K6ECSM64.js → agent-KDM4CBOU.js} +40 -35
- package/chunks/agent-headless-AS7K2K57.js +79 -0
- package/chunks/{anthropicContentGenerator-V2QOGVYD.js → anthropicContentGenerator-WCBYB6JG.js} +337 -27
- package/chunks/{artifact-tool-6K6U7XYJ.js → artifact-tool-ANV4CFCR.js} +2 -2
- package/chunks/{askUserQuestion-GD2IJJ7I.js → askUserQuestion-MALEB47H.js} +2 -2
- package/chunks/{bridge-3KJEWDNE.js → bridge-JNEW6FES.js} +46 -41
- package/chunks/{build-S6DO7LMM.js → build-GDBLPA24.js} +1 -1
- package/chunks/{ca-6W3SK7OQ.js → ca-4OJN75WT.js} +46 -5
- package/chunks/{channel-management-service-XR7GZSWF.js → channel-management-service-QOO7TD3T.js} +21 -6
- package/chunks/{channel-settings-store-HW4FXXUA.js → channel-settings-store-4CSMTR4L.js} +47 -42
- package/chunks/{channel-worker-group-XDPTDWTX.js → channel-worker-group-ERSUOPIR.js} +8 -8
- package/chunks/{channel-worker-manager-YYEHVRRE.js → channel-worker-manager-X247YDQ7.js} +8 -8
- package/chunks/{channel-worker-supervisor-74HTWA2G.js → channel-worker-supervisor-ORJIEEPP.js} +4 -4
- package/chunks/{chunk-VWOOBLTY.js → chunk-25QQVOCG.js} +5 -5
- package/chunks/{chunk-CAPPWD3X.js → chunk-2A6MHYIA.js} +3 -3
- package/chunks/{chunk-2XSLTRFZ.js → chunk-2CTKGIFR.js} +2 -2
- package/chunks/{chunk-DZLYR4U3.js → chunk-2DNKEBXY.js} +1 -1
- package/chunks/{chunk-UWMLWVCA.js → chunk-2IIJTXYF.js} +26 -10
- package/chunks/{chunk-JYBU6YUE.js → chunk-2M5N3DHY.js} +1 -1
- package/chunks/{chunk-AQIDMUGU.js → chunk-2PNQQ4UR.js} +2 -2
- package/chunks/{chunk-OKF7JF3R.js → chunk-2UISUFHQ.js} +3 -3
- package/chunks/{chunk-2LQTH543.js → chunk-33FNCQSY.js} +2 -2
- package/chunks/{chunk-M7OONWYU.js → chunk-3LGZEYOF.js} +4 -2
- package/chunks/{chunk-ZURDMIDR.js → chunk-3MHPWQ2M.js} +242 -76
- package/chunks/{chunk-UHUSJ6X7.js → chunk-3RXUYQJI.js} +25 -6
- package/chunks/{chunk-E5Z2AVNV.js → chunk-3SH53ANB.js} +0 -11
- package/chunks/{chunk-BNWB5CYE.js → chunk-3WXMXT7C.js} +22 -11
- package/chunks/{chunk-A2D5BAVP.js → chunk-42IKVPST.js} +1 -1
- package/chunks/{chunk-2DN4J57Y.js → chunk-432XCUHF.js} +1 -1
- package/chunks/{chunk-EVKE2FZL.js → chunk-433VD3HX.js} +4 -4
- package/chunks/{chunk-Q43KPN7X.js → chunk-434YCHSV.js} +6 -6
- package/chunks/{chunk-5TBMQLGG.js → chunk-4LKVQFHM.js} +2 -2
- package/chunks/{chunk-YDLJGZHL.js → chunk-4NFY2S7N.js} +0 -33
- package/chunks/{chunk-6PE7N3A4.js → chunk-5UJ6A3CH.js} +145 -10
- package/chunks/{chunk-GNR2RNMP.js → chunk-5UZITEHA.js} +3 -3
- package/chunks/chunk-6FMJLI5M.js +1591 -0
- package/chunks/{chunk-RPLGZJV2.js → chunk-6O5DVH27.js} +1 -1
- package/chunks/{chunk-2RFKHEXL.js → chunk-6PLDPT2C.js} +1 -1
- package/chunks/{chunk-7AEJDLRA.js → chunk-7IYLHTTM.js} +3 -3
- package/chunks/{chunk-65PQENQP.js → chunk-7K2WTPQO.js} +5 -5
- package/chunks/{chunk-P4WOAOJW.js → chunk-7MY2AR5A.js} +72 -26
- package/chunks/{chunk-GXIJHV66.js → chunk-A2A34TSB.js} +3 -3
- package/chunks/{chunk-XWWKIXVD.js → chunk-A5YZ3FA2.js} +2 -1
- package/chunks/{chunk-64LQLPL7.js → chunk-A6SX5TAH.js} +3 -3
- package/chunks/{chunk-SZ3KHTDR.js → chunk-AKA24BGO.js} +1 -1
- package/chunks/chunk-AQ37AY7B.js +93 -0
- package/chunks/{chunk-2N7CODY5.js → chunk-AQEWCKX4.js} +2 -2
- package/chunks/{chunk-KCO4FLFJ.js → chunk-AYB4HSBI.js} +3 -3
- package/chunks/{chunk-WZRWHXFE.js → chunk-BFHXDAR7.js} +1 -1
- package/chunks/{chunk-L55JWS76.js → chunk-BGXZBI5B.js} +1 -1
- package/chunks/{chunk-5MKRTI4T.js → chunk-BKUN5QHP.js} +7 -7
- package/chunks/{chunk-Y4IHBGBP.js → chunk-BV4QX43X.js} +1 -1
- package/chunks/{chunk-PB3MBFKG.js → chunk-C4L2MEIT.js} +4 -4
- package/chunks/{chunk-TCIFAA7K.js → chunk-CHCLO3M7.js} +14 -14
- package/chunks/{chunk-CVHIL5IG.js → chunk-CWEIMFFW.js} +13 -6
- package/chunks/{chunk-2FAK6PNM.js → chunk-DUIJ2IXG.js} +5 -13
- package/chunks/{chunk-T2QMKU3R.js → chunk-DVGTU5TC.js} +19 -7
- package/chunks/{chunk-LGAOC3ZS.js → chunk-DYA25Y7U.js} +1 -1
- package/chunks/{chunk-SGFT55XI.js → chunk-E4WHKETF.js} +32 -4
- package/chunks/{chunk-WBL3FJEU.js → chunk-FC4KQFCS.js} +1 -1
- package/chunks/{chunk-MHAIJPTD.js → chunk-FJHA23GM.js} +12 -12
- package/chunks/{chunk-S7W2GKIO.js → chunk-G7XXKQYS.js} +2 -0
- package/chunks/{chunk-MR5EAQ5M.js → chunk-GALUTA2C.js} +1 -1
- package/chunks/{chunk-7I5GTCT4.js → chunk-GB3AB7TR.js} +4008 -3648
- package/chunks/{chunk-QIZKCVM3.js → chunk-GHJM2C2T.js} +6 -8
- package/chunks/chunk-GOFAQQZA.js +132 -0
- package/chunks/{chunk-BCZFQXWK.js → chunk-GTM6IHBB.js} +2 -2
- package/chunks/{chunk-5ZF5XXTS.js → chunk-GVISB2OH.js} +2 -2
- package/chunks/{chunk-FNMZK765.js → chunk-H36SETQS.js} +1 -1
- package/chunks/{chunk-UBEPNVDI.js → chunk-H4346YW5.js} +28 -16
- package/chunks/{chunk-CQL64ESB.js → chunk-H4DSRWAS.js} +24 -13
- package/chunks/{chunk-YGF33UXG.js → chunk-H6MC6VQX.js} +222 -173
- package/chunks/{chunk-GZXCZHCT.js → chunk-I3G5JWBV.js} +1 -1
- package/chunks/{chunk-Y6AXW2OG.js → chunk-I5GNT6ZS.js} +7 -1
- package/chunks/{chunk-GEBV2JGB.js → chunk-I6FAHB4N.js} +1 -1
- package/chunks/{chunk-UPUG4GXM.js → chunk-I7JDGNG6.js} +3 -3
- package/chunks/{chunk-JHNRZMHI.js → chunk-II6WPWHY.js} +9 -9
- package/chunks/{chunk-B4AJNNOL.js → chunk-J26HHFI5.js} +1 -1
- package/chunks/{chunk-S3TWXGKA.js → chunk-JE7KQ2UP.js} +4 -2
- package/chunks/{chunk-ZHBO7WVX.js → chunk-JELIWHXD.js} +1 -1
- package/chunks/{chunk-3EFXSQCM.js → chunk-JRIDA5HF.js} +7 -7
- package/chunks/{chunk-TFRMVU6R.js → chunk-K4CGQN4Q.js} +1 -1
- package/chunks/{chunk-WUZ7H6DP.js → chunk-K5Q62CGR.js} +1 -1
- package/chunks/{chunk-JCW2R7WC.js → chunk-K623ENWT.js} +3 -79
- package/chunks/{chunk-T2NCM2ET.js → chunk-K6KS3LTN.js} +2 -749
- package/chunks/{chunk-TDL6LB4K.js → chunk-KG22G46Y.js} +22 -10
- package/chunks/{chunk-GATT5TKW.js → chunk-KKN2IE7Q.js} +1 -1
- package/chunks/{chunk-JMONIXMJ.js → chunk-KVUBYJDM.js} +2 -2
- package/chunks/{chunk-TBBV36Y4.js → chunk-KXSYDCP2.js} +4 -4
- package/chunks/{chunk-EIF3FXTB.js → chunk-LAPK3GLC.js} +121 -18
- package/chunks/chunk-LBOVL47Y.js +29 -0
- package/chunks/{chunk-U3E3UQAA.js → chunk-LBWNSLJK.js} +4 -4
- package/chunks/{chunk-S4WJVPZW.js → chunk-LL4U3BSH.js} +15 -7
- package/chunks/{chunk-657BH7VM.js → chunk-LRJWFR6L.js} +4 -4
- package/chunks/{chunk-PT722TDT.js → chunk-M2F5PLOW.js} +770 -125
- package/chunks/{chunk-3L2SPEBH.js → chunk-M744OFVE.js} +1 -1
- package/chunks/{chunk-VYOXCEPJ.js → chunk-MBKPUM5Y.js} +1 -1
- package/chunks/chunk-MISUEWB4.js +8749 -0
- package/chunks/{chunk-PONHVBRT.js → chunk-MOHAWIAW.js} +2 -2
- package/chunks/{chunk-HMRM2A3U.js → chunk-MSIVKDRC.js} +4 -4
- package/chunks/{record-artifact-XAMSFSW4.js → chunk-MYT7N6QH.js} +22 -7
- package/chunks/{chunk-X5WNMMIA.js → chunk-NGWYUZZO.js} +11510 -15137
- package/chunks/{chunk-PQNHRFJC.js → chunk-NYX53SV4.js} +0 -2
- package/chunks/{chunk-6RPMI2AB.js → chunk-NZB4NDJL.js} +10 -10
- package/chunks/{chunk-BGTQCTQW.js → chunk-O2ZYHG33.js} +6 -5
- package/chunks/chunk-O6GEWCJA.js +21 -0
- package/chunks/{chunk-JX27F6QS.js → chunk-OBAIHYFT.js} +1 -1
- package/chunks/{chunk-BPZKP57P.js → chunk-OCRM53TT.js} +3 -3
- package/chunks/{chunk-V7RNNPGC.js → chunk-P5Y23G2L.js} +18 -1
- package/chunks/{chunk-FTD6DP4T.js → chunk-PDDYAXL2.js} +5 -1
- package/chunks/{chunk-JSD33JG6.js → chunk-PGEGUNH5.js} +67 -10
- package/chunks/{chunk-A4COXFB3.js → chunk-PGP7Y3RQ.js} +5 -5
- package/chunks/{chunk-T3O2B4XO.js → chunk-PHODQP2V.js} +6 -6
- package/chunks/{chunk-BMFALVGQ.js → chunk-PXA5AWHY.js} +1 -1
- package/chunks/chunk-QL4TN4HS.js +59 -0
- package/chunks/{chunk-W4MIWP6M.js → chunk-QMBEW7EW.js} +2 -2
- package/chunks/{chunk-U4VTUMMK.js → chunk-QONSRAEV.js} +1 -1
- package/chunks/{chunk-LW3RFMG7.js → chunk-QYPT3QUD.js} +3 -3
- package/chunks/{chunk-TV64SXKD.js → chunk-RGJ4JWSU.js} +131 -48
- package/chunks/{chunk-75MIQ3LV.js → chunk-RPYYTL7E.js} +61 -13
- package/chunks/{chunk-52ZSWYEG.js → chunk-SK2UKB45.js} +1 -1
- package/chunks/{chunk-PLDQBIO6.js → chunk-SWEBEXPI.js} +1 -1
- package/chunks/chunk-T3CHYWJZ.js +758 -0
- package/chunks/{chunk-VCPIZRYH.js → chunk-TFFMATHX.js} +9 -7
- package/chunks/{chunk-J7OACQDE.js → chunk-TNVKFQXQ.js} +458 -97
- package/chunks/{chunk-A3NDJ5SB.js → chunk-TYERNYH4.js} +2 -2
- package/chunks/{chunk-GKX7E4CO.js → chunk-U25CMJYY.js} +1 -1
- package/chunks/{chunk-7XATOOE7.js → chunk-UH7Z7Y45.js} +1 -1
- package/chunks/{chunk-XFZYFU3I.js → chunk-UHQ3L6GC.js} +1 -1
- package/chunks/{chunk-GZ3RCT54.js → chunk-UHTJC7O3.js} +1 -1
- package/chunks/{chunk-XZC5VLBZ.js → chunk-UKZEXS6K.js} +6 -0
- package/chunks/{chunk-LO4ROVP4.js → chunk-UOFFZNXV.js} +111 -13
- package/chunks/{chunk-5YKDXHUY.js → chunk-URN76TKR.js} +2 -2
- package/chunks/{chunk-T4TXDL7G.js → chunk-UWLG4UCE.js} +132 -35
- package/chunks/{chunk-KAMYKP7E.js → chunk-UWSXFI6E.js} +1 -1
- package/chunks/{chunk-7BAU433D.js → chunk-VS3GXRNZ.js} +1198 -240
- package/chunks/{chunk-EJGJIBRS.js → chunk-VWF42XC6.js} +3 -3
- package/chunks/{chunk-RCUQIPTN.js → chunk-W7XZ3KP5.js} +1 -1
- package/chunks/{chunk-OCESJA77.js → chunk-WISQLM4Q.js} +1197 -1154
- package/chunks/{chunk-NOKIVHOL.js → chunk-WK4TJUEA.js} +1 -1
- package/chunks/{chunk-JFMA7Y5M.js → chunk-WP4HGHFG.js} +5 -5
- package/chunks/{chunk-4G2BISNC.js → chunk-XC2VAFVZ.js} +1 -1
- package/chunks/{chunk-2LKVPASC.js → chunk-XC656O42.js} +3 -3
- package/chunks/{chunk-5KTQXHPY.js → chunk-XCLLRKY5.js} +3 -3
- package/chunks/{chunk-HV26XH34.js → chunk-XFDPIC4P.js} +3 -3
- package/chunks/{chunk-JTV5K7NH.js → chunk-XSA5EKTJ.js} +1 -1
- package/chunks/{chunk-75GFAX4R.js → chunk-YAVY33G4.js} +1 -1
- package/chunks/{chunk-WBSMNTSV.js → chunk-YXEVDA66.js} +2 -2
- package/chunks/{chunk-7DXQIJID.js → chunk-ZRFJ75D7.js} +3 -3
- package/chunks/{chunk-XBYYDKAZ.js → chunk-ZTN6OA5J.js} +8 -7
- package/chunks/{computer-use-ZTIDHMMA.js → computer-use-Z4NCIIJN.js} +40 -35
- package/chunks/{config-utils-NYSXDMEQ.js → config-utils-64LM6OEQ.js} +4 -4
- package/chunks/{contextCommand-2PIEU37Z.js → contextCommand-HVM7XFCB.js} +43 -38
- package/chunks/{core-runtime-3XEYLQFK.js → core-runtime-NL3ZBHBU.js} +40 -35
- package/chunks/{create-sub-session-SBYUMSSS.js → create-sub-session-AM32K2HD.js} +2 -2
- package/chunks/{create-sub-session-R76FVXCI.js → create-sub-session-XHSCDYFU.js} +43 -38
- package/chunks/{cron-create-2QK6TCEC.js → cron-create-HPXYE6C5.js} +4 -4
- package/chunks/{cron-delete-FDCDFYMG.js → cron-delete-FPVNTKPK.js} +4 -4
- package/chunks/{cron-list-XN3WVBTP.js → cron-list-ZEI6PAAV.js} +4 -4
- package/chunks/{daemon-Q2AB5Z23.js → daemon-PCNCI5YU.js} +72 -3
- package/chunks/daemon-status-provider-XD23SNAM.js +94 -0
- package/chunks/{daemon-trust-policy-ILUDTLHD.js → daemon-trust-policy-NOHK7IW5.js} +46 -41
- package/chunks/{daemon-trust-policy-monitor-HS3PKKRO.js → daemon-trust-policy-monitor-ZBTSR333.js} +46 -41
- package/chunks/{de-SY6O76BF.js → de-A6TI4LBB.js} +46 -5
- package/chunks/{deferred-core-runtime-X4QV662U.js → deferred-core-runtime-JJBHKM2C.js} +40 -35
- package/chunks/{dist-HVRQ2CFL.js → dist-4LAMY2SK.js} +1180 -5
- package/chunks/{dist-DOLYHMXE.js → dist-4T4NCJFL.js} +2 -2
- package/chunks/dist-7KOL6OMD.js +13467 -0
- package/chunks/{dist-SSU66DM4.js → dist-BH76AT7N.js} +1 -1
- package/chunks/{dist-BSTVRPMT.js → dist-BXA3JXVQ.js} +541 -19
- package/chunks/{dist-SV7Q3AWJ.js → dist-OEEFI6UU.js} +12 -9
- package/chunks/{dist-YGBBMK3Z.js → dist-SMLVOWKV.js} +5 -4
- package/chunks/{dist-IXQEQWRG.js → dist-V2RK6S6Q.js} +1 -1
- package/chunks/{earlyInputCapture-XKLZT7ZD.js → earlyInputCapture-KLAZDAIP.js} +41 -36
- package/chunks/{edit-HHGIOTQ2.js → edit-YQZWCISX.js} +40 -35
- package/chunks/{en-NBK3JKCE.js → en-RESOFG55.js} +46 -5
- package/chunks/{enter-worktree-ZN7PUQ46.js → enter-worktree-WLVWI3FP.js} +40 -35
- package/chunks/{enterPlanMode-EIFIDSIV.js → enterPlanMode-6RYXFQUD.js} +40 -35
- package/chunks/{environment-XXQ75D2Q.js → environment-DXJTXSVT.js} +43 -38
- package/chunks/{errors-4GMVU7CK.js → errors-XGAGG2S2.js} +43 -38
- package/chunks/{exit-worktree-GXMI4ATY.js → exit-worktree-C4276VPP.js} +40 -35
- package/chunks/{exitPlanMode-34UVY7M6.js → exitPlanMode-MM5HIRUF.js} +40 -35
- package/chunks/{fast-path-VPIVA7L6.js → fast-path-PIXYOHCH.js} +6 -2
- package/chunks/{fr-4KG5V7UT.js → fr-QF7RI5ZE.js} +46 -5
- package/chunks/{gemini-4BWIK4WD.js → gemini-43RLVUNP.js} +158 -96
- package/chunks/{geminiContentGenerator-3XVV5MSS.js → geminiContentGenerator-PNQ4TSID.js} +6 -6
- package/chunks/{glob-TZ2ABCJG.js → glob-ZMBQKAU5.js} +40 -35
- package/chunks/goal-tools-Y767F7LZ.js +335 -0
- package/chunks/{grep-BEF463NA.js → grep-HSV37W2Q.js} +40 -35
- package/chunks/handleAutoUpdate-QDHZPBAY.js +85 -0
- package/chunks/{i18n-FMM5FDXR.js → i18n-ME22A6RN.js} +42 -37
- package/chunks/{image-gen-HHVLF7HS.js → image-gen-IFC7ZWSB.js} +9 -9
- package/chunks/{initializer-625TIAIO.js → initializer-J7H2CHVB.js} +47 -42
- package/chunks/{installationInfo-6AM4I2Y3.js → installationInfo-R7FXPQN5.js} +41 -36
- package/chunks/{ja-F3GSQXMF.js → ja-URQESVGW.js} +46 -5
- package/chunks/{keychain-token-storage-72IYCAZV.js → keychain-token-storage-7BT4TQ2A.js} +2 -2
- package/chunks/{kittyProtocolDetector-MBRTDRBK.js → kittyProtocolDetector-BFLAKYXH.js} +1 -1
- package/chunks/list-OYDIBA4N.js +93 -0
- package/chunks/{list-agents-R6KDXQR3.js → list-agents-GATIBBQQ.js} +2 -2
- package/chunks/{loadedSettingsAdapter-SPUTNKAV.js → loadedSettingsAdapter-OK6GK2GE.js} +46 -41
- package/chunks/{loggingContentGenerator-LKOF7XI7.js → loggingContentGenerator-U4ZEG4GL.js} +53 -38
- package/chunks/{loop-wakeup-3IQKCYAH.js → loop-wakeup-3DZMQQQQ.js} +13 -6
- package/chunks/{ls-DKZ37A7N.js → ls-7F4GHXIH.js} +4 -4
- package/chunks/{lsp-QNWN7KN3.js → lsp-6FEHVBWI.js} +2 -2
- package/chunks/{managed-npm-update-ACQGGIN5.js → managed-npm-update-PGKAJLLO.js} +43 -38
- package/chunks/mcp-S4DXJD2G.js +87 -0
- package/chunks/{monitor-DF52UVHI.js → monitor-E5ZFMT74.js} +40 -35
- package/chunks/nonInteractiveCli-HNOHKEPE.js +149 -0
- package/chunks/{notebook-edit-FCWS4XVN.js → notebook-edit-6QDN6VZJ.js} +40 -35
- package/chunks/{openaiContentGenerator-7LDK3DCJ.js → openaiContentGenerator-3NLB2C5O.js} +19 -19
- package/chunks/{pidfile-6ERW3DF4.js → pidfile-ZMOIUGG6.js} +41 -36
- package/chunks/{processUtils-COKZAMUP.js → processUtils-E4QGQVWW.js} +2 -2
- package/chunks/{pt-EQ33KWEN.js → pt-EEEQXRUI.js} +46 -5
- package/chunks/{qwenContentGenerator-TKWUMR7N.js → qwenContentGenerator-2LFRWJTM.js} +46 -41
- package/chunks/{qwenOAuth2-7HMU47SF.js → qwenOAuth2-N32BUQDC.js} +8 -8
- package/chunks/{read-file-X6DRC574.js → read-file-GLDCWZBG.js} +11 -11
- package/chunks/{read-mcp-resource-GFTWYXMK.js → read-mcp-resource-AFS3UKZO.js} +2 -2
- package/chunks/record-artifact-ECZSCEG5.js +21 -0
- package/chunks/{resumeHistoryUtils-PFPM2GWM.js → resumeHistoryUtils-F5BE5QDW.js} +48 -43
- package/chunks/ripGrep-T23Y4AGY.js +77 -0
- package/chunks/{ru-7OZAUKGG.js → ru-WGZDYQAB.js} +46 -5
- package/chunks/{run-qwen-serve-TSTCO4XE.js → run-qwen-serve-TI2HGLLU.js} +290 -75
- package/chunks/{runtime-DAUPSUKI.js → runtime-WCWM3DO7.js} +53 -46
- package/chunks/{scheduler-KMADMT26.js → scheduler-2QZO5AV5.js} +40 -35
- package/chunks/{sdk-exporters-http-WO556XNU.js → sdk-exporters-http-IKNWQJNV.js} +3 -3
- package/chunks/{sdk-impl-LPAVACSF.js → sdk-impl-7CUUMQDB.js} +3 -3
- package/chunks/{send-message-SAWK4DZX.js → send-message-X7G2JSII.js} +6 -11
- package/chunks/{serve-NNRWS6F4.js → serve-DZOMYUFU.js} +46 -41
- package/chunks/{server-WEH7DVCH.js → server-N4AJRKIQ.js} +2269 -1016
- package/chunks/{session-WXC56V2I.js → session-GS6AKMN7.js} +151 -86
- package/chunks/{settings-DJDXFDZ3.js → settings-CUN3SELH.js} +50 -45
- package/chunks/{shell-JN5VRQXD.js → shell-NGBFVXC5.js} +40 -35
- package/chunks/{skill-SGXPKJCS.js → skill-SC2BSO75.js} +30 -16
- package/chunks/{skill-settings-VJ5PDMZI.js → skill-settings-XVPCPW5K.js} +45 -40
- package/chunks/{spawnChannel-ETMJW7YX.js → spawnChannel-RILO4YY3.js} +42 -37
- package/chunks/{standalone-update-MK3Z7KBI.js → standalone-update-TMLT6LVJ.js} +43 -38
- package/chunks/{startInteractiveUI-ZCGIXPGT.js → startInteractiveUI-J45WOEOU.js} +883 -1112
- package/chunks/{syntheticOutput-355CB6CJ.js → syntheticOutput-FHRY3BPQ.js} +3 -3
- package/chunks/{task-create-INGWNUG4.js → task-create-LAQXBIHC.js} +11 -10
- package/chunks/{task-list-5XNNGTF4.js → task-list-V6K5DRDH.js} +6 -6
- package/chunks/{task-stop-4ROAOBXH.js → task-stop-LQXE52L6.js} +2 -2
- package/chunks/{task-update-CRK5VWWZ.js → task-update-NXRCXSPB.js} +11 -10
- package/chunks/{team-create-QQGAJG7P.js → team-create-W3EVWCTA.js} +40 -35
- package/chunks/{team-delete-S2RCXA4P.js → team-delete-Z4KGO7RC.js} +6 -6
- package/chunks/{team-plan-approval-RT7Q5R6O.js → team-plan-approval-URYVKJF4.js} +40 -35
- package/chunks/theme-manager-CUAMS2NI.js +81 -0
- package/chunks/{todoWrite-7WM3VDMY.js → todoWrite-OFIZDI7P.js} +32 -4
- package/chunks/{tool-search-Z3Z4AYKP.js → tool-search-DCICFL32.js} +15 -14
- package/chunks/total-session-admission-3ZTAXVUK.js +89 -0
- package/chunks/{trustedFolders-X2JEIO57.js → trustedFolders-EVCN36O5.js} +42 -37
- package/chunks/{update-relaunch-VWNPYDIP.js → update-relaunch-XLW46RHQ.js} +5 -5
- package/chunks/{updateCheck-KAQH67DV.js → updateCheck-ZHVXDAIH.js} +44 -39
- package/chunks/{useAutoAcceptIndicator-JH6BCF7S.js → useAutoAcceptIndicator-ZGD6BJSP.js} +50 -45
- package/chunks/{validateNonInterActiveAuth-GIUJ2UFS.js → validateNonInterActiveAuth-R3BAQFDY.js} +88 -83
- package/chunks/{version-BGLYIJUY.js → version-PMWREGCG.js} +1 -1
- package/chunks/{web-fetch-OTDU4VQF.js → web-fetch-PGN27SGF.js} +14 -14
- package/chunks/{web-search-FP6SIHPR.js → web-search-KW4UNMRE.js} +8 -8
- package/chunks/{workflow-YCIVBYSB.js → workflow-SN3TJBTJ.js} +363 -310
- package/chunks/workspace-providers-status-O3HUZGGR.js +90 -0
- package/chunks/{workspace-registration-store-OTMS3H4C.js → workspace-registration-store-M3FJ74RS.js} +2 -2
- package/chunks/{workspace-registry-O63R6IZ4.js → workspace-registry-U7ISW23N.js} +47 -42
- package/chunks/{workspace-service-M6LLHKJ5.js → workspace-service-VH6IWADT.js} +53 -48
- package/chunks/{workspace-skills-status-C2V7BAIS.js → workspace-skills-status-XANARSZS.js} +48 -43
- package/chunks/{workspace-trust-reconciler-IBUPOUJN.js → workspace-trust-reconciler-35EFR4GC.js} +53 -48
- package/chunks/write-file-NCRSGUDT.js +79 -0
- package/chunks/{zh-H3YDK5QW.js → zh-OHX23Q44.js} +43 -5
- package/chunks/{zh-TW-JYCP7XUA.js → zh-TW-4G7YKDAQ.js} +43 -5
- package/chunks/zoom-image-X7CIADYC.js +224 -0
- package/cli.js +55 -48
- package/locales/ca.js +60 -4
- package/locales/de.js +62 -4
- package/locales/en.js +59 -4
- package/locales/fr.js +64 -4
- package/locales/ja.js +61 -4
- package/locales/pt.js +60 -4
- package/locales/ru.js +63 -4
- package/locales/zh-TW.js +52 -4
- package/locales/zh.js +52 -4
- package/package.json +3 -3
- package/web-shell/assets/{arc-75-Wdeo3.js → arc-CaMTqKio.js} +1 -1
- package/web-shell/assets/{architectureDiagram-3BPJPVTR-FKeXQbyP.js → architectureDiagram-3BPJPVTR-Bjxztij2.js} +1 -1
- package/web-shell/assets/{blockDiagram-GPEHLZMM-CY0vc-A3.js → blockDiagram-GPEHLZMM-BYJzeHi9.js} +1 -1
- package/web-shell/assets/{c4Diagram-AAUBKEIU-CNP-A-8u.js → c4Diagram-AAUBKEIU-fYAa-Eil.js} +1 -1
- package/web-shell/assets/channel-LEZei0-5.js +1 -0
- package/web-shell/assets/{chunk-2J33WTMH-GybS4Gii.js → chunk-2J33WTMH-B1OTlTml.js} +1 -1
- package/web-shell/assets/{chunk-4BX2VUAB-02H91V8v.js → chunk-4BX2VUAB-DNj4uy6k.js} +1 -1
- package/web-shell/assets/{chunk-55IACEB6-D3M-2VT6.js → chunk-55IACEB6-DAqNmg3c.js} +1 -1
- package/web-shell/assets/{chunk-727SXJPM-CCu29u4H.js → chunk-727SXJPM-BwB4ddxE.js} +1 -1
- package/web-shell/assets/{chunk-AQP2D5EJ-CaFKWgrn.js → chunk-AQP2D5EJ-DmHR_UZs.js} +1 -1
- package/web-shell/assets/{chunk-FMBD7UC4-ZZpPqIwQ.js → chunk-FMBD7UC4-BlfOXumo.js} +1 -1
- package/web-shell/assets/{chunk-ND2GUHAM-D22DqGs8.js → chunk-ND2GUHAM-BKogiSy7.js} +1 -1
- package/web-shell/assets/{chunk-QZHKN3VN-Bu85S0fw.js → chunk-QZHKN3VN-DEclVrOF.js} +1 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK-BiaRhfvf.js +1 -0
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2-BiaRhfvf.js +1 -0
- package/web-shell/assets/{cose-bilkent-S5V4N54A-f1CK1Gwe.js → cose-bilkent-S5V4N54A-CwtS21WT.js} +1 -1
- package/web-shell/assets/{dagre-BM42HDAG-D0Ow8F_n.js → dagre-BM42HDAG-BAAIlB4p.js} +1 -1
- package/web-shell/assets/{diagram-2AECGRRQ-BPrmTWp8.js → diagram-2AECGRRQ-ChljtF_V.js} +1 -1
- package/web-shell/assets/{diagram-5GNKFQAL-HccuFAzy.js → diagram-5GNKFQAL-BIXVd31-.js} +1 -1
- package/web-shell/assets/{diagram-KO2AKTUF-BrS76mbA.js → diagram-KO2AKTUF-BEiBaS15.js} +1 -1
- package/web-shell/assets/{diagram-LMA3HP47-V7T9lU-5.js → diagram-LMA3HP47-C-g4tWKM.js} +1 -1
- package/web-shell/assets/{diagram-OG6HWLK6-DKidyJMR.js → diagram-OG6HWLK6-CNCCbNQG.js} +1 -1
- package/web-shell/assets/{erDiagram-TEJ5UH35-DBadZIkp.js → erDiagram-TEJ5UH35-v8ysnsdI.js} +1 -1
- package/web-shell/assets/{flowDiagram-I6XJVG4X-BymfqdNJ.js → flowDiagram-I6XJVG4X-LKVlLjwA.js} +1 -1
- package/web-shell/assets/{ganttDiagram-6RSMTGT7-DOw340jf.js → ganttDiagram-6RSMTGT7-DA5MrKYG.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-PVQCEYII-_8EiD8sl.js → gitGraphDiagram-PVQCEYII-Cyg5fe6d.js} +1 -1
- package/web-shell/assets/index-BgOcEaVt.js +1756 -0
- package/web-shell/assets/index-C2GE3DAF.js +74 -0
- package/web-shell/assets/{index-CKIadvET.js → index-CKdUkVVS.js} +1 -1
- package/web-shell/assets/index-DA5Lvscv.css +5 -0
- package/web-shell/assets/{infoDiagram-5YYISTIA-D61KYQBu.js → infoDiagram-5YYISTIA-SLsfu3Qd.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-YF4QCWOH-CsiXSpNx.js → ishikawaDiagram-YF4QCWOH-CmHOmTNx.js} +1 -1
- package/web-shell/assets/{journeyDiagram-JHISSGLW-Sdfionyh.js → journeyDiagram-JHISSGLW-C3gM_HFQ.js} +1 -1
- package/web-shell/assets/{kanban-definition-UN3LZRKU-C3WI3Cnl.js → kanban-definition-UN3LZRKU-BbHD7duM.js} +1 -1
- package/web-shell/assets/{linear-Dpigcc62.js → linear-CSBvm435.js} +1 -1
- package/web-shell/assets/{mermaid.core-Ct97pqgW.js → mermaid.core-CPMw15lU.js} +5 -5
- package/web-shell/assets/{mindmap-definition-RKZ34NQL-BzeaN0rB.js → mindmap-definition-RKZ34NQL-C_tNqXQW.js} +1 -1
- package/web-shell/assets/{pieDiagram-4H26LBE5-CvjgcbVD.js → pieDiagram-4H26LBE5-DH_N-8yY.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-W4KKPZXB-BUzgTNdH.js → quadrantDiagram-W4KKPZXB-CRbS8UkN.js} +1 -1
- package/web-shell/assets/{requirementDiagram-4Y6WPE33-B7zKlgUQ.js → requirementDiagram-4Y6WPE33-DJgdZPZn.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-5OEKKPKP-Bb9CQgrT.js → sankeyDiagram-5OEKKPKP-vhL1y5zx.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-3UESZ5HK-DJ6V7itG.js → sequenceDiagram-3UESZ5HK-UQthhFwd.js} +1 -1
- package/web-shell/assets/{stateDiagram-AJRCARHV-IImflERY.js → stateDiagram-AJRCARHV-CAywEm20.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-lfJQHw-7.js +1 -0
- package/web-shell/assets/{timeline-definition-PNZ67QCA-6Q_uWHKh.js → timeline-definition-PNZ67QCA-CLO8b3FD.js} +1 -1
- package/web-shell/assets/{vennDiagram-CIIHVFJN-TmyKyjwv.js → vennDiagram-CIIHVFJN-BNAAh0Mu.js} +1 -1
- package/web-shell/assets/{wardley-L42UT6IY-CRh9uiPv.js → wardley-L42UT6IY-CUY7bLpN.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-YWT4CUSO-59TKAW8w.js → wardleyDiagram-YWT4CUSO-CSg_ORdW.js} +1 -1
- package/web-shell/assets/{xychartDiagram-2RQKCTM6-GCSUIK2L.js → xychartDiagram-2RQKCTM6-BjffV208.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/agent-headless-NO4Y2HOE.js +0 -74
- package/chunks/chunk-6QIGFD5W.js +0 -82
- package/chunks/chunk-HGT6JR3U.js +0 -177
- package/chunks/daemon-status-provider-3XJI6CAL.js +0 -89
- package/chunks/handleAutoUpdate-L6ERF36Y.js +0 -80
- package/chunks/list-L2GA674Y.js +0 -88
- package/chunks/mcp-SZLHKFJW.js +0 -82
- package/chunks/nonInteractiveCli-5T7KYKLK.js +0 -144
- package/chunks/ripGrep-OWV2IVJC.js +0 -72
- package/chunks/theme-manager-EEWIQJ7J.js +0 -76
- package/chunks/total-session-admission-44JKRWQD.js +0 -84
- package/chunks/workspace-providers-status-S35YAIUS.js +0 -85
- package/chunks/write-file-3BZC3EAE.js +0 -72
- package/chunks/zoom-image-TZ6S2O57.js +0 -351
- package/web-shell/assets/channel-DPYMT76A.js +0 -1
- package/web-shell/assets/classDiagram-4FO5ZUOK--JstsIgL.js +0 -1
- package/web-shell/assets/classDiagram-v2-Q7XG4LA2--JstsIgL.js +0 -1
- package/web-shell/assets/index-D1eXNRHe.js +0 -1389
- package/web-shell/assets/index-DVLD4CQq.css +0 -5
- package/web-shell/assets/stateDiagram-v2-BHNVJYJU-CYI_YoNR.js +0 -1
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
// Force strict mode and setup for ESM
|
|
2
2
|
"use strict";
|
|
3
|
-
import {
|
|
4
|
-
openQwenAsrRealtimeStream,
|
|
5
|
-
openVoiceStream,
|
|
6
|
-
openVoiceStreamWithRetry
|
|
7
|
-
} from "./chunk-BCZFQXWK.js";
|
|
8
3
|
import {
|
|
9
4
|
GENERATION_MAX_PROMPT_BYTES,
|
|
10
5
|
MAX_REMEMBER_CONTENT_BYTES,
|
|
@@ -13,6 +8,7 @@ import {
|
|
|
13
8
|
formatWorkspaceMemoryDreamSummary,
|
|
14
9
|
formatWorkspaceMemoryForgetSummary,
|
|
15
10
|
isValidServerName,
|
|
11
|
+
loadSettingsCached,
|
|
16
12
|
normalizeChannelDelivery,
|
|
17
13
|
parseChannelDelivery,
|
|
18
14
|
redactMcpServersSetting,
|
|
@@ -21,7 +17,12 @@ import {
|
|
|
21
17
|
shouldSuppressRememberErrorDetails,
|
|
22
18
|
workspaceMemoryFailureCode,
|
|
23
19
|
workspaceMemoryFailureDiagnostics
|
|
24
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-5UJ6A3CH.js";
|
|
21
|
+
import {
|
|
22
|
+
openQwenAsrRealtimeStream,
|
|
23
|
+
openVoiceStream,
|
|
24
|
+
openVoiceStreamWithRetry
|
|
25
|
+
} from "./chunk-GTM6IHBB.js";
|
|
25
26
|
import {
|
|
26
27
|
SetupGithubError,
|
|
27
28
|
collectSessionData,
|
|
@@ -33,13 +34,13 @@ import {
|
|
|
33
34
|
toJson,
|
|
34
35
|
toJsonl,
|
|
35
36
|
toMarkdown
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UOFFZNXV.js";
|
|
37
38
|
import {
|
|
38
39
|
OBSERVED_CONTACT_MAX_FRESH_WITHIN_SECONDS,
|
|
39
40
|
ObservedChannelContactStore
|
|
40
|
-
} from "./chunk-
|
|
41
|
-
import "./chunk-
|
|
42
|
-
import "./chunk-
|
|
41
|
+
} from "./chunk-DYA25Y7U.js";
|
|
42
|
+
import "./chunk-4NFY2S7N.js";
|
|
43
|
+
import "./chunk-UHQ3L6GC.js";
|
|
43
44
|
import "./chunk-2MIN6GRR.js";
|
|
44
45
|
import "./chunk-QHTIBUWB.js";
|
|
45
46
|
import "./chunk-QTERJVPZ.js";
|
|
@@ -101,14 +102,18 @@ import {
|
|
|
101
102
|
setRateLimiter,
|
|
102
103
|
unsafeRevealSecret,
|
|
103
104
|
validateMcpRuntimeServerName
|
|
104
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-H6MC6VQX.js";
|
|
105
106
|
import {
|
|
106
107
|
isLoopbackBind
|
|
107
108
|
} from "./chunk-RXFQM6FQ.js";
|
|
109
|
+
import {
|
|
110
|
+
createWorkspaceSkillsStatusProvider
|
|
111
|
+
} from "./chunk-H4346YW5.js";
|
|
112
|
+
import "./chunk-BGXZBI5B.js";
|
|
108
113
|
import {
|
|
109
114
|
evaluateDaemonWorkspaceTrust,
|
|
110
115
|
readDaemonTrustPolicySnapshot
|
|
111
|
-
} from "./chunk-
|
|
116
|
+
} from "./chunk-XFDPIC4P.js";
|
|
112
117
|
import {
|
|
113
118
|
EMPTY_WORKSPACE_VOICE_UPDATE_ERROR,
|
|
114
119
|
MAX_WORKSPACE_SKILL_NAME_LENGTH,
|
|
@@ -122,14 +127,14 @@ import {
|
|
|
122
127
|
validateWorkspaceSkillName,
|
|
123
128
|
validateWorkspaceVoiceState,
|
|
124
129
|
voiceSettingsScopeToWire
|
|
125
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-7MY2AR5A.js";
|
|
126
131
|
import {
|
|
127
132
|
PermissionRulesValidationError,
|
|
128
133
|
buildPermissionSettings,
|
|
129
134
|
isPermissionRuleType,
|
|
130
135
|
normalizePermissionRules,
|
|
131
136
|
readPermissionRuleSet
|
|
132
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-GALUTA2C.js";
|
|
133
138
|
import {
|
|
134
139
|
assertVoiceBaseUrlNetworkAllowed,
|
|
135
140
|
isStreamingVoiceModel,
|
|
@@ -137,13 +142,13 @@ import {
|
|
|
137
142
|
resolveVoiceTranscriptionConfig,
|
|
138
143
|
sanitizeVoiceErrorMessage,
|
|
139
144
|
transcribeVoiceAudio
|
|
140
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-2A6MHYIA.js";
|
|
141
146
|
import {
|
|
142
147
|
isVoiceEnabled,
|
|
143
148
|
isVoiceMode,
|
|
144
149
|
readVoiceModel
|
|
145
|
-
} from "./chunk-
|
|
146
|
-
import "./chunk-
|
|
150
|
+
} from "./chunk-XSA5EKTJ.js";
|
|
151
|
+
import "./chunk-JELIWHXD.js";
|
|
147
152
|
import {
|
|
148
153
|
WorkspacePermissionRulesSessionRequiredError,
|
|
149
154
|
WorkspaceSettingsPartialPersistError,
|
|
@@ -152,28 +157,28 @@ import {
|
|
|
152
157
|
} from "./chunk-OA4JVLSA.js";
|
|
153
158
|
import {
|
|
154
159
|
createTotalSessionAdmissionController
|
|
155
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-AKA24BGO.js";
|
|
156
161
|
import {
|
|
157
162
|
WorkspaceGenerationClosedError,
|
|
158
163
|
createSingleWorkspaceRegistry,
|
|
159
164
|
createWorkspaceSessionOwnerIndex
|
|
160
|
-
} from "./chunk-
|
|
165
|
+
} from "./chunk-2M5N3DHY.js";
|
|
161
166
|
import "./chunk-GRC5HGPI.js";
|
|
162
167
|
import {
|
|
163
168
|
assertValidChannelSecretUpdates
|
|
164
|
-
} from "./chunk-
|
|
169
|
+
} from "./chunk-GVISB2OH.js";
|
|
165
170
|
import {
|
|
166
171
|
createDaemonStatusProvider
|
|
167
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-KXSYDCP2.js";
|
|
168
173
|
import "./chunk-VXZBKKQR.js";
|
|
169
|
-
import "./chunk-
|
|
170
|
-
import "./chunk-
|
|
174
|
+
import "./chunk-GHJM2C2T.js";
|
|
175
|
+
import "./chunk-3SH53ANB.js";
|
|
171
176
|
import {
|
|
172
177
|
SessionArtifactAuthorizationError,
|
|
173
178
|
SessionArtifactValidationError,
|
|
174
179
|
createAcpSessionBridge,
|
|
175
180
|
parseSessionSource
|
|
176
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-3MHPWQ2M.js";
|
|
177
182
|
import {
|
|
178
183
|
EVENT_SCHEMA_VERSION,
|
|
179
184
|
EventBus,
|
|
@@ -181,41 +186,37 @@ import {
|
|
|
181
186
|
} from "./chunk-GLWP3FDB.js";
|
|
182
187
|
import "./chunk-XCGIMOLN.js";
|
|
183
188
|
import "./chunk-OCPBI7J5.js";
|
|
184
|
-
import "./chunk-
|
|
189
|
+
import "./chunk-UWSXFI6E.js";
|
|
185
190
|
import {
|
|
186
191
|
createWorkspaceProvidersStatusProvider
|
|
187
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-JRIDA5HF.js";
|
|
188
193
|
import {
|
|
189
194
|
getAuthTypeFromEnv,
|
|
190
195
|
resolveCliGenerationConfig
|
|
191
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-AYB4HSBI.js";
|
|
192
197
|
import {
|
|
193
198
|
snapshotProcessEnv
|
|
194
|
-
} from "./chunk-
|
|
195
|
-
import {
|
|
196
|
-
createWorkspaceSkillsStatusProvider
|
|
197
|
-
} from "./chunk-UBEPNVDI.js";
|
|
198
|
-
import "./chunk-L55JWS76.js";
|
|
199
|
+
} from "./chunk-DUIJ2IXG.js";
|
|
199
200
|
import {
|
|
200
201
|
STATUS_SCHEMA_VERSION,
|
|
201
202
|
createIdleWorkspaceMemoryStatus,
|
|
202
203
|
mapDomainErrorToErrorKind
|
|
203
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-PDDYAXL2.js";
|
|
204
205
|
import "./chunk-Z4X5MTRT.js";
|
|
205
|
-
import "./chunk-
|
|
206
|
+
import "./chunk-FC4KQFCS.js";
|
|
206
207
|
import {
|
|
207
208
|
daemonObservedContactsPath,
|
|
208
209
|
loadChannelsConfig
|
|
209
|
-
} from "./chunk-
|
|
210
|
-
import "./chunk-
|
|
210
|
+
} from "./chunk-3WXMXT7C.js";
|
|
211
|
+
import "./chunk-BKUN5QHP.js";
|
|
211
212
|
import "./chunk-57OAHC2Y.js";
|
|
212
213
|
import {
|
|
213
214
|
parseChannelWebhookConfigLenient
|
|
214
|
-
} from "./chunk-
|
|
215
|
-
import "./chunk-
|
|
215
|
+
} from "./chunk-2CTKGIFR.js";
|
|
216
|
+
import "./chunk-K4CGQN4Q.js";
|
|
216
217
|
import {
|
|
217
218
|
supportedChannelCatalog
|
|
218
|
-
} from "./chunk-
|
|
219
|
+
} from "./chunk-ZTN6OA5J.js";
|
|
219
220
|
import "./chunk-V6WHFGST.js";
|
|
220
221
|
import {
|
|
221
222
|
MAX_REGISTERED_WORKSPACES,
|
|
@@ -224,8 +225,8 @@ import {
|
|
|
224
225
|
WorkspaceRegistrationStoreLimitError,
|
|
225
226
|
normalizeWorkspaceDisplayName,
|
|
226
227
|
workspaceRegistrationId
|
|
227
|
-
} from "./chunk-
|
|
228
|
-
import "./chunk-
|
|
228
|
+
} from "./chunk-2PNQQ4UR.js";
|
|
229
|
+
import "./chunk-UKZEXS6K.js";
|
|
229
230
|
import {
|
|
230
231
|
BranchWhilePromptActiveError,
|
|
231
232
|
CancelSentinelCollisionError,
|
|
@@ -258,13 +259,13 @@ import {
|
|
|
258
259
|
WorkspaceInitRaceError,
|
|
259
260
|
WorkspaceInitSymlinkError,
|
|
260
261
|
WorkspaceMismatchError
|
|
261
|
-
} from "./chunk-
|
|
262
|
+
} from "./chunk-J26HHFI5.js";
|
|
262
263
|
import {
|
|
263
264
|
MAX_WORKSPACE_PATH_LENGTH,
|
|
264
265
|
canonicalizeWorkspace,
|
|
265
266
|
canonicalizeWorkspaces,
|
|
266
267
|
translateAndCheckAbsoluteWorkspacePath
|
|
267
|
-
} from "./chunk-
|
|
268
|
+
} from "./chunk-6PLDPT2C.js";
|
|
268
269
|
import {
|
|
269
270
|
ChannelDeliveryError,
|
|
270
271
|
MAX_CHANNEL_STARTUP_FAILURES,
|
|
@@ -274,10 +275,10 @@ import {
|
|
|
274
275
|
QWEN_SERVER_TOKEN_ENV,
|
|
275
276
|
isChannelDeliveryError,
|
|
276
277
|
isChannelWebhookEnqueueError
|
|
277
|
-
} from "./chunk-
|
|
278
|
+
} from "./chunk-QONSRAEV.js";
|
|
278
279
|
import {
|
|
279
280
|
normalizeWorkerDiagnostic
|
|
280
|
-
} from "./chunk-
|
|
281
|
+
} from "./chunk-UHTJC7O3.js";
|
|
281
282
|
import {
|
|
282
283
|
normalizeServeChannelSelection
|
|
283
284
|
} from "./chunk-ALMR3E6Q.js";
|
|
@@ -286,10 +287,11 @@ import {
|
|
|
286
287
|
redactLogCredentials
|
|
287
288
|
} from "./chunk-M5GB774H.js";
|
|
288
289
|
import "./chunk-5HBA2Z7V.js";
|
|
289
|
-
import "./chunk-
|
|
290
|
+
import "./chunk-K6KS3LTN.js";
|
|
291
|
+
import "./chunk-T3CHYWJZ.js";
|
|
290
292
|
import {
|
|
291
293
|
sanitizeLogText
|
|
292
|
-
} from "./chunk-
|
|
294
|
+
} from "./chunk-GB3AB7TR.js";
|
|
293
295
|
import "./chunk-UDXSXLER.js";
|
|
294
296
|
import {
|
|
295
297
|
getDialogSettingKeys,
|
|
@@ -300,31 +302,27 @@ import {
|
|
|
300
302
|
getWritableScopes,
|
|
301
303
|
loadSettings,
|
|
302
304
|
validateSettingValue
|
|
303
|
-
} from "./chunk-
|
|
305
|
+
} from "./chunk-LAPK3GLC.js";
|
|
304
306
|
import "./chunk-RKUWKYED.js";
|
|
307
|
+
import "./chunk-GOXKNSDZ.js";
|
|
308
|
+
import "./chunk-IDS7MSUP.js";
|
|
305
309
|
import {
|
|
306
310
|
SUPPORTED_LANGUAGES,
|
|
307
311
|
detectSystemLanguage,
|
|
308
312
|
resolveLanguageSetting,
|
|
309
313
|
resolveSupportedLanguage
|
|
310
|
-
} from "./chunk-
|
|
311
|
-
import "./chunk-
|
|
312
|
-
import "./chunk-GOXKNSDZ.js";
|
|
313
|
-
import "./chunk-IDS7MSUP.js";
|
|
314
|
+
} from "./chunk-CHCLO3M7.js";
|
|
315
|
+
import "./chunk-AQEWCKX4.js";
|
|
314
316
|
import "./chunk-6PEXNQTX.js";
|
|
315
|
-
import "./chunk-VYOXCEPJ.js";
|
|
316
|
-
import "./chunk-VJNBRRZG.js";
|
|
317
317
|
import {
|
|
318
318
|
getWorkspaceTrustStatus
|
|
319
|
-
} from "./chunk-
|
|
319
|
+
} from "./chunk-434YCHSV.js";
|
|
320
320
|
import "./chunk-ALGGS7UH.js";
|
|
321
321
|
import {
|
|
322
322
|
isWithinRoot as isWithinRoot2
|
|
323
323
|
} from "./chunk-MR3PXB6E.js";
|
|
324
|
-
import
|
|
325
|
-
|
|
326
|
-
writeStderrLineSafe
|
|
327
|
-
} from "./chunk-OWAK7LMW.js";
|
|
324
|
+
import "./chunk-MBKPUM5Y.js";
|
|
325
|
+
import "./chunk-VJNBRRZG.js";
|
|
328
326
|
import {
|
|
329
327
|
ALL_PROVIDERS,
|
|
330
328
|
BTW_MAX_INPUT_LENGTH,
|
|
@@ -398,19 +396,20 @@ import {
|
|
|
398
396
|
writeWorkspaceContextFile,
|
|
399
397
|
writeWorktreeSession,
|
|
400
398
|
writeWorktreeSessionMarker
|
|
401
|
-
} from "./chunk-
|
|
399
|
+
} from "./chunk-NGWYUZZO.js";
|
|
400
|
+
import "./chunk-GOFAQQZA.js";
|
|
401
|
+
import "./chunk-5M6IDOMF.js";
|
|
402
402
|
import "./chunk-TWPJO254.js";
|
|
403
403
|
import "./chunk-H6XPXXMH.js";
|
|
404
|
-
import "./chunk-5M6IDOMF.js";
|
|
405
|
-
import "./chunk-UPUG4GXM.js";
|
|
406
|
-
import "./chunk-64LQLPL7.js";
|
|
407
|
-
import "./chunk-2LQTH543.js";
|
|
408
|
-
import "./chunk-KRXPRVGL.js";
|
|
409
|
-
import "./chunk-BMFALVGQ.js";
|
|
410
404
|
import {
|
|
411
405
|
MAX_JOBS,
|
|
412
406
|
nextDurableFireMs
|
|
413
|
-
} from "./chunk-
|
|
407
|
+
} from "./chunk-CWEIMFFW.js";
|
|
408
|
+
import "./chunk-I7JDGNG6.js";
|
|
409
|
+
import "./chunk-A6SX5TAH.js";
|
|
410
|
+
import "./chunk-33FNCQSY.js";
|
|
411
|
+
import "./chunk-6PVPNMXU.js";
|
|
412
|
+
import "./chunk-PXA5AWHY.js";
|
|
414
413
|
import {
|
|
415
414
|
nextFireTime,
|
|
416
415
|
parseCron
|
|
@@ -423,22 +422,26 @@ import {
|
|
|
423
422
|
readCronTasks,
|
|
424
423
|
taskHasLegacyCondition,
|
|
425
424
|
updateCronTasks
|
|
426
|
-
} from "./chunk-
|
|
425
|
+
} from "./chunk-MOHAWIAW.js";
|
|
426
|
+
import "./chunk-MYT7N6QH.js";
|
|
427
|
+
import "./chunk-O6GEWCJA.js";
|
|
427
428
|
import "./chunk-T26EAKDL.js";
|
|
428
|
-
import "./chunk-6PVPNMXU.js";
|
|
429
429
|
import "./chunk-CPBF7KYF.js";
|
|
430
|
-
import "./chunk-
|
|
431
|
-
import "./chunk-
|
|
432
|
-
import "./chunk-
|
|
433
|
-
import "./chunk-
|
|
430
|
+
import "./chunk-MISUEWB4.js";
|
|
431
|
+
import "./chunk-KRXPRVGL.js";
|
|
432
|
+
import "./chunk-A5YZ3FA2.js";
|
|
433
|
+
import "./chunk-YAVY33G4.js";
|
|
434
|
+
import "./chunk-2UISUFHQ.js";
|
|
435
|
+
import "./chunk-6FMJLI5M.js";
|
|
434
436
|
import {
|
|
435
437
|
APPROVAL_MODES,
|
|
436
438
|
SubagentError,
|
|
437
439
|
SubagentErrorCode
|
|
438
|
-
} from "./chunk-
|
|
440
|
+
} from "./chunk-PGEGUNH5.js";
|
|
439
441
|
import "./chunk-S6LOFUVP.js";
|
|
440
|
-
import "./chunk-
|
|
441
|
-
import "./chunk-
|
|
442
|
+
import "./chunk-K623ENWT.js";
|
|
443
|
+
import "./chunk-AQ37AY7B.js";
|
|
444
|
+
import "./chunk-432XCUHF.js";
|
|
442
445
|
import "./chunk-ZPJWUGCS.js";
|
|
443
446
|
import {
|
|
444
447
|
QwenOAuth2Client,
|
|
@@ -448,15 +451,15 @@ import {
|
|
|
448
451
|
isDeviceAuthorizationSuccess,
|
|
449
452
|
isDeviceTokenPending,
|
|
450
453
|
isDeviceTokenSuccess
|
|
451
|
-
} from "./chunk-
|
|
454
|
+
} from "./chunk-XC656O42.js";
|
|
452
455
|
import "./chunk-NAVJD2PQ.js";
|
|
453
|
-
import "./chunk-
|
|
454
|
-
import "./chunk-
|
|
456
|
+
import "./chunk-QYPT3QUD.js";
|
|
457
|
+
import "./chunk-QMBEW7EW.js";
|
|
455
458
|
import "./chunk-DGEIYUC3.js";
|
|
456
459
|
import "./chunk-MPHPFVKK.js";
|
|
457
460
|
import "./chunk-GLNBDYUX.js";
|
|
458
461
|
import "./chunk-DJ2GSRLV.js";
|
|
459
|
-
import "./chunk-
|
|
462
|
+
import "./chunk-XCLLRKY5.js";
|
|
460
463
|
import {
|
|
461
464
|
addDaemonRequestAttribute,
|
|
462
465
|
emitDaemonLog,
|
|
@@ -466,41 +469,49 @@ import {
|
|
|
466
469
|
recordDaemonHttpRequest,
|
|
467
470
|
recordDaemonHttpResponse,
|
|
468
471
|
withDaemonRequestSpan
|
|
469
|
-
} from "./chunk-
|
|
472
|
+
} from "./chunk-RPYYTL7E.js";
|
|
470
473
|
import "./chunk-2J3OJGTL.js";
|
|
471
474
|
import "./chunk-P3QQPMQA.js";
|
|
472
|
-
import "./chunk-
|
|
475
|
+
import "./chunk-6O5DVH27.js";
|
|
473
476
|
import "./chunk-GLCZKT5V.js";
|
|
474
|
-
import "./chunk-
|
|
477
|
+
import "./chunk-2DNKEBXY.js";
|
|
475
478
|
import "./chunk-CR3C7WXL.js";
|
|
476
479
|
import "./chunk-XWRJCPHC.js";
|
|
477
480
|
import {
|
|
481
|
+
CursorNotAtLineBoundaryError,
|
|
482
|
+
LargeNonUtf8TextError,
|
|
483
|
+
TextScanBudgetExceededError,
|
|
478
484
|
decodeBufferWithEncodingInfoAsync,
|
|
479
485
|
getAllGeminiMdFilenames,
|
|
486
|
+
isUtf8CompatibleEncoding,
|
|
480
487
|
isWithinRoot,
|
|
481
488
|
parseLineTolerant,
|
|
482
489
|
read
|
|
483
|
-
} from "./chunk-
|
|
490
|
+
} from "./chunk-M2F5PLOW.js";
|
|
484
491
|
import "./chunk-VGC4I5JJ.js";
|
|
485
|
-
import "./chunk-
|
|
486
|
-
import "./chunk-
|
|
487
|
-
import "./chunk-
|
|
488
|
-
import "./chunk-
|
|
492
|
+
import "./chunk-E4WHKETF.js";
|
|
493
|
+
import "./chunk-BV4QX43X.js";
|
|
494
|
+
import "./chunk-I5GNT6ZS.js";
|
|
495
|
+
import "./chunk-TFFMATHX.js";
|
|
489
496
|
import "./chunk-46UV252V.js";
|
|
490
497
|
import "./chunk-ZBVS26BY.js";
|
|
491
|
-
import "./chunk-
|
|
492
|
-
import "./chunk-
|
|
493
|
-
import "./chunk-
|
|
494
|
-
import "./chunk-
|
|
498
|
+
import "./chunk-BFHXDAR7.js";
|
|
499
|
+
import "./chunk-TYERNYH4.js";
|
|
500
|
+
import "./chunk-UH7Z7Y45.js";
|
|
501
|
+
import "./chunk-O2ZYHG33.js";
|
|
495
502
|
import "./chunk-W4RQUHY3.js";
|
|
496
|
-
import "./chunk-
|
|
503
|
+
import "./chunk-G7XXKQYS.js";
|
|
497
504
|
import {
|
|
498
505
|
FatalConfigError,
|
|
499
506
|
Storage,
|
|
500
507
|
createDebugLogger,
|
|
501
508
|
runWithoutDebugLogSession
|
|
502
|
-
} from "./chunk-
|
|
509
|
+
} from "./chunk-3RXUYQJI.js";
|
|
503
510
|
import "./chunk-VOQXFAY5.js";
|
|
511
|
+
import {
|
|
512
|
+
writeStderrLine,
|
|
513
|
+
writeStderrLineSafe
|
|
514
|
+
} from "./chunk-OWAK7LMW.js";
|
|
504
515
|
import "./chunk-75DOP5OR.js";
|
|
505
516
|
import "./chunk-DMTGGOSA.js";
|
|
506
517
|
import "./chunk-YQ3U5MUC.js";
|
|
@@ -936,7 +947,9 @@ init_esbuild_shims();
|
|
|
936
947
|
init_esbuild_shims();
|
|
937
948
|
import * as path2 from "node:path";
|
|
938
949
|
var MAX_READ_BYTES = 256 * 1024;
|
|
950
|
+
var MAX_TEXT_SCAN_BYTES = 8 * 1024 * 1024;
|
|
939
951
|
var MAX_WRITE_BYTES = 5 * 1024 * 1024;
|
|
952
|
+
var BINARY_PROBE_BYTES = 4096;
|
|
940
953
|
function shouldIgnore(absolute, boundWorkspace, ignore, kind = "file") {
|
|
941
954
|
const rel = path2.relative(boundWorkspace, absolute);
|
|
942
955
|
if (rel === "" || rel.startsWith("..")) return { ignored: false };
|
|
@@ -1089,6 +1102,64 @@ init_esbuild_shims();
|
|
|
1089
1102
|
import { createHash as createHash2, randomBytes } from "node:crypto";
|
|
1090
1103
|
import { constants as fsConstants, promises as fsp2 } from "node:fs";
|
|
1091
1104
|
import * as path4 from "node:path";
|
|
1105
|
+
|
|
1106
|
+
// packages/cli/src/serve/fs/text-cursor.ts
|
|
1107
|
+
init_esbuild_shims();
|
|
1108
|
+
var CURSOR_VERSION = 1;
|
|
1109
|
+
var MAX_TEXT_CURSOR_CHARS = 1024;
|
|
1110
|
+
function encodeTextCursor(state) {
|
|
1111
|
+
return Buffer.from(
|
|
1112
|
+
JSON.stringify({ v: CURSOR_VERSION, ...state }),
|
|
1113
|
+
"utf8"
|
|
1114
|
+
).toString("base64url");
|
|
1115
|
+
}
|
|
1116
|
+
__name(encodeTextCursor, "encodeTextCursor");
|
|
1117
|
+
function decodeTextCursor(cursor) {
|
|
1118
|
+
if (cursor.length === 0 || cursor.length > MAX_TEXT_CURSOR_CHARS) {
|
|
1119
|
+
throw new FsError(
|
|
1120
|
+
"parse_error",
|
|
1121
|
+
`cursor must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
|
|
1122
|
+
{ hint: "pass a cursor returned by a previous read" }
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
let parsed;
|
|
1126
|
+
try {
|
|
1127
|
+
parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
1128
|
+
} catch {
|
|
1129
|
+
throw new FsError("parse_error", "cursor is not a valid read cursor", {
|
|
1130
|
+
hint: "pass a cursor returned by a previous read"
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1134
|
+
throw new FsError("parse_error", "cursor is not a valid read cursor", {
|
|
1135
|
+
hint: "pass a cursor returned by a previous read"
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
const raw = parsed;
|
|
1139
|
+
const off = raw["off"];
|
|
1140
|
+
const size = raw["size"];
|
|
1141
|
+
const dev = raw["dev"];
|
|
1142
|
+
const ino = raw["ino"];
|
|
1143
|
+
if (raw["v"] !== CURSOR_VERSION || !Number.isSafeInteger(off) || off < 0 || !Number.isSafeInteger(size) || size < 0 || typeof dev !== "string" || typeof ino !== "string") {
|
|
1144
|
+
throw new FsError("parse_error", "cursor is not a valid read cursor", {
|
|
1145
|
+
hint: "pass a cursor returned by a previous read"
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
return { off, size, dev, ino };
|
|
1149
|
+
}
|
|
1150
|
+
__name(decodeTextCursor, "decodeTextCursor");
|
|
1151
|
+
function assertCursorMatchesFile(cursor, stats, path14) {
|
|
1152
|
+
if (String(stats.dev) !== cursor.dev || String(stats.ino) !== cursor.ino || stats.size < cursor.size) {
|
|
1153
|
+
throw new FsError(
|
|
1154
|
+
"hash_mismatch",
|
|
1155
|
+
`cursor no longer matches the file it was issued for: ${path14}`,
|
|
1156
|
+
{ hint: "re-read the file from the beginning to get a fresh cursor" }
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
__name(assertCursorMatchesFile, "assertCursorMatchesFile");
|
|
1161
|
+
|
|
1162
|
+
// packages/cli/src/serve/fs/workspace-file-system.ts
|
|
1092
1163
|
function createWorkspaceFileSystemFactory(deps) {
|
|
1093
1164
|
const boundWorkspaces = canonicalizeWorkspaces(deps.boundWorkspaces);
|
|
1094
1165
|
if (boundWorkspaces.length === 0) {
|
|
@@ -1227,7 +1298,19 @@ var WorkspaceFileSystemImpl = class {
|
|
|
1227
1298
|
`limit must be a positive integer, got ${opts.limit}`
|
|
1228
1299
|
);
|
|
1229
1300
|
}
|
|
1230
|
-
|
|
1301
|
+
if (opts.cursor !== void 0 && opts.line !== void 0) {
|
|
1302
|
+
throw new FsError(
|
|
1303
|
+
"parse_error",
|
|
1304
|
+
"cursor and line are mutually exclusive; a cursor already encodes where to resume"
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
if (opts.maxBytes !== void 0 && (!Number.isSafeInteger(opts.maxBytes) || opts.maxBytes < 1 || opts.maxBytes > MAX_READ_BYTES)) {
|
|
1308
|
+
throw new FsError(
|
|
1309
|
+
"parse_error",
|
|
1310
|
+
`maxBytes must be a positive integer in [1, ${MAX_READ_BYTES}], got ${opts.maxBytes}`
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
const snapshot = await readTextFromResolvedFile(p, opts, this.deps.lowFs);
|
|
1231
1314
|
this.deps.generationGuard?.assertOpen();
|
|
1232
1315
|
const ignoreVerdict = this.ignoreVerdict(p, "file");
|
|
1233
1316
|
const meta = snapshot.meta;
|
|
@@ -1882,7 +1965,7 @@ function validateWriteTextAtomicOptions(opts) {
|
|
|
1882
1965
|
}
|
|
1883
1966
|
}
|
|
1884
1967
|
__name(validateWriteTextAtomicOptions, "validateWriteTextAtomicOptions");
|
|
1885
|
-
async function
|
|
1968
|
+
async function readTextFromResolvedFile(p, opts, lowFs) {
|
|
1886
1969
|
const pre = await fsp2.lstat(p);
|
|
1887
1970
|
if (pre.isSymbolicLink()) {
|
|
1888
1971
|
throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
|
|
@@ -1892,12 +1975,32 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
|
|
|
1892
1975
|
if (!pre.isFile()) {
|
|
1893
1976
|
throw new FsError("parse_error", `path is not a regular file: ${p}`);
|
|
1894
1977
|
}
|
|
1978
|
+
if (opts.cursor !== void 0) {
|
|
1979
|
+
return readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs);
|
|
1980
|
+
}
|
|
1981
|
+
const wantsWindow = opts.limit !== void 0 || opts.maxBytes !== void 0 || opts.line !== void 0;
|
|
1982
|
+
if (pre.size > MAX_READ_BYTES && wantsWindow) {
|
|
1983
|
+
return readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs);
|
|
1984
|
+
}
|
|
1985
|
+
return readTextSnapshotFromResolvedFile(p, opts, pre);
|
|
1986
|
+
}
|
|
1987
|
+
__name(readTextFromResolvedFile, "readTextFromResolvedFile");
|
|
1988
|
+
async function readTextSnapshotFromResolvedFile(p, opts = {}, knownPre) {
|
|
1989
|
+
const pre = knownPre ?? await fsp2.lstat(p);
|
|
1990
|
+
if (pre.isSymbolicLink()) {
|
|
1991
|
+
throw new FsError("symlink_escape", `path is a symlink: ${p}`, {
|
|
1992
|
+
hint: "re-resolve the target file instead of reading through a link"
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
if (!pre.isFile()) {
|
|
1996
|
+
throw new FsError("parse_error", `path is not a regular file: ${p}`);
|
|
1997
|
+
}
|
|
1895
1998
|
if (pre.size > MAX_READ_BYTES) {
|
|
1896
1999
|
throw new FsError(
|
|
1897
2000
|
"file_too_large",
|
|
1898
2001
|
`file of ${pre.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
|
|
1899
2002
|
{
|
|
1900
|
-
hint: "use readBytes for explicit byte-windowed access
|
|
2003
|
+
hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
|
|
1901
2004
|
}
|
|
1902
2005
|
);
|
|
1903
2006
|
}
|
|
@@ -1914,8 +2017,10 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
|
|
|
1914
2017
|
startLineIndex,
|
|
1915
2018
|
opts.limit ?? Number.POSITIVE_INFINITY
|
|
1916
2019
|
);
|
|
1917
|
-
const
|
|
2020
|
+
const maxOutputBytes = opts.maxBytes ?? MAX_READ_BYTES;
|
|
2021
|
+
const sizeOutcome = enforceReadSize(raw.length, maxOutputBytes);
|
|
1918
2022
|
let content = sliced.content;
|
|
2023
|
+
let byteTruncated = false;
|
|
1919
2024
|
const meta = {
|
|
1920
2025
|
encoding: decoded.encoding,
|
|
1921
2026
|
bom: decoded.bom,
|
|
@@ -1924,22 +2029,243 @@ async function readTextSnapshotFromResolvedFile(p, opts = {}) {
|
|
|
1924
2029
|
originalLineCount: sliced.originalLineCount,
|
|
1925
2030
|
hash: hashBuffer(raw)
|
|
1926
2031
|
};
|
|
2032
|
+
const output = Buffer.from(content, "utf-8");
|
|
2033
|
+
if (output.length > maxOutputBytes) {
|
|
2034
|
+
content = safeUtf8Truncate(output, maxOutputBytes).toString("utf-8");
|
|
2035
|
+
meta.lineEnding = detectLineEnding(content);
|
|
2036
|
+
meta.truncated = true;
|
|
2037
|
+
byteTruncated = true;
|
|
2038
|
+
}
|
|
1927
2039
|
if (sizeOutcome.truncated) {
|
|
1928
|
-
const buf = Buffer.from(content, "utf-8");
|
|
1929
|
-
if (buf.length > sizeOutcome.bytesToRead) {
|
|
1930
|
-
content = safeUtf8Truncate(buf, sizeOutcome.bytesToRead).toString(
|
|
1931
|
-
"utf-8"
|
|
1932
|
-
);
|
|
1933
|
-
meta.lineEnding = detectLineEnding(content);
|
|
1934
|
-
}
|
|
1935
2040
|
meta.truncated = true;
|
|
1936
2041
|
}
|
|
1937
2042
|
if (opts.limit !== void 0 && Number.isFinite(opts.limit) && sliced.originalLineCount > opts.limit + startLineIndex) {
|
|
1938
2043
|
meta.truncated = true;
|
|
1939
2044
|
}
|
|
2045
|
+
const pageableLineCount = sliced.originalLineCount - (decoded.content.endsWith("\n") ? 1 : 0);
|
|
2046
|
+
meta.hasMore = byteTruncated || sliced.endLine < pageableLineCount;
|
|
2047
|
+
const bomBytes = decoded.bom ? 3 : 0;
|
|
2048
|
+
const decodedBytesMatchSource = isUtf8CompatibleEncoding(decoded.encoding) && Buffer.from(decoded.content, "utf-8").equals(raw.subarray(bomBytes));
|
|
2049
|
+
if (meta.hasMore && !byteTruncated && decodedBytesMatchSource) {
|
|
2050
|
+
const startByte = bomBytes + sliced.startByteOffset;
|
|
2051
|
+
const contentBytes = Buffer.byteLength(content, "utf-8");
|
|
2052
|
+
const nextOffset = startByte + contentBytes + 1;
|
|
2053
|
+
if (nextOffset < raw.length) {
|
|
2054
|
+
meta.nextCursor = encodeTextCursor({
|
|
2055
|
+
off: nextOffset,
|
|
2056
|
+
size: raw.length,
|
|
2057
|
+
dev: String(pre.dev),
|
|
2058
|
+
ino: String(pre.ino)
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
1940
2062
|
return { content, meta };
|
|
1941
2063
|
}
|
|
1942
2064
|
__name(readTextSnapshotFromResolvedFile, "readTextSnapshotFromResolvedFile");
|
|
2065
|
+
function assertStreamWindowStable(before, after, p, reason) {
|
|
2066
|
+
const beforeSize = toBigInt(before.size);
|
|
2067
|
+
const afterSize = toBigInt(after.size);
|
|
2068
|
+
if (afterSize < beforeSize || afterSize === beforeSize && (after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs)) {
|
|
2069
|
+
throw new FsError("hash_mismatch", `${reason}: ${p}`, {
|
|
2070
|
+
hint: "retry after re-reading the latest file"
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
__name(assertStreamWindowStable, "assertStreamWindowStable");
|
|
2075
|
+
async function readTextCursorWindowFromResolvedFile(p, pre, opts, lowFs) {
|
|
2076
|
+
const cursor = decodeTextCursor(opts.cursor);
|
|
2077
|
+
const fh = await fsp2.open(p, "r");
|
|
2078
|
+
let opened;
|
|
2079
|
+
let afterRead;
|
|
2080
|
+
let window;
|
|
2081
|
+
let primaryError;
|
|
2082
|
+
let hasPrimaryError = false;
|
|
2083
|
+
try {
|
|
2084
|
+
opened = await fh.stat();
|
|
2085
|
+
assertSameFile(pre, opened, p, "read");
|
|
2086
|
+
assertStreamWindowStable(pre, opened, p, "file changed before read");
|
|
2087
|
+
assertCursorMatchesFile(cursor, opened, p);
|
|
2088
|
+
try {
|
|
2089
|
+
const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
|
|
2090
|
+
if (probe.length > 0) {
|
|
2091
|
+
const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
|
|
2092
|
+
if (looksBinary(probe.subarray(0, bytesRead))) {
|
|
2093
|
+
throw new FsError("binary_file", `binary file: ${p}`, {
|
|
2094
|
+
hint: "use readBytes for binary content"
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
window = await lowFs.readTextCursorFromHandle({
|
|
2099
|
+
fileHandle: fh,
|
|
2100
|
+
startOffset: cursor.off,
|
|
2101
|
+
fileSize: opened.size,
|
|
2102
|
+
maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
|
|
2103
|
+
maxSnapBytes: MAX_TEXT_SCAN_BYTES,
|
|
2104
|
+
...opts.limit !== void 0 ? { limit: opts.limit } : {}
|
|
2105
|
+
});
|
|
2106
|
+
} catch (err) {
|
|
2107
|
+
hasPrimaryError = true;
|
|
2108
|
+
primaryError = err;
|
|
2109
|
+
}
|
|
2110
|
+
afterRead = await fh.stat();
|
|
2111
|
+
} finally {
|
|
2112
|
+
await fh.close();
|
|
2113
|
+
}
|
|
2114
|
+
if (opened === void 0 || afterRead === void 0) {
|
|
2115
|
+
throw new FsError("internal_error", `failed to stat opened file: ${p}`);
|
|
2116
|
+
}
|
|
2117
|
+
const post = await fsp2.lstat(p);
|
|
2118
|
+
if (post.isSymbolicLink()) {
|
|
2119
|
+
throw new FsError(
|
|
2120
|
+
"symlink_escape",
|
|
2121
|
+
`path was replaced with a symlink during read: ${p}`,
|
|
2122
|
+
{ hint: "TOCTOU swap detected via post-read lstat" }
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
assertSameFile(opened, afterRead, p, "read");
|
|
2126
|
+
assertStreamWindowStable(opened, afterRead, p, "file changed during read");
|
|
2127
|
+
assertSameFile(opened, post, p, "read");
|
|
2128
|
+
assertStreamWindowStable(opened, post, p, "file changed during read");
|
|
2129
|
+
if (hasPrimaryError) {
|
|
2130
|
+
if (primaryError instanceof LargeNonUtf8TextError) {
|
|
2131
|
+
throw new FsError("binary_file", primaryError.message, {
|
|
2132
|
+
cause: primaryError,
|
|
2133
|
+
hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
if (primaryError instanceof CursorNotAtLineBoundaryError) {
|
|
2137
|
+
throw new FsError("parse_error", primaryError.message, {
|
|
2138
|
+
cause: primaryError,
|
|
2139
|
+
hint: "pass a cursor returned by a previous read"
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
throw primaryError;
|
|
2143
|
+
}
|
|
2144
|
+
if (window === void 0) {
|
|
2145
|
+
throw new FsError(
|
|
2146
|
+
"internal_error",
|
|
2147
|
+
`cursor text read returned no result: ${p}`
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
2150
|
+
const meta = {
|
|
2151
|
+
encoding: window.encoding,
|
|
2152
|
+
bom: window.bom,
|
|
2153
|
+
lineEnding: window.lineEnding,
|
|
2154
|
+
sizeBytes: opened.size,
|
|
2155
|
+
truncated: true,
|
|
2156
|
+
hasMore: window.nextOffset !== void 0 || window.truncatedByBytes === true
|
|
2157
|
+
};
|
|
2158
|
+
if (window.nextOffset !== void 0) {
|
|
2159
|
+
meta.nextCursor = encodeTextCursor({
|
|
2160
|
+
off: window.nextOffset,
|
|
2161
|
+
size: opened.size,
|
|
2162
|
+
dev: String(opened.dev),
|
|
2163
|
+
ino: String(opened.ino)
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
return { content: window.content, meta };
|
|
2167
|
+
}
|
|
2168
|
+
__name(readTextCursorWindowFromResolvedFile, "readTextCursorWindowFromResolvedFile");
|
|
2169
|
+
async function readLargeTextWindowFromResolvedFile(p, pre, opts, lowFs) {
|
|
2170
|
+
const fh = await fsp2.open(p, "r");
|
|
2171
|
+
let opened;
|
|
2172
|
+
let afterRead;
|
|
2173
|
+
let result;
|
|
2174
|
+
let primaryError;
|
|
2175
|
+
let hasPrimaryError = false;
|
|
2176
|
+
try {
|
|
2177
|
+
opened = await fh.stat();
|
|
2178
|
+
assertSameFile(pre, opened, p, "read");
|
|
2179
|
+
assertStreamWindowStable(pre, opened, p, "file changed before read");
|
|
2180
|
+
try {
|
|
2181
|
+
const probe = Buffer.alloc(Math.min(BINARY_PROBE_BYTES, opened.size));
|
|
2182
|
+
if (probe.length > 0) {
|
|
2183
|
+
const { bytesRead } = await fh.read(probe, 0, probe.length, 0);
|
|
2184
|
+
if (looksBinary(probe.subarray(0, bytesRead))) {
|
|
2185
|
+
throw new FsError("binary_file", `binary file: ${p}`, {
|
|
2186
|
+
hint: "use readBytes for binary content"
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
result = await lowFs.readTextFileFromHandle({
|
|
2191
|
+
fileHandle: fh,
|
|
2192
|
+
fileSize: opened.size,
|
|
2193
|
+
limit: opts.limit ?? Number.POSITIVE_INFINITY,
|
|
2194
|
+
line: opts.line !== void 0 ? opts.line - 1 : 0,
|
|
2195
|
+
maxOutputBytes: opts.maxBytes ?? MAX_READ_BYTES,
|
|
2196
|
+
maxScanBytes: MAX_TEXT_SCAN_BYTES
|
|
2197
|
+
});
|
|
2198
|
+
} catch (err) {
|
|
2199
|
+
hasPrimaryError = true;
|
|
2200
|
+
primaryError = err;
|
|
2201
|
+
}
|
|
2202
|
+
afterRead = await fh.stat();
|
|
2203
|
+
} finally {
|
|
2204
|
+
await fh.close();
|
|
2205
|
+
}
|
|
2206
|
+
if (opened === void 0 || afterRead === void 0) {
|
|
2207
|
+
throw new FsError("internal_error", `failed to stat opened file: ${p}`);
|
|
2208
|
+
}
|
|
2209
|
+
const post = await fsp2.lstat(p);
|
|
2210
|
+
if (post.isSymbolicLink()) {
|
|
2211
|
+
throw new FsError(
|
|
2212
|
+
"symlink_escape",
|
|
2213
|
+
`path was replaced with a symlink during read: ${p}`,
|
|
2214
|
+
{ hint: "TOCTOU swap detected via post-read lstat" }
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
assertSameFile(opened, afterRead, p, "read");
|
|
2218
|
+
assertStreamWindowStable(opened, afterRead, p, "file changed during read");
|
|
2219
|
+
assertSameFile(opened, post, p, "read");
|
|
2220
|
+
assertStreamWindowStable(opened, post, p, "file changed during read");
|
|
2221
|
+
if (hasPrimaryError) {
|
|
2222
|
+
if (primaryError instanceof LargeNonUtf8TextError) {
|
|
2223
|
+
throw new FsError("binary_file", primaryError.message, {
|
|
2224
|
+
cause: primaryError,
|
|
2225
|
+
hint: "convert the file to UTF-8, or use readBytes for the raw bytes"
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
if (primaryError instanceof TextScanBudgetExceededError) {
|
|
2229
|
+
throw new FsError("file_too_large", primaryError.message, {
|
|
2230
|
+
cause: primaryError,
|
|
2231
|
+
hint: `line offsets are resolved by scanning from byte 0 and stop after ${MAX_TEXT_SCAN_BYTES} bytes; page with the cursor from a shallower read to reach this offset in O(1), or use readBytes for raw bytes`
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
throw primaryError;
|
|
2235
|
+
}
|
|
2236
|
+
if (result === void 0) {
|
|
2237
|
+
throw new FsError(
|
|
2238
|
+
"internal_error",
|
|
2239
|
+
`large text range read returned no result: ${p}`
|
|
2240
|
+
);
|
|
2241
|
+
}
|
|
2242
|
+
const content = result.content;
|
|
2243
|
+
const readMeta = result._meta;
|
|
2244
|
+
const meta = {
|
|
2245
|
+
encoding: readMeta?.encoding,
|
|
2246
|
+
bom: readMeta?.bom,
|
|
2247
|
+
lineEnding: readMeta?.lineEnding ?? detectLineEnding(content),
|
|
2248
|
+
// Size as of `open`, not as of now: it describes the snapshot the
|
|
2249
|
+
// returned window was cut from. A file that grew during the read
|
|
2250
|
+
// reports the smaller, consistent number.
|
|
2251
|
+
sizeBytes: opened.size,
|
|
2252
|
+
truncated: true,
|
|
2253
|
+
hasMore: readMeta?.nextByteOffset !== void 0 || readMeta?.truncatedByBytes === true
|
|
2254
|
+
};
|
|
2255
|
+
if (readMeta?.nextByteOffset !== void 0) {
|
|
2256
|
+
meta.nextCursor = encodeTextCursor({
|
|
2257
|
+
off: readMeta.nextByteOffset,
|
|
2258
|
+
size: opened.size,
|
|
2259
|
+
dev: String(opened.dev),
|
|
2260
|
+
ino: String(opened.ino)
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2263
|
+
if (readMeta?.originalLineCountExact === true && readMeta?.originalLineCount !== void 0) {
|
|
2264
|
+
meta.originalLineCount = readMeta.originalLineCount;
|
|
2265
|
+
}
|
|
2266
|
+
return { content, meta };
|
|
2267
|
+
}
|
|
2268
|
+
__name(readLargeTextWindowFromResolvedFile, "readLargeTextWindowFromResolvedFile");
|
|
1943
2269
|
async function readStableRegularFileBuffer(p, pre) {
|
|
1944
2270
|
const fh = await fsp2.open(p, "r");
|
|
1945
2271
|
let opened;
|
|
@@ -1951,7 +2277,7 @@ async function readStableRegularFileBuffer(p, pre) {
|
|
|
1951
2277
|
"file_too_large",
|
|
1952
2278
|
`file of ${opened.size} bytes exceeds read cap of ${MAX_READ_BYTES} bytes`,
|
|
1953
2279
|
{
|
|
1954
|
-
hint: "use readBytes for explicit byte-windowed access
|
|
2280
|
+
hint: "use a finite line limit for large UTF-8 text, or readBytes for explicit byte-windowed access"
|
|
1955
2281
|
}
|
|
1956
2282
|
);
|
|
1957
2283
|
}
|
|
@@ -1987,9 +2313,15 @@ function sliceDecodedText(content, startLine, limit) {
|
|
|
1987
2313
|
const originalLineCount = lines.length;
|
|
1988
2314
|
const endLine = Math.min(startLine + limit, originalLineCount);
|
|
1989
2315
|
const actualStartLine = Math.min(startLine, originalLineCount);
|
|
2316
|
+
let startByteOffset = 0;
|
|
2317
|
+
for (let i = 0; i < actualStartLine; i++) {
|
|
2318
|
+
startByteOffset += Buffer.byteLength(lines[i], "utf-8") + 1;
|
|
2319
|
+
}
|
|
1990
2320
|
return {
|
|
1991
2321
|
content: lines.slice(actualStartLine, endLine).join("\n"),
|
|
1992
|
-
originalLineCount
|
|
2322
|
+
originalLineCount,
|
|
2323
|
+
startByteOffset,
|
|
2324
|
+
endLine
|
|
1993
2325
|
};
|
|
1994
2326
|
}
|
|
1995
2327
|
__name(sliceDecodedText, "sliceDecodedText");
|
|
@@ -2780,13 +3112,29 @@ async function handleGetFile(req, res, deps) {
|
|
|
2780
3112
|
});
|
|
2781
3113
|
return;
|
|
2782
3114
|
}
|
|
3115
|
+
const rawCursor = req.query["cursor"];
|
|
3116
|
+
if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
|
|
3117
|
+
applyReadHeaders(res);
|
|
3118
|
+
res.status(400).json({
|
|
3119
|
+
errorKind: "parse_error",
|
|
3120
|
+
error: `\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`,
|
|
3121
|
+
status: 400
|
|
3122
|
+
});
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
3125
|
+
const cursor = rawCursor;
|
|
2783
3126
|
const fs6 = factory.forRequest({
|
|
2784
3127
|
originatorClientId: clientId ?? void 0,
|
|
2785
3128
|
route: ROUTE2
|
|
2786
3129
|
});
|
|
2787
3130
|
try {
|
|
2788
3131
|
const resolved = await fs6.resolve(queryPath, "read");
|
|
2789
|
-
const out = await fs6.readText(resolved, {
|
|
3132
|
+
const out = await fs6.readText(resolved, {
|
|
3133
|
+
maxBytes,
|
|
3134
|
+
line,
|
|
3135
|
+
limit,
|
|
3136
|
+
cursor
|
|
3137
|
+
});
|
|
2790
3138
|
const returnedBytes = Buffer.byteLength(out.content, "utf-8");
|
|
2791
3139
|
applyReadHeaders(res);
|
|
2792
3140
|
res.status(200).json({
|
|
@@ -2801,7 +3149,9 @@ async function handleGetFile(req, res, deps) {
|
|
|
2801
3149
|
truncated: out.meta.truncated === true,
|
|
2802
3150
|
hash: out.meta.hash,
|
|
2803
3151
|
matchedIgnore: out.meta.matchedIgnore ?? null,
|
|
2804
|
-
originalLineCount: out.meta.originalLineCount ?? null
|
|
3152
|
+
originalLineCount: out.meta.originalLineCount ?? null,
|
|
3153
|
+
nextCursor: out.meta.nextCursor ?? null,
|
|
3154
|
+
hasMore: out.meta.hasMore === true
|
|
2805
3155
|
});
|
|
2806
3156
|
} catch (err) {
|
|
2807
3157
|
sendFsError(res, err, ROUTE2);
|
|
@@ -4506,11 +4856,16 @@ async function validateManagedMemoryAvailable(deps, res, kind, assertGenerationO
|
|
|
4506
4856
|
}
|
|
4507
4857
|
}
|
|
4508
4858
|
__name(validateManagedMemoryAvailable, "validateManagedMemoryAvailable");
|
|
4509
|
-
function
|
|
4859
|
+
function mountWorkspaceMemoryRememberRoutesAt(app, basePath, mutate, resolveRouteDeps) {
|
|
4510
4860
|
app.post(
|
|
4511
|
-
|
|
4512
|
-
|
|
4861
|
+
`${basePath}/remember`,
|
|
4862
|
+
mutate({ strict: true }),
|
|
4513
4863
|
async (req, res) => {
|
|
4864
|
+
const deps = resolveRouteDeps(req, res, {
|
|
4865
|
+
creating: true,
|
|
4866
|
+
kind: "remember"
|
|
4867
|
+
});
|
|
4868
|
+
if (!deps) return;
|
|
4514
4869
|
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
4515
4870
|
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4516
4871
|
if (!requireTrustedWorkspace(deps, res)) return;
|
|
@@ -4574,9 +4929,14 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
|
|
|
4574
4929
|
}
|
|
4575
4930
|
);
|
|
4576
4931
|
app.get(
|
|
4577
|
-
|
|
4578
|
-
|
|
4932
|
+
`${basePath}/remember/:taskId`,
|
|
4933
|
+
mutate({ strict: true }),
|
|
4579
4934
|
(req, res) => {
|
|
4935
|
+
const deps = resolveRouteDeps(req, res, {
|
|
4936
|
+
creating: false,
|
|
4937
|
+
kind: "remember"
|
|
4938
|
+
});
|
|
4939
|
+
if (!deps) return;
|
|
4580
4940
|
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
4581
4941
|
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4582
4942
|
if (!requireTrustedWorkspace(deps, res)) return;
|
|
@@ -4597,64 +4957,70 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
|
|
|
4597
4957
|
res.status(200).json(task);
|
|
4598
4958
|
}
|
|
4599
4959
|
);
|
|
4600
|
-
app.post(
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
}
|
|
4617
|
-
|
|
4618
|
-
res.status(400).json({
|
|
4619
|
-
error: `\`query\` exceeds the ${MAX_REMEMBER_CONTENT_BYTES}-byte limit`,
|
|
4620
|
-
code: "invalid_query"
|
|
4621
|
-
});
|
|
4622
|
-
return;
|
|
4623
|
-
}
|
|
4624
|
-
const originatorClientId = validateOriginatorClientId(deps, req, res);
|
|
4625
|
-
if (originatorClientId === null) return;
|
|
4626
|
-
if (!await validateManagedMemoryAvailable(
|
|
4627
|
-
deps,
|
|
4628
|
-
res,
|
|
4629
|
-
"forget",
|
|
4630
|
-
assertGenerationOpen
|
|
4631
|
-
))
|
|
4632
|
-
return;
|
|
4633
|
-
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4634
|
-
try {
|
|
4635
|
-
const task = deps.lane.enqueueForget({
|
|
4636
|
-
query: trimmedQuery,
|
|
4637
|
-
...originatorClientId ? { originatorClientId } : {},
|
|
4638
|
-
...assertGenerationOpen ? { assertGenerationOpen } : {}
|
|
4639
|
-
});
|
|
4640
|
-
res.status(202).json(task);
|
|
4641
|
-
} catch (err) {
|
|
4642
|
-
const code = workspaceMemoryFailureCode(
|
|
4643
|
-
err,
|
|
4644
|
-
"forget_failed",
|
|
4645
|
-
logWorkspaceMemoryExtractionError
|
|
4646
|
-
);
|
|
4647
|
-
res.status(publicErrorStatus(code)).json({
|
|
4648
|
-
error: publicErrorMessage(code, "forget"),
|
|
4649
|
-
code
|
|
4650
|
-
});
|
|
4651
|
-
}
|
|
4960
|
+
app.post(`${basePath}/forget`, mutate({ strict: true }), async (req, res) => {
|
|
4961
|
+
const deps = resolveRouteDeps(req, res, {
|
|
4962
|
+
creating: true,
|
|
4963
|
+
kind: "forget"
|
|
4964
|
+
});
|
|
4965
|
+
if (!deps) return;
|
|
4966
|
+
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
4967
|
+
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4968
|
+
if (!requireTrustedWorkspace(deps, res)) return;
|
|
4969
|
+
const body = deps.safeBody(req);
|
|
4970
|
+
const query = body["query"];
|
|
4971
|
+
const trimmedQuery = typeof query === "string" ? query.trim() : "";
|
|
4972
|
+
if (!trimmedQuery) {
|
|
4973
|
+
res.status(400).json({
|
|
4974
|
+
error: "`query` must be a non-empty string",
|
|
4975
|
+
code: "invalid_query"
|
|
4976
|
+
});
|
|
4977
|
+
return;
|
|
4652
4978
|
}
|
|
4653
|
-
|
|
4979
|
+
if (Buffer.byteLength(trimmedQuery, "utf8") > MAX_REMEMBER_CONTENT_BYTES) {
|
|
4980
|
+
res.status(400).json({
|
|
4981
|
+
error: `\`query\` exceeds the ${MAX_REMEMBER_CONTENT_BYTES}-byte limit`,
|
|
4982
|
+
code: "invalid_query"
|
|
4983
|
+
});
|
|
4984
|
+
return;
|
|
4985
|
+
}
|
|
4986
|
+
const originatorClientId = validateOriginatorClientId(deps, req, res);
|
|
4987
|
+
if (originatorClientId === null) return;
|
|
4988
|
+
if (!await validateManagedMemoryAvailable(
|
|
4989
|
+
deps,
|
|
4990
|
+
res,
|
|
4991
|
+
"forget",
|
|
4992
|
+
assertGenerationOpen
|
|
4993
|
+
))
|
|
4994
|
+
return;
|
|
4995
|
+
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4996
|
+
try {
|
|
4997
|
+
const task = deps.lane.enqueueForget({
|
|
4998
|
+
query: trimmedQuery,
|
|
4999
|
+
...originatorClientId ? { originatorClientId } : {},
|
|
5000
|
+
...assertGenerationOpen ? { assertGenerationOpen } : {}
|
|
5001
|
+
});
|
|
5002
|
+
res.status(202).json(task);
|
|
5003
|
+
} catch (err) {
|
|
5004
|
+
const code = workspaceMemoryFailureCode(
|
|
5005
|
+
err,
|
|
5006
|
+
"forget_failed",
|
|
5007
|
+
logWorkspaceMemoryExtractionError
|
|
5008
|
+
);
|
|
5009
|
+
res.status(publicErrorStatus(code)).json({
|
|
5010
|
+
error: publicErrorMessage(code, "forget"),
|
|
5011
|
+
code
|
|
5012
|
+
});
|
|
5013
|
+
}
|
|
5014
|
+
});
|
|
4654
5015
|
app.get(
|
|
4655
|
-
|
|
4656
|
-
|
|
5016
|
+
`${basePath}/forget/:taskId`,
|
|
5017
|
+
mutate({ strict: true }),
|
|
4657
5018
|
(req, res) => {
|
|
5019
|
+
const deps = resolveRouteDeps(req, res, {
|
|
5020
|
+
creating: false,
|
|
5021
|
+
kind: "forget"
|
|
5022
|
+
});
|
|
5023
|
+
if (!deps) return;
|
|
4658
5024
|
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
4659
5025
|
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4660
5026
|
if (!requireTrustedWorkspace(deps, res)) return;
|
|
@@ -4675,68 +5041,88 @@ function mountWorkspaceMemoryRememberRoutes(app, deps) {
|
|
|
4675
5041
|
res.status(200).json(task);
|
|
4676
5042
|
}
|
|
4677
5043
|
);
|
|
4678
|
-
app.post(
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
}
|
|
4700
|
-
|
|
4701
|
-
}
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
error: publicErrorMessage(code, "dream"),
|
|
4709
|
-
code
|
|
4710
|
-
});
|
|
4711
|
-
}
|
|
4712
|
-
}
|
|
4713
|
-
);
|
|
4714
|
-
app.get(
|
|
4715
|
-
"/workspace/memory/dream/:taskId",
|
|
4716
|
-
deps.mutate({ strict: true }),
|
|
4717
|
-
(req, res) => {
|
|
4718
|
-
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
4719
|
-
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
4720
|
-
if (!requireTrustedWorkspace(deps, res)) return;
|
|
4721
|
-
const requesterClientId = validateOriginatorClientId(deps, req, res);
|
|
4722
|
-
if (requesterClientId === null) return;
|
|
4723
|
-
const task = deps.lane.get(
|
|
4724
|
-
req.params["taskId"],
|
|
4725
|
-
requesterClientId,
|
|
4726
|
-
"dream"
|
|
5044
|
+
app.post(`${basePath}/dream`, mutate({ strict: true }), async (req, res) => {
|
|
5045
|
+
const deps = resolveRouteDeps(req, res, {
|
|
5046
|
+
creating: true,
|
|
5047
|
+
kind: "dream"
|
|
5048
|
+
});
|
|
5049
|
+
if (!deps) return;
|
|
5050
|
+
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
5051
|
+
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
5052
|
+
if (!requireTrustedWorkspace(deps, res)) return;
|
|
5053
|
+
const originatorClientId = validateOriginatorClientId(deps, req, res);
|
|
5054
|
+
if (originatorClientId === null) return;
|
|
5055
|
+
if (!await validateManagedMemoryAvailable(
|
|
5056
|
+
deps,
|
|
5057
|
+
res,
|
|
5058
|
+
"dream",
|
|
5059
|
+
assertGenerationOpen
|
|
5060
|
+
))
|
|
5061
|
+
return;
|
|
5062
|
+
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
5063
|
+
try {
|
|
5064
|
+
const task = deps.lane.enqueueDream({
|
|
5065
|
+
...originatorClientId ? { originatorClientId } : {},
|
|
5066
|
+
...assertGenerationOpen ? { assertGenerationOpen } : {}
|
|
5067
|
+
});
|
|
5068
|
+
res.status(202).json(task);
|
|
5069
|
+
} catch (err) {
|
|
5070
|
+
const code = workspaceMemoryFailureCode(
|
|
5071
|
+
err,
|
|
5072
|
+
"dream_failed",
|
|
5073
|
+
logWorkspaceMemoryExtractionError
|
|
4727
5074
|
);
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
5075
|
+
res.status(publicErrorStatus(code)).json({
|
|
5076
|
+
error: publicErrorMessage(code, "dream"),
|
|
5077
|
+
code
|
|
5078
|
+
});
|
|
5079
|
+
}
|
|
5080
|
+
});
|
|
5081
|
+
app.get(`${basePath}/dream/:taskId`, mutate({ strict: true }), (req, res) => {
|
|
5082
|
+
const deps = resolveRouteDeps(req, res, {
|
|
5083
|
+
creating: false,
|
|
5084
|
+
kind: "dream"
|
|
5085
|
+
});
|
|
5086
|
+
if (!deps) return;
|
|
5087
|
+
const assertGenerationOpen = deps.captureGenerationAssertion?.();
|
|
5088
|
+
if (!requireOpenGeneration(assertGenerationOpen, res)) return;
|
|
5089
|
+
if (!requireTrustedWorkspace(deps, res)) return;
|
|
5090
|
+
const requesterClientId = validateOriginatorClientId(deps, req, res);
|
|
5091
|
+
if (requesterClientId === null) return;
|
|
5092
|
+
const task = deps.lane.get(
|
|
5093
|
+
req.params["taskId"],
|
|
5094
|
+
requesterClientId,
|
|
5095
|
+
"dream"
|
|
5096
|
+
);
|
|
5097
|
+
if (!task) {
|
|
5098
|
+
res.status(404).json({
|
|
5099
|
+
error: "Workspace memory dream task not found",
|
|
5100
|
+
code: "dream_task_not_found"
|
|
5101
|
+
});
|
|
5102
|
+
return;
|
|
4736
5103
|
}
|
|
5104
|
+
res.status(200).json(task);
|
|
5105
|
+
});
|
|
5106
|
+
}
|
|
5107
|
+
__name(mountWorkspaceMemoryRememberRoutesAt, "mountWorkspaceMemoryRememberRoutesAt");
|
|
5108
|
+
function mountWorkspaceMemoryRememberRoutes(app, deps) {
|
|
5109
|
+
mountWorkspaceMemoryRememberRoutesAt(
|
|
5110
|
+
app,
|
|
5111
|
+
"/workspace/memory",
|
|
5112
|
+
deps.mutate,
|
|
5113
|
+
() => deps
|
|
4737
5114
|
);
|
|
4738
5115
|
}
|
|
4739
5116
|
__name(mountWorkspaceMemoryRememberRoutes, "mountWorkspaceMemoryRememberRoutes");
|
|
5117
|
+
function mountWorkspaceQualifiedMemoryRememberRoutes(app, deps) {
|
|
5118
|
+
mountWorkspaceMemoryRememberRoutesAt(
|
|
5119
|
+
app,
|
|
5120
|
+
"/workspaces/:workspace/memory",
|
|
5121
|
+
deps.mutate,
|
|
5122
|
+
deps.resolveRouteDeps
|
|
5123
|
+
);
|
|
5124
|
+
}
|
|
5125
|
+
__name(mountWorkspaceQualifiedMemoryRememberRoutes, "mountWorkspaceQualifiedMemoryRememberRoutes");
|
|
4740
5126
|
|
|
4741
5127
|
// packages/cli/src/serve/workspace-memory.ts
|
|
4742
5128
|
init_esbuild_shims();
|
|
@@ -6851,18 +7237,34 @@ async function removeTasksForSessions(projectRoot, sessionIds) {
|
|
|
6851
7237
|
__name(removeTasksForSessions, "removeTasksForSessions");
|
|
6852
7238
|
|
|
6853
7239
|
// packages/cli/src/serve/server/session-archive.ts
|
|
7240
|
+
var DaemonDrainingError = class extends Error {
|
|
7241
|
+
static {
|
|
7242
|
+
__name(this, "DaemonDrainingError");
|
|
7243
|
+
}
|
|
7244
|
+
name = "DaemonDrainingError";
|
|
7245
|
+
code = "daemon_draining";
|
|
7246
|
+
constructor() {
|
|
7247
|
+
super("The daemon is draining and no longer accepts session maintenance.");
|
|
7248
|
+
}
|
|
7249
|
+
};
|
|
6854
7250
|
var SessionArchiveCoordinator = class {
|
|
6855
7251
|
static {
|
|
6856
7252
|
__name(this, "SessionArchiveCoordinator");
|
|
6857
7253
|
}
|
|
6858
7254
|
exclusive = /* @__PURE__ */ new Set();
|
|
6859
7255
|
shared = /* @__PURE__ */ new Map();
|
|
7256
|
+
maintenanceSealed = false;
|
|
7257
|
+
activeMaintenance = 0;
|
|
7258
|
+
maintenanceDrain;
|
|
6860
7259
|
assertNotTransitioning(sessionId) {
|
|
6861
7260
|
if (this.exclusive.has(sessionId)) {
|
|
6862
7261
|
throw new SessionArchivingError(sessionId);
|
|
6863
7262
|
}
|
|
6864
7263
|
}
|
|
6865
7264
|
async runExclusiveMany(sessionIds, fn) {
|
|
7265
|
+
if (this.maintenanceSealed) {
|
|
7266
|
+
throw new DaemonDrainingError();
|
|
7267
|
+
}
|
|
6866
7268
|
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
6867
7269
|
for (const sessionId of uniqueSessionIds) {
|
|
6868
7270
|
this.assertNotTransitioning(sessionId);
|
|
@@ -6873,14 +7275,34 @@ var SessionArchiveCoordinator = class {
|
|
|
6873
7275
|
for (const sessionId of uniqueSessionIds) {
|
|
6874
7276
|
this.exclusive.add(sessionId);
|
|
6875
7277
|
}
|
|
7278
|
+
this.activeMaintenance++;
|
|
6876
7279
|
try {
|
|
6877
7280
|
return await fn();
|
|
6878
7281
|
} finally {
|
|
6879
7282
|
for (const sessionId of uniqueSessionIds) {
|
|
6880
7283
|
this.exclusive.delete(sessionId);
|
|
6881
7284
|
}
|
|
7285
|
+
this.activeMaintenance--;
|
|
7286
|
+
if (this.activeMaintenance === 0) {
|
|
7287
|
+
this.maintenanceDrain?.resolve();
|
|
7288
|
+
this.maintenanceDrain = void 0;
|
|
7289
|
+
}
|
|
6882
7290
|
}
|
|
6883
7291
|
}
|
|
7292
|
+
sealMaintenanceAndWait() {
|
|
7293
|
+
this.maintenanceSealed = true;
|
|
7294
|
+
if (this.activeMaintenance === 0) {
|
|
7295
|
+
return Promise.resolve();
|
|
7296
|
+
}
|
|
7297
|
+
if (!this.maintenanceDrain) {
|
|
7298
|
+
let resolve5;
|
|
7299
|
+
const promise = new Promise((done) => {
|
|
7300
|
+
resolve5 = done;
|
|
7301
|
+
});
|
|
7302
|
+
this.maintenanceDrain = { promise, resolve: resolve5 };
|
|
7303
|
+
}
|
|
7304
|
+
return this.maintenanceDrain.promise;
|
|
7305
|
+
}
|
|
6884
7306
|
async runSharedMany(sessionIds, fn) {
|
|
6885
7307
|
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
6886
7308
|
for (const sessionId of uniqueSessionIds) {
|
|
@@ -6903,70 +7325,280 @@ var SessionArchiveCoordinator = class {
|
|
|
6903
7325
|
}
|
|
6904
7326
|
}
|
|
6905
7327
|
};
|
|
7328
|
+
async function runWithDaemonWriterLease(params) {
|
|
7329
|
+
const {
|
|
7330
|
+
action,
|
|
7331
|
+
sessionId,
|
|
7332
|
+
service,
|
|
7333
|
+
mutate,
|
|
7334
|
+
mutationAppliedAfterError,
|
|
7335
|
+
afterMutationApplied
|
|
7336
|
+
} = params;
|
|
7337
|
+
let lease;
|
|
7338
|
+
try {
|
|
7339
|
+
lease = await service.acquireSessionWriterLease(sessionId, {
|
|
7340
|
+
processKind: "daemon",
|
|
7341
|
+
reclaimPolicy: "never"
|
|
7342
|
+
});
|
|
7343
|
+
} catch (error2) {
|
|
7344
|
+
return { mutationApplied: false, error: error2 };
|
|
7345
|
+
}
|
|
7346
|
+
let value;
|
|
7347
|
+
let mutationApplied = false;
|
|
7348
|
+
let mutationError;
|
|
7349
|
+
try {
|
|
7350
|
+
const mutation = await mutate(() => lease.assertOwnedAndUnchanged());
|
|
7351
|
+
value = mutation.value;
|
|
7352
|
+
mutationApplied = mutation.mutationApplied;
|
|
7353
|
+
} catch (error2) {
|
|
7354
|
+
mutationError = error2;
|
|
7355
|
+
try {
|
|
7356
|
+
mutationApplied = await mutationAppliedAfterError();
|
|
7357
|
+
} catch {
|
|
7358
|
+
mutationApplied = false;
|
|
7359
|
+
}
|
|
7360
|
+
}
|
|
7361
|
+
let maintenanceError;
|
|
7362
|
+
if (mutationApplied) {
|
|
7363
|
+
try {
|
|
7364
|
+
await afterMutationApplied();
|
|
7365
|
+
} catch (error2) {
|
|
7366
|
+
maintenanceError = error2;
|
|
7367
|
+
logSessionArchiveWarning(
|
|
7368
|
+
`scheduled task lifecycle update failed action=${action} workspace=${safeLogValue(
|
|
7369
|
+
service.getProjectRoot()
|
|
7370
|
+
)} session=${safeLogValue(sessionId)} error=${safeLogValue(
|
|
7371
|
+
errorMessage(error2)
|
|
7372
|
+
)}`
|
|
7373
|
+
);
|
|
7374
|
+
}
|
|
7375
|
+
}
|
|
7376
|
+
let releaseError;
|
|
7377
|
+
try {
|
|
7378
|
+
await lease.release();
|
|
7379
|
+
} catch (error2) {
|
|
7380
|
+
releaseError = error2;
|
|
7381
|
+
}
|
|
7382
|
+
if (releaseError !== void 0) {
|
|
7383
|
+
logMaintenanceLeaseReleaseFailure({
|
|
7384
|
+
action,
|
|
7385
|
+
workspace: service.getProjectRoot(),
|
|
7386
|
+
sessionId,
|
|
7387
|
+
error: releaseError,
|
|
7388
|
+
mutationApplied
|
|
7389
|
+
});
|
|
7390
|
+
if (mutationError !== void 0) {
|
|
7391
|
+
logSessionArchiveWarning(
|
|
7392
|
+
`session maintenance mutation also failed action=${action} workspace=${safeLogValue(
|
|
7393
|
+
service.getProjectRoot()
|
|
7394
|
+
)} session=${safeLogValue(sessionId)} error=${safeLogValue(
|
|
7395
|
+
errorMessage(mutationError)
|
|
7396
|
+
)}`
|
|
7397
|
+
);
|
|
7398
|
+
}
|
|
7399
|
+
return { mutationApplied, error: releaseError, maintenanceError };
|
|
7400
|
+
}
|
|
7401
|
+
if (mutationError !== void 0) {
|
|
7402
|
+
return { mutationApplied, error: mutationError, maintenanceError };
|
|
7403
|
+
}
|
|
7404
|
+
return { value, mutationApplied, maintenanceError };
|
|
7405
|
+
}
|
|
7406
|
+
__name(runWithDaemonWriterLease, "runWithDaemonWriterLease");
|
|
7407
|
+
function logMaintenanceLeaseReleaseFailure(params) {
|
|
7408
|
+
const errorKind = typeof params.error === "object" && params.error !== null && typeof params.error.errorKind === "string" ? params.error.errorKind : "unknown";
|
|
7409
|
+
logSessionArchiveWarning(
|
|
7410
|
+
`session maintenance lease release failed action=${params.action} workspace=${safeLogValue(
|
|
7411
|
+
params.workspace
|
|
7412
|
+
)} session=${safeLogValue(params.sessionId)} errorKind=${safeLogValue(
|
|
7413
|
+
errorKind
|
|
7414
|
+
)} mutationApplied=${params.mutationApplied}`
|
|
7415
|
+
);
|
|
7416
|
+
}
|
|
7417
|
+
__name(logMaintenanceLeaseReleaseFailure, "logMaintenanceLeaseReleaseFailure");
|
|
7418
|
+
async function classifySessionLocation(service, sessionId) {
|
|
7419
|
+
return service.getSessionLocation(sessionId);
|
|
7420
|
+
}
|
|
7421
|
+
__name(classifySessionLocation, "classifySessionLocation");
|
|
7422
|
+
function sessionLocationError(sessionId) {
|
|
7423
|
+
return new Error(`Session archive conflict: ${sessionId}`);
|
|
7424
|
+
}
|
|
7425
|
+
__name(sessionLocationError, "sessionLocationError");
|
|
7426
|
+
function updateScheduledTaskForMaintenance(service, sessionId, action) {
|
|
7427
|
+
if (action === "archive") {
|
|
7428
|
+
return disableTasksForSessions(service.getProjectRoot(), [sessionId]);
|
|
7429
|
+
}
|
|
7430
|
+
if (action === "unarchive") {
|
|
7431
|
+
return enableTasksForSessions(service.getProjectRoot(), [sessionId]);
|
|
7432
|
+
}
|
|
7433
|
+
return removeTasksForSessions(service.getProjectRoot(), [sessionId]);
|
|
7434
|
+
}
|
|
7435
|
+
__name(updateScheduledTaskForMaintenance, "updateScheduledTaskForMaintenance");
|
|
7436
|
+
async function deletePersistedSessionWithLease(service, sessionId) {
|
|
7437
|
+
const initialLocation = await classifySessionLocation(service, sessionId);
|
|
7438
|
+
if (initialLocation === void 0) {
|
|
7439
|
+
return { kind: "notFound", mutationApplied: false };
|
|
7440
|
+
}
|
|
7441
|
+
if (initialLocation === "conflict") {
|
|
7442
|
+
return {
|
|
7443
|
+
kind: "error",
|
|
7444
|
+
error: sessionLocationError(sessionId),
|
|
7445
|
+
mutationApplied: false
|
|
7446
|
+
};
|
|
7447
|
+
}
|
|
7448
|
+
const mutation = await runWithDaemonWriterLease({
|
|
7449
|
+
action: "delete",
|
|
7450
|
+
sessionId,
|
|
7451
|
+
service,
|
|
7452
|
+
mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
|
|
7453
|
+
const lockedLocation = await classifySessionLocation(service, sessionId);
|
|
7454
|
+
if (lockedLocation === void 0) {
|
|
7455
|
+
return {
|
|
7456
|
+
value: "notFound",
|
|
7457
|
+
mutationApplied: false
|
|
7458
|
+
};
|
|
7459
|
+
}
|
|
7460
|
+
if (lockedLocation === "conflict") {
|
|
7461
|
+
throw sessionLocationError(sessionId);
|
|
7462
|
+
}
|
|
7463
|
+
await assertOwnedAndUnchanged();
|
|
7464
|
+
const removed = await service.removeSession(sessionId);
|
|
7465
|
+
return {
|
|
7466
|
+
value: removed ? "removed" : "notFound",
|
|
7467
|
+
mutationApplied: removed
|
|
7468
|
+
};
|
|
7469
|
+
}, "mutate"),
|
|
7470
|
+
mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === void 0, "mutationAppliedAfterError"),
|
|
7471
|
+
afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "delete"), "afterMutationApplied")
|
|
7472
|
+
});
|
|
7473
|
+
if (mutation.error !== void 0) {
|
|
7474
|
+
return {
|
|
7475
|
+
kind: "error",
|
|
7476
|
+
error: mutation.error,
|
|
7477
|
+
mutationApplied: mutation.mutationApplied
|
|
7478
|
+
};
|
|
7479
|
+
}
|
|
7480
|
+
return {
|
|
7481
|
+
kind: mutation.value ?? "notFound",
|
|
7482
|
+
mutationApplied: mutation.mutationApplied
|
|
7483
|
+
};
|
|
7484
|
+
}
|
|
7485
|
+
__name(deletePersistedSessionWithLease, "deletePersistedSessionWithLease");
|
|
6906
7486
|
async function deleteDaemonSessions(params) {
|
|
6907
7487
|
const { sessionIds, service, bridge, coordinator, onError } = params;
|
|
6908
7488
|
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
6909
|
-
const closeErrors = [];
|
|
6910
|
-
const removed = [];
|
|
6911
|
-
const notFound = [];
|
|
6912
|
-
const removeErrors = [];
|
|
6913
7489
|
for (const sessionId of uniqueSessionIds) {
|
|
6914
7490
|
coordinator.assertNotTransitioning(sessionId);
|
|
6915
7491
|
}
|
|
6916
|
-
await Promise.all(
|
|
7492
|
+
const results = await Promise.all(
|
|
6917
7493
|
uniqueSessionIds.map(async (sessionId) => {
|
|
6918
7494
|
try {
|
|
6919
|
-
await coordinator.runExclusiveMany([sessionId], async () => {
|
|
6920
|
-
let shouldRemove = false;
|
|
7495
|
+
return await coordinator.runExclusiveMany([sessionId], async () => {
|
|
6921
7496
|
try {
|
|
6922
7497
|
await bridge.closeSession(sessionId);
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
7498
|
+
} catch (error2) {
|
|
7499
|
+
if (isSessionNotFoundError(error2)) {
|
|
7500
|
+
const result2 = await deletePersistedSessionWithLease(
|
|
7501
|
+
service,
|
|
7502
|
+
sessionId
|
|
7503
|
+
);
|
|
7504
|
+
if (result2.kind === "error") {
|
|
7505
|
+
onError?.({
|
|
7506
|
+
phase: "remove",
|
|
7507
|
+
sessionId,
|
|
7508
|
+
error: errorMessage(result2.error)
|
|
7509
|
+
});
|
|
7510
|
+
}
|
|
7511
|
+
return result2;
|
|
6931
7512
|
}
|
|
7513
|
+
onError?.({
|
|
7514
|
+
phase: "close",
|
|
7515
|
+
sessionId,
|
|
7516
|
+
error: errorMessage(error2)
|
|
7517
|
+
});
|
|
7518
|
+
return {
|
|
7519
|
+
kind: "error",
|
|
7520
|
+
error: error2,
|
|
7521
|
+
mutationApplied: false
|
|
7522
|
+
};
|
|
6932
7523
|
}
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
removeErrors.push({ sessionId, error: message });
|
|
7524
|
+
const result = await deletePersistedSessionWithLease(
|
|
7525
|
+
service,
|
|
7526
|
+
sessionId
|
|
7527
|
+
);
|
|
7528
|
+
if (result.kind === "error") {
|
|
7529
|
+
onError?.({
|
|
7530
|
+
phase: "remove",
|
|
7531
|
+
sessionId,
|
|
7532
|
+
error: errorMessage(result.error)
|
|
7533
|
+
});
|
|
6944
7534
|
}
|
|
7535
|
+
return result;
|
|
6945
7536
|
});
|
|
6946
|
-
} catch (
|
|
6947
|
-
if (
|
|
6948
|
-
throw
|
|
7537
|
+
} catch (error2) {
|
|
7538
|
+
if (error2 instanceof DaemonDrainingError) {
|
|
7539
|
+
throw error2;
|
|
6949
7540
|
}
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
7541
|
+
onError?.({
|
|
7542
|
+
phase: "delete",
|
|
7543
|
+
sessionId,
|
|
7544
|
+
error: errorMessage(error2)
|
|
7545
|
+
});
|
|
7546
|
+
return {
|
|
7547
|
+
kind: "error",
|
|
7548
|
+
error: error2,
|
|
7549
|
+
mutationApplied: false
|
|
7550
|
+
};
|
|
6953
7551
|
}
|
|
6954
7552
|
})
|
|
6955
7553
|
);
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
7554
|
+
const removed = [];
|
|
7555
|
+
const notFound = [];
|
|
7556
|
+
const errors = [];
|
|
7557
|
+
for (let i = 0; i < results.length; i++) {
|
|
7558
|
+
const sessionId = uniqueSessionIds[i];
|
|
7559
|
+
const result = results[i];
|
|
7560
|
+
if (result.kind === "removed") {
|
|
7561
|
+
removed.push(sessionId);
|
|
7562
|
+
} else if (result.kind === "notFound") {
|
|
7563
|
+
notFound.push(sessionId);
|
|
7564
|
+
} else {
|
|
7565
|
+
errors.push({ sessionId, error: errorMessage(result.error) });
|
|
6961
7566
|
}
|
|
6962
|
-
|
|
6963
|
-
return { removed, notFound, errors
|
|
7567
|
+
}
|
|
7568
|
+
return { removed, notFound, errors };
|
|
6964
7569
|
}
|
|
6965
7570
|
__name(deleteDaemonSessions, "deleteDaemonSessions");
|
|
6966
|
-
async function
|
|
6967
|
-
const
|
|
6968
|
-
|
|
6969
|
-
)
|
|
7571
|
+
async function deleteDaemonSessionIfOrphan(params) {
|
|
7572
|
+
const { sessionId, service, bridge, coordinator } = params;
|
|
7573
|
+
coordinator.assertNotTransitioning(sessionId);
|
|
7574
|
+
const result = await coordinator.runExclusiveMany([sessionId], async () => {
|
|
7575
|
+
let killed = false;
|
|
7576
|
+
try {
|
|
7577
|
+
killed = await bridge.killSession(sessionId, {
|
|
7578
|
+
requireZeroAttaches: true
|
|
7579
|
+
});
|
|
7580
|
+
} catch (error2) {
|
|
7581
|
+
if (!isSessionNotFoundError(error2)) throw error2;
|
|
7582
|
+
killed = true;
|
|
7583
|
+
}
|
|
7584
|
+
if (!killed) {
|
|
7585
|
+
return void 0;
|
|
7586
|
+
}
|
|
7587
|
+
return deletePersistedSessionWithLease(service, sessionId);
|
|
7588
|
+
});
|
|
7589
|
+
if (result === void 0) {
|
|
7590
|
+
return false;
|
|
7591
|
+
}
|
|
7592
|
+
if (result.kind === "error") {
|
|
7593
|
+
throw result.error;
|
|
7594
|
+
}
|
|
7595
|
+
return true;
|
|
7596
|
+
}
|
|
7597
|
+
__name(deleteDaemonSessionIfOrphan, "deleteDaemonSessionIfOrphan");
|
|
7598
|
+
async function assertSessionLoadable(workspaceCwd, sessionId, runtimeBaseDir) {
|
|
7599
|
+
const location = await new SessionService(workspaceCwd, {
|
|
7600
|
+
runtimeBaseDir
|
|
7601
|
+
}).getSessionLocation(sessionId);
|
|
6970
7602
|
if (location === "archived") {
|
|
6971
7603
|
throw new SessionArchivedError(sessionId);
|
|
6972
7604
|
}
|
|
@@ -6976,10 +7608,10 @@ async function assertSessionLoadable(workspaceCwd, sessionId) {
|
|
|
6976
7608
|
return location;
|
|
6977
7609
|
}
|
|
6978
7610
|
__name(assertSessionLoadable, "assertSessionLoadable");
|
|
6979
|
-
async function assertSessionArchived(workspaceCwd, sessionId) {
|
|
6980
|
-
const location = await new SessionService(workspaceCwd
|
|
6981
|
-
|
|
6982
|
-
);
|
|
7611
|
+
async function assertSessionArchived(workspaceCwd, sessionId, runtimeBaseDir) {
|
|
7612
|
+
const location = await new SessionService(workspaceCwd, {
|
|
7613
|
+
runtimeBaseDir
|
|
7614
|
+
}).getSessionLocation(sessionId);
|
|
6983
7615
|
if (location === "active") {
|
|
6984
7616
|
throw new SessionNotArchivedError(sessionId);
|
|
6985
7617
|
}
|
|
@@ -6995,43 +7627,6 @@ function isSessionNotFoundError(err) {
|
|
|
6995
7627
|
return err instanceof SessionNotFoundError || err instanceof Error && err.name === "SessionNotFoundError";
|
|
6996
7628
|
}
|
|
6997
7629
|
__name(isSessionNotFoundError, "isSessionNotFoundError");
|
|
6998
|
-
async function classifySessionLocations(service, sessionIds) {
|
|
6999
|
-
const result = {
|
|
7000
|
-
active: [],
|
|
7001
|
-
archived: [],
|
|
7002
|
-
notFound: [],
|
|
7003
|
-
errors: []
|
|
7004
|
-
};
|
|
7005
|
-
const locationResults = await Promise.allSettled(
|
|
7006
|
-
sessionIds.map(async (sessionId) => ({
|
|
7007
|
-
sessionId,
|
|
7008
|
-
location: await service.getSessionLocation(sessionId)
|
|
7009
|
-
}))
|
|
7010
|
-
);
|
|
7011
|
-
for (let i = 0; i < locationResults.length; i++) {
|
|
7012
|
-
const sessionId = sessionIds[i];
|
|
7013
|
-
const locationResult = locationResults[i];
|
|
7014
|
-
if (locationResult.status === "rejected") {
|
|
7015
|
-
result.errors.push({ sessionId, error: locationResult.reason });
|
|
7016
|
-
continue;
|
|
7017
|
-
}
|
|
7018
|
-
const location = locationResult.value.location;
|
|
7019
|
-
if (location === void 0) {
|
|
7020
|
-
result.notFound.push(sessionId);
|
|
7021
|
-
} else if (location === "archived") {
|
|
7022
|
-
result.archived.push(sessionId);
|
|
7023
|
-
} else if (location === "conflict") {
|
|
7024
|
-
result.errors.push({
|
|
7025
|
-
sessionId,
|
|
7026
|
-
error: new Error(`Session archive conflict: ${sessionId}`)
|
|
7027
|
-
});
|
|
7028
|
-
} else {
|
|
7029
|
-
result.active.push(sessionId);
|
|
7030
|
-
}
|
|
7031
|
-
}
|
|
7032
|
-
return result;
|
|
7033
|
-
}
|
|
7034
|
-
__name(classifySessionLocations, "classifySessionLocations");
|
|
7035
7630
|
function logSessionArchiveResult(action, result) {
|
|
7036
7631
|
const changedLabel = action === "archive" ? "archived" : "unarchived";
|
|
7037
7632
|
const alreadyLabel = action === "archive" ? "alreadyArchived" : "alreadyActive";
|
|
@@ -7071,59 +7666,126 @@ __name(sanitizeLogLine, "sanitizeLogLine");
|
|
|
7071
7666
|
async function archiveDaemonSessions(params) {
|
|
7072
7667
|
const { sessionIds, service, bridge, coordinator } = params;
|
|
7073
7668
|
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
7074
|
-
const
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
const
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
notFound.push(...initial.notFound);
|
|
7082
|
-
errors.push(...initial.errors);
|
|
7083
|
-
if (activeIds.length > 0) {
|
|
7084
|
-
await coordinator.runExclusiveMany(activeIds, async () => {
|
|
7085
|
-
const locked = await classifySessionLocations(service, activeIds);
|
|
7086
|
-
const closableIds = locked.active;
|
|
7087
|
-
alreadyArchived.push(...locked.archived);
|
|
7088
|
-
notFound.push(...locked.notFound);
|
|
7089
|
-
errors.push(...locked.errors);
|
|
7090
|
-
const closeResults = await Promise.allSettled(
|
|
7091
|
-
closableIds.map(async (sessionId) => {
|
|
7669
|
+
for (const sessionId of uniqueSessionIds) {
|
|
7670
|
+
coordinator.assertNotTransitioning(sessionId);
|
|
7671
|
+
}
|
|
7672
|
+
const results = await Promise.all(
|
|
7673
|
+
uniqueSessionIds.map(async (sessionId) => {
|
|
7674
|
+
try {
|
|
7675
|
+
return await coordinator.runExclusiveMany([sessionId], async () => {
|
|
7092
7676
|
try {
|
|
7093
7677
|
await bridge.closeSession(sessionId, void 0, {
|
|
7094
7678
|
requireAgentClose: true
|
|
7095
7679
|
});
|
|
7096
|
-
} catch (
|
|
7097
|
-
if (!isSessionNotFoundError(
|
|
7098
|
-
|
|
7680
|
+
} catch (error2) {
|
|
7681
|
+
if (!isSessionNotFoundError(error2)) {
|
|
7682
|
+
return {
|
|
7683
|
+
kind: "error",
|
|
7684
|
+
error: error2,
|
|
7685
|
+
mutationApplied: false
|
|
7686
|
+
};
|
|
7099
7687
|
}
|
|
7100
7688
|
}
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7689
|
+
const initialLocation = await classifySessionLocation(
|
|
7690
|
+
service,
|
|
7691
|
+
sessionId
|
|
7692
|
+
);
|
|
7693
|
+
if (initialLocation === void 0) {
|
|
7694
|
+
return { kind: "notFound", mutationApplied: false };
|
|
7695
|
+
}
|
|
7696
|
+
if (initialLocation === "archived") {
|
|
7697
|
+
return {
|
|
7698
|
+
kind: "alreadyArchived",
|
|
7699
|
+
mutationApplied: false
|
|
7700
|
+
};
|
|
7701
|
+
}
|
|
7702
|
+
if (initialLocation === "conflict") {
|
|
7703
|
+
return {
|
|
7704
|
+
kind: "error",
|
|
7705
|
+
error: sessionLocationError(sessionId),
|
|
7706
|
+
mutationApplied: false
|
|
7707
|
+
};
|
|
7708
|
+
}
|
|
7709
|
+
const mutation = await runWithDaemonWriterLease({
|
|
7710
|
+
action: "archive",
|
|
7711
|
+
sessionId,
|
|
7712
|
+
service,
|
|
7713
|
+
mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
|
|
7714
|
+
const lockedLocation = await classifySessionLocation(
|
|
7715
|
+
service,
|
|
7716
|
+
sessionId
|
|
7717
|
+
);
|
|
7718
|
+
if (lockedLocation === void 0) {
|
|
7719
|
+
return {
|
|
7720
|
+
value: "notFound",
|
|
7721
|
+
mutationApplied: false
|
|
7722
|
+
};
|
|
7723
|
+
}
|
|
7724
|
+
if (lockedLocation === "archived") {
|
|
7725
|
+
return {
|
|
7726
|
+
value: "alreadyArchived",
|
|
7727
|
+
mutationApplied: false
|
|
7728
|
+
};
|
|
7729
|
+
}
|
|
7730
|
+
if (lockedLocation === "conflict") {
|
|
7731
|
+
throw sessionLocationError(sessionId);
|
|
7732
|
+
}
|
|
7733
|
+
await assertOwnedAndUnchanged();
|
|
7734
|
+
const result = await service.archiveSessions([sessionId], {
|
|
7735
|
+
knownLocation: "active"
|
|
7736
|
+
});
|
|
7737
|
+
if (result.errors[0]) throw result.errors[0].error;
|
|
7738
|
+
if (result.archived.length > 0) {
|
|
7739
|
+
return {
|
|
7740
|
+
value: "archived",
|
|
7741
|
+
mutationApplied: true
|
|
7742
|
+
};
|
|
7743
|
+
}
|
|
7744
|
+
return {
|
|
7745
|
+
value: result.alreadyArchived.length > 0 ? "alreadyArchived" : "notFound",
|
|
7746
|
+
mutationApplied: false
|
|
7747
|
+
};
|
|
7748
|
+
}, "mutate"),
|
|
7749
|
+
mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "archived", "mutationAppliedAfterError"),
|
|
7750
|
+
afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(service, sessionId, "archive"), "afterMutationApplied")
|
|
7751
|
+
});
|
|
7752
|
+
if (mutation.error !== void 0) {
|
|
7753
|
+
return {
|
|
7754
|
+
kind: "error",
|
|
7755
|
+
error: mutation.error,
|
|
7756
|
+
mutationApplied: mutation.mutationApplied
|
|
7757
|
+
};
|
|
7758
|
+
}
|
|
7759
|
+
return {
|
|
7760
|
+
kind: mutation.value ?? "notFound",
|
|
7761
|
+
mutationApplied: mutation.mutationApplied
|
|
7762
|
+
};
|
|
7116
7763
|
});
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
errors.push(...archiveResult.errors);
|
|
7121
|
-
} catch (err) {
|
|
7122
|
-
for (const sessionId of archiveIds) {
|
|
7123
|
-
errors.push({ sessionId, error: err });
|
|
7764
|
+
} catch (error2) {
|
|
7765
|
+
if (error2 instanceof DaemonDrainingError) {
|
|
7766
|
+
throw error2;
|
|
7124
7767
|
}
|
|
7768
|
+
return {
|
|
7769
|
+
kind: "error",
|
|
7770
|
+
error: error2,
|
|
7771
|
+
mutationApplied: false,
|
|
7772
|
+
maintenanceError: void 0
|
|
7773
|
+
};
|
|
7125
7774
|
}
|
|
7126
|
-
})
|
|
7775
|
+
})
|
|
7776
|
+
);
|
|
7777
|
+
const archived = [];
|
|
7778
|
+
const alreadyArchived = [];
|
|
7779
|
+
const notFound = [];
|
|
7780
|
+
const errors = [];
|
|
7781
|
+
for (let i = 0; i < results.length; i++) {
|
|
7782
|
+
const sessionId = uniqueSessionIds[i];
|
|
7783
|
+
const result = results[i];
|
|
7784
|
+
if (result.kind === "archived") archived.push(sessionId);
|
|
7785
|
+
else if (result.kind === "alreadyArchived") {
|
|
7786
|
+
alreadyArchived.push(sessionId);
|
|
7787
|
+
} else if (result.kind === "notFound") notFound.push(sessionId);
|
|
7788
|
+
else errors.push({ sessionId, error: result.error });
|
|
7127
7789
|
}
|
|
7128
7790
|
logSessionArchiveResult("archive", {
|
|
7129
7791
|
requested: uniqueSessionIds,
|
|
@@ -7132,51 +7794,144 @@ async function archiveDaemonSessions(params) {
|
|
|
7132
7794
|
notFound,
|
|
7133
7795
|
errors
|
|
7134
7796
|
});
|
|
7135
|
-
await disableTasksForSessions(service.getProjectRoot(), archived).catch(
|
|
7136
|
-
(err) => {
|
|
7137
|
-
logSessionArchiveWarning(
|
|
7138
|
-
`disableTasksForSessions failed for [${archived.join(", ")}]: ${err instanceof Error ? err.message : String(err)} \u2014 bound tasks may keep firing until reconciled`
|
|
7139
|
-
);
|
|
7140
|
-
}
|
|
7141
|
-
);
|
|
7142
7797
|
return { archived, alreadyArchived, notFound, errors };
|
|
7143
7798
|
}
|
|
7144
7799
|
__name(archiveDaemonSessions, "archiveDaemonSessions");
|
|
7145
7800
|
async function unarchiveDaemonSessions(params) {
|
|
7146
7801
|
const { sessionIds, service, coordinator } = params;
|
|
7147
7802
|
const uniqueSessionIds = [...new Set(sessionIds)];
|
|
7148
|
-
const
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
const
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7803
|
+
for (const sessionId of uniqueSessionIds) {
|
|
7804
|
+
coordinator.assertNotTransitioning(sessionId);
|
|
7805
|
+
}
|
|
7806
|
+
const results = await Promise.all(
|
|
7807
|
+
uniqueSessionIds.map(async (sessionId) => {
|
|
7808
|
+
try {
|
|
7809
|
+
return await coordinator.runExclusiveMany([sessionId], async () => {
|
|
7810
|
+
const initialLocation = await classifySessionLocation(
|
|
7811
|
+
service,
|
|
7812
|
+
sessionId
|
|
7813
|
+
);
|
|
7814
|
+
if (initialLocation === void 0) {
|
|
7815
|
+
return { kind: "notFound", mutationApplied: false };
|
|
7816
|
+
}
|
|
7817
|
+
if (initialLocation === "active") {
|
|
7818
|
+
let maintenanceError;
|
|
7819
|
+
try {
|
|
7820
|
+
await updateScheduledTaskForMaintenance(
|
|
7821
|
+
service,
|
|
7822
|
+
sessionId,
|
|
7823
|
+
"unarchive"
|
|
7824
|
+
);
|
|
7825
|
+
} catch (error2) {
|
|
7826
|
+
maintenanceError = error2;
|
|
7827
|
+
logSessionArchiveWarning(
|
|
7828
|
+
`scheduled task lifecycle update failed action=unarchive workspace=${safeLogValue(
|
|
7829
|
+
service.getProjectRoot()
|
|
7830
|
+
)} session=${safeLogValue(sessionId)} error=${safeLogValue(
|
|
7831
|
+
errorMessage(error2)
|
|
7832
|
+
)}`
|
|
7833
|
+
);
|
|
7834
|
+
}
|
|
7835
|
+
return {
|
|
7836
|
+
kind: "alreadyActive",
|
|
7837
|
+
mutationApplied: false,
|
|
7838
|
+
maintenanceError
|
|
7839
|
+
};
|
|
7840
|
+
}
|
|
7841
|
+
if (initialLocation === "conflict") {
|
|
7842
|
+
return {
|
|
7843
|
+
kind: "error",
|
|
7844
|
+
error: sessionLocationError(sessionId),
|
|
7845
|
+
mutationApplied: false
|
|
7846
|
+
};
|
|
7847
|
+
}
|
|
7848
|
+
const mutation = await runWithDaemonWriterLease({
|
|
7849
|
+
action: "unarchive",
|
|
7850
|
+
sessionId,
|
|
7851
|
+
service,
|
|
7852
|
+
mutate: /* @__PURE__ */ __name(async (assertOwnedAndUnchanged) => {
|
|
7853
|
+
const lockedLocation = await classifySessionLocation(
|
|
7854
|
+
service,
|
|
7855
|
+
sessionId
|
|
7856
|
+
);
|
|
7857
|
+
if (lockedLocation === void 0) {
|
|
7858
|
+
return {
|
|
7859
|
+
value: "notFound",
|
|
7860
|
+
mutationApplied: false
|
|
7861
|
+
};
|
|
7862
|
+
}
|
|
7863
|
+
if (lockedLocation === "active") {
|
|
7864
|
+
return {
|
|
7865
|
+
value: "alreadyActive",
|
|
7866
|
+
mutationApplied: false
|
|
7867
|
+
};
|
|
7868
|
+
}
|
|
7869
|
+
if (lockedLocation === "conflict") {
|
|
7870
|
+
throw sessionLocationError(sessionId);
|
|
7871
|
+
}
|
|
7872
|
+
await assertOwnedAndUnchanged();
|
|
7873
|
+
const result = await service.unarchiveSessions([sessionId], {
|
|
7874
|
+
knownLocation: "archived"
|
|
7875
|
+
});
|
|
7876
|
+
if (result.errors[0]) throw result.errors[0].error;
|
|
7877
|
+
if (result.unarchived.length > 0) {
|
|
7878
|
+
return {
|
|
7879
|
+
value: "unarchived",
|
|
7880
|
+
mutationApplied: true
|
|
7881
|
+
};
|
|
7882
|
+
}
|
|
7883
|
+
return {
|
|
7884
|
+
value: result.alreadyActive.length > 0 ? "alreadyActive" : "notFound",
|
|
7885
|
+
mutationApplied: false
|
|
7886
|
+
};
|
|
7887
|
+
}, "mutate"),
|
|
7888
|
+
mutationAppliedAfterError: /* @__PURE__ */ __name(async () => await classifySessionLocation(service, sessionId) === "active", "mutationAppliedAfterError"),
|
|
7889
|
+
afterMutationApplied: /* @__PURE__ */ __name(() => updateScheduledTaskForMaintenance(
|
|
7890
|
+
service,
|
|
7891
|
+
sessionId,
|
|
7892
|
+
"unarchive"
|
|
7893
|
+
), "afterMutationApplied")
|
|
7168
7894
|
});
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
errors.push({ sessionId, error: err });
|
|
7895
|
+
if (mutation.error !== void 0) {
|
|
7896
|
+
return {
|
|
7897
|
+
kind: "error",
|
|
7898
|
+
error: mutation.error,
|
|
7899
|
+
mutationApplied: mutation.mutationApplied
|
|
7900
|
+
};
|
|
7176
7901
|
}
|
|
7902
|
+
return {
|
|
7903
|
+
kind: mutation.value ?? "notFound",
|
|
7904
|
+
mutationApplied: mutation.mutationApplied,
|
|
7905
|
+
maintenanceError: mutation.maintenanceError
|
|
7906
|
+
};
|
|
7907
|
+
});
|
|
7908
|
+
} catch (error2) {
|
|
7909
|
+
if (error2 instanceof DaemonDrainingError) {
|
|
7910
|
+
throw error2;
|
|
7177
7911
|
}
|
|
7912
|
+
return {
|
|
7913
|
+
kind: "error",
|
|
7914
|
+
error: error2,
|
|
7915
|
+
mutationApplied: false,
|
|
7916
|
+
maintenanceError: void 0
|
|
7917
|
+
};
|
|
7178
7918
|
}
|
|
7179
|
-
})
|
|
7919
|
+
})
|
|
7920
|
+
);
|
|
7921
|
+
const unarchived = [];
|
|
7922
|
+
const alreadyActive = [];
|
|
7923
|
+
const notFound = [];
|
|
7924
|
+
const errors = [];
|
|
7925
|
+
for (let i = 0; i < results.length; i++) {
|
|
7926
|
+
const sessionId = uniqueSessionIds[i];
|
|
7927
|
+
const result = results[i];
|
|
7928
|
+
if (result.kind === "unarchived") unarchived.push(sessionId);
|
|
7929
|
+
else if (result.kind === "alreadyActive") alreadyActive.push(sessionId);
|
|
7930
|
+
else if (result.kind === "notFound") notFound.push(sessionId);
|
|
7931
|
+
else errors.push({ sessionId, error: result.error });
|
|
7932
|
+
if (result.maintenanceError !== void 0) {
|
|
7933
|
+
errors.push({ sessionId, error: result.maintenanceError });
|
|
7934
|
+
}
|
|
7180
7935
|
}
|
|
7181
7936
|
logSessionArchiveResult("unarchive", {
|
|
7182
7937
|
requested: uniqueSessionIds,
|
|
@@ -7185,17 +7940,6 @@ async function unarchiveDaemonSessions(params) {
|
|
|
7185
7940
|
notFound,
|
|
7186
7941
|
errors
|
|
7187
7942
|
});
|
|
7188
|
-
const resumeSessionIds = [.../* @__PURE__ */ new Set([...unarchived, ...alreadyActive])];
|
|
7189
|
-
try {
|
|
7190
|
-
await enableTasksForSessions(service.getProjectRoot(), resumeSessionIds);
|
|
7191
|
-
} catch (err) {
|
|
7192
|
-
logSessionArchiveWarning(
|
|
7193
|
-
`enableTasksForSessions failed for [${resumeSessionIds.join(", ")}]: ${err instanceof Error ? err.message : String(err)}`
|
|
7194
|
-
);
|
|
7195
|
-
for (const sessionId of resumeSessionIds) {
|
|
7196
|
-
errors.push({ sessionId, error: err });
|
|
7197
|
-
}
|
|
7198
|
-
}
|
|
7199
7943
|
return { unarchived, alreadyActive, notFound, errors };
|
|
7200
7944
|
}
|
|
7201
7945
|
__name(unarchiveDaemonSessions, "unarchiveDaemonSessions");
|
|
@@ -7596,6 +8340,13 @@ function pickSessionArtifactInput(params) {
|
|
|
7596
8340
|
}
|
|
7597
8341
|
__name(pickSessionArtifactInput, "pickSessionArtifactInput");
|
|
7598
8342
|
function toRpcError(err) {
|
|
8343
|
+
if (err instanceof DaemonDrainingError) {
|
|
8344
|
+
return {
|
|
8345
|
+
code: RPC.INTERNAL_ERROR,
|
|
8346
|
+
message: err.message,
|
|
8347
|
+
data: { errorKind: "daemon_draining" }
|
|
8348
|
+
};
|
|
8349
|
+
}
|
|
7599
8350
|
const writerError = sessionWriterRpcError(err);
|
|
7600
8351
|
if (writerError) return writerError;
|
|
7601
8352
|
if (err instanceof AcpParamError || err instanceof InvalidCursorError) {
|
|
@@ -7804,7 +8555,7 @@ function rpcErrorFrame(id, err) {
|
|
|
7804
8555
|
__name(rpcErrorFrame, "rpcErrorFrame");
|
|
7805
8556
|
var ACP_PROTOCOL_VERSION = 1;
|
|
7806
8557
|
var AcpDispatcher = class {
|
|
7807
|
-
constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0) {
|
|
8558
|
+
constructor(bridge, boundWorkspace, getEnv, workspace, workspaceRememberLane, fsFactory, deviceFlowRegistry, sessionShellCommandEnabled = false, registry, archiveCoordinator = new SessionArchiveCoordinator(), isWorkspaceTrusted = () => true, captureGenerationAssertion = () => void 0, sessionRuntimeBaseDir = Storage.getRuntimeBaseDir()) {
|
|
7808
8559
|
this.bridge = bridge;
|
|
7809
8560
|
this.boundWorkspace = boundWorkspace;
|
|
7810
8561
|
this.getEnv = getEnv;
|
|
@@ -7817,6 +8568,7 @@ var AcpDispatcher = class {
|
|
|
7817
8568
|
this.archiveCoordinator = archiveCoordinator;
|
|
7818
8569
|
this.isWorkspaceTrusted = isWorkspaceTrusted;
|
|
7819
8570
|
this.captureGenerationAssertion = captureGenerationAssertion;
|
|
8571
|
+
this.sessionRuntimeBaseDir = sessionRuntimeBaseDir;
|
|
7820
8572
|
this.agentManager = createDaemonSubagentManager(boundWorkspace);
|
|
7821
8573
|
}
|
|
7822
8574
|
static {
|
|
@@ -7824,13 +8576,15 @@ var AcpDispatcher = class {
|
|
|
7824
8576
|
}
|
|
7825
8577
|
agentManager;
|
|
7826
8578
|
killOrphanSession(sessionId, removePersistedSession = false) {
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
8579
|
+
const cleanup = removePersistedSession ? deleteDaemonSessionIfOrphan({
|
|
8580
|
+
sessionId,
|
|
8581
|
+
service: new SessionService(this.boundWorkspace, {
|
|
8582
|
+
runtimeBaseDir: this.sessionRuntimeBaseDir
|
|
8583
|
+
}),
|
|
8584
|
+
bridge: this.bridge,
|
|
8585
|
+
coordinator: this.archiveCoordinator
|
|
8586
|
+
}) : this.bridge.killSession(sessionId, { requireZeroAttaches: true });
|
|
8587
|
+
void cleanup.catch(
|
|
7834
8588
|
(err) => writeStderrLine(
|
|
7835
8589
|
`qwen serve: /acp orphan killSession(${logSafe(sessionId)}) failed: ${logSafe(errMsg(err))}`
|
|
7836
8590
|
)
|
|
@@ -8080,6 +8834,12 @@ var AcpDispatcher = class {
|
|
|
8080
8834
|
* (it mints the connection) and never reaches here.
|
|
8081
8835
|
*/
|
|
8082
8836
|
async handle(conn, msg, sessionHeader, reqLoopback) {
|
|
8837
|
+
return Storage.runWithResolvedRuntimeBaseDir(
|
|
8838
|
+
this.sessionRuntimeBaseDir,
|
|
8839
|
+
() => this.handleInRuntime(conn, msg, sessionHeader, reqLoopback)
|
|
8840
|
+
);
|
|
8841
|
+
}
|
|
8842
|
+
async handleInRuntime(conn, msg, sessionHeader, reqLoopback) {
|
|
8083
8843
|
const loopback = reqLoopback ?? conn.fromLoopback;
|
|
8084
8844
|
if (isResponse(msg)) {
|
|
8085
8845
|
try {
|
|
@@ -9926,8 +10686,26 @@ var AcpDispatcher = class {
|
|
|
9926
10686
|
);
|
|
9927
10687
|
return;
|
|
9928
10688
|
}
|
|
10689
|
+
const rawCursor = params["cursor"];
|
|
10690
|
+
if (rawCursor !== void 0 && (typeof rawCursor !== "string" || rawCursor.length === 0 || rawCursor.length > MAX_TEXT_CURSOR_CHARS)) {
|
|
10691
|
+
if (id !== void 0)
|
|
10692
|
+
conn.sendConn(
|
|
10693
|
+
error(
|
|
10694
|
+
id,
|
|
10695
|
+
RPC.INVALID_PARAMS,
|
|
10696
|
+
`\`cursor\` must be a non-empty string of at most ${MAX_TEXT_CURSOR_CHARS} characters`
|
|
10697
|
+
)
|
|
10698
|
+
);
|
|
10699
|
+
return;
|
|
10700
|
+
}
|
|
10701
|
+
const cursor = rawCursor;
|
|
9929
10702
|
const resolved = await fs6.resolve(p, "read");
|
|
9930
|
-
const out = await fs6.readText(resolved, {
|
|
10703
|
+
const out = await fs6.readText(resolved, {
|
|
10704
|
+
maxBytes,
|
|
10705
|
+
line,
|
|
10706
|
+
limit,
|
|
10707
|
+
cursor
|
|
10708
|
+
});
|
|
9931
10709
|
this.replyConn(conn, id, {
|
|
9932
10710
|
path: p,
|
|
9933
10711
|
content: out.content,
|
|
@@ -13061,7 +13839,8 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
13061
13839
|
() => {
|
|
13062
13840
|
const guard = opts.workspaceRegistry?.primaryEntry.current?.guard;
|
|
13063
13841
|
return guard ? () => guard.assertOpen() : void 0;
|
|
13064
|
-
}
|
|
13842
|
+
},
|
|
13843
|
+
opts.workspaceRegistry?.primary.sessionRuntimeBaseDir ?? Storage.getRuntimeBaseDir()
|
|
13065
13844
|
);
|
|
13066
13845
|
dispatcherRef.current = dispatcher;
|
|
13067
13846
|
const primaryMount = {
|
|
@@ -13368,7 +14147,8 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
13368
14147
|
() => {
|
|
13369
14148
|
const guard = rt.generationGuard;
|
|
13370
14149
|
return guard ? () => guard.assertOpen() : void 0;
|
|
13371
|
-
}
|
|
14150
|
+
},
|
|
14151
|
+
rt.sessionRuntimeBaseDir
|
|
13372
14152
|
);
|
|
13373
14153
|
secondaryDispatcherRef.current = secondaryDispatcher;
|
|
13374
14154
|
return {
|
|
@@ -14108,6 +14888,16 @@ function mountAcpHttp(app, bridge, opts) {
|
|
|
14108
14888
|
memoryTasks: mount?.workspaceRememberLane.pendingCount() ?? 0
|
|
14109
14889
|
};
|
|
14110
14890
|
}, "getWorkspaceActivity"),
|
|
14891
|
+
ensureWorkspaceRememberLane: /* @__PURE__ */ __name((workspaceId) => {
|
|
14892
|
+
if (disposed) return void 0;
|
|
14893
|
+
const existing = mountForWorkspace(workspaceId);
|
|
14894
|
+
if (existing) return existing.workspaceRememberLane;
|
|
14895
|
+
const rt = opts.workspaceRegistry?.getByWorkspaceId(workspaceId);
|
|
14896
|
+
if (!rt) return void 0;
|
|
14897
|
+
const mount = getOrCreateSecondaryMount(rt);
|
|
14898
|
+
return mount?.workspaceRememberLane;
|
|
14899
|
+
}, "ensureWorkspaceRememberLane"),
|
|
14900
|
+
getWorkspaceRememberLane: /* @__PURE__ */ __name((workspaceId) => mountForWorkspace(workspaceId)?.workspaceRememberLane, "getWorkspaceRememberLane"),
|
|
14111
14901
|
commitWorkspaceRemoval: /* @__PURE__ */ __name((workspaceId) => {
|
|
14112
14902
|
const mount = secondaryMounts.get(workspaceId);
|
|
14113
14903
|
mount?.workspaceRememberLane.dispose();
|
|
@@ -16646,13 +17436,17 @@ function createExtensionsController(deps) {
|
|
|
16646
17436
|
const startedAt = Date.now();
|
|
16647
17437
|
try {
|
|
16648
17438
|
runtime.workspaceService.invalidateWorkspaceSkillsStatus();
|
|
16649
|
-
|
|
16650
|
-
|
|
16651
|
-
|
|
16652
|
-
|
|
16653
|
-
|
|
16654
|
-
|
|
16655
|
-
|
|
17439
|
+
try {
|
|
17440
|
+
return {
|
|
17441
|
+
status: "fulfilled",
|
|
17442
|
+
result: await runtime.bridge.refreshExtensionsForAllSessions(
|
|
17443
|
+
bridgeMutationEvent(event)
|
|
17444
|
+
),
|
|
17445
|
+
elapsedMs: Date.now() - startedAt
|
|
17446
|
+
};
|
|
17447
|
+
} finally {
|
|
17448
|
+
runtime.workspaceService.invalidateWorkspaceSkillsStatus();
|
|
17449
|
+
}
|
|
16656
17450
|
} catch (reason) {
|
|
16657
17451
|
return {
|
|
16658
17452
|
status: "rejected",
|
|
@@ -16727,10 +17521,14 @@ function createExtensionsController(deps) {
|
|
|
16727
17521
|
const { result, elapsedMs } = await runReconciliation(async () => {
|
|
16728
17522
|
workspace.invalidateWorkspaceSkillsStatus();
|
|
16729
17523
|
const startedAt = Date.now();
|
|
16730
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
17524
|
+
try {
|
|
17525
|
+
const result2 = await bridge.refreshExtensionsForAllSessions(
|
|
17526
|
+
bridgeMutationEvent(event)
|
|
17527
|
+
);
|
|
17528
|
+
return { result: result2, elapsedMs: Date.now() - startedAt };
|
|
17529
|
+
} finally {
|
|
17530
|
+
workspace.invalidateWorkspaceSkillsStatus();
|
|
17531
|
+
}
|
|
16734
17532
|
});
|
|
16735
17533
|
const warnings = [...commitWarnings];
|
|
16736
17534
|
if (result.failed > 0) {
|
|
@@ -17249,11 +18047,15 @@ function registerWorkspaceExtensionRoutes(app, deps) {
|
|
|
17249
18047
|
async () => await Promise.allSettled(
|
|
17250
18048
|
runtimes.map(async (runtime) => {
|
|
17251
18049
|
runtime.workspaceService.invalidateWorkspaceSkillsStatus();
|
|
17252
|
-
|
|
17253
|
-
|
|
17254
|
-
|
|
17255
|
-
|
|
17256
|
-
|
|
18050
|
+
try {
|
|
18051
|
+
const result = await runtime.bridge.refreshExtensionsForAllSessions();
|
|
18052
|
+
if (result.failed > 0) {
|
|
18053
|
+
throw new Error(
|
|
18054
|
+
`${result.failed} extension session refresh(es) failed`
|
|
18055
|
+
);
|
|
18056
|
+
}
|
|
18057
|
+
} finally {
|
|
18058
|
+
runtime.workspaceService.invalidateWorkspaceSkillsStatus();
|
|
17257
18059
|
}
|
|
17258
18060
|
})
|
|
17259
18061
|
)
|
|
@@ -19071,6 +19873,12 @@ var legacySessionTelemetryRoutes = [
|
|
|
19071
19873
|
attribution: "handler_resolved",
|
|
19072
19874
|
route: "POST /session/:id/fork"
|
|
19073
19875
|
},
|
|
19876
|
+
{
|
|
19877
|
+
method: "POST",
|
|
19878
|
+
path: "/session/:id/side-task",
|
|
19879
|
+
attribution: "handler_resolved",
|
|
19880
|
+
route: "POST /session/:id/side-task"
|
|
19881
|
+
},
|
|
19074
19882
|
{
|
|
19075
19883
|
method: "POST",
|
|
19076
19884
|
path: "/session/:id/cd",
|
|
@@ -21045,10 +21853,8 @@ var VirtualSubagentSessions = class {
|
|
|
21045
21853
|
totalTokens: task.stats?.totalTokens
|
|
21046
21854
|
};
|
|
21047
21855
|
}
|
|
21048
|
-
const
|
|
21049
|
-
|
|
21050
|
-
runtimeDir,
|
|
21051
|
-
runtime.workspaceCwd,
|
|
21856
|
+
const projectDir = Storage.runWithResolvedRuntimeBaseDir(
|
|
21857
|
+
runtime.sessionRuntimeBaseDir,
|
|
21052
21858
|
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
21053
21859
|
);
|
|
21054
21860
|
const sessionDir = getSubagentSessionDir(projectDir, parentSessionId);
|
|
@@ -21083,10 +21889,8 @@ var VirtualSubagentSessions = class {
|
|
|
21083
21889
|
return void 0;
|
|
21084
21890
|
}
|
|
21085
21891
|
async findLegacyTaskByToolCall(runtime, parentSessionId, toolCallId) {
|
|
21086
|
-
const
|
|
21087
|
-
|
|
21088
|
-
runtimeDir,
|
|
21089
|
-
runtime.workspaceCwd,
|
|
21892
|
+
const projectDir = Storage.runWithResolvedRuntimeBaseDir(
|
|
21893
|
+
runtime.sessionRuntimeBaseDir,
|
|
21090
21894
|
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
21091
21895
|
);
|
|
21092
21896
|
const parentRecords = await read(
|
|
@@ -21159,10 +21963,8 @@ var VirtualSubagentSessions = class {
|
|
|
21159
21963
|
};
|
|
21160
21964
|
}
|
|
21161
21965
|
async readParentToolCallMetrics(runtime, parentSessionId, toolCallId) {
|
|
21162
|
-
const
|
|
21163
|
-
|
|
21164
|
-
runtimeDir,
|
|
21165
|
-
runtime.workspaceCwd,
|
|
21966
|
+
const projectDir = Storage.runWithResolvedRuntimeBaseDir(
|
|
21967
|
+
runtime.sessionRuntimeBaseDir,
|
|
21166
21968
|
() => new Storage(runtime.workspaceCwd).getProjectDir()
|
|
21167
21969
|
);
|
|
21168
21970
|
const records = await read(
|
|
@@ -21174,7 +21976,11 @@ var VirtualSubagentSessions = class {
|
|
|
21174
21976
|
let task = await this.findTask(
|
|
21175
21977
|
runtime,
|
|
21176
21978
|
parentSessionId,
|
|
21177
|
-
(candidate) =>
|
|
21979
|
+
(candidate) => (
|
|
21980
|
+
// /fork has no parent transcript tool call, so its task ID is the
|
|
21981
|
+
// stable reference used by Web Shell.
|
|
21982
|
+
candidate.id === toolCallId || candidate.toolUseId === toolCallId || candidate.id.endsWith(`-${toolCallId}`)
|
|
21983
|
+
)
|
|
21178
21984
|
);
|
|
21179
21985
|
const metrics = task && task.status !== "running" ? await this.readParentToolCallMetrics(
|
|
21180
21986
|
runtime,
|
|
@@ -21234,16 +22040,35 @@ var VirtualSubagentSessions = class {
|
|
|
21234
22040
|
}
|
|
21235
22041
|
};
|
|
21236
22042
|
|
|
22043
|
+
// packages/cli/src/serve/workspace-runtime-storage.ts
|
|
22044
|
+
init_esbuild_shims();
|
|
22045
|
+
function runWithWorkspaceRuntimeStorage(runtime, fn) {
|
|
22046
|
+
return Storage.runWithResolvedRuntimeBaseDir(
|
|
22047
|
+
runtime.sessionRuntimeBaseDir,
|
|
22048
|
+
fn
|
|
22049
|
+
);
|
|
22050
|
+
}
|
|
22051
|
+
__name(runWithWorkspaceRuntimeStorage, "runWithWorkspaceRuntimeStorage");
|
|
22052
|
+
function createWorkspaceRuntimeSessionService(runtime, options = {}) {
|
|
22053
|
+
return new SessionService(runtime.workspaceCwd, {
|
|
22054
|
+
...options,
|
|
22055
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir
|
|
22056
|
+
});
|
|
22057
|
+
}
|
|
22058
|
+
__name(createWorkspaceRuntimeSessionService, "createWorkspaceRuntimeSessionService");
|
|
22059
|
+
|
|
21237
22060
|
// packages/cli/src/serve/routes/session.ts
|
|
21238
22061
|
var GIT_RESERVED_BRANCH = "HEAD";
|
|
21239
22062
|
var MAX_BRANCH_NAME_BYTES = 1e3;
|
|
21240
22063
|
var MAX_BRANCH_COMPONENT_BYTES = 200;
|
|
22064
|
+
var HTTP_SESSION_ID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
21241
22065
|
var WORKSPACE_TRANSCRIPT_RESPONSE_MAX_BYTES = 32 * 1024 * 1024;
|
|
21242
22066
|
var WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES = 64 * 1024;
|
|
21243
22067
|
var TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR = "Transcript pagination state exceeds the safe limit";
|
|
21244
22068
|
var CHANNEL_DELIVERY_AUTHORIZATION_GRACE_MS = 6e4;
|
|
21245
22069
|
var PRIMARY_ONLY_LIVE_SESSION_ROUTES = [
|
|
21246
22070
|
"POST /session/:id/branch",
|
|
22071
|
+
"POST /session/:id/side-task",
|
|
21247
22072
|
"POST /session/:id/fork",
|
|
21248
22073
|
"POST /session/:id/cd"
|
|
21249
22074
|
];
|
|
@@ -21258,7 +22083,8 @@ function isReadOnlyWorkspaceInspection(runtime) {
|
|
|
21258
22083
|
}
|
|
21259
22084
|
__name(isReadOnlyWorkspaceInspection, "isReadOnlyWorkspaceInspection");
|
|
21260
22085
|
function runWorkspaceInspectionWithLogPolicy(runtime, read2) {
|
|
21261
|
-
|
|
22086
|
+
const readInRuntime = /* @__PURE__ */ __name(() => runWithWorkspaceRuntimeStorage(runtime, read2), "readInRuntime");
|
|
22087
|
+
return isReadOnlyWorkspaceInspection(runtime) ? runWithoutDebugLogSession(readInRuntime) : readInRuntime();
|
|
21262
22088
|
}
|
|
21263
22089
|
__name(runWorkspaceInspectionWithLogPolicy, "runWorkspaceInspectionWithLogPolicy");
|
|
21264
22090
|
function requireSessionArtifactClientId(clientId, res) {
|
|
@@ -21395,6 +22221,15 @@ function shouldPreserveTranscriptResolutionError(err) {
|
|
|
21395
22221
|
return err instanceof SessionArchivedError || err instanceof SessionConflictError || err instanceof SessionNotFoundError;
|
|
21396
22222
|
}
|
|
21397
22223
|
__name(shouldPreserveTranscriptResolutionError, "shouldPreserveTranscriptResolutionError");
|
|
22224
|
+
function isSessionLive(bridge, sessionId) {
|
|
22225
|
+
try {
|
|
22226
|
+
bridge.getSessionSummary(sessionId);
|
|
22227
|
+
return true;
|
|
22228
|
+
} catch (err) {
|
|
22229
|
+
return !(err instanceof SessionNotFoundError);
|
|
22230
|
+
}
|
|
22231
|
+
}
|
|
22232
|
+
__name(isSessionLive, "isSessionLive");
|
|
21398
22233
|
function parseOptionalApprovalMode(body, res) {
|
|
21399
22234
|
const rawApprovalMode = body["approvalMode"];
|
|
21400
22235
|
if (rawApprovalMode === void 0) {
|
|
@@ -21429,6 +22264,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
21429
22264
|
const transcriptCursorCodecs = /* @__PURE__ */ new Map();
|
|
21430
22265
|
const activeBranchSessions = /* @__PURE__ */ new Map();
|
|
21431
22266
|
const inFlightBranchWorkspaces = /* @__PURE__ */ new Set();
|
|
22267
|
+
const inFlightSessionIds = /* @__PURE__ */ new Set();
|
|
21432
22268
|
const clearBranchSessionEntry = /* @__PURE__ */ __name((sessionId) => {
|
|
21433
22269
|
for (const [cwd, sid] of activeBranchSessions) {
|
|
21434
22270
|
if (sid === sessionId) {
|
|
@@ -21595,9 +22431,30 @@ function registerSessionRoutes(app, deps) {
|
|
|
21595
22431
|
}
|
|
21596
22432
|
return runtime;
|
|
21597
22433
|
}, "resolveRuntimeForCatalogRoute");
|
|
21598
|
-
const
|
|
22434
|
+
const resolveLegacyPrimaryRuntimeFromParam = /* @__PURE__ */ __name((req, res) => {
|
|
22435
|
+
const entry = resolveWorkspaceEntryFromParam(
|
|
22436
|
+
workspaceRegistry,
|
|
22437
|
+
req,
|
|
22438
|
+
res,
|
|
22439
|
+
"id"
|
|
22440
|
+
);
|
|
22441
|
+
if (!entry) return null;
|
|
22442
|
+
if (!entry.primary) {
|
|
22443
|
+
sendWorkspaceMismatch2(res, entry.workspaceCwd);
|
|
22444
|
+
return null;
|
|
22445
|
+
}
|
|
22446
|
+
const runtime = entry.state === "active" ? entry.current?.runtime : void 0;
|
|
22447
|
+
if (!runtime) {
|
|
22448
|
+
sendWorkspaceRuntimeUnavailable(res, entry);
|
|
22449
|
+
return null;
|
|
22450
|
+
}
|
|
22451
|
+
return runtime;
|
|
22452
|
+
}, "resolveLegacyPrimaryRuntimeFromParam");
|
|
22453
|
+
const hasActivePersistedSessions = /* @__PURE__ */ __name(async (runtime) => {
|
|
21599
22454
|
try {
|
|
21600
|
-
const page = await
|
|
22455
|
+
const page = await createWorkspaceRuntimeSessionService(
|
|
22456
|
+
runtime
|
|
22457
|
+
).listSessions({
|
|
21601
22458
|
archiveState: "active",
|
|
21602
22459
|
size: 1
|
|
21603
22460
|
});
|
|
@@ -21647,20 +22504,28 @@ function registerSessionRoutes(app, deps) {
|
|
|
21647
22504
|
try {
|
|
21648
22505
|
const result = await archiveCoordinator.runSharedMany(
|
|
21649
22506
|
[sessionId],
|
|
21650
|
-
async () => {
|
|
22507
|
+
() => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
|
|
21651
22508
|
if (target.archiveState === "archived") {
|
|
21652
|
-
await assertSessionArchived(
|
|
22509
|
+
await assertSessionArchived(
|
|
22510
|
+
target.runtime.workspaceCwd,
|
|
22511
|
+
sessionId,
|
|
22512
|
+
target.runtime.sessionRuntimeBaseDir
|
|
22513
|
+
);
|
|
21653
22514
|
} else {
|
|
21654
|
-
await assertSessionLoadable(
|
|
22515
|
+
await assertSessionLoadable(
|
|
22516
|
+
target.runtime.workspaceCwd,
|
|
22517
|
+
sessionId,
|
|
22518
|
+
target.runtime.sessionRuntimeBaseDir
|
|
22519
|
+
);
|
|
21655
22520
|
}
|
|
21656
22521
|
return exportSessionTranscript({
|
|
21657
|
-
workspaceCwd: target.workspaceCwd,
|
|
22522
|
+
workspaceCwd: target.runtime.workspaceCwd,
|
|
21658
22523
|
sessionId,
|
|
21659
22524
|
format,
|
|
21660
22525
|
archiveState: target.archiveState,
|
|
21661
22526
|
config: { getChannel: /* @__PURE__ */ __name(() => "daemon", "getChannel") }
|
|
21662
22527
|
});
|
|
21663
|
-
}
|
|
22528
|
+
})
|
|
21664
22529
|
);
|
|
21665
22530
|
const filename = result.filename.replace(/["\\\r\n]/g, "_");
|
|
21666
22531
|
res.status(200).set("Cache-Control", "no-store").set("X-Content-Type-Options", "nosniff").set("Content-Type", result.mimeType).set("Content-Disposition", `attachment; filename="${filename}"`).send(result.content);
|
|
@@ -21676,7 +22541,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
21676
22541
|
sendBridgeError2(res, err, {
|
|
21677
22542
|
route: target.route,
|
|
21678
22543
|
sessionId,
|
|
21679
|
-
...target.workspaceQualified ? { workspaceCwd: target.workspaceCwd } : {}
|
|
22544
|
+
...target.workspaceQualified ? { workspaceCwd: target.runtime.workspaceCwd } : {}
|
|
21680
22545
|
});
|
|
21681
22546
|
}
|
|
21682
22547
|
}, "handleSessionExport");
|
|
@@ -21861,7 +22726,8 @@ function registerSessionRoutes(app, deps) {
|
|
|
21861
22726
|
const activeInRuntime = /* @__PURE__ */ __name(async (runtime) => {
|
|
21862
22727
|
const location = await assertSessionLoadable(
|
|
21863
22728
|
runtime.workspaceCwd,
|
|
21864
|
-
sessionId
|
|
22729
|
+
sessionId,
|
|
22730
|
+
runtime.sessionRuntimeBaseDir
|
|
21865
22731
|
);
|
|
21866
22732
|
return location === "active";
|
|
21867
22733
|
}, "activeInRuntime");
|
|
@@ -21964,19 +22830,6 @@ function registerSessionRoutes(app, deps) {
|
|
|
21964
22830
|
sessionId: e.sessionId,
|
|
21965
22831
|
error: e.error instanceof Error ? e.error.message : String(e.error)
|
|
21966
22832
|
})), "serializeSessionErrors");
|
|
21967
|
-
const resolveWorkspaceParam = /* @__PURE__ */ __name((req, res) => {
|
|
21968
|
-
const workspaceCwd = req.params["id"] ?? "";
|
|
21969
|
-
if (!path10.isAbsolute(workspaceCwd)) {
|
|
21970
|
-
res.status(400).json({ error: "`:id` must decode to an absolute workspace path" });
|
|
21971
|
-
return null;
|
|
21972
|
-
}
|
|
21973
|
-
const key = canonicalizeWorkspace(workspaceCwd);
|
|
21974
|
-
if (key !== boundWorkspace) {
|
|
21975
|
-
sendWorkspaceMismatch2(res, key);
|
|
21976
|
-
return null;
|
|
21977
|
-
}
|
|
21978
|
-
return key;
|
|
21979
|
-
}, "resolveWorkspaceParam");
|
|
21980
22833
|
const withPrimaryOnlyMutableSession = /* @__PURE__ */ __name((route, handler) => {
|
|
21981
22834
|
if (!isPrimaryOnlyLiveSessionRoute(route)) {
|
|
21982
22835
|
throw new Error(`Unregistered primary-only session route: ${route}`);
|
|
@@ -22039,201 +22892,246 @@ function registerSessionRoutes(app, deps) {
|
|
|
22039
22892
|
}
|
|
22040
22893
|
const clientId = parseClientIdHeader(req, res);
|
|
22041
22894
|
if (clientId === null) return;
|
|
22042
|
-
|
|
22043
|
-
let
|
|
22044
|
-
|
|
22045
|
-
|
|
22046
|
-
if (body["worktree"] !== void 0 && body["worktree"] !== null) {
|
|
22895
|
+
const rawSessionId = body["sessionId"];
|
|
22896
|
+
let requestedSessionId;
|
|
22897
|
+
if (rawSessionId !== void 0 && rawSessionId !== null) {
|
|
22898
|
+
if (typeof rawSessionId !== "string" || !HTTP_SESSION_ID_REGEX.test(rawSessionId)) {
|
|
22047
22899
|
res.status(400).json({
|
|
22048
|
-
error:
|
|
22049
|
-
code: "
|
|
22900
|
+
error: '`sessionId` must be a UUID (e.g. "550e8400-e29b-41d4-a716-446655440000")',
|
|
22901
|
+
code: "invalid_session_id"
|
|
22050
22902
|
});
|
|
22051
22903
|
return;
|
|
22052
22904
|
}
|
|
22053
|
-
|
|
22054
|
-
|
|
22055
|
-
|
|
22056
|
-
|
|
22905
|
+
requestedSessionId = rawSessionId.toLowerCase();
|
|
22906
|
+
const sessionIdToCheck = requestedSessionId;
|
|
22907
|
+
if (isSessionLive(runtime.bridge, sessionIdToCheck)) {
|
|
22908
|
+
res.status(409).json({
|
|
22909
|
+
error: `Session "${requestedSessionId}" already exists`,
|
|
22910
|
+
code: "session_id_conflict"
|
|
22057
22911
|
});
|
|
22058
22912
|
return;
|
|
22059
22913
|
}
|
|
22060
|
-
const
|
|
22061
|
-
|
|
22062
|
-
|
|
22063
|
-
|
|
22064
|
-
|
|
22065
|
-
|
|
22914
|
+
const runtimeOutputDir = loadSettingsCached(workspaceCwd).merged.advanced?.runtimeOutputDir;
|
|
22915
|
+
if (await Storage.runWithRuntimeBaseDir(
|
|
22916
|
+
runtimeOutputDir,
|
|
22917
|
+
workspaceCwd,
|
|
22918
|
+
() => new SessionService(workspaceCwd).sessionExistsInAnyState(
|
|
22919
|
+
sessionIdToCheck
|
|
22920
|
+
)
|
|
22921
|
+
)) {
|
|
22922
|
+
res.status(409).json({
|
|
22923
|
+
error: `Session "${requestedSessionId}" already exists`,
|
|
22924
|
+
code: "session_id_conflict"
|
|
22066
22925
|
});
|
|
22067
22926
|
return;
|
|
22068
22927
|
}
|
|
22069
|
-
if (
|
|
22070
|
-
(
|
|
22071
|
-
|
|
22072
|
-
|
|
22073
|
-
error: `Invalid branch name: ${branchName}`,
|
|
22074
|
-
code: "branch_invalid_name"
|
|
22928
|
+
if (inFlightSessionIds.has(requestedSessionId)) {
|
|
22929
|
+
res.status(409).json({
|
|
22930
|
+
error: `Session "${requestedSessionId}" creation already in progress`,
|
|
22931
|
+
code: "session_id_conflict"
|
|
22075
22932
|
});
|
|
22076
22933
|
return;
|
|
22077
22934
|
}
|
|
22078
|
-
|
|
22079
|
-
|
|
22080
|
-
|
|
22081
|
-
|
|
22935
|
+
inFlightSessionIds.add(requestedSessionId);
|
|
22936
|
+
}
|
|
22937
|
+
let branchMeta;
|
|
22938
|
+
let branchBaseCommit;
|
|
22939
|
+
let worktreeMeta;
|
|
22940
|
+
try {
|
|
22941
|
+
const rawBranch = body["branch"];
|
|
22942
|
+
if (rawBranch !== void 0 && rawBranch !== null) {
|
|
22943
|
+
if (body["worktree"] !== void 0 && body["worktree"] !== null) {
|
|
22944
|
+
res.status(400).json({
|
|
22945
|
+
error: "`branch` and `worktree` are mutually exclusive",
|
|
22946
|
+
code: "branch_and_worktree_conflict"
|
|
22947
|
+
});
|
|
22948
|
+
return;
|
|
22949
|
+
}
|
|
22950
|
+
if (typeof rawBranch !== "object" || Array.isArray(rawBranch)) {
|
|
22951
|
+
res.status(400).json({
|
|
22952
|
+
error: '`branch` must be an object (e.g. `{"name":"feat/my-feature"}`)',
|
|
22953
|
+
code: "invalid_branch"
|
|
22954
|
+
});
|
|
22955
|
+
return;
|
|
22956
|
+
}
|
|
22957
|
+
const branchReq = rawBranch;
|
|
22958
|
+
const branchName = branchReq["name"];
|
|
22959
|
+
if (typeof branchName !== "string" || branchName.length === 0) {
|
|
22960
|
+
res.status(400).json({
|
|
22961
|
+
error: "`branch.name` must be a non-empty string",
|
|
22962
|
+
code: "branch_invalid_name"
|
|
22963
|
+
});
|
|
22964
|
+
return;
|
|
22965
|
+
}
|
|
22966
|
+
if (/[^\p{L}\p{N}._/-]/u.test(branchName) || branchName.includes("..") || branchName.includes("//") || branchName.startsWith(".") || branchName.startsWith("-") || branchName.startsWith("/") || branchName.endsWith("/") || branchName.endsWith(".") || branchName.endsWith(".git") || branchName.includes("@{") || branchName.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")) || branchName.toUpperCase() === GIT_RESERVED_BRANCH || Buffer.byteLength(branchName, "utf8") > MAX_BRANCH_NAME_BYTES || branchName.split("/").some(
|
|
22967
|
+
(c) => Buffer.byteLength(c, "utf8") > MAX_BRANCH_COMPONENT_BYTES
|
|
22968
|
+
)) {
|
|
22969
|
+
res.status(400).json({
|
|
22970
|
+
error: `Invalid branch name: ${branchName}`,
|
|
22971
|
+
code: "branch_invalid_name"
|
|
22972
|
+
});
|
|
22973
|
+
return;
|
|
22974
|
+
}
|
|
22975
|
+
const existingBranchSession = activeBranchSessions.get(workspaceCwd);
|
|
22976
|
+
if (existingBranchSession) {
|
|
22977
|
+
try {
|
|
22978
|
+
runtime.bridge.getSessionSummary(existingBranchSession);
|
|
22979
|
+
res.status(409).json({
|
|
22980
|
+
error: "A branch session is already active for this workspace",
|
|
22981
|
+
code: "branch_session_conflict",
|
|
22982
|
+
existingSessionId: existingBranchSession
|
|
22983
|
+
});
|
|
22984
|
+
return;
|
|
22985
|
+
} catch {
|
|
22986
|
+
activeBranchSessions.delete(workspaceCwd);
|
|
22987
|
+
}
|
|
22988
|
+
}
|
|
22989
|
+
const sharedCheckoutSession = runtime.bridge.listWorkspaceSessions(workspaceCwd).find((session2) => !session2.worktree && session2.clientCount > 0);
|
|
22990
|
+
if (sharedCheckoutSession) {
|
|
22082
22991
|
res.status(409).json({
|
|
22083
|
-
error: "
|
|
22992
|
+
error: "Another session is already active in this workspace; creating a branch would move its shared checkout",
|
|
22084
22993
|
code: "branch_session_conflict",
|
|
22085
|
-
existingSessionId:
|
|
22994
|
+
existingSessionId: sharedCheckoutSession.sessionId
|
|
22086
22995
|
});
|
|
22087
22996
|
return;
|
|
22997
|
+
}
|
|
22998
|
+
let wtService;
|
|
22999
|
+
try {
|
|
23000
|
+
wtService = new GitWorktreeService(workspaceCwd);
|
|
22088
23001
|
} catch {
|
|
22089
|
-
|
|
23002
|
+
res.status(500).json({
|
|
23003
|
+
error: "Failed to initialize git service",
|
|
23004
|
+
code: "branch_init_failed"
|
|
23005
|
+
});
|
|
23006
|
+
return;
|
|
22090
23007
|
}
|
|
23008
|
+
if (!await wtService.isGitRepository()) {
|
|
23009
|
+
res.status(400).json({
|
|
23010
|
+
error: "Branch creation requires a git repository",
|
|
23011
|
+
code: "branch_not_git_repo"
|
|
23012
|
+
});
|
|
23013
|
+
return;
|
|
23014
|
+
}
|
|
23015
|
+
if (await branchExists(workspaceCwd, branchName)) {
|
|
23016
|
+
res.status(409).json({
|
|
23017
|
+
error: `Branch "${branchName}" already exists`,
|
|
23018
|
+
code: "branch_already_exists"
|
|
23019
|
+
});
|
|
23020
|
+
return;
|
|
23021
|
+
}
|
|
23022
|
+
let dirty;
|
|
23023
|
+
try {
|
|
23024
|
+
dirty = await isDirtyTree(workspaceCwd);
|
|
23025
|
+
} catch {
|
|
23026
|
+
res.status(500).json({
|
|
23027
|
+
error: "Failed to check working tree status",
|
|
23028
|
+
code: "branch_status_failed"
|
|
23029
|
+
});
|
|
23030
|
+
return;
|
|
23031
|
+
}
|
|
23032
|
+
if (dirty) {
|
|
23033
|
+
res.status(409).json({
|
|
23034
|
+
error: "Uncommitted changes detected. Commit or stash first.",
|
|
23035
|
+
code: "branch_dirty_tree"
|
|
23036
|
+
});
|
|
23037
|
+
return;
|
|
23038
|
+
}
|
|
23039
|
+
const baseCommit = await getHeadCommit(workspaceCwd);
|
|
23040
|
+
const baseBranch = await wtService.getCurrentBranch().catch(() => "HEAD");
|
|
23041
|
+
if (inFlightBranchWorkspaces.has(workspaceCwd) || activeBranchSessions.has(workspaceCwd)) {
|
|
23042
|
+
res.status(409).json({
|
|
23043
|
+
error: "A branch session is already being created for this workspace",
|
|
23044
|
+
code: "branch_session_conflict"
|
|
23045
|
+
});
|
|
23046
|
+
return;
|
|
23047
|
+
}
|
|
23048
|
+
inFlightBranchWorkspaces.add(workspaceCwd);
|
|
23049
|
+
try {
|
|
23050
|
+
await createBranch(workspaceCwd, branchName);
|
|
23051
|
+
} catch (checkoutErr) {
|
|
23052
|
+
daemonLog?.warn("branch checkout failed", {
|
|
23053
|
+
error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
|
|
23054
|
+
});
|
|
23055
|
+
await rollbackBranchCreation(
|
|
23056
|
+
workspaceCwd,
|
|
23057
|
+
{ name: branchName, baseBranch },
|
|
23058
|
+
baseCommit,
|
|
23059
|
+
daemonLog
|
|
23060
|
+
);
|
|
23061
|
+
res.status(500).json({
|
|
23062
|
+
error: "Failed to create branch",
|
|
23063
|
+
code: "branch_checkout_failed"
|
|
23064
|
+
});
|
|
23065
|
+
return;
|
|
23066
|
+
}
|
|
23067
|
+
branchMeta = { name: branchName, baseBranch };
|
|
23068
|
+
branchBaseCommit = baseCommit;
|
|
23069
|
+
sessionScope = "thread";
|
|
22091
23070
|
}
|
|
22092
|
-
const
|
|
22093
|
-
if (
|
|
22094
|
-
|
|
22095
|
-
|
|
22096
|
-
|
|
22097
|
-
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
|
|
22105
|
-
|
|
22106
|
-
|
|
22107
|
-
|
|
22108
|
-
|
|
22109
|
-
|
|
22110
|
-
|
|
22111
|
-
|
|
22112
|
-
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22117
|
-
|
|
22118
|
-
|
|
22119
|
-
|
|
22120
|
-
|
|
22121
|
-
|
|
22122
|
-
|
|
22123
|
-
|
|
22124
|
-
|
|
22125
|
-
|
|
22126
|
-
|
|
22127
|
-
|
|
22128
|
-
|
|
22129
|
-
|
|
22130
|
-
|
|
22131
|
-
|
|
22132
|
-
|
|
22133
|
-
|
|
22134
|
-
|
|
22135
|
-
|
|
22136
|
-
|
|
22137
|
-
|
|
22138
|
-
|
|
22139
|
-
|
|
22140
|
-
|
|
22141
|
-
|
|
22142
|
-
|
|
22143
|
-
|
|
22144
|
-
|
|
22145
|
-
|
|
22146
|
-
|
|
22147
|
-
|
|
22148
|
-
|
|
22149
|
-
|
|
22150
|
-
|
|
22151
|
-
|
|
22152
|
-
try {
|
|
22153
|
-
await createBranch(workspaceCwd, branchName);
|
|
22154
|
-
} catch (checkoutErr) {
|
|
22155
|
-
daemonLog?.warn("branch checkout failed", {
|
|
22156
|
-
error: checkoutErr instanceof Error ? checkoutErr.message : String(checkoutErr)
|
|
22157
|
-
});
|
|
22158
|
-
await rollbackBranchCreation(
|
|
22159
|
-
workspaceCwd,
|
|
22160
|
-
{ name: branchName, baseBranch },
|
|
22161
|
-
baseCommit,
|
|
22162
|
-
daemonLog
|
|
22163
|
-
);
|
|
22164
|
-
res.status(500).json({
|
|
22165
|
-
error: "Failed to create branch",
|
|
22166
|
-
code: "branch_checkout_failed"
|
|
22167
|
-
});
|
|
22168
|
-
return;
|
|
22169
|
-
}
|
|
22170
|
-
branchMeta = { name: branchName, baseBranch };
|
|
22171
|
-
branchBaseCommit = baseCommit;
|
|
22172
|
-
sessionScope = "thread";
|
|
22173
|
-
}
|
|
22174
|
-
let worktreeMeta;
|
|
22175
|
-
const rawWorktree = body["worktree"];
|
|
22176
|
-
if (rawWorktree !== void 0 && rawWorktree !== null) {
|
|
22177
|
-
if (typeof rawWorktree !== "object" || Array.isArray(rawWorktree)) {
|
|
22178
|
-
res.status(400).json({
|
|
22179
|
-
error: '`worktree` must be an object (e.g. `{}` or `{"slug":"my-task"}`)',
|
|
22180
|
-
code: "invalid_worktree"
|
|
22181
|
-
});
|
|
22182
|
-
return;
|
|
22183
|
-
}
|
|
22184
|
-
const wtReq = rawWorktree;
|
|
22185
|
-
let wtService;
|
|
22186
|
-
try {
|
|
22187
|
-
wtService = new GitWorktreeService(workspaceCwd);
|
|
22188
|
-
} catch {
|
|
22189
|
-
res.status(500).json({
|
|
22190
|
-
error: "Failed to initialize worktree service",
|
|
22191
|
-
code: "worktree_init_failed"
|
|
22192
|
-
});
|
|
22193
|
-
return;
|
|
22194
|
-
}
|
|
22195
|
-
if (!await wtService.isGitRepository()) {
|
|
22196
|
-
res.status(400).json({
|
|
22197
|
-
error: "Worktree isolation requires a git repository",
|
|
22198
|
-
code: "worktree_not_git_repo"
|
|
22199
|
-
});
|
|
22200
|
-
return;
|
|
22201
|
-
}
|
|
22202
|
-
const rawSlug = wtReq["slug"];
|
|
22203
|
-
let slug;
|
|
22204
|
-
if (rawSlug === void 0 || rawSlug === null) {
|
|
22205
|
-
slug = GitWorktreeService.generateAutoSlug();
|
|
22206
|
-
} else if (typeof rawSlug !== "string" || rawSlug.length === 0) {
|
|
22207
|
-
res.status(400).json({
|
|
22208
|
-
error: "`worktree.slug` must be a non-empty string when provided",
|
|
22209
|
-
code: "worktree_invalid_slug"
|
|
22210
|
-
});
|
|
22211
|
-
return;
|
|
22212
|
-
} else {
|
|
22213
|
-
slug = rawSlug;
|
|
22214
|
-
}
|
|
22215
|
-
const slugError = GitWorktreeService.validateUserWorktreeSlug(slug);
|
|
22216
|
-
if (slugError) {
|
|
22217
|
-
res.status(400).json({ error: slugError, code: "worktree_invalid_slug" });
|
|
22218
|
-
return;
|
|
23071
|
+
const rawWorktree = body["worktree"];
|
|
23072
|
+
if (rawWorktree !== void 0 && rawWorktree !== null) {
|
|
23073
|
+
if (typeof rawWorktree !== "object" || Array.isArray(rawWorktree)) {
|
|
23074
|
+
res.status(400).json({
|
|
23075
|
+
error: '`worktree` must be an object (e.g. `{}` or `{"slug":"my-task"}`)',
|
|
23076
|
+
code: "invalid_worktree"
|
|
23077
|
+
});
|
|
23078
|
+
return;
|
|
23079
|
+
}
|
|
23080
|
+
const wtReq = rawWorktree;
|
|
23081
|
+
let wtService;
|
|
23082
|
+
try {
|
|
23083
|
+
wtService = new GitWorktreeService(workspaceCwd);
|
|
23084
|
+
} catch {
|
|
23085
|
+
res.status(500).json({
|
|
23086
|
+
error: "Failed to initialize worktree service",
|
|
23087
|
+
code: "worktree_init_failed"
|
|
23088
|
+
});
|
|
23089
|
+
return;
|
|
23090
|
+
}
|
|
23091
|
+
if (!await wtService.isGitRepository()) {
|
|
23092
|
+
res.status(400).json({
|
|
23093
|
+
error: "Worktree isolation requires a git repository",
|
|
23094
|
+
code: "worktree_not_git_repo"
|
|
23095
|
+
});
|
|
23096
|
+
return;
|
|
23097
|
+
}
|
|
23098
|
+
const rawSlug = wtReq["slug"];
|
|
23099
|
+
let slug;
|
|
23100
|
+
if (rawSlug === void 0 || rawSlug === null) {
|
|
23101
|
+
slug = GitWorktreeService.generateAutoSlug();
|
|
23102
|
+
} else if (typeof rawSlug !== "string" || rawSlug.length === 0) {
|
|
23103
|
+
res.status(400).json({
|
|
23104
|
+
error: "`worktree.slug` must be a non-empty string when provided",
|
|
23105
|
+
code: "worktree_invalid_slug"
|
|
23106
|
+
});
|
|
23107
|
+
return;
|
|
23108
|
+
} else {
|
|
23109
|
+
slug = rawSlug;
|
|
23110
|
+
}
|
|
23111
|
+
const slugError = GitWorktreeService.validateUserWorktreeSlug(slug);
|
|
23112
|
+
if (slugError) {
|
|
23113
|
+
res.status(400).json({ error: slugError, code: "worktree_invalid_slug" });
|
|
23114
|
+
return;
|
|
23115
|
+
}
|
|
23116
|
+
const baseBranch = await wtService.getCurrentBranch().catch(() => void 0);
|
|
23117
|
+
const wtResult = await wtService.createUserWorktree(slug, baseBranch);
|
|
23118
|
+
if (!wtResult.success || !wtResult.worktree) {
|
|
23119
|
+
res.status(500).json({
|
|
23120
|
+
error: wtResult.error ?? "Failed to create worktree",
|
|
23121
|
+
code: "worktree_create_failed"
|
|
23122
|
+
});
|
|
23123
|
+
return;
|
|
23124
|
+
}
|
|
23125
|
+
worktreeMeta = {
|
|
23126
|
+
slug,
|
|
23127
|
+
path: wtResult.worktree.path,
|
|
23128
|
+
branch: wtResult.worktree.branch
|
|
23129
|
+
};
|
|
23130
|
+
sessionScope = "thread";
|
|
22219
23131
|
}
|
|
22220
|
-
|
|
22221
|
-
|
|
22222
|
-
if (!wtResult.success || !wtResult.worktree) {
|
|
22223
|
-
res.status(500).json({
|
|
22224
|
-
error: wtResult.error ?? "Failed to create worktree",
|
|
22225
|
-
code: "worktree_create_failed"
|
|
22226
|
-
});
|
|
22227
|
-
return;
|
|
23132
|
+
if (requestedSessionId !== void 0) {
|
|
23133
|
+
sessionScope = "thread";
|
|
22228
23134
|
}
|
|
22229
|
-
worktreeMeta = {
|
|
22230
|
-
slug,
|
|
22231
|
-
path: wtResult.worktree.path,
|
|
22232
|
-
branch: wtResult.worktree.branch
|
|
22233
|
-
};
|
|
22234
|
-
sessionScope = "thread";
|
|
22235
|
-
}
|
|
22236
|
-
try {
|
|
22237
23135
|
const session = await runtime.bridge.spawnOrAttach({
|
|
22238
23136
|
workspaceCwd,
|
|
22239
23137
|
modelServiceId,
|
|
@@ -22243,20 +23141,60 @@ function registerSessionRoutes(app, deps) {
|
|
|
22243
23141
|
...source.sourceType !== void 0 ? { sourceType: source.sourceType } : {},
|
|
22244
23142
|
...source.sourceId !== void 0 ? { sourceId: source.sourceId } : {},
|
|
22245
23143
|
...worktreeMeta ? { worktree: worktreeMeta } : {},
|
|
22246
|
-
...branchMeta ? { branch: branchMeta } : {}
|
|
23144
|
+
...branchMeta ? { branch: branchMeta } : {},
|
|
23145
|
+
...requestedSessionId !== void 0 ? { sessionId: requestedSessionId } : {}
|
|
22247
23146
|
});
|
|
23147
|
+
if (requestedSessionId !== void 0 && session.sessionId !== requestedSessionId) {
|
|
23148
|
+
if (daemonLog) {
|
|
23149
|
+
daemonLog.warn("session id not honored by agent", {
|
|
23150
|
+
requested: requestedSessionId,
|
|
23151
|
+
actual: session.sessionId
|
|
23152
|
+
});
|
|
23153
|
+
}
|
|
23154
|
+
if (!session.attached) {
|
|
23155
|
+
await runWithWorkspaceRuntimeStorage(
|
|
23156
|
+
runtime,
|
|
23157
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23158
|
+
sessionId: session.sessionId,
|
|
23159
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23160
|
+
bridge: runtime.bridge,
|
|
23161
|
+
coordinator: archiveCoordinator
|
|
23162
|
+
})
|
|
23163
|
+
).catch(() => false);
|
|
23164
|
+
}
|
|
23165
|
+
if (worktreeMeta) {
|
|
23166
|
+
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
23167
|
+
});
|
|
23168
|
+
}
|
|
23169
|
+
if (branchMeta) {
|
|
23170
|
+
await rollbackBranchCreation(
|
|
23171
|
+
workspaceCwd,
|
|
23172
|
+
branchMeta,
|
|
23173
|
+
branchBaseCommit,
|
|
23174
|
+
daemonLog
|
|
23175
|
+
);
|
|
23176
|
+
}
|
|
23177
|
+
res.status(500).json({
|
|
23178
|
+
error: "Agent did not honor the requested session id",
|
|
23179
|
+
code: "session_id_not_honored"
|
|
23180
|
+
});
|
|
23181
|
+
return;
|
|
23182
|
+
}
|
|
22248
23183
|
try {
|
|
22249
23184
|
runtime.generationGuard?.assertOpen();
|
|
22250
23185
|
} catch (error2) {
|
|
22251
23186
|
if (!session.attached) {
|
|
22252
23187
|
try {
|
|
22253
|
-
const
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
|
|
22257
|
-
|
|
22258
|
-
|
|
22259
|
-
|
|
23188
|
+
const removed = await runWithWorkspaceRuntimeStorage(
|
|
23189
|
+
runtime,
|
|
23190
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23191
|
+
sessionId: session.sessionId,
|
|
23192
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23193
|
+
bridge: runtime.bridge,
|
|
23194
|
+
coordinator: archiveCoordinator
|
|
23195
|
+
})
|
|
23196
|
+
);
|
|
23197
|
+
if (removed) {
|
|
22260
23198
|
if (worktreeMeta) {
|
|
22261
23199
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
22262
23200
|
});
|
|
@@ -22288,13 +23226,16 @@ function registerSessionRoutes(app, deps) {
|
|
|
22288
23226
|
}
|
|
22289
23227
|
if (!session.attached) {
|
|
22290
23228
|
try {
|
|
22291
|
-
const
|
|
22292
|
-
|
|
22293
|
-
|
|
22294
|
-
|
|
22295
|
-
|
|
22296
|
-
|
|
22297
|
-
|
|
23229
|
+
const removed = await runWithWorkspaceRuntimeStorage(
|
|
23230
|
+
runtime,
|
|
23231
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23232
|
+
sessionId: session.sessionId,
|
|
23233
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23234
|
+
bridge: runtime.bridge,
|
|
23235
|
+
coordinator: archiveCoordinator
|
|
23236
|
+
})
|
|
23237
|
+
);
|
|
23238
|
+
if (removed) {
|
|
22298
23239
|
if (worktreeMeta) {
|
|
22299
23240
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
22300
23241
|
});
|
|
@@ -22353,9 +23294,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
22353
23294
|
).catch(() => {
|
|
22354
23295
|
});
|
|
22355
23296
|
await writeWorktreeSession(
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
),
|
|
23297
|
+
createWorkspaceRuntimeSessionService(
|
|
23298
|
+
runtime
|
|
23299
|
+
).getWorktreeSessionPath(session.sessionId),
|
|
22359
23300
|
{
|
|
22360
23301
|
slug: worktreeMeta.slug,
|
|
22361
23302
|
worktreePath: worktreeMeta.path,
|
|
@@ -22373,11 +23314,15 @@ function registerSessionRoutes(app, deps) {
|
|
|
22373
23314
|
error: cdErr instanceof Error ? cdErr.message : String(cdErr)
|
|
22374
23315
|
});
|
|
22375
23316
|
}
|
|
22376
|
-
|
|
22377
|
-
|
|
22378
|
-
|
|
22379
|
-
|
|
22380
|
-
|
|
23317
|
+
await runWithWorkspaceRuntimeStorage(
|
|
23318
|
+
runtime,
|
|
23319
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23320
|
+
sessionId: session.sessionId,
|
|
23321
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23322
|
+
bridge: runtime.bridge,
|
|
23323
|
+
coordinator: archiveCoordinator
|
|
23324
|
+
})
|
|
23325
|
+
).catch(() => false);
|
|
22381
23326
|
await new GitWorktreeService(workspaceCwd).removeUserWorktree(worktreeMeta.slug, { deleteBranch: true }).catch(() => {
|
|
22382
23327
|
});
|
|
22383
23328
|
res.status(500).json({
|
|
@@ -22406,6 +23351,10 @@ function registerSessionRoutes(app, deps) {
|
|
|
22406
23351
|
);
|
|
22407
23352
|
}
|
|
22408
23353
|
sendBridgeError2(res, err, { route: "POST /session" });
|
|
23354
|
+
} finally {
|
|
23355
|
+
if (requestedSessionId !== void 0) {
|
|
23356
|
+
inFlightSessionIds.delete(requestedSessionId);
|
|
23357
|
+
}
|
|
22409
23358
|
}
|
|
22410
23359
|
});
|
|
22411
23360
|
const restoreSessionHandler = /* @__PURE__ */ __name((action) => async (req, res) => {
|
|
@@ -22502,9 +23451,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
22502
23451
|
const session = await archiveCoordinator.runSharedMany(
|
|
22503
23452
|
[sessionId],
|
|
22504
23453
|
async () => {
|
|
22505
|
-
await assertSessionLoadable(
|
|
22506
|
-
|
|
22507
|
-
|
|
23454
|
+
await assertSessionLoadable(
|
|
23455
|
+
workspaceCwd,
|
|
23456
|
+
sessionId,
|
|
23457
|
+
runtime.sessionRuntimeBaseDir
|
|
23458
|
+
);
|
|
23459
|
+
const metadata = await createWorkspaceRuntimeSessionService(
|
|
23460
|
+
runtime
|
|
22508
23461
|
).readCreationMetadata(sessionId);
|
|
22509
23462
|
runtime.generationGuard?.assertOpen();
|
|
22510
23463
|
return action === "load" ? await runtime.bridge.loadSession({
|
|
@@ -22554,7 +23507,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
22554
23507
|
}
|
|
22555
23508
|
if (!session.worktree) {
|
|
22556
23509
|
const sidecar = await readWorktreeSession(
|
|
22557
|
-
|
|
23510
|
+
createWorkspaceRuntimeSessionService(
|
|
23511
|
+
runtime
|
|
23512
|
+
).getWorktreeSessionPath(sessionId)
|
|
22558
23513
|
).catch(() => null);
|
|
22559
23514
|
if (sidecar) {
|
|
22560
23515
|
let realTarget;
|
|
@@ -22757,13 +23712,72 @@ function registerSessionRoutes(app, deps) {
|
|
|
22757
23712
|
{ name },
|
|
22758
23713
|
{ clientId }
|
|
22759
23714
|
);
|
|
23715
|
+
try {
|
|
23716
|
+
runtime.generationGuard?.assertOpen();
|
|
23717
|
+
} catch (error2) {
|
|
23718
|
+
if (!result.attached) {
|
|
23719
|
+
await runWithWorkspaceRuntimeStorage(
|
|
23720
|
+
runtime,
|
|
23721
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23722
|
+
sessionId: result.sessionId,
|
|
23723
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23724
|
+
bridge: runtime.bridge,
|
|
23725
|
+
coordinator: archiveCoordinator
|
|
23726
|
+
})
|
|
23727
|
+
).catch(() => false);
|
|
23728
|
+
} else {
|
|
23729
|
+
await runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
|
|
23730
|
+
});
|
|
23731
|
+
}
|
|
23732
|
+
throw error2;
|
|
23733
|
+
}
|
|
23734
|
+
if (!res.writable) {
|
|
23735
|
+
if (!result.attached) {
|
|
23736
|
+
void runWithWorkspaceRuntimeStorage(
|
|
23737
|
+
runtime,
|
|
23738
|
+
() => deleteDaemonSessionIfOrphan({
|
|
23739
|
+
sessionId: result.sessionId,
|
|
23740
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
23741
|
+
bridge: runtime.bridge,
|
|
23742
|
+
coordinator: archiveCoordinator
|
|
23743
|
+
})
|
|
23744
|
+
).catch(() => {
|
|
23745
|
+
});
|
|
23746
|
+
} else {
|
|
23747
|
+
runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
|
|
23748
|
+
});
|
|
23749
|
+
}
|
|
23750
|
+
return;
|
|
23751
|
+
}
|
|
23752
|
+
res.status(201).json(result);
|
|
23753
|
+
}
|
|
23754
|
+
)
|
|
23755
|
+
);
|
|
23756
|
+
app.post(
|
|
23757
|
+
"/session/:id/side-task",
|
|
23758
|
+
mutate(),
|
|
23759
|
+
withPrimaryOnlyMutableSession(
|
|
23760
|
+
"POST /session/:id/side-task",
|
|
23761
|
+
async (req, res, sessionId, runtime) => {
|
|
23762
|
+
const body = safeBody(req);
|
|
23763
|
+
let name = typeof body?.["name"] === "string" ? body["name"] : void 0;
|
|
23764
|
+
if (name) {
|
|
23765
|
+
name = Array.from(name.replace(/[\x00-\x1F\x7F-\x9F]/g, "")).slice(0, 200).join("");
|
|
23766
|
+
}
|
|
23767
|
+
const clientId = parseClientIdHeader(req, res);
|
|
23768
|
+
if (clientId === null) return;
|
|
23769
|
+
const result = await runtime.bridge.createSideTaskSession(
|
|
23770
|
+
sessionId,
|
|
23771
|
+
{ name },
|
|
23772
|
+
{ clientId }
|
|
23773
|
+
);
|
|
22760
23774
|
try {
|
|
22761
23775
|
runtime.generationGuard?.assertOpen();
|
|
22762
23776
|
} catch (error2) {
|
|
22763
23777
|
if (!result.attached) {
|
|
22764
23778
|
const killed = await runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).catch(() => false);
|
|
22765
23779
|
if (killed) {
|
|
22766
|
-
await
|
|
23780
|
+
await createWorkspaceRuntimeSessionService(runtime).removeSession(result.sessionId).catch(() => {
|
|
22767
23781
|
});
|
|
22768
23782
|
}
|
|
22769
23783
|
} else {
|
|
@@ -22774,7 +23788,12 @@ function registerSessionRoutes(app, deps) {
|
|
|
22774
23788
|
}
|
|
22775
23789
|
if (!res.writable) {
|
|
22776
23790
|
if (!result.attached) {
|
|
22777
|
-
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).
|
|
23791
|
+
runtime.bridge.killSession(result.sessionId, { requireZeroAttaches: true }).then((killed) => {
|
|
23792
|
+
if (!killed) return void 0;
|
|
23793
|
+
return createWorkspaceRuntimeSessionService(
|
|
23794
|
+
runtime
|
|
23795
|
+
).removeSession(result.sessionId);
|
|
23796
|
+
}).catch(() => {
|
|
22778
23797
|
});
|
|
22779
23798
|
} else {
|
|
22780
23799
|
runtime.bridge.detachClient(result.sessionId, result.clientId).catch(() => {
|
|
@@ -22870,7 +23889,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
22870
23889
|
app.get("/session/:id/export", async (req, res) => {
|
|
22871
23890
|
await handleSessionExport(req, res, {
|
|
22872
23891
|
route: "GET /session/:id/export",
|
|
22873
|
-
|
|
23892
|
+
runtime: workspaceRegistry.primary
|
|
22874
23893
|
});
|
|
22875
23894
|
});
|
|
22876
23895
|
app.get("/workspaces/:workspace/session/:id/export", async (req, res) => {
|
|
@@ -22879,7 +23898,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
22879
23898
|
if (!runtime) return;
|
|
22880
23899
|
await handleSessionExport(req, res, {
|
|
22881
23900
|
route,
|
|
22882
|
-
|
|
23901
|
+
runtime,
|
|
22883
23902
|
workspaceQualified: true
|
|
22884
23903
|
});
|
|
22885
23904
|
});
|
|
@@ -22891,7 +23910,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
22891
23910
|
if (!runtime) return;
|
|
22892
23911
|
await handleSessionExport(req, res, {
|
|
22893
23912
|
route,
|
|
22894
|
-
|
|
23913
|
+
runtime,
|
|
22895
23914
|
workspaceQualified: true,
|
|
22896
23915
|
archiveState: "archived"
|
|
22897
23916
|
});
|
|
@@ -22988,67 +24007,74 @@ function registerSessionRoutes(app, deps) {
|
|
|
22988
24007
|
}
|
|
22989
24008
|
try {
|
|
22990
24009
|
const result = await runWithoutDebugLogSession(
|
|
22991
|
-
() => archiveCoordinator.runSharedMany(
|
|
22992
|
-
|
|
22993
|
-
|
|
22994
|
-
|
|
22995
|
-
|
|
22996
|
-
|
|
22997
|
-
|
|
22998
|
-
|
|
22999
|
-
|
|
23000
|
-
|
|
23001
|
-
let page;
|
|
23002
|
-
try {
|
|
23003
|
-
page = await reader.readPage(sessionId, {
|
|
23004
|
-
...limit !== void 0 ? { limit } : {},
|
|
23005
|
-
...cursor !== void 0 ? { cursor } : {},
|
|
23006
|
-
...beforeRecordId !== void 0 ? { beforeRecordId } : {},
|
|
23007
|
-
maxBytes: SESSION_TRANSCRIPT_MAX_PAGE_BYTES
|
|
23008
|
-
});
|
|
23009
|
-
} catch (error2) {
|
|
23010
|
-
if (error2.code !== "ENOENT") {
|
|
23011
|
-
throw error2;
|
|
23012
|
-
}
|
|
23013
|
-
if (cursor !== void 0) {
|
|
23014
|
-
throw new SessionTranscriptSnapshotUnavailableError(sessionId);
|
|
24010
|
+
() => archiveCoordinator.runSharedMany(
|
|
24011
|
+
[sessionId],
|
|
24012
|
+
() => runWithWorkspaceRuntimeStorage(runtime, async () => {
|
|
24013
|
+
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
24014
|
+
if (cursor === void 0) {
|
|
24015
|
+
await assertSessionLoadable(
|
|
24016
|
+
runtime.workspaceCwd,
|
|
24017
|
+
sessionId,
|
|
24018
|
+
runtime.sessionRuntimeBaseDir
|
|
24019
|
+
);
|
|
23015
24020
|
}
|
|
23016
|
-
const
|
|
23017
|
-
|
|
23018
|
-
|
|
24021
|
+
const codec = getTranscriptCursorCodec(runtime);
|
|
24022
|
+
const reader = new SessionTranscriptReader(
|
|
24023
|
+
runtime.workspaceCwd,
|
|
24024
|
+
codec
|
|
24025
|
+
);
|
|
24026
|
+
let page;
|
|
24027
|
+
try {
|
|
24028
|
+
page = await reader.readPage(sessionId, {
|
|
24029
|
+
...limit !== void 0 ? { limit } : {},
|
|
24030
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
24031
|
+
...beforeRecordId !== void 0 ? { beforeRecordId } : {},
|
|
24032
|
+
maxBytes: SESSION_TRANSCRIPT_MAX_PAGE_BYTES
|
|
24033
|
+
});
|
|
24034
|
+
} catch (error2) {
|
|
24035
|
+
if (error2.code !== "ENOENT") {
|
|
24036
|
+
throw error2;
|
|
24037
|
+
}
|
|
24038
|
+
if (cursor !== void 0) {
|
|
24039
|
+
throw new SessionTranscriptSnapshotUnavailableError(sessionId);
|
|
24040
|
+
}
|
|
24041
|
+
const location = await service.getSessionLocation(sessionId);
|
|
24042
|
+
if (location === "archived") {
|
|
24043
|
+
throw new SessionArchivedError(sessionId);
|
|
24044
|
+
}
|
|
24045
|
+
if (location === "conflict") {
|
|
24046
|
+
throw new SessionConflictError(sessionId);
|
|
24047
|
+
}
|
|
24048
|
+
throw new SessionNotFoundError(sessionId);
|
|
23019
24049
|
}
|
|
23020
|
-
if (
|
|
23021
|
-
throw new
|
|
24050
|
+
if (page.records.some((record) => record.sessionId !== sessionId)) {
|
|
24051
|
+
throw new SessionTranscriptSnapshotUnavailableError(sessionId);
|
|
23022
24052
|
}
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
|
|
23028
|
-
|
|
23029
|
-
|
|
23030
|
-
page,
|
|
23031
|
-
encodeCursor: /* @__PURE__ */ __name((state) => codec.encode(state), "encodeCursor")
|
|
23032
|
-
});
|
|
23033
|
-
const cursorTooLarge = replay.nextCursor !== void 0 && Buffer.byteLength(replay.nextCursor) > WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES;
|
|
23034
|
-
return {
|
|
23035
|
-
v: 1,
|
|
23036
|
-
sessionId,
|
|
23037
|
-
events: replay.updates.map((update) => ({
|
|
24053
|
+
const replay = await replayTranscriptRecordPage({
|
|
24054
|
+
sessionId,
|
|
24055
|
+
page,
|
|
24056
|
+
encodeCursor: /* @__PURE__ */ __name((state) => codec.encode(state), "encodeCursor")
|
|
24057
|
+
});
|
|
24058
|
+
const cursorTooLarge = replay.nextCursor !== void 0 && Buffer.byteLength(replay.nextCursor) > WORKSPACE_TRANSCRIPT_CURSOR_MAX_BYTES;
|
|
24059
|
+
return {
|
|
23038
24060
|
v: 1,
|
|
23039
|
-
|
|
23040
|
-
|
|
23041
|
-
|
|
23042
|
-
|
|
23043
|
-
|
|
23044
|
-
|
|
23045
|
-
|
|
23046
|
-
|
|
23047
|
-
|
|
23048
|
-
|
|
23049
|
-
|
|
23050
|
-
|
|
23051
|
-
|
|
24061
|
+
sessionId,
|
|
24062
|
+
events: replay.updates.map((update) => ({
|
|
24063
|
+
v: 1,
|
|
24064
|
+
type: "session_update",
|
|
24065
|
+
data: update
|
|
24066
|
+
})),
|
|
24067
|
+
...replay.nextCursor && !cursorTooLarge ? { nextCursor: replay.nextCursor } : {},
|
|
24068
|
+
hasMore: cursorTooLarge ? false : replay.hasMore,
|
|
24069
|
+
startTime: replay.startTime,
|
|
24070
|
+
lastUpdated: replay.lastUpdated,
|
|
24071
|
+
...replay.partial || cursorTooLarge ? {
|
|
24072
|
+
partial: true,
|
|
24073
|
+
replayError: cursorTooLarge ? TRANSCRIPT_CURSOR_TOO_LARGE_REPLAY_ERROR : replay.replayError
|
|
24074
|
+
} : {}
|
|
24075
|
+
};
|
|
24076
|
+
})
|
|
24077
|
+
)
|
|
23052
24078
|
);
|
|
23053
24079
|
const serialized = serializeWorkspaceTranscriptResponse(
|
|
23054
24080
|
result,
|
|
@@ -23701,18 +24727,22 @@ function registerSessionRoutes(app, deps) {
|
|
|
23701
24727
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23702
24728
|
if (uniqueIds === void 0) return;
|
|
23703
24729
|
try {
|
|
23704
|
-
const
|
|
23705
|
-
const
|
|
23706
|
-
|
|
23707
|
-
|
|
23708
|
-
|
|
23709
|
-
|
|
23710
|
-
|
|
23711
|
-
|
|
23712
|
-
|
|
23713
|
-
)
|
|
23714
|
-
|
|
23715
|
-
|
|
24730
|
+
const runtime = workspaceRegistry.primary;
|
|
24731
|
+
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
24732
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24733
|
+
runtime,
|
|
24734
|
+
() => deleteDaemonSessions({
|
|
24735
|
+
sessionIds: uniqueIds,
|
|
24736
|
+
service,
|
|
24737
|
+
bridge,
|
|
24738
|
+
coordinator: archiveCoordinator,
|
|
24739
|
+
onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
|
|
24740
|
+
writeStderrLine(
|
|
24741
|
+
`qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
|
|
24742
|
+
);
|
|
24743
|
+
}, "onError")
|
|
24744
|
+
})
|
|
24745
|
+
);
|
|
23716
24746
|
for (const removedId of result.removed) {
|
|
23717
24747
|
clearBranchSessionEntry(removedId);
|
|
23718
24748
|
}
|
|
@@ -23724,16 +24754,20 @@ function registerSessionRoutes(app, deps) {
|
|
|
23724
24754
|
app.post("/sessions/archive", mutate(), async (req, res) => {
|
|
23725
24755
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23726
24756
|
if (uniqueIds === void 0) return;
|
|
23727
|
-
const
|
|
24757
|
+
const runtime = workspaceRegistry.primary;
|
|
24758
|
+
const service = createWorkspaceRuntimeSessionService(runtime, {
|
|
23728
24759
|
onWarning: logSessionArchiveWarning
|
|
23729
24760
|
});
|
|
23730
24761
|
try {
|
|
23731
|
-
const result = await
|
|
23732
|
-
|
|
23733
|
-
|
|
23734
|
-
|
|
23735
|
-
|
|
23736
|
-
|
|
24762
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24763
|
+
runtime,
|
|
24764
|
+
() => archiveDaemonSessions({
|
|
24765
|
+
sessionIds: uniqueIds,
|
|
24766
|
+
service,
|
|
24767
|
+
bridge,
|
|
24768
|
+
coordinator: archiveCoordinator
|
|
24769
|
+
})
|
|
24770
|
+
);
|
|
23737
24771
|
res.status(200).json({
|
|
23738
24772
|
archived: result.archived,
|
|
23739
24773
|
alreadyArchived: result.alreadyArchived,
|
|
@@ -23747,15 +24781,19 @@ function registerSessionRoutes(app, deps) {
|
|
|
23747
24781
|
app.post("/sessions/unarchive", mutate(), async (req, res) => {
|
|
23748
24782
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23749
24783
|
if (uniqueIds === void 0) return;
|
|
23750
|
-
const
|
|
24784
|
+
const runtime = workspaceRegistry.primary;
|
|
24785
|
+
const service = createWorkspaceRuntimeSessionService(runtime, {
|
|
23751
24786
|
onWarning: logSessionArchiveWarning
|
|
23752
24787
|
});
|
|
23753
24788
|
try {
|
|
23754
|
-
const result = await
|
|
23755
|
-
|
|
23756
|
-
|
|
23757
|
-
|
|
23758
|
-
|
|
24789
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24790
|
+
runtime,
|
|
24791
|
+
() => unarchiveDaemonSessions({
|
|
24792
|
+
sessionIds: uniqueIds,
|
|
24793
|
+
service,
|
|
24794
|
+
coordinator: archiveCoordinator
|
|
24795
|
+
})
|
|
24796
|
+
);
|
|
23759
24797
|
res.status(200).json({
|
|
23760
24798
|
unarchived: result.unarchived,
|
|
23761
24799
|
alreadyActive: result.alreadyActive,
|
|
@@ -23778,18 +24816,21 @@ function registerSessionRoutes(app, deps) {
|
|
|
23778
24816
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23779
24817
|
if (uniqueIds === void 0) return;
|
|
23780
24818
|
try {
|
|
23781
|
-
const service =
|
|
23782
|
-
const result = await
|
|
23783
|
-
|
|
23784
|
-
|
|
23785
|
-
|
|
23786
|
-
|
|
23787
|
-
|
|
23788
|
-
|
|
23789
|
-
|
|
23790
|
-
|
|
23791
|
-
|
|
23792
|
-
|
|
24819
|
+
const service = createWorkspaceRuntimeSessionService(runtime);
|
|
24820
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24821
|
+
runtime,
|
|
24822
|
+
() => deleteDaemonSessions({
|
|
24823
|
+
sessionIds: uniqueIds,
|
|
24824
|
+
service,
|
|
24825
|
+
bridge: runtime.bridge,
|
|
24826
|
+
coordinator: archiveCoordinator,
|
|
24827
|
+
onError: /* @__PURE__ */ __name(({ phase, sessionId, error: error2 }) => {
|
|
24828
|
+
writeStderrLine(
|
|
24829
|
+
`qwen serve: ${phase}Session failed for ${safeLogValue(sessionId)}: ${safeLogValue(error2)}`
|
|
24830
|
+
);
|
|
24831
|
+
}, "onError")
|
|
24832
|
+
})
|
|
24833
|
+
);
|
|
23793
24834
|
for (const removedId of result.removed) {
|
|
23794
24835
|
clearBranchSessionEntry(removedId);
|
|
23795
24836
|
}
|
|
@@ -23808,16 +24849,19 @@ function registerSessionRoutes(app, deps) {
|
|
|
23808
24849
|
if (!runtime) return;
|
|
23809
24850
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23810
24851
|
if (uniqueIds === void 0) return;
|
|
23811
|
-
const service =
|
|
24852
|
+
const service = createWorkspaceRuntimeSessionService(runtime, {
|
|
23812
24853
|
onWarning: logSessionArchiveWarning
|
|
23813
24854
|
});
|
|
23814
24855
|
try {
|
|
23815
|
-
const result = await
|
|
23816
|
-
|
|
23817
|
-
|
|
23818
|
-
|
|
23819
|
-
|
|
23820
|
-
|
|
24856
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24857
|
+
runtime,
|
|
24858
|
+
() => archiveDaemonSessions({
|
|
24859
|
+
sessionIds: uniqueIds,
|
|
24860
|
+
service,
|
|
24861
|
+
bridge: runtime.bridge,
|
|
24862
|
+
coordinator: archiveCoordinator
|
|
24863
|
+
})
|
|
24864
|
+
);
|
|
23821
24865
|
res.status(200).json({
|
|
23822
24866
|
archived: result.archived,
|
|
23823
24867
|
alreadyArchived: result.alreadyArchived,
|
|
@@ -23838,15 +24882,18 @@ function registerSessionRoutes(app, deps) {
|
|
|
23838
24882
|
if (!runtime) return;
|
|
23839
24883
|
const uniqueIds = parseSessionIdsBody(req, res);
|
|
23840
24884
|
if (uniqueIds === void 0) return;
|
|
23841
|
-
const service =
|
|
24885
|
+
const service = createWorkspaceRuntimeSessionService(runtime, {
|
|
23842
24886
|
onWarning: logSessionArchiveWarning
|
|
23843
24887
|
});
|
|
23844
24888
|
try {
|
|
23845
|
-
const result = await
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
24889
|
+
const result = await runWithWorkspaceRuntimeStorage(
|
|
24890
|
+
runtime,
|
|
24891
|
+
() => unarchiveDaemonSessions({
|
|
24892
|
+
sessionIds: uniqueIds,
|
|
24893
|
+
service,
|
|
24894
|
+
coordinator: archiveCoordinator
|
|
24895
|
+
})
|
|
24896
|
+
);
|
|
23850
24897
|
res.status(200).json({
|
|
23851
24898
|
unarchived: result.unarchived,
|
|
23852
24899
|
alreadyActive: result.alreadyActive,
|
|
@@ -23890,74 +24937,80 @@ function registerSessionRoutes(app, deps) {
|
|
|
23890
24937
|
const sessionId = requireSessionId(req, res);
|
|
23891
24938
|
if (sessionId === null) return;
|
|
23892
24939
|
try {
|
|
23893
|
-
await archiveCoordinator.runSharedMany(
|
|
23894
|
-
|
|
23895
|
-
|
|
23896
|
-
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
|
|
23901
|
-
|
|
24940
|
+
await archiveCoordinator.runSharedMany(
|
|
24941
|
+
[sessionId],
|
|
24942
|
+
() => runWithWorkspaceRuntimeStorage(target.runtime, async () => {
|
|
24943
|
+
const sessionService = createWorkspaceRuntimeSessionService(
|
|
24944
|
+
target.runtime
|
|
24945
|
+
);
|
|
24946
|
+
let exists = await sessionService.sessionExistsInAnyState(sessionId);
|
|
24947
|
+
if (!exists) {
|
|
24948
|
+
try {
|
|
24949
|
+
const summary = target.runtime.bridge.getSessionSummary(sessionId);
|
|
24950
|
+
exists = summary.workspaceCwd === target.runtime.workspaceCwd;
|
|
24951
|
+
} catch {
|
|
24952
|
+
exists = false;
|
|
24953
|
+
}
|
|
23902
24954
|
}
|
|
23903
|
-
|
|
23904
|
-
|
|
23905
|
-
|
|
23906
|
-
|
|
23907
|
-
|
|
23908
|
-
|
|
23909
|
-
|
|
23910
|
-
|
|
23911
|
-
|
|
23912
|
-
|
|
23913
|
-
|
|
23914
|
-
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
23922
|
-
|
|
23923
|
-
|
|
23924
|
-
|
|
23925
|
-
|
|
23926
|
-
|
|
23927
|
-
|
|
23928
|
-
|
|
23929
|
-
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
|
|
23935
|
-
|
|
24955
|
+
if (!exists) {
|
|
24956
|
+
res.status(404).json({
|
|
24957
|
+
error: `No session with id "${sessionId}"`,
|
|
24958
|
+
sessionId
|
|
24959
|
+
});
|
|
24960
|
+
return;
|
|
24961
|
+
}
|
|
24962
|
+
const body = safeBody(req);
|
|
24963
|
+
const rawIsPinned = body["isPinned"];
|
|
24964
|
+
if (rawIsPinned !== void 0 && typeof rawIsPinned !== "boolean") {
|
|
24965
|
+
res.status(400).json({
|
|
24966
|
+
error: "`isPinned` must be a boolean",
|
|
24967
|
+
code: "invalid_session_organization",
|
|
24968
|
+
field: "isPinned"
|
|
24969
|
+
});
|
|
24970
|
+
return;
|
|
24971
|
+
}
|
|
24972
|
+
const rawGroupId = body["groupId"];
|
|
24973
|
+
if (rawGroupId !== void 0 && rawGroupId !== null && typeof rawGroupId !== "string") {
|
|
24974
|
+
res.status(400).json({
|
|
24975
|
+
error: "`groupId` must be a string or null",
|
|
24976
|
+
code: "invalid_session_organization",
|
|
24977
|
+
field: "groupId"
|
|
24978
|
+
});
|
|
24979
|
+
return;
|
|
24980
|
+
}
|
|
24981
|
+
const rawColor = body["color"];
|
|
24982
|
+
if (rawColor !== void 0 && rawColor !== null && (typeof rawColor !== "string" || !GROUP_COLOR_OPTIONS.includes(
|
|
24983
|
+
rawColor
|
|
24984
|
+
))) {
|
|
24985
|
+
res.status(400).json({
|
|
24986
|
+
error: "`color` must be a supported color or null",
|
|
24987
|
+
code: "invalid_session_organization",
|
|
24988
|
+
field: "color"
|
|
24989
|
+
});
|
|
24990
|
+
return;
|
|
24991
|
+
}
|
|
24992
|
+
const organization = await createSessionOrganizationService(
|
|
24993
|
+
target.runtime.workspaceCwd
|
|
24994
|
+
).updateSessionOrganization(sessionId, {
|
|
24995
|
+
...rawIsPinned !== void 0 ? { isPinned: rawIsPinned } : {},
|
|
24996
|
+
...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
|
|
24997
|
+
...rawColor !== void 0 ? { color: rawColor } : {}
|
|
23936
24998
|
});
|
|
23937
|
-
|
|
23938
|
-
}
|
|
23939
|
-
|
|
23940
|
-
target.workspaceCwd
|
|
23941
|
-
).updateSessionOrganization(sessionId, {
|
|
23942
|
-
...rawIsPinned !== void 0 ? { isPinned: rawIsPinned } : {},
|
|
23943
|
-
...rawGroupId !== void 0 ? { groupId: rawGroupId } : {},
|
|
23944
|
-
...rawColor !== void 0 ? { color: rawColor } : {}
|
|
23945
|
-
});
|
|
23946
|
-
res.status(200).json({ sessionId, ...organization });
|
|
23947
|
-
});
|
|
24999
|
+
res.status(200).json({ sessionId, ...organization });
|
|
25000
|
+
})
|
|
25001
|
+
);
|
|
23948
25002
|
} catch (err) {
|
|
23949
25003
|
if (sendSessionOrganizationError(res, err)) return;
|
|
23950
25004
|
sendBridgeError2(res, err, {
|
|
23951
25005
|
route: target.route,
|
|
23952
25006
|
sessionId,
|
|
23953
|
-
workspaceCwd: target.workspaceCwd
|
|
25007
|
+
workspaceCwd: target.runtime.workspaceCwd
|
|
23954
25008
|
});
|
|
23955
25009
|
}
|
|
23956
25010
|
}, "handleSessionOrganizationUpdate");
|
|
23957
25011
|
app.patch("/session/:id/organization", mutate(), async (req, res) => {
|
|
23958
25012
|
await handleSessionOrganizationUpdate(req, res, {
|
|
23959
|
-
|
|
23960
|
-
bridge,
|
|
25013
|
+
runtime: workspaceRegistry.primary,
|
|
23961
25014
|
route: "PATCH /session/:id/organization"
|
|
23962
25015
|
});
|
|
23963
25016
|
});
|
|
@@ -23969,8 +25022,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
23969
25022
|
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
23970
25023
|
if (!runtime) return;
|
|
23971
25024
|
await handleSessionOrganizationUpdate(req, res, {
|
|
23972
|
-
|
|
23973
|
-
bridge: runtime.bridge,
|
|
25025
|
+
runtime,
|
|
23974
25026
|
route
|
|
23975
25027
|
});
|
|
23976
25028
|
}
|
|
@@ -23992,14 +25044,17 @@ function registerSessionRoutes(app, deps) {
|
|
|
23992
25044
|
}
|
|
23993
25045
|
});
|
|
23994
25046
|
app.post("/workspace/:id/session-groups", mutate(), async (req, res) => {
|
|
23995
|
-
const
|
|
23996
|
-
if (
|
|
25047
|
+
const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
|
|
25048
|
+
if (runtime === null) return;
|
|
23997
25049
|
const body = safeBody(req);
|
|
23998
25050
|
try {
|
|
23999
|
-
const group = await
|
|
24000
|
-
|
|
24001
|
-
|
|
24002
|
-
|
|
25051
|
+
const group = await runWithWorkspaceRuntimeStorage(
|
|
25052
|
+
runtime,
|
|
25053
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
|
|
25054
|
+
name: body["name"],
|
|
25055
|
+
color: body["color"]
|
|
25056
|
+
})
|
|
25057
|
+
);
|
|
24003
25058
|
res.status(201).json({ group });
|
|
24004
25059
|
} catch (err) {
|
|
24005
25060
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -24012,17 +25067,20 @@ function registerSessionRoutes(app, deps) {
|
|
|
24012
25067
|
"/workspace/:id/session-groups/:groupId",
|
|
24013
25068
|
mutate(),
|
|
24014
25069
|
async (req, res) => {
|
|
24015
|
-
const
|
|
24016
|
-
if (
|
|
25070
|
+
const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
|
|
25071
|
+
if (runtime === null) return;
|
|
24017
25072
|
const body = safeBody(req);
|
|
24018
25073
|
try {
|
|
24019
|
-
const group = await
|
|
24020
|
-
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24024
|
-
|
|
24025
|
-
|
|
25074
|
+
const group = await runWithWorkspaceRuntimeStorage(
|
|
25075
|
+
runtime,
|
|
25076
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
|
|
25077
|
+
req.params["groupId"] ?? "",
|
|
25078
|
+
{
|
|
25079
|
+
...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
|
|
25080
|
+
...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
|
|
25081
|
+
...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
|
|
25082
|
+
}
|
|
25083
|
+
)
|
|
24026
25084
|
);
|
|
24027
25085
|
res.status(200).json({ group });
|
|
24028
25086
|
} catch (err) {
|
|
@@ -24037,11 +25095,14 @@ function registerSessionRoutes(app, deps) {
|
|
|
24037
25095
|
"/workspace/:id/session-groups/:groupId",
|
|
24038
25096
|
mutate(),
|
|
24039
25097
|
async (req, res) => {
|
|
24040
|
-
const
|
|
24041
|
-
if (
|
|
25098
|
+
const runtime = resolveLegacyPrimaryRuntimeFromParam(req, res);
|
|
25099
|
+
if (runtime === null) return;
|
|
24042
25100
|
try {
|
|
24043
|
-
const deleted = await
|
|
24044
|
-
|
|
25101
|
+
const deleted = await runWithWorkspaceRuntimeStorage(
|
|
25102
|
+
runtime,
|
|
25103
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
|
|
25104
|
+
req.params["groupId"] ?? ""
|
|
25105
|
+
)
|
|
24045
25106
|
);
|
|
24046
25107
|
res.status(200).json({ deleted });
|
|
24047
25108
|
} catch (err) {
|
|
@@ -24076,12 +25137,13 @@ function registerSessionRoutes(app, deps) {
|
|
|
24076
25137
|
if (!runtime) return;
|
|
24077
25138
|
const body = safeBody(req);
|
|
24078
25139
|
try {
|
|
24079
|
-
const group = await
|
|
24080
|
-
runtime
|
|
24081
|
-
|
|
24082
|
-
|
|
24083
|
-
|
|
24084
|
-
|
|
25140
|
+
const group = await runWithWorkspaceRuntimeStorage(
|
|
25141
|
+
runtime,
|
|
25142
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).createGroup({
|
|
25143
|
+
name: body["name"],
|
|
25144
|
+
color: body["color"]
|
|
25145
|
+
})
|
|
25146
|
+
);
|
|
24085
25147
|
res.status(201).json({ group });
|
|
24086
25148
|
} catch (err) {
|
|
24087
25149
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -24098,13 +25160,17 @@ function registerSessionRoutes(app, deps) {
|
|
|
24098
25160
|
if (!runtime) return;
|
|
24099
25161
|
const body = safeBody(req);
|
|
24100
25162
|
try {
|
|
24101
|
-
const group = await
|
|
24102
|
-
runtime
|
|
24103
|
-
|
|
24104
|
-
|
|
24105
|
-
|
|
24106
|
-
|
|
24107
|
-
|
|
25163
|
+
const group = await runWithWorkspaceRuntimeStorage(
|
|
25164
|
+
runtime,
|
|
25165
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).updateGroup(
|
|
25166
|
+
req.params["groupId"] ?? "",
|
|
25167
|
+
{
|
|
25168
|
+
...Object.prototype.hasOwnProperty.call(body, "name") ? { name: body["name"] } : {},
|
|
25169
|
+
...Object.prototype.hasOwnProperty.call(body, "color") ? { color: body["color"] } : {},
|
|
25170
|
+
...Object.prototype.hasOwnProperty.call(body, "order") ? { order: body["order"] } : {}
|
|
25171
|
+
}
|
|
25172
|
+
)
|
|
25173
|
+
);
|
|
24108
25174
|
res.status(200).json({ group });
|
|
24109
25175
|
} catch (err) {
|
|
24110
25176
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -24120,9 +25186,12 @@ function registerSessionRoutes(app, deps) {
|
|
|
24120
25186
|
const runtime = requireTrustedRuntimeForWorkspaceRoute(req, res, route);
|
|
24121
25187
|
if (!runtime) return;
|
|
24122
25188
|
try {
|
|
24123
|
-
const deleted = await
|
|
24124
|
-
runtime
|
|
24125
|
-
|
|
25189
|
+
const deleted = await runWithWorkspaceRuntimeStorage(
|
|
25190
|
+
runtime,
|
|
25191
|
+
() => createSessionOrganizationService(runtime.workspaceCwd).deleteGroup(
|
|
25192
|
+
req.params["groupId"] ?? ""
|
|
25193
|
+
)
|
|
25194
|
+
);
|
|
24126
25195
|
res.status(200).json({ deleted });
|
|
24127
25196
|
} catch (err) {
|
|
24128
25197
|
if (sendSessionOrganizationError(res, err)) return;
|
|
@@ -24210,7 +25279,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
24210
25279
|
...parentSessionId !== void 0 ? { parentSessionId } : {},
|
|
24211
25280
|
...parsedSource
|
|
24212
25281
|
};
|
|
24213
|
-
const usePersisted = readOnlySecondary || runtime.primary || view === "organized" || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0 || (cursor !== void 0 && cursor !== "" ? isNumericSessionCursor(cursor) : await hasActivePersistedSessions(
|
|
25282
|
+
const usePersisted = readOnlySecondary || runtime.primary || view === "organized" || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0 || (cursor !== void 0 && cursor !== "" ? isNumericSessionCursor(cursor) : await hasActivePersistedSessions(runtime));
|
|
24214
25283
|
if (!usePersisted && (view !== void 0 || archiveState === "archived" || parentSessionId !== void 0 || parsedSource.sourceType !== void 0)) {
|
|
24215
25284
|
throw new Error(
|
|
24216
25285
|
"session list live path received persisted-only options"
|
|
@@ -24707,11 +25776,14 @@ function requireOpenGeneration2(target, res) {
|
|
|
24707
25776
|
}
|
|
24708
25777
|
}
|
|
24709
25778
|
__name(requireOpenGeneration2, "requireOpenGeneration");
|
|
24710
|
-
async function rollbackCronMutation(
|
|
25779
|
+
async function rollbackCronMutation(target, before, after, route) {
|
|
24711
25780
|
if (!before || !after) return;
|
|
24712
|
-
await
|
|
24713
|
-
|
|
24714
|
-
(
|
|
25781
|
+
await runWithScheduledTaskTarget(
|
|
25782
|
+
target,
|
|
25783
|
+
() => updateCronTasks(
|
|
25784
|
+
target.workspaceCwd,
|
|
25785
|
+
(tasks) => isDeepStrictEqual2(tasks, after) ? before : tasks
|
|
25786
|
+
)
|
|
24715
25787
|
).catch((error2) => {
|
|
24716
25788
|
writeStderrLine(
|
|
24717
25789
|
`qwen serve: ${route} failed to roll back a stale task mutation: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
@@ -24719,6 +25791,27 @@ async function rollbackCronMutation(workspaceCwd, before, after, route) {
|
|
|
24719
25791
|
});
|
|
24720
25792
|
}
|
|
24721
25793
|
__name(rollbackCronMutation, "rollbackCronMutation");
|
|
25794
|
+
async function teardownBoundSession(target, sessionId) {
|
|
25795
|
+
if (target.cleanupSession) {
|
|
25796
|
+
await target.cleanupSession(sessionId).catch(() => {
|
|
25797
|
+
});
|
|
25798
|
+
} else if (target.bridge) {
|
|
25799
|
+
await target.bridge.closeSession(sessionId).catch(() => {
|
|
25800
|
+
});
|
|
25801
|
+
await new SessionService(target.workspaceCwd, {
|
|
25802
|
+
runtimeBaseDir: target.runtimeBaseDir
|
|
25803
|
+
}).removeSession(sessionId).catch(() => {
|
|
25804
|
+
});
|
|
25805
|
+
}
|
|
25806
|
+
}
|
|
25807
|
+
__name(teardownBoundSession, "teardownBoundSession");
|
|
25808
|
+
function runWithScheduledTaskTarget(target, fn) {
|
|
25809
|
+
if (target.runtimeBaseDir === void 0) {
|
|
25810
|
+
return fn();
|
|
25811
|
+
}
|
|
25812
|
+
return Storage.runWithResolvedRuntimeBaseDir(target.runtimeBaseDir, fn);
|
|
25813
|
+
}
|
|
25814
|
+
__name(runWithScheduledTaskTarget, "runWithScheduledTaskTarget");
|
|
24722
25815
|
function computeNextRunAt(task) {
|
|
24723
25816
|
if (task.enabled === false) return null;
|
|
24724
25817
|
return nextDurableFireMs(task);
|
|
@@ -24793,7 +25886,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
24793
25886
|
if (!target) return;
|
|
24794
25887
|
if (!requireOpenGeneration2(target, res)) return;
|
|
24795
25888
|
try {
|
|
24796
|
-
const tasks = await
|
|
25889
|
+
const tasks = await runWithScheduledTaskTarget(
|
|
25890
|
+
target,
|
|
25891
|
+
() => readCronTasks(target.workspaceCwd)
|
|
25892
|
+
);
|
|
24797
25893
|
if (!requireOpenGeneration2(target, res)) return;
|
|
24798
25894
|
res.status(200).json({ v: 1, tasks: tasks.map(toView) });
|
|
24799
25895
|
} catch (err) {
|
|
@@ -24887,7 +25983,10 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
24887
25983
|
let boundSessionId;
|
|
24888
25984
|
if (bridge) {
|
|
24889
25985
|
try {
|
|
24890
|
-
if ((await
|
|
25986
|
+
if ((await runWithScheduledTaskTarget(
|
|
25987
|
+
target,
|
|
25988
|
+
() => readCronTasks(workspaceCwd)
|
|
25989
|
+
)).length >= MAX_SCHEDULED_TASKS) {
|
|
24891
25990
|
res.status(409).json({
|
|
24892
25991
|
error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
|
|
24893
25992
|
code: "max_tasks_reached"
|
|
@@ -24906,10 +26005,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
24906
26005
|
});
|
|
24907
26006
|
boundSessionId = session.sessionId;
|
|
24908
26007
|
if (!requireOpenGeneration2(target, res)) {
|
|
24909
|
-
await
|
|
24910
|
-
});
|
|
24911
|
-
await new SessionService(workspaceCwd).removeSession(boundSessionId).catch(() => {
|
|
24912
|
-
});
|
|
26008
|
+
await teardownBoundSession(target, boundSessionId);
|
|
24913
26009
|
return;
|
|
24914
26010
|
}
|
|
24915
26011
|
try {
|
|
@@ -24946,29 +26042,29 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
24946
26042
|
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
24947
26043
|
};
|
|
24948
26044
|
const rollbackSession = /* @__PURE__ */ __name(async () => {
|
|
24949
|
-
if (boundSessionId !== void 0
|
|
24950
|
-
await
|
|
24951
|
-
});
|
|
24952
|
-
await new SessionService(workspaceCwd).removeSession(boundSessionId).catch(() => {
|
|
24953
|
-
});
|
|
26045
|
+
if (boundSessionId !== void 0) {
|
|
26046
|
+
await teardownBoundSession(target, boundSessionId);
|
|
24954
26047
|
}
|
|
24955
26048
|
}, "rollbackSession");
|
|
24956
26049
|
let overCap = false;
|
|
24957
26050
|
let rollbackBefore;
|
|
24958
26051
|
let rollbackAfter;
|
|
24959
26052
|
try {
|
|
24960
|
-
await
|
|
24961
|
-
|
|
24962
|
-
(
|
|
24963
|
-
|
|
24964
|
-
|
|
24965
|
-
|
|
24966
|
-
|
|
24967
|
-
|
|
24968
|
-
|
|
24969
|
-
|
|
24970
|
-
|
|
24971
|
-
|
|
26053
|
+
await runWithScheduledTaskTarget(
|
|
26054
|
+
target,
|
|
26055
|
+
() => updateCronTasks(
|
|
26056
|
+
workspaceCwd,
|
|
26057
|
+
(tasks) => {
|
|
26058
|
+
if (tasks.length >= MAX_SCHEDULED_TASKS) {
|
|
26059
|
+
overCap = true;
|
|
26060
|
+
return tasks;
|
|
26061
|
+
}
|
|
26062
|
+
rollbackBefore = tasks;
|
|
26063
|
+
rollbackAfter = [...tasks, task];
|
|
26064
|
+
return rollbackAfter;
|
|
26065
|
+
},
|
|
26066
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
26067
|
+
)
|
|
24972
26068
|
);
|
|
24973
26069
|
} catch (err) {
|
|
24974
26070
|
await rollbackSession();
|
|
@@ -24987,7 +26083,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
24987
26083
|
target.assertGenerationOpen?.();
|
|
24988
26084
|
} catch (error2) {
|
|
24989
26085
|
await rollbackCronMutation(
|
|
24990
|
-
|
|
26086
|
+
target,
|
|
24991
26087
|
rollbackBefore,
|
|
24992
26088
|
rollbackAfter,
|
|
24993
26089
|
`POST ${base}`
|
|
@@ -25121,44 +26217,47 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25121
26217
|
let rollbackBefore;
|
|
25122
26218
|
let rollbackAfter;
|
|
25123
26219
|
try {
|
|
25124
|
-
await
|
|
25125
|
-
|
|
25126
|
-
(
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
|
|
25130
|
-
|
|
25131
|
-
|
|
25132
|
-
|
|
25133
|
-
|
|
25134
|
-
|
|
25135
|
-
|
|
25136
|
-
blockedByArchive = true;
|
|
25137
|
-
return tasks;
|
|
25138
|
-
}
|
|
25139
|
-
const next = { ...current, ...patch };
|
|
25140
|
-
if (clearName) delete next.name;
|
|
25141
|
-
if (clearDelivery) delete next.delivery;
|
|
25142
|
-
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
25143
|
-
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
25144
|
-
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
25145
|
-
const becameOneShot = patch.recurring === false && current.recurring !== false;
|
|
25146
|
-
{
|
|
25147
|
-
const now = Date.now();
|
|
25148
|
-
const minute = now - now % 6e4;
|
|
25149
|
-
if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
|
|
25150
|
-
next.lastFiredAt = minute;
|
|
25151
|
-
} else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
|
|
25152
|
-
next.createdAt = now;
|
|
25153
|
-
next.lastFiredAt = minute;
|
|
26220
|
+
await runWithScheduledTaskTarget(
|
|
26221
|
+
target,
|
|
26222
|
+
() => updateCronTasks(
|
|
26223
|
+
workspaceCwd,
|
|
26224
|
+
(tasks) => {
|
|
26225
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
26226
|
+
if (idx === -1) return tasks;
|
|
26227
|
+
found = true;
|
|
26228
|
+
const current = tasks[idx];
|
|
26229
|
+
if (patch.enabled === true && taskHasLegacyCondition(current)) {
|
|
26230
|
+
blockedLegacy = true;
|
|
26231
|
+
return tasks;
|
|
25154
26232
|
}
|
|
25155
|
-
|
|
25156
|
-
|
|
25157
|
-
|
|
25158
|
-
|
|
25159
|
-
|
|
25160
|
-
|
|
25161
|
-
|
|
26233
|
+
if (patch.enabled === true && current.disabledByArchive === true) {
|
|
26234
|
+
blockedByArchive = true;
|
|
26235
|
+
return tasks;
|
|
26236
|
+
}
|
|
26237
|
+
const next = { ...current, ...patch };
|
|
26238
|
+
if (clearName) delete next.name;
|
|
26239
|
+
if (clearDelivery) delete next.delivery;
|
|
26240
|
+
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
26241
|
+
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
26242
|
+
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
26243
|
+
const becameOneShot = patch.recurring === false && current.recurring !== false;
|
|
26244
|
+
{
|
|
26245
|
+
const now = Date.now();
|
|
26246
|
+
const minute = now - now % 6e4;
|
|
26247
|
+
if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
|
|
26248
|
+
next.lastFiredAt = minute;
|
|
26249
|
+
} else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
|
|
26250
|
+
next.createdAt = now;
|
|
26251
|
+
next.lastFiredAt = minute;
|
|
26252
|
+
}
|
|
26253
|
+
}
|
|
26254
|
+
updated = next;
|
|
26255
|
+
rollbackBefore = tasks;
|
|
26256
|
+
rollbackAfter = tasks.map((t, i) => i === idx ? next : t);
|
|
26257
|
+
return rollbackAfter;
|
|
26258
|
+
},
|
|
26259
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
26260
|
+
)
|
|
25162
26261
|
);
|
|
25163
26262
|
} catch (err) {
|
|
25164
26263
|
if (sendGenerationClosedError(res, err)) return;
|
|
@@ -25176,7 +26275,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25176
26275
|
target.assertGenerationOpen?.();
|
|
25177
26276
|
} catch (error2) {
|
|
25178
26277
|
await rollbackCronMutation(
|
|
25179
|
-
|
|
26278
|
+
target,
|
|
25180
26279
|
rollbackBefore,
|
|
25181
26280
|
rollbackAfter,
|
|
25182
26281
|
`PATCH ${base}/${id}`
|
|
@@ -25245,21 +26344,24 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25245
26344
|
let rollbackBefore;
|
|
25246
26345
|
let rollbackAfter;
|
|
25247
26346
|
try {
|
|
25248
|
-
await
|
|
25249
|
-
|
|
25250
|
-
(
|
|
25251
|
-
|
|
25252
|
-
|
|
25253
|
-
|
|
25254
|
-
|
|
25255
|
-
|
|
25256
|
-
|
|
25257
|
-
|
|
25258
|
-
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25262
|
-
|
|
26347
|
+
await runWithScheduledTaskTarget(
|
|
26348
|
+
target,
|
|
26349
|
+
() => updateCronTasks(
|
|
26350
|
+
workspaceCwd,
|
|
26351
|
+
(tasks) => {
|
|
26352
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
26353
|
+
if (idx === -1) return tasks;
|
|
26354
|
+
const match = tasks[idx].sessionId;
|
|
26355
|
+
if (typeof match === "string" && match.length > 0) {
|
|
26356
|
+
boundSessionId = match;
|
|
26357
|
+
}
|
|
26358
|
+
removed = true;
|
|
26359
|
+
rollbackBefore = tasks;
|
|
26360
|
+
rollbackAfter = tasks.filter((_, i) => i !== idx);
|
|
26361
|
+
return rollbackAfter;
|
|
26362
|
+
},
|
|
26363
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
26364
|
+
)
|
|
25263
26365
|
);
|
|
25264
26366
|
} catch (err) {
|
|
25265
26367
|
if (sendGenerationClosedError(res, err)) return;
|
|
@@ -25277,7 +26379,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25277
26379
|
target.assertGenerationOpen?.();
|
|
25278
26380
|
} catch (error2) {
|
|
25279
26381
|
await rollbackCronMutation(
|
|
25280
|
-
|
|
26382
|
+
target,
|
|
25281
26383
|
rollbackBefore,
|
|
25282
26384
|
rollbackAfter,
|
|
25283
26385
|
`DELETE ${base}/${id}`
|
|
@@ -25321,37 +26423,40 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25321
26423
|
let rollbackBefore;
|
|
25322
26424
|
let rollbackAfter;
|
|
25323
26425
|
try {
|
|
25324
|
-
await
|
|
25325
|
-
|
|
25326
|
-
(
|
|
25327
|
-
|
|
25328
|
-
|
|
25329
|
-
|
|
25330
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
25333
|
-
|
|
25334
|
-
|
|
25335
|
-
|
|
25336
|
-
|
|
25337
|
-
|
|
25338
|
-
|
|
25339
|
-
|
|
25340
|
-
|
|
25341
|
-
|
|
25342
|
-
|
|
25343
|
-
|
|
25344
|
-
|
|
25345
|
-
|
|
25346
|
-
|
|
25347
|
-
|
|
25348
|
-
|
|
25349
|
-
|
|
25350
|
-
|
|
25351
|
-
|
|
25352
|
-
|
|
25353
|
-
|
|
25354
|
-
|
|
26426
|
+
await runWithScheduledTaskTarget(
|
|
26427
|
+
target,
|
|
26428
|
+
() => updateCronTasks(
|
|
26429
|
+
workspaceCwd,
|
|
26430
|
+
(tasks) => {
|
|
26431
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
26432
|
+
if (idx === -1) return tasks;
|
|
26433
|
+
found = true;
|
|
26434
|
+
const current = tasks[idx];
|
|
26435
|
+
if (taskHasLegacyCondition(current)) {
|
|
26436
|
+
blockedLegacy = true;
|
|
26437
|
+
return tasks;
|
|
26438
|
+
}
|
|
26439
|
+
if (current.enabled === false) {
|
|
26440
|
+
blockedDisabled = true;
|
|
26441
|
+
return tasks;
|
|
26442
|
+
}
|
|
26443
|
+
const next = {
|
|
26444
|
+
...current,
|
|
26445
|
+
lastFiredAt: now,
|
|
26446
|
+
runs: appendCronRun(current.runs, {
|
|
26447
|
+
at: now,
|
|
26448
|
+
kind: "manual",
|
|
26449
|
+
...current.sessionId ? { sessionId: current.sessionId } : {}
|
|
26450
|
+
})
|
|
26451
|
+
};
|
|
26452
|
+
updated = next;
|
|
26453
|
+
rollbackBefore = tasks;
|
|
26454
|
+
const nextTasks = !current.recurring ? tasks.filter((_, i) => i !== idx) : tasks.map((t, i) => i === idx ? next : t);
|
|
26455
|
+
rollbackAfter = nextTasks;
|
|
26456
|
+
return nextTasks;
|
|
26457
|
+
},
|
|
26458
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
26459
|
+
)
|
|
25355
26460
|
);
|
|
25356
26461
|
} catch (err) {
|
|
25357
26462
|
if (sendGenerationClosedError(res, err)) return;
|
|
@@ -25369,7 +26474,7 @@ function registerScheduledTaskCrudRoutes(app, deps) {
|
|
|
25369
26474
|
target.assertGenerationOpen?.();
|
|
25370
26475
|
} catch (error2) {
|
|
25371
26476
|
await rollbackCronMutation(
|
|
25372
|
-
|
|
26477
|
+
target,
|
|
25373
26478
|
rollbackBefore,
|
|
25374
26479
|
rollbackAfter,
|
|
25375
26480
|
`POST ${base}/${id}/run`
|
|
@@ -25425,6 +26530,12 @@ function registerScheduledTasksRoutes(app, deps) {
|
|
|
25425
26530
|
if (runtime && !requireTrustedWorkspaceRuntime(runtime, res)) return null;
|
|
25426
26531
|
return {
|
|
25427
26532
|
workspaceCwd: boundWorkspace,
|
|
26533
|
+
...runtime ? {
|
|
26534
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir,
|
|
26535
|
+
...deps.cleanupSession ? {
|
|
26536
|
+
cleanupSession: /* @__PURE__ */ __name((sessionId) => deps.cleanupSession(runtime, sessionId), "cleanupSession")
|
|
26537
|
+
} : {}
|
|
26538
|
+
} : {},
|
|
25428
26539
|
bridge: runtime?.bridge ?? bridge,
|
|
25429
26540
|
...runtime?.generationGuard ? {
|
|
25430
26541
|
assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
@@ -25443,7 +26554,8 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
|
25443
26554
|
mutate,
|
|
25444
26555
|
safeBody: safeBody2,
|
|
25445
26556
|
manageScheduledTaskSessions,
|
|
25446
|
-
channelDeliveryAuthorizations
|
|
26557
|
+
channelDeliveryAuthorizations,
|
|
26558
|
+
cleanupSession
|
|
25447
26559
|
} = deps;
|
|
25448
26560
|
registerScheduledTaskCrudRoutes(app, {
|
|
25449
26561
|
prefix: "/workspaces/:workspace",
|
|
@@ -25457,6 +26569,10 @@ function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
|
25457
26569
|
if (!requireTrustedWorkspaceRuntime(runtime, res)) return null;
|
|
25458
26570
|
return {
|
|
25459
26571
|
workspaceCwd: runtime.workspaceCwd,
|
|
26572
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir,
|
|
26573
|
+
...cleanupSession ? {
|
|
26574
|
+
cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession")
|
|
26575
|
+
} : {},
|
|
25460
26576
|
// Mirror the primary surface: only bind a session when management is on,
|
|
25461
26577
|
// so a bound task always has something to keep it resident + rehydrate it.
|
|
25462
26578
|
bridge: manageScheduledTaskSessions ? runtime.bridge : void 0,
|
|
@@ -25735,7 +26851,7 @@ __name(collectBoundSessionIds, "collectBoundSessionIds");
|
|
|
25735
26851
|
var KEEPALIVE_REVIVE_TIMEOUT_MS = 3e4;
|
|
25736
26852
|
var KEEPALIVE_SPAWN_TIMEOUT_MS = 3e4;
|
|
25737
26853
|
var MAX_REVIVE_BACKOFF_MS = 30 * 6e4;
|
|
25738
|
-
async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding) {
|
|
26854
|
+
async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawnTimeoutMs, binding, cleanupSession) {
|
|
25739
26855
|
const unbound = tasks.filter(
|
|
25740
26856
|
(t) => !t.sessionId && t.enabled !== false && !taskHasLegacyCondition(t) && !binding.has(t.id)
|
|
25741
26857
|
);
|
|
@@ -25753,16 +26869,14 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
|
|
|
25753
26869
|
sourceId: task.id
|
|
25754
26870
|
});
|
|
25755
26871
|
let timedOut = false;
|
|
25756
|
-
rawSpawn.then(({ sessionId: sessionId2 }) => {
|
|
26872
|
+
rawSpawn.then(async ({ sessionId: sessionId2 }) => {
|
|
25757
26873
|
if (timedOut) {
|
|
25758
26874
|
log.debug(
|
|
25759
26875
|
"keepalive: late spawn resolved, cleaning up",
|
|
25760
26876
|
task.id,
|
|
25761
26877
|
sessionId2
|
|
25762
26878
|
);
|
|
25763
|
-
|
|
25764
|
-
});
|
|
25765
|
-
new SessionService(boundWorkspace).removeSession(sessionId2).catch(() => {
|
|
26879
|
+
await cleanupSession(sessionId2).catch(() => {
|
|
25766
26880
|
});
|
|
25767
26881
|
}
|
|
25768
26882
|
}).catch(() => {
|
|
@@ -25810,9 +26924,7 @@ async function bindAndNameSessions(bridge, boundWorkspace, tasks, renamed, spawn
|
|
|
25810
26924
|
} catch (err) {
|
|
25811
26925
|
log.debug("keepalive: failed to bind task", task.id, err);
|
|
25812
26926
|
if (spawnedSessionId !== void 0) {
|
|
25813
|
-
await
|
|
25814
|
-
});
|
|
25815
|
-
await new SessionService(boundWorkspace).removeSession(spawnedSessionId).catch(() => {
|
|
26927
|
+
await cleanupSession(spawnedSessionId).catch(() => {
|
|
25816
26928
|
});
|
|
25817
26929
|
}
|
|
25818
26930
|
}
|
|
@@ -25834,11 +26946,17 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
25834
26946
|
const { bridge, boundWorkspace, intervalMs } = opts;
|
|
25835
26947
|
const reviveTimeoutMs = opts.reviveTimeoutMs ?? KEEPALIVE_REVIVE_TIMEOUT_MS;
|
|
25836
26948
|
const spawnTimeoutMs = opts.spawnTimeoutMs ?? KEEPALIVE_SPAWN_TIMEOUT_MS;
|
|
26949
|
+
const cleanupSession = opts.cleanupSession ?? (async (sessionId) => {
|
|
26950
|
+
await bridge.closeSession(sessionId);
|
|
26951
|
+
await new SessionService(boundWorkspace, {
|
|
26952
|
+
runtimeBaseDir: opts.runtimeBaseDir
|
|
26953
|
+
}).removeSession(sessionId);
|
|
26954
|
+
});
|
|
25837
26955
|
const reviveState = /* @__PURE__ */ new Map();
|
|
25838
26956
|
const reviving = /* @__PURE__ */ new Set();
|
|
25839
26957
|
const binding = /* @__PURE__ */ new Set();
|
|
25840
26958
|
const renamed = /* @__PURE__ */ new Set();
|
|
25841
|
-
const
|
|
26959
|
+
const tickInRuntime = /* @__PURE__ */ __name(async () => {
|
|
25842
26960
|
let tasks;
|
|
25843
26961
|
try {
|
|
25844
26962
|
tasks = await readCronTasks(boundWorkspace);
|
|
@@ -25916,9 +27034,14 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
25916
27034
|
tasks,
|
|
25917
27035
|
renamed,
|
|
25918
27036
|
spawnTimeoutMs,
|
|
25919
|
-
binding
|
|
27037
|
+
binding,
|
|
27038
|
+
cleanupSession
|
|
25920
27039
|
);
|
|
25921
|
-
}, "
|
|
27040
|
+
}, "tickInRuntime");
|
|
27041
|
+
const tick = /* @__PURE__ */ __name(() => opts.runtimeBaseDir === void 0 ? tickInRuntime() : Storage.runWithResolvedRuntimeBaseDir(
|
|
27042
|
+
opts.runtimeBaseDir,
|
|
27043
|
+
tickInRuntime
|
|
27044
|
+
), "tick");
|
|
25922
27045
|
let running = false;
|
|
25923
27046
|
const timer = setInterval(() => {
|
|
25924
27047
|
if (running) return;
|
|
@@ -25929,7 +27052,10 @@ function startScheduledTaskKeepalive(opts) {
|
|
|
25929
27052
|
}, intervalMs);
|
|
25930
27053
|
timer.unref?.();
|
|
25931
27054
|
let bindDebounce;
|
|
25932
|
-
const cronFilePath = getCronFilePath(boundWorkspace)
|
|
27055
|
+
const cronFilePath = opts.runtimeBaseDir === void 0 ? getCronFilePath(boundWorkspace) : Storage.runWithResolvedRuntimeBaseDir(
|
|
27056
|
+
opts.runtimeBaseDir,
|
|
27057
|
+
() => getCronFilePath(boundWorkspace)
|
|
27058
|
+
);
|
|
25933
27059
|
const cronDir = path11.dirname(cronFilePath);
|
|
25934
27060
|
const cronFileName = path11.basename(cronFilePath);
|
|
25935
27061
|
let fileWatcher;
|
|
@@ -26442,7 +27568,7 @@ init_esbuild_shims();
|
|
|
26442
27568
|
|
|
26443
27569
|
// packages/cli/src/serve/server/serve-features.ts
|
|
26444
27570
|
init_esbuild_shims();
|
|
26445
|
-
var DEFAULT_MAX_SESSIONS =
|
|
27571
|
+
var DEFAULT_MAX_SESSIONS = 32;
|
|
26446
27572
|
var DEFAULT_MAX_PENDING_PROMPTS_PER_SESSION = 5;
|
|
26447
27573
|
var SERVE_LANGUAGE_CODES = [
|
|
26448
27574
|
...SUPPORTED_LANGUAGES.map((language) => language.code),
|
|
@@ -27424,6 +28550,14 @@ function sendPermissionVoteError(res, err, ctx, daemonLog) {
|
|
|
27424
28550
|
}
|
|
27425
28551
|
__name(sendPermissionVoteError, "sendPermissionVoteError");
|
|
27426
28552
|
function sendBridgeError(res, err, ctx, daemonLog) {
|
|
28553
|
+
if (err instanceof DaemonDrainingError) {
|
|
28554
|
+
res.status(503).json({
|
|
28555
|
+
error: err.message,
|
|
28556
|
+
code: err.code,
|
|
28557
|
+
errorKind: err.code
|
|
28558
|
+
});
|
|
28559
|
+
return;
|
|
28560
|
+
}
|
|
27427
28561
|
if (sendGenerationClosedError(res, err)) return;
|
|
27428
28562
|
if (err instanceof SessionWriterError) {
|
|
27429
28563
|
res.status(err.httpStatus).json({
|
|
@@ -29607,9 +30741,18 @@ function registerWorkspaceManagementRoutes(app, deps) {
|
|
|
29607
30741
|
}
|
|
29608
30742
|
}
|
|
29609
30743
|
);
|
|
30744
|
+
const protectExistingWorkspaceRegistration = mutate({ strict: true });
|
|
29610
30745
|
app.post(
|
|
29611
30746
|
"/workspaces",
|
|
29612
|
-
mutate(
|
|
30747
|
+
mutate(),
|
|
30748
|
+
(req, res, next) => {
|
|
30749
|
+
const body = safeBody2(req);
|
|
30750
|
+
if (body["kind"] === "scratch") {
|
|
30751
|
+
next();
|
|
30752
|
+
return;
|
|
30753
|
+
}
|
|
30754
|
+
protectExistingWorkspaceRegistration(req, res, next);
|
|
30755
|
+
},
|
|
29613
30756
|
async (req, res) => {
|
|
29614
30757
|
const body = safeBody2(req);
|
|
29615
30758
|
if ("kind" in body) {
|
|
@@ -32730,6 +33873,18 @@ function parsePairingCode(body, res) {
|
|
|
32730
33873
|
return code.trim().toUpperCase();
|
|
32731
33874
|
}
|
|
32732
33875
|
__name(parsePairingCode, "parsePairingCode");
|
|
33876
|
+
function parsePairingSenderId(body, res) {
|
|
33877
|
+
const senderId = body["senderId"];
|
|
33878
|
+
if (typeof senderId !== "string" || senderId.length === 0) {
|
|
33879
|
+
res.status(400).json({
|
|
33880
|
+
error: "`senderId` must be a non-empty string.",
|
|
33881
|
+
code: "invalid_channel_pairing_sender_id"
|
|
33882
|
+
});
|
|
33883
|
+
return void 0;
|
|
33884
|
+
}
|
|
33885
|
+
return senderId;
|
|
33886
|
+
}
|
|
33887
|
+
__name(parsePairingSenderId, "parsePairingSenderId");
|
|
32733
33888
|
function errorCode2(error2) {
|
|
32734
33889
|
if (!error2 || typeof error2 !== "object") return void 0;
|
|
32735
33890
|
try {
|
|
@@ -32751,6 +33906,7 @@ var ERROR_STATUS = /* @__PURE__ */ new Map([
|
|
|
32751
33906
|
["untrusted_workspace", 403],
|
|
32752
33907
|
["channel_instance_not_found", 404],
|
|
32753
33908
|
["channel_pairing_request_not_found", 404],
|
|
33909
|
+
["channel_pairing_approval_not_found", 404],
|
|
32754
33910
|
["channel_pairing_not_enabled", 409],
|
|
32755
33911
|
["channel_settings_conflict", 409],
|
|
32756
33912
|
["channel_runtime_owner_mismatch", 409],
|
|
@@ -32807,6 +33963,8 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
|
|
|
32807
33963
|
const register = /* @__PURE__ */ __name((prefix, resolveRuntime) => {
|
|
32808
33964
|
const pairingRead = deps.mutate({ strict: true });
|
|
32809
33965
|
const pairingApprove = deps.mutate({ strict: true });
|
|
33966
|
+
const pairingApprovalsRead = deps.mutate({ strict: true });
|
|
33967
|
+
const pairingRevoke = deps.mutate({ strict: true });
|
|
32810
33968
|
const upsert = deps.mutate({ strict: true });
|
|
32811
33969
|
const remove = deps.mutate({ strict: true });
|
|
32812
33970
|
const startup = deps.mutate({ strict: true });
|
|
@@ -32869,6 +34027,40 @@ function registerWorkspaceChannelManagementRoutes(app, deps) {
|
|
|
32869
34027
|
}
|
|
32870
34028
|
}
|
|
32871
34029
|
);
|
|
34030
|
+
app.get(
|
|
34031
|
+
`${prefix}/channels/:name/pairing-approvals`,
|
|
34032
|
+
pairingApprovalsRead,
|
|
34033
|
+
async (req, res) => {
|
|
34034
|
+
const resolved = await target(req, res);
|
|
34035
|
+
if (!resolved || !validateClient(req, res, resolved.runtime)) return;
|
|
34036
|
+
const name = parseInstanceName(req, res);
|
|
34037
|
+
if (!name) return;
|
|
34038
|
+
try {
|
|
34039
|
+
noStore(res);
|
|
34040
|
+
res.status(200).json(await resolved.service.pairingApprovals(name));
|
|
34041
|
+
} catch (error2) {
|
|
34042
|
+
sendManagementError(res, error2);
|
|
34043
|
+
}
|
|
34044
|
+
}
|
|
34045
|
+
);
|
|
34046
|
+
app.delete(
|
|
34047
|
+
`${prefix}/channels/:name/pairing-approvals`,
|
|
34048
|
+
pairingRevoke,
|
|
34049
|
+
async (req, res) => {
|
|
34050
|
+
const resolved = await target(req, res);
|
|
34051
|
+
if (!resolved || !validateClient(req, res, resolved.runtime)) return;
|
|
34052
|
+
const name = parseInstanceName(req, res);
|
|
34053
|
+
if (!name) return;
|
|
34054
|
+
const senderId = parsePairingSenderId(deps.safeBody(req), res);
|
|
34055
|
+
if (!senderId) return;
|
|
34056
|
+
try {
|
|
34057
|
+
noStore(res);
|
|
34058
|
+
res.status(200).json(await resolved.service.revokePairingApproval(name, senderId));
|
|
34059
|
+
} catch (error2) {
|
|
34060
|
+
sendManagementError(res, error2);
|
|
34061
|
+
}
|
|
34062
|
+
}
|
|
34063
|
+
);
|
|
32872
34064
|
app.put(`${prefix}/channels/:name`, upsert, async (req, res) => {
|
|
32873
34065
|
const resolved = await target(req, res);
|
|
32874
34066
|
if (!resolved || !validateClient(req, res, resolved.runtime)) return;
|
|
@@ -33993,6 +35185,16 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
33993
35185
|
defaultBridgeForAdmission = bridge;
|
|
33994
35186
|
}
|
|
33995
35187
|
const archiveCoordinator = new SessionArchiveCoordinator();
|
|
35188
|
+
app.locals.sessionArchiveCoordinator = archiveCoordinator;
|
|
35189
|
+
const cleanupSession = /* @__PURE__ */ __name((runtime, sessionId) => runWithWorkspaceRuntimeStorage(
|
|
35190
|
+
runtime,
|
|
35191
|
+
() => deleteDaemonSessionIfOrphan({
|
|
35192
|
+
sessionId,
|
|
35193
|
+
service: createWorkspaceRuntimeSessionService(runtime),
|
|
35194
|
+
bridge: runtime.bridge,
|
|
35195
|
+
coordinator: archiveCoordinator
|
|
35196
|
+
})
|
|
35197
|
+
), "cleanupSession");
|
|
33996
35198
|
installSelfOriginStripMiddleware(app, getPort);
|
|
33997
35199
|
app.locals.fsFactory = fsFactory;
|
|
33998
35200
|
app.locals.boundWorkspace = boundWorkspace;
|
|
@@ -34057,6 +35259,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34057
35259
|
{
|
|
34058
35260
|
workspaceId: hashDaemonWorkspace(boundWorkspace),
|
|
34059
35261
|
workspaceCwd: boundWorkspace,
|
|
35262
|
+
sessionRuntimeBaseDir: Storage.getRuntimeBaseDir(),
|
|
34060
35263
|
primary: true,
|
|
34061
35264
|
trusted: deps.primaryWorkspaceTrusted ?? false,
|
|
34062
35265
|
env: primaryRuntimeEnvMetadata ?? {
|
|
@@ -34338,6 +35541,49 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34338
35541
|
isWorkspaceTrusted: isPrimaryWorkspaceTrusted,
|
|
34339
35542
|
captureGenerationAssertion: capturePrimaryGenerationAssertion
|
|
34340
35543
|
});
|
|
35544
|
+
mountWorkspaceQualifiedMemoryRememberRoutes(app, {
|
|
35545
|
+
mutate,
|
|
35546
|
+
resolveRouteDeps: /* @__PURE__ */ __name((req, res, { creating, kind }) => {
|
|
35547
|
+
const runtime = resolveWorkspaceRuntimeFromParam(
|
|
35548
|
+
workspaceRegistry,
|
|
35549
|
+
req,
|
|
35550
|
+
res
|
|
35551
|
+
);
|
|
35552
|
+
if (!runtime || !requireTrustedWorkspaceRuntime(runtime, res))
|
|
35553
|
+
return null;
|
|
35554
|
+
const handle = acpHandleRef.current;
|
|
35555
|
+
const lane = runtime.primary ? workspaceRememberLane : creating ? handle?.ensureWorkspaceRememberLane(runtime.workspaceId) : handle?.getWorkspaceRememberLane(runtime.workspaceId);
|
|
35556
|
+
if (!lane) {
|
|
35557
|
+
if (!handle) {
|
|
35558
|
+
res.status(501).json({
|
|
35559
|
+
error: "Workspace-qualified memory is not enabled on this daemon.",
|
|
35560
|
+
code: "workspace_memory_unavailable",
|
|
35561
|
+
workspaceCwd: runtime.workspaceCwd,
|
|
35562
|
+
workspaceId: runtime.workspaceId
|
|
35563
|
+
});
|
|
35564
|
+
} else if (!creating) {
|
|
35565
|
+
res.status(404).json({
|
|
35566
|
+
error: `Workspace memory ${kind} task not found`,
|
|
35567
|
+
code: `${kind}_task_not_found`
|
|
35568
|
+
});
|
|
35569
|
+
} else {
|
|
35570
|
+
sendWorkspaceRuntimeUnavailable(res, runtime);
|
|
35571
|
+
}
|
|
35572
|
+
return null;
|
|
35573
|
+
}
|
|
35574
|
+
return {
|
|
35575
|
+
bridge: runtime.bridge,
|
|
35576
|
+
lane,
|
|
35577
|
+
parseClientId: parseClientIdHeader,
|
|
35578
|
+
safeBody,
|
|
35579
|
+
isWorkspaceTrusted: /* @__PURE__ */ __name(() => runtime.trusted, "isWorkspaceTrusted"),
|
|
35580
|
+
captureGenerationAssertion: /* @__PURE__ */ __name(() => {
|
|
35581
|
+
const guard = runtime.generationGuard;
|
|
35582
|
+
return guard ? () => guard.assertOpen() : void 0;
|
|
35583
|
+
}, "captureGenerationAssertion")
|
|
35584
|
+
};
|
|
35585
|
+
}, "resolveRouteDeps")
|
|
35586
|
+
});
|
|
34341
35587
|
mountWorkspaceAgentsRoutes(app, {
|
|
34342
35588
|
bridge: primaryBridge,
|
|
34343
35589
|
boundWorkspace: primaryBoundWorkspace,
|
|
@@ -34681,6 +35927,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34681
35927
|
safeBody,
|
|
34682
35928
|
bridge: deps.manageScheduledTaskSessions ? primaryBridge : void 0,
|
|
34683
35929
|
getRuntime: /* @__PURE__ */ __name(() => workspaceRegistry.primaryEntry.state === "active" ? workspaceRegistry.primaryEntry.current?.runtime : void 0, "getRuntime"),
|
|
35930
|
+
cleanupSession,
|
|
34684
35931
|
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
34685
35932
|
});
|
|
34686
35933
|
registerGoalsRoutes(app, {
|
|
@@ -34694,7 +35941,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34694
35941
|
mutate,
|
|
34695
35942
|
safeBody,
|
|
34696
35943
|
manageScheduledTaskSessions: deps.manageScheduledTaskSessions === true,
|
|
34697
|
-
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations
|
|
35944
|
+
channelDeliveryAuthorizations: deps.channelDeliveryAuthorizations,
|
|
35945
|
+
cleanupSession
|
|
34698
35946
|
});
|
|
34699
35947
|
registerUsageStatsRoutes(app);
|
|
34700
35948
|
if (deps.manageScheduledTaskSessions) {
|
|
@@ -34714,23 +35962,26 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34714
35962
|
}, "registerScheduledTaskAuthorizations");
|
|
34715
35963
|
const idleTimeoutMs = opts.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
34716
35964
|
const keepaliveIntervalMs = computeKeepaliveIntervalMs(idleTimeoutMs);
|
|
34717
|
-
const rehydrateWorkspace = /* @__PURE__ */ __name((
|
|
34718
|
-
void
|
|
34719
|
-
|
|
34720
|
-
|
|
34721
|
-
|
|
34722
|
-
|
|
34723
|
-
|
|
34724
|
-
|
|
35965
|
+
const rehydrateWorkspace = /* @__PURE__ */ __name((runtime) => {
|
|
35966
|
+
void runWithWorkspaceRuntimeStorage(
|
|
35967
|
+
runtime,
|
|
35968
|
+
() => rehydrateScheduledTaskSessions({
|
|
35969
|
+
bridge: runtime.bridge,
|
|
35970
|
+
boundWorkspace: runtime.workspaceCwd,
|
|
35971
|
+
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead"),
|
|
35972
|
+
onError: /* @__PURE__ */ __name((sessionId, err) => {
|
|
35973
|
+
process.stderr.write(
|
|
35974
|
+
`qwen serve: failed to rehydrate scheduled-task session ${sessionId}: ${err instanceof Error ? err.message : String(err)}
|
|
34725
35975
|
`
|
|
34726
|
-
|
|
34727
|
-
|
|
34728
|
-
|
|
34729
|
-
|
|
34730
|
-
|
|
34731
|
-
|
|
34732
|
-
|
|
34733
|
-
|
|
35976
|
+
);
|
|
35977
|
+
}, "onError")
|
|
35978
|
+
// Outer catch is defense-in-depth: rehydrateScheduledTaskSessions already
|
|
35979
|
+
// catches readCronTasks failures and per-session load errors internally
|
|
35980
|
+
// (returning { loaded, failed }), so this only guards an unexpected throw
|
|
35981
|
+
// from the function entry itself. Log rather than swallow it — a silent
|
|
35982
|
+
// failure here leaves every bound task dormant with no diagnostic.
|
|
35983
|
+
})
|
|
35984
|
+
).catch((err) => {
|
|
34734
35985
|
process.stderr.write(
|
|
34735
35986
|
`qwen serve: unexpected scheduled-task rehydration failure: ${err instanceof Error ? err.message : String(err)}
|
|
34736
35987
|
`
|
|
@@ -34746,9 +35997,11 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
|
|
|
34746
35997
|
bridge: runtime.bridge,
|
|
34747
35998
|
boundWorkspace: runtime.workspaceCwd,
|
|
34748
35999
|
intervalMs: keepaliveIntervalMs,
|
|
36000
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir,
|
|
36001
|
+
cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession"),
|
|
34749
36002
|
onTasksRead: /* @__PURE__ */ __name((tasks) => registerScheduledTaskAuthorizations(runtime.workspaceCwd, tasks), "onTasksRead")
|
|
34750
36003
|
});
|
|
34751
|
-
rehydrateWorkspace(runtime
|
|
36004
|
+
rehydrateWorkspace(runtime);
|
|
34752
36005
|
keepaliveStops.set(runtime.workspaceCwd, keepalive.stop);
|
|
34753
36006
|
}, "startKeepaliveForWorkspace");
|
|
34754
36007
|
for (const runtime of workspaceRegistry.list()) {
|