@qwen-code/qwen-code 0.22.2-preview.1 → 0.22.3
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/computer-use/SKILL.md +3 -3
- package/bundled/goal-draft/SKILL.md +109 -0
- package/bundled/qc-helper/docs/configuration/settings.md +37 -36
- package/bundled/qc-helper/docs/features/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/dws.md +2 -0
- package/bundled/qc-helper/docs/features/channels/overview.md +34 -3
- package/bundled/qc-helper/docs/features/code-review.md +3 -3
- package/bundled/qc-helper/docs/features/commands.md +2 -1
- package/bundled/qc-helper/docs/features/computer-use.md +2 -2
- package/bundled/qc-helper/docs/features/goals.md +58 -0
- package/bundled/qc-helper/docs/features/headless.md +13 -11
- package/bundled/qc-helper/docs/features/status-line.md +3 -3
- package/bundled/qc-helper/docs/features/tool-use-summaries.md +1 -1
- package/bundled/qc-helper/docs/qwen-serve.md +1 -1
- package/bundled/review/SKILL.md +81 -31
- package/bundled/review/references/persistence.md +7 -3
- package/bundled/review/references/posting.md +10 -4
- package/chunks/MaxSizedBox-X42SXBJH.js +110 -0
- package/chunks/{StandaloneSessionPicker-5D2L22SF.js → StandaloneSessionPicker-2FJAOLGG.js} +81 -83
- package/chunks/{acpAgent-4DCKLA32.js → acpAgent-2ZMIJAFV.js} +1153 -357
- package/chunks/{agent-B4AFZL6H.js → agent-X5WX3L2I.js} +44 -46
- package/chunks/agent-headless-IZM25LJA.js +85 -0
- package/chunks/{anthropicContentGenerator-U76GTVB6.js → anthropicContentGenerator-YVTB6QX7.js} +46 -50
- package/chunks/{artifact-tool-XDJCZZCF.js → artifact-tool-XSMPHZBT.js} +11 -3
- package/chunks/{askUserQuestion-ZXXERLEV.js → askUserQuestion-4SWJY65V.js} +2 -2
- package/chunks/bridge-ME6QXZNA.js +119 -0
- package/chunks/{channel-management-service-HXXS3HOZ.js → channel-management-service-HQ6KDS7C.js} +6 -6
- package/chunks/channel-settings-store-PEOI7XCG.js +120 -0
- package/chunks/{channel-worker-group-EVDC2P4K.js → channel-worker-group-6NA6BBZV.js} +8 -7
- package/chunks/{channel-worker-manager-IJJZHGEI.js → channel-worker-manager-NEZ2J6RK.js} +10 -8
- package/chunks/{channel-worker-supervisor-YSKB5GVB.js → channel-worker-supervisor-FKU7DIHJ.js} +6 -5
- package/chunks/{chunk-7QGEJI7M.js → chunk-23RFD54N.js} +1 -1
- package/chunks/{chunk-JLU3FPQR.js → chunk-2HYKTO7V.js} +5 -5
- package/chunks/chunk-2LNNVAUV.js +1584 -0
- package/chunks/{chunk-FJAITR4L.js → chunk-2OBKDPZZ.js} +2 -2
- package/chunks/{chunk-JSY43GMI.js → chunk-2OUD5T67.js} +185 -174
- package/chunks/{chunk-LJP2BBMK.js → chunk-2SXSLSQE.js} +4 -4
- package/chunks/chunk-2TNL5KPM.js +49 -0
- package/chunks/{chunk-XMSMTU6H.js → chunk-2YOHKHYR.js} +4 -4
- package/chunks/{chunk-MCKJTBZN.js → chunk-36GSQ3MM.js} +2 -2
- package/chunks/chunk-36LGBEM6.js +130 -0
- package/chunks/{chunk-ZWKGZB2K.js → chunk-3JXM2CVW.js} +3 -3
- package/chunks/{chunk-X3XGCJ32.js → chunk-3SZC4VP4.js} +28 -111
- package/chunks/{chunk-ILPXSKGQ.js → chunk-3WK3QDNV.js} +2 -2
- package/chunks/{chunk-IKN3IUJP.js → chunk-3XKLXHGK.js} +17 -9
- package/chunks/{chunk-ZLTEQYNC.js → chunk-42IDLQWS.js} +26 -20
- package/chunks/chunk-4CMJKUND.js +95 -0
- package/chunks/{chunk-77TOMRBG.js → chunk-4K7KNVWH.js} +3 -3
- package/chunks/{chunk-SQPOJ4ZI.js → chunk-4NDLQAY2.js} +27 -270
- package/chunks/{chunk-V3GINY6K.js → chunk-4QHPPXK2.js} +16 -8
- package/chunks/{chunk-VBF4KZRQ.js → chunk-4TT3IVGA.js} +1 -1
- package/chunks/{chunk-IOGKXPL3.js → chunk-4VPCTGH6.js} +6 -6
- package/chunks/chunk-4VQBQLIZ.js +293 -0
- package/chunks/{chunk-UCSV2IZW.js → chunk-62GQFYID.js} +3 -3
- package/chunks/{chunk-SLEWBQWM.js → chunk-6DIGWMGT.js} +2 -2
- package/chunks/{chunk-BRVWYMKV.js → chunk-6MBXY6WM.js} +1 -1
- package/chunks/{chunk-PVBT5QPD.js → chunk-6PJOTWAN.js} +1 -1
- package/chunks/{chunk-WZ3QKPMQ.js → chunk-6X7EU5TI.js} +19 -31
- package/chunks/{chunk-KQYW2GB5.js → chunk-6ZPDLGHN.js} +6 -6
- package/chunks/{chunk-AKQA3WCH.js → chunk-734C6JGI.js} +723 -3399
- package/chunks/{chunk-F7M6ZFGU.js → chunk-73RM4POK.js} +8 -8
- package/chunks/{chunk-ELY4QVIB.js → chunk-7EQQR46F.js} +1 -1
- package/chunks/{chunk-KGJGEEVR.js → chunk-7FA2II6K.js} +10 -1
- package/chunks/chunk-7J6OTNGO.js +424 -0
- package/chunks/{chunk-LWLEPXKK.js → chunk-7LOELM2I.js} +19 -2
- package/chunks/{chunk-DIMEPKCW.js → chunk-7S226YTK.js} +1 -1
- package/chunks/{chunk-AWFZDYSD.js → chunk-7T52W4SW.js} +1 -1
- package/chunks/{chunk-3JKUX4PB.js → chunk-7VMIMAVB.js} +9 -9
- package/chunks/{chunk-2MHGD7EE.js → chunk-A3LWD5MK.js} +1 -1
- package/chunks/{chunk-E4I5MVBR.js → chunk-ABS25QER.js} +1 -1
- package/chunks/{chunk-TDQBVEPK.js → chunk-AIAOIFY4.js} +10 -8
- package/chunks/{chunk-NEZZHGEI.js → chunk-AYFA7MZV.js} +6 -6
- package/chunks/{chunk-FVDQ5E67.js → chunk-B466ZSHZ.js} +3 -3
- package/chunks/{chunk-6US7BF3G.js → chunk-B5PHIJGI.js} +183 -5
- package/chunks/{chunk-4TPAG3O7.js → chunk-BFPESSTR.js} +1 -1
- package/chunks/{chunk-WBT3STGU.js → chunk-BKWNKLZB.js} +20 -20
- package/chunks/{chunk-T45CL2NT.js → chunk-BOWFGCEU.js} +3 -3
- package/chunks/{chunk-IPQA4SR5.js → chunk-BWORX6FA.js} +1 -1
- package/chunks/{chunk-BKDAF7ES.js → chunk-BXDAPVQU.js} +2 -2
- package/chunks/{chunk-ZEADBZLO.js → chunk-C2X7KY45.js} +3 -3
- package/chunks/{chunk-PTQF7WRA.js → chunk-C3PEFRKD.js} +6 -6
- package/chunks/{chunk-7OBH4AM2.js → chunk-CAJTKR6W.js} +5 -5
- package/chunks/{chunk-2FN2HNTI.js → chunk-CFJY4DGX.js} +2 -2
- package/chunks/{chunk-SUE2ZMUH.js → chunk-CIZCL2MW.js} +49 -31
- package/chunks/{chunk-W2WRNJKX.js → chunk-CLWO3B77.js} +6 -6
- package/chunks/{chunk-U45D46O5.js → chunk-CMHFCLBU.js} +1 -1
- package/chunks/{chunk-LRKMQPMD.js → chunk-CQH5KTKC.js} +1 -1
- package/chunks/{chunk-JECO75XD.js → chunk-D5LUXLUH.js} +2 -2
- package/chunks/chunk-DJBQCO2E.js +842 -0
- package/chunks/{chunk-BQBUZDDH.js → chunk-DJECZIJX.js} +42 -42
- package/chunks/{chunk-GTUZ3R6I.js → chunk-DJEZ55D4.js} +351 -113
- package/chunks/{chunk-HPECDZ6X.js → chunk-DJPASAUV.js} +3866 -1077
- package/chunks/{chunk-VYWCFWI5.js → chunk-DMLVSW7L.js} +542 -654
- package/chunks/{chunk-EB4VDXNI.js → chunk-DYXFD5RO.js} +182 -3
- package/chunks/{chunk-ZKAZP2ZG.js → chunk-EB6QRGHM.js} +3 -3
- package/chunks/{chunk-UWICO5KN.js → chunk-EFWRMA2I.js} +3 -3
- package/chunks/{chunk-3UZCLCXR.js → chunk-EKSCLBBF.js} +3 -3
- package/chunks/{chunk-ALTQLFEG.js → chunk-EQSBPBZ3.js} +5 -194
- package/chunks/{chunk-624NHDGB.js → chunk-ERFDKH32.js} +11 -0
- package/chunks/{chunk-4K44OMLI.js → chunk-FROAFEFB.js} +3 -3
- package/chunks/{chunk-MZS7GEC7.js → chunk-FTF2YIZ5.js} +1 -1
- package/chunks/{chunk-Z7VOMGDC.js → chunk-FTJMWDND.js} +0 -24
- package/chunks/{chunk-ZJG323IA.js → chunk-G6FECKTJ.js} +7 -5
- package/chunks/{chunk-TMGAS5TO.js → chunk-GBJBJ4HX.js} +26 -4
- package/chunks/{chunk-UCQOSV6A.js → chunk-GPGU4S2N.js} +3 -3
- package/chunks/{chunk-BHTJAO36.js → chunk-GVIVASYK.js} +7 -7
- package/chunks/chunk-H72BQNM3.js +645 -0
- package/chunks/{chunk-Z4X5MTRT.js → chunk-HCOBAG2L.js} +2 -4
- package/chunks/{chunk-FCSWZAS3.js → chunk-HP5LR5HL.js} +5 -5
- package/chunks/{chunk-7JPW6IYH.js → chunk-HVC3PNVC.js} +1 -1
- package/chunks/{chunk-OI2DR6QB.js → chunk-I6LYRJPB.js} +3 -3
- package/chunks/{chunk-E55H6BZ7.js → chunk-ICURCKIU.js} +1335 -119
- package/chunks/{chunk-PAJGKZAA.js → chunk-ISKH4QX3.js} +14 -12
- package/chunks/{chunk-AYVIGUUK.js → chunk-JB4JIVTJ.js} +1 -1
- package/chunks/{chunk-FN5C6C7G.js → chunk-JHYH6PYQ.js} +192 -478
- package/chunks/{chunk-T6OODF2U.js → chunk-JWALNCLT.js} +1 -1
- package/chunks/{chunk-SKNVVYIJ.js → chunk-K5KXUXWC.js} +3 -3
- package/chunks/{chunk-XUX6O2ZT.js → chunk-KID24ZFN.js} +4 -1
- package/chunks/{chunk-I6DY753S.js → chunk-KJO2LBUK.js} +944 -18
- package/chunks/{chunk-5T4LWWNX.js → chunk-KYWTPLBJ.js} +18 -21
- package/chunks/{chunk-CZFQ62RM.js → chunk-LHBUKJG2.js} +4 -4
- package/chunks/{chunk-TOF4UZHH.js → chunk-LUEHOUHM.js} +3 -3
- package/chunks/{chunk-2YDYDDE2.js → chunk-M3QRM3DE.js} +3 -3
- package/chunks/{chunk-GNMJNDZE.js → chunk-M6FOJXW3.js} +1 -1
- package/chunks/{chunk-ZGWDHSUM.js → chunk-MF7HCQWZ.js} +4 -4
- package/chunks/{chunk-66GIFJ63.js → chunk-MK2GIB46.js} +1 -1
- package/chunks/{chunk-TFV4RXPU.js → chunk-MO3FC2WT.js} +1 -1
- package/chunks/{chunk-TR7G7XFQ.js → chunk-MPNBVAEU.js} +5 -5
- package/chunks/{chunk-K3LPAED5.js → chunk-MQM5PJML.js} +24 -4
- package/chunks/{chunk-3WBMPR3S.js → chunk-MSBO7X2W.js} +1 -1
- package/chunks/{chunk-5PA6UEYA.js → chunk-MZCJWS5Y.js} +1 -1
- package/chunks/{chunk-BGXZBI5B.js → chunk-N4X7G4J2.js} +2 -1
- package/chunks/{chunk-27ONXAFY.js → chunk-NIFYWDYN.js} +1 -1
- package/chunks/{chunk-AP7WZONS.js → chunk-NMOD2FXQ.js} +19 -9
- package/chunks/{chunk-IJVDHPKD.js → chunk-NU7RKEZR.js} +2 -2
- package/chunks/{chunk-5URK47RN.js → chunk-NV55WWD6.js} +11595 -10375
- package/chunks/{chunk-HABT2Z7R.js → chunk-OU5APVWO.js} +4 -4
- package/chunks/{chunk-QR4AHMGQ.js → chunk-P2G476QN.js} +13 -13
- package/chunks/{chunk-5SM2AK65.js → chunk-PADPMMYM.js} +5 -5
- package/chunks/{chunk-RRKNX553.js → chunk-PDQGMSZK.js} +1 -1
- package/chunks/{chunk-GTUKW3I6.js → chunk-PPKZ7JOE.js} +1 -1
- package/chunks/{chunk-SAH4BD2J.js → chunk-PQEISIKS.js} +67 -0
- package/chunks/{chunk-XIRDDFRS.js → chunk-PZ66FRIC.js} +2644 -2296
- package/chunks/{chunk-H3HZ4AWW.js → chunk-Q2MSPKIJ.js} +1 -1
- package/chunks/{chunk-WEGXPP5E.js → chunk-QFCDF5PL.js} +1 -1
- package/chunks/{chunk-OF2DPXUS.js → chunk-QYMAKPY5.js} +119 -24
- package/chunks/{chunk-JVPFTDBK.js → chunk-RFIDDFAL.js} +1 -1
- package/chunks/chunk-RKFGE7JH.js +93 -0
- package/chunks/{chunk-CPPYZHBN.js → chunk-RU7BK6B3.js} +1 -1
- package/chunks/chunk-SEONHUS3.js +275 -0
- package/chunks/{chunk-DEYPMJPD.js → chunk-SMPR7SPO.js} +1 -1
- package/chunks/chunk-SS4MRMKE.js +3525 -0
- package/chunks/{chunk-BPMVPWBT.js → chunk-SS5SDCD3.js} +6 -6
- package/chunks/{chunk-J3CBIEDS.js → chunk-ST5MDGH3.js} +32 -15
- package/chunks/{chunk-J5352S3S.js → chunk-ST5V3ZOC.js} +3 -3
- package/chunks/{chunk-7CWEZQ6T.js → chunk-STUJ7IMZ.js} +0 -77
- package/chunks/{chunk-4K7NQDCG.js → chunk-T4EFG2P5.js} +18 -9
- package/chunks/{chunk-TWSKM647.js → chunk-T7KMERIX.js} +1 -1
- package/chunks/{chunk-5CMWFBML.js → chunk-TEBDFQBZ.js} +1 -1
- package/chunks/{chunk-EC5BONC3.js → chunk-TPI7O7HR.js} +1 -1
- package/chunks/{chunk-T2CRBIDJ.js → chunk-TTX2JUE6.js} +1 -1
- package/chunks/{chunk-VOEMVOM4.js → chunk-TVC6HQ2U.js} +2 -2
- package/chunks/{chunk-WXDZZFH3.js → chunk-TZBSGJ6C.js} +6 -6
- package/chunks/chunk-U54AYGEC.js +337 -0
- package/chunks/{chunk-2NNTE2ED.js → chunk-UHQFIS7N.js} +15 -0
- package/chunks/{chunk-76WGY6LW.js → chunk-URE3QBBB.js} +3 -3
- package/chunks/{chunk-KOJ6MHD5.js → chunk-UTLCH2FK.js} +1 -1
- package/chunks/{chunk-7DPKPBOQ.js → chunk-V2NDP3I4.js} +2 -2
- package/chunks/{chunk-FJWICLG7.js → chunk-V4264FEG.js} +9 -9
- package/chunks/{chunk-XR7OIAQF.js → chunk-V5J4J5TP.js} +2 -2
- package/chunks/{chunk-7UJTY5V3.js → chunk-V7EESTJV.js} +1 -1
- package/chunks/{chunk-Z6L3C4VF.js → chunk-VBCPNIQD.js} +39 -39
- package/chunks/{chunk-ATLGYSYH.js → chunk-VGIFXISB.js} +4 -4
- package/chunks/{chunk-X2UOOG5V.js → chunk-VQUGEVGR.js} +1 -1
- package/chunks/{chunk-XJS54K4A.js → chunk-VTHREBQM.js} +2 -2
- package/chunks/{chunk-AA7VBRBG.js → chunk-W3JH33JE.js} +8 -8
- package/chunks/{chunk-FPH6TXD3.js → chunk-WAOIHTJS.js} +1 -1
- package/chunks/{chunk-CDUN63IN.js → chunk-WGY3AVGM.js} +3 -3
- package/chunks/{chunk-JLGFGPZJ.js → chunk-WNPDGUJO.js} +22 -3
- package/chunks/{chunk-O3BUXIPM.js → chunk-WXEA74YB.js} +3 -3
- package/chunks/{chunk-YRLW2MSX.js → chunk-XBVNNDPK.js} +11 -4
- package/chunks/{chunk-VL4YX3FH.js → chunk-XF63PKEN.js} +1 -1
- package/chunks/{chunk-R7G7GKOX.js → chunk-XHF7WQ6B.js} +3 -3
- package/chunks/{chunk-3FSBMAYD.js → chunk-XQFT3QUF.js} +1 -1
- package/chunks/{chunk-3D6PDLNJ.js → chunk-XSG6G3G6.js} +49 -32
- package/chunks/{chunk-5JCZ3UKB.js → chunk-Y5S7LBOZ.js} +44 -7
- package/chunks/{chunk-OLS3MAXQ.js → chunk-YLSQLSH7.js} +15 -9
- package/chunks/{chunk-2SERYG4T.js → chunk-YTDVNSUQ.js} +1 -1
- package/chunks/{chunk-KPF2K55D.js → chunk-ZEYFMJQA.js} +39 -8
- package/chunks/{chunk-OT4YKUUV.js → chunk-ZU4UDIWX.js} +2 -2
- package/chunks/chunk-ZWJDJ6RU.js +2597 -0
- package/chunks/{chunk-R3T33BG5.js → chunk-ZYMLPEZQ.js} +3 -3
- package/chunks/{chunk-DID6IRGC.js → chunk-ZZMSC3RG.js} +56 -39
- package/chunks/{chunk-L436XFLJ.js → chunk-ZZUKP7HV.js} +1 -1
- package/chunks/config-utils-R6M3TA34.js +113 -0
- package/chunks/contextCommand-ZCAP23J6.js +106 -0
- package/chunks/{core-runtime-CEJRHCRF.js → core-runtime-AXB6SK5D.js} +59 -61
- package/chunks/{create-sub-session-RVHSWVAP.js → create-sub-session-23ITIELI.js} +3 -3
- package/chunks/{create-sub-session-DFZVIG56.js → create-sub-session-4QNE64MR.js} +164 -85
- package/chunks/{cron-create-IJGVR5R2.js → cron-create-KJ4IY6PP.js} +57 -10
- package/chunks/{cron-delete-4N5BI6GL.js → cron-delete-MBLQCAYY.js} +4 -4
- package/chunks/{cron-list-2CATIPUX.js → cron-list-DWH2PQ47.js} +4 -4
- package/chunks/{daemon-NAYK4XXU.js → daemon-3GNHB3M2.js} +523 -8
- package/chunks/{daemon-git-worktree-guard-L6ZUFKF7.js → daemon-git-worktree-guard-IVAJJWYK.js} +56 -58
- package/chunks/daemon-status-provider-K3SJ5C2U.js +117 -0
- package/chunks/daemon-trust-policy-DOR3YG62.js +112 -0
- package/chunks/{daemon-trust-policy-monitor-2G3EKQEU.js → daemon-trust-policy-monitor-KGGROSIV.js} +64 -66
- package/chunks/deferred-core-runtime-WOYLUQQ7.js +114 -0
- package/chunks/{display-image-6KHQNEAE.js → display-image-BE7I6ZB6.js} +5 -5
- package/chunks/{dist-DJBNNPLN.js → dist-4WXLCBDR.js} +1 -1
- package/chunks/{dist-TJUDJTCB.js → dist-5VXFRTWU.js} +280 -48
- package/chunks/{dist-6H6RZ5H6.js → dist-6BPYWHVD.js} +89 -65
- package/chunks/{dist-ZBVOXSKF.js → dist-GFN5DCBX.js} +74 -65
- package/chunks/{dist-SATKXKUR.js → dist-HZNT6GQS.js} +1 -1
- package/chunks/{dist-FVJZSIO4.js → dist-LVZCXVPF.js} +72 -20
- package/chunks/{dist-7CKN54NL.js → dist-N6W6E753.js} +71 -64
- package/chunks/{dist-4Q7NTUNB.js → dist-NSV4NBPK.js} +31 -14
- package/chunks/{dist-UQUFZDIY.js → dist-SWQMYP2Q.js} +18 -16
- package/chunks/earlyInputCapture-OHBEVO4K.js +107 -0
- package/chunks/{edit-ZERGX3RV.js → edit-LEQLAGPZ.js} +45 -47
- package/chunks/{en-6MDBWMTG.js → en-YLXBXM4Z.js} +2 -1
- package/chunks/{enter-worktree-UOZ6ZTP7.js → enter-worktree-35QCAAFP.js} +7 -7
- package/chunks/{enterPlanMode-W2RP3P5B.js → enterPlanMode-ONQN3WHE.js} +47 -49
- package/chunks/{environment-ZBJ23YVR.js → environment-UANTR7A4.js} +60 -62
- package/chunks/errors-WAK6KFBC.js +113 -0
- package/chunks/{exit-worktree-G2QATUCV.js → exit-worktree-XQD6D543.js} +7 -7
- package/chunks/exitPlanMode-UEYBG6P5.js +83 -0
- package/chunks/{fast-path-4MWBCEUF.js → fast-path-WUL7UZ6H.js} +7 -7
- package/chunks/{fast-path-settings-XMFBYFUH.js → fast-path-settings-XH426LUU.js} +3 -3
- package/chunks/{glob-DKTNG32L.js → glob-Y54QUWDY.js} +44 -46
- package/chunks/{goal-tools-CNVXMSZD.js → goal-tools-PTD3MBA7.js} +10 -8
- package/chunks/{grep-3NLSS32D.js → grep-5GPICQBU.js} +6 -6
- package/chunks/handleAutoUpdate-FP3NWNSG.js +109 -0
- package/chunks/i18n-INIU5X7A.js +124 -0
- package/chunks/{image-gen-63NN2H5N.js → image-gen-J6FDGUZP.js} +8 -10
- package/chunks/initializer-TYODV6GE.js +113 -0
- package/chunks/installationInfo-AAPKYDSZ.js +107 -0
- package/chunks/{keychain-token-storage-3MGFRYGM.js → keychain-token-storage-37XPR34V.js} +2 -2
- package/chunks/list-TUODDN6J.js +116 -0
- package/chunks/{list-agents-EXRSHIDJ.js → list-agents-DI3YFTDT.js} +2 -2
- package/chunks/{gemini-X5GQHQYF.js → llm-NSAVK5V3.js} +117 -114
- package/chunks/{geminiContentGenerator-UDSWXZXL.js → llm-content-generator-AY2QKXHE.js} +29 -29
- package/chunks/loadedSettingsAdapter-KJCLZ3C4.js +110 -0
- package/chunks/{loggingContentGenerator-73C7TKDK.js → loggingContentGenerator-DSFQHXIF.js} +328 -37
- package/chunks/{loop-wakeup-XBPB2BRO.js → loop-wakeup-XJFONSQ7.js} +5 -5
- package/chunks/{ls-WFONAND2.js → ls-3VAT2J7A.js} +4 -4
- package/chunks/{lsp-DUKPDUXN.js → lsp-5W7IRUBH.js} +2 -2
- package/chunks/{managed-npm-update-H2KOLQZU.js → managed-npm-update-TSWENTK5.js} +57 -59
- package/chunks/mcp-MWSAPFOL.js +110 -0
- package/chunks/{monitor-TGCMNJJH.js → monitor-RW4GWJHB.js} +44 -46
- package/chunks/nonInteractiveCli-JXKL343Q.js +185 -0
- package/chunks/{notebook-edit-YEUNZYDX.js → notebook-edit-CQNYS5OR.js} +45 -47
- package/chunks/{open-with-auth-4UI3KHUR.js → open-with-auth-YN3QZHVM.js} +1 -1
- package/chunks/{openaiContentGenerator-J7LD4VSL.js → openaiContentGenerator-J6QIF7EX.js} +26 -28
- package/chunks/pidfile-QOIQZFT2.js +111 -0
- package/chunks/process-registry-OAEG6WGC.js +662 -0
- package/chunks/{processUtils-ZHFC7CSL.js → processUtils-GPHNANKZ.js} +2 -2
- package/chunks/prompt-terminal-ledger-FOMFTYOM.js +105 -0
- package/chunks/{qwenContentGenerator-YEWWK3JQ.js → qwenContentGenerator-WWDXPYQI.js} +49 -51
- package/chunks/{qwenOAuth2-JIYAWXTW.js → qwenOAuth2-OF5WRBQT.js} +7 -9
- package/chunks/{read-file-ZQI3WPVK.js → read-file-FQUQHC6N.js} +13 -13
- package/chunks/{read-mcp-resource-7A7NFSFL.js → read-mcp-resource-XD257PGJ.js} +2 -2
- package/chunks/{record-artifact-CPJ4IJSD.js → record-artifact-VW23GS4F.js} +4 -4
- package/chunks/{report-findings-VFM5DENC.js → report-findings-AO5VYFLR.js} +9 -5
- package/chunks/{request-shutdown-6IW46GD7.js → request-shutdown-BCLA3JV2.js} +7 -7
- package/chunks/resumeHistoryUtils-NSGF3UCB.js +118 -0
- package/chunks/ripGrep-4CAT6SKV.js +39 -0
- package/chunks/{run-qwen-serve-WHWU7NZ6.js → run-qwen-serve-5X6IDZER.js} +371 -357
- package/chunks/{runtime-E7BSPWQP.js → runtime-HK27GMPF.js} +69 -71
- package/chunks/scheduled-tasks-MN2ZZ5P6.js +127 -0
- package/chunks/{scheduler-TJPATFOM.js → scheduler-WD4MHMO5.js} +58 -60
- package/chunks/{sdk-exporters-http-XXSKBD2C.js → sdk-exporters-http-TTU2CHBU.js} +2 -2
- package/chunks/{sdk-impl-VPNBLV7I.js → sdk-impl-UUMVYMAL.js} +11 -5
- package/chunks/{send-message-OXZK6USO.js → send-message-AJ4OCUBV.js} +25 -9
- package/chunks/serve-2XCHPPGG.js +118 -0
- package/chunks/{server-AXCN7QBJ.js → server-GO2N5DH7.js} +6080 -4964
- package/chunks/{session-HO4US3AG.js → session-IFNHTUBT.js} +112 -112
- package/chunks/session-pr-refresh-I3UBWMVP.js +364 -0
- package/chunks/{settings-B2PFJJN4.js → settings-L6N54CU6.js} +63 -65
- package/chunks/{shell-7XMSANI3.js → shell-4Y5LLW6N.js} +44 -46
- package/chunks/{skill-NL3VH562.js → skill-YOWTRAKQ.js} +68 -24
- package/chunks/skill-settings-ZL4JY5UE.js +118 -0
- package/chunks/spawnChannel-ZST6XJVJ.js +112 -0
- package/chunks/standalone-update-THVU3OKY.js +118 -0
- package/chunks/{startInteractiveUI-G2XKSCQ7.js → startInteractiveUI-XDFSHBZD.js} +3076 -2475
- package/chunks/{stdioHelpers-7A2EE64Z.js → stdioHelpers-AY6XCDY2.js} +3 -1
- package/chunks/{syntheticOutput-5AJ444QT.js → syntheticOutput-ML43GEFN.js} +3 -3
- package/chunks/{task-create-TY7P6UHG.js → task-create-QN4LYRSE.js} +11 -11
- package/chunks/{task-list-BELMPA75.js → task-list-JPLGK45U.js} +5 -5
- package/chunks/{task-stop-U3S3KZG2.js → task-stop-CXEH5L2D.js} +2 -2
- package/chunks/{task-update-O4IGDPCK.js → task-update-IWEOJFV2.js} +11 -11
- package/chunks/{team-create-IYBUOORE.js → team-create-OOPXCDBA.js} +44 -46
- package/chunks/{team-delete-YWFXX77L.js → team-delete-RZVVSGCY.js} +5 -5
- package/chunks/{team-plan-approval-YKU57LBM.js → team-plan-approval-DSX5EWAT.js} +44 -46
- package/chunks/terminal-image-renderer-KS25G33E.js +114 -0
- package/chunks/theme-manager-YMZNG45F.js +102 -0
- package/chunks/{todoWrite-435EO2CS.js → todoWrite-WDJNQEMW.js} +43 -25
- package/chunks/{tool-search-4Q3KASIQ.js → tool-search-J5Q6U7DN.js} +22 -22
- package/chunks/total-session-admission-PVN64JVV.js +114 -0
- package/chunks/trustedFolders-FATSC4YI.js +122 -0
- package/chunks/{types-WYCFCEHR.js → types-HKLPXZB3.js} +1 -3
- package/chunks/{update-relaunch-4DC2KKFS.js → update-relaunch-SIKHLHVR.js} +6 -6
- package/chunks/updateCheck-D3YG2WCD.js +118 -0
- package/chunks/useAutoAcceptIndicator-ILINOSAS.js +120 -0
- package/chunks/{validateNonInterActiveAuth-YAE4YPO3.js → validateNonInterActiveAuth-JUDQP6V4.js} +105 -105
- package/chunks/{version-QFP7OGWX.js → version-C63GDDWN.js} +1 -1
- package/chunks/{web-fetch-6T23IK6Q.js → web-fetch-FOQZMNSC.js} +16 -18
- package/chunks/{web-search-WBWTCZK2.js → web-search-PUJTBFUC.js} +9 -11
- package/chunks/{web-shell-static-A6QMUNNV.js → web-shell-static-HNB4FDOE.js} +2 -2
- package/chunks/{workflow-FMAA3D4R.js → workflow-Y5IPINVH.js} +128 -94
- package/chunks/workspace-providers-status-IJ4VHFMB.js +114 -0
- package/chunks/{workspace-registration-store-CMMX7EPX.js → workspace-registration-store-SMJWI2AI.js} +1 -1
- package/chunks/workspace-registry-BTGZIMPK.js +123 -0
- package/chunks/workspace-service-SIN67ITC.js +126 -0
- package/chunks/workspace-skills-status-F3RKCUIX.js +113 -0
- package/chunks/{workspace-trust-reconciler-PJDQUTJL.js → workspace-trust-reconciler-PLIDLJZX.js} +72 -72
- package/chunks/write-file-PAIGB33C.js +88 -0
- package/chunks/{zh-TW-MV4FWFB6.js → zh-TW-RPTMRTHG.js} +2 -1
- package/chunks/{zh-X3WGU6SI.js → zh-UNY63FR3.js} +2 -1
- package/chunks/{zoom-image-WVYVFRXF.js → zoom-image-LYQD7BQA.js} +13 -13
- package/cli.js +16 -16
- package/locales/en.js +2 -0
- package/locales/zh-TW.js +2 -0
- package/locales/zh.js +2 -0
- package/package.json +3 -3
- package/web-shell/assets/{abnfDiagram-VCTEODGH-d-8xa8uz.js → abnfDiagram-VCTEODGH-TRCMSA_6.js} +1 -1
- package/web-shell/assets/{arc-BhB7CrGK.js → arc-D9Uls5b3.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-BDCd_IcJ.js → architectureDiagram-5GKGNRK7-Bwb8jPXg.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-C-AHu6mi.js → blockDiagram-NRAW4CY4-DHj71TSX.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-CFjQt0vl.js → c4Diagram-UCG6FXSJ-uKBBdbyr.js} +1 -1
- package/web-shell/assets/channel-CXjVLaBa.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-DRjwqaDq.js → chunk-2Q5K7J3B-BZd0Phrl.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-eHM9noJE.js → chunk-5VM5RSS4-7KNeNBqN.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-CcSWUYn1.js → chunk-F27PBJKO-BeboS7Fi.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-DNr-RF5S.js → chunk-G27WJ6UU-RV3JONoj.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-rVJHoNF8.js → chunk-JWPE2WC7-Yw9FCFsP.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-B2aX0Gzy.js → chunk-LCL6LL3I-GIMnydDe.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-DVp07n32.js → chunk-POPQ4Y6H-Cfrux7bL.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-C6QB_KUr.js → chunk-SVP7TREG-BlvIN0CO.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-CLVxDNCy.js → chunk-XXDRQBXY-DMs7Rr4t.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DANEijO3.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DANEijO3.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-B_aKX3A3.js → cose-bilkent-JH36ORCC-DNGqTNwI.js} +1 -1
- package/web-shell/assets/{cynefin-OW5HDTMX-BBw2pPUa.js → cynefin-OW5HDTMX-CojMpaoH.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-WWPiBTwk.js → cynefinDiagram-5FMLGOSQ-DF07YXGo.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-CPtIdka-.js → dagre-3AP2YEHR-17-4WtCH.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-Dj5og1Xi.js → diagram-S7CK7UJ4-G3Wuyz9m.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-CC_x70YC.js → diagram-UQ7AKVKN-nyWIKZ8P.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-rXMfsO4n.js → diagram-VSXAHHWV-tKHhmYSC.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-DEmLYQbh.js → diagram-VX7I27RA-CpDf1hYk.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-B0ys6Vxx.js → diagram-Z3DM3KII-Cah2IFXG.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-Bq6y6lKH.js → ebnfDiagram-PWID7BFC-DNaCkgxy.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-l69JeBZ4.js → erDiagram-SSCWMZ5O-CAdRgcf1.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-Cm-EzGY4.js → flowDiagram-A5DVABFB-CMUJAShL.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-BRS9ZOp7.js → ganttDiagram-EL5Y4UJY-o-_MUNey.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-DAMRKgLk.js → gitGraphDiagram-WWUBYQGX-_aG-2Z7O.js} +1 -1
- package/web-shell/assets/{index-Bncx8E8M.js → index-BK_NKxiJ.js} +1 -1
- package/web-shell/assets/index-Ci-z4zWY.js +1913 -0
- package/web-shell/assets/index-LDlXZRHA.css +36 -0
- package/web-shell/assets/{infoDiagram-RXCK75RN-DasffaZp.js → infoDiagram-RXCK75RN-qJPeZbGP.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-CmRUt3C-.js → ishikawaDiagram-5VMMS53U-7Om4vNo1.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-DzhE_c1Z.js → journeyDiagram-EYS64GPL-BNtXqmBW.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-BH5b6nn3.js → kanban-definition-3QL26DDD-COgFec8P.js} +1 -1
- package/web-shell/assets/{layout-BxoLK-LY.js → layout-B9n81PC9.js} +1 -1
- package/web-shell/assets/{linear-CqDPvVI7.js → linear-Bb6nXZQq.js} +1 -1
- package/web-shell/assets/{mermaid.core-DBoN4plo.js → mermaid.core-Cgrm3JVT.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-DJJtXPEM.js → mindmap-definition-FBJOCRG2-TKwLTjnG.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-DmgPXP5l.js → pegDiagram-XKGWAZYB-BJPuvlpi.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-1ezjzcI5.js → pieDiagram-E7YTZNPT-D01VkNsW.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-ChKARz3k.js → quadrantDiagram-AXDQQJYC-C4hHsiv-.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-k7mNB_QT.js → railroadDiagram-O6MQD6OU-CuEO4xK2.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-B0XFsii0.js → requirementDiagram-EFPCY7ZU-D5J_vIo5.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-repJ2Ukk.js → sankeyDiagram-P5KCCOFB-DQKY223V.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-D0gUSKGu.js → sequenceDiagram-WJ2MYXX4-D27YV_cm.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-CE463F74.js → sizeCapture-X5ZJPWSS-TJg8UcwV.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-003zYtJa.js → stateDiagram-HBIQ2CUA-CmnPzUIx.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-DNKPyrDc.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-DBj8MFpu.js → swimlanes-XN3QIQJK-ByeP3_Nu.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-ZL1HPC6w.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-D2aCh4a9.js → timeline-definition-24CTP7MA-BsFA5juR.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-BHMfWBpl.js → vennDiagram-4TSXK5OY-DREP2ECo.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-RdHAj66j.js → wardleyDiagram-VM6X3IG4-iyd9lKi2.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-BgJWOvq0.js → xychartDiagram-S5SC5T6Z-CVr1_j9q.js} +1 -1
- package/web-shell/index.html +3 -3
- package/chunks/MaxSizedBox-BFVLZP2E.js +0 -112
- package/chunks/agent-headless-UCBCS4V4.js +0 -87
- package/chunks/bridge-FRNYLYY7.js +0 -119
- package/chunks/channel-settings-store-IV4KDL7N.js +0 -117
- package/chunks/chunk-I6VVOZDK.js +0 -202
- package/chunks/chunk-JS73NNWF.js +0 -30
- package/chunks/chunk-K2OJUPOE.js +0 -78
- package/chunks/chunk-P3QQPMQA.js +0 -19
- package/chunks/chunk-SDVF6A42.js +0 -945
- package/chunks/chunk-VGHZT6JR.js +0 -51
- package/chunks/config-utils-PMX4QZ5Y.js +0 -113
- package/chunks/contextCommand-NZRLVAFC.js +0 -108
- package/chunks/daemon-status-provider-FTTYZEKN.js +0 -118
- package/chunks/daemon-trust-policy-WMGFPA3Z.js +0 -114
- package/chunks/deferred-core-runtime-BUFEFYNA.js +0 -116
- package/chunks/earlyInputCapture-ROPLMXA7.js +0 -109
- package/chunks/errors-U5KNAADB.js +0 -115
- package/chunks/exitPlanMode-VFJ5R5DD.js +0 -85
- package/chunks/handleAutoUpdate-W4BUYFT7.js +0 -111
- package/chunks/i18n-KX7FEKJJ.js +0 -126
- package/chunks/initializer-SNVVLS7Y.js +0 -115
- package/chunks/installationInfo-D4XGQNHJ.js +0 -109
- package/chunks/list-WYECMLXZ.js +0 -118
- package/chunks/loadedSettingsAdapter-5WZBXBCR.js +0 -112
- package/chunks/mcp-CBWAROY3.js +0 -112
- package/chunks/nonInteractiveCli-O232UUV7.js +0 -185
- package/chunks/pidfile-MSPQ255Y.js +0 -113
- package/chunks/process-registry-PMJOA5CO.js +0 -172
- package/chunks/prompt-terminal-ledger-YPGMNDXT.js +0 -107
- package/chunks/resumeHistoryUtils-35D4KAVT.js +0 -120
- package/chunks/ripGrep-46N4FLOS.js +0 -39
- package/chunks/serve-WQ54UIYG.js +0 -120
- package/chunks/skill-settings-SKMN5YXC.js +0 -120
- package/chunks/spawnChannel-NE43EEO3.js +0 -113
- package/chunks/standalone-update-XOCWGXAH.js +0 -120
- package/chunks/terminal-image-renderer-NREKYTAD.js +0 -116
- package/chunks/theme-manager-IJS6OICX.js +0 -104
- package/chunks/total-session-admission-L5RPEFZ2.js +0 -114
- package/chunks/trustedFolders-OILZCHRD.js +0 -124
- package/chunks/updateCheck-AK4COHNK.js +0 -120
- package/chunks/useAutoAcceptIndicator-O2N2Q6KG.js +0 -122
- package/chunks/workspace-providers-status-OCFEWIPQ.js +0 -116
- package/chunks/workspace-registry-WJLZPRTG.js +0 -123
- package/chunks/workspace-service-5ZOBMMIB.js +0 -131
- package/chunks/workspace-skills-status-B6NJZD4B.js +0 -115
- package/chunks/write-file-B2RNX6SU.js +0 -90
- package/web-shell/assets/channel-CU-Zyv0r.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-C0J2_LKs.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-C0J2_LKs.js +0 -1
- package/web-shell/assets/index-C-XlQn24.css +0 -5
- package/web-shell/assets/index-gdvMN4J1.js +0 -1860
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-2uACDdJN.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-C4JJkavU.js +0 -8
|
@@ -0,0 +1,1584 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
parseChannelDelivery
|
|
5
|
+
} from "./chunk-4CMJKUND.js";
|
|
6
|
+
import {
|
|
7
|
+
parseCallerSuppliedSessionId
|
|
8
|
+
} from "./chunk-ZEZKIS2K.js";
|
|
9
|
+
import {
|
|
10
|
+
isInternalWorkspaceRuntime
|
|
11
|
+
} from "./chunk-NYWWQ437.js";
|
|
12
|
+
import {
|
|
13
|
+
SessionNotFoundError
|
|
14
|
+
} from "./chunk-ERFDKH32.js";
|
|
15
|
+
import {
|
|
16
|
+
canonicalizeWorkspace
|
|
17
|
+
} from "./chunk-6PLDPT2C.js";
|
|
18
|
+
import {
|
|
19
|
+
isChannelDeliveryError
|
|
20
|
+
} from "./chunk-RKFGE7JH.js";
|
|
21
|
+
import {
|
|
22
|
+
SessionService,
|
|
23
|
+
stripTerminalControlSequences
|
|
24
|
+
} from "./chunk-PZ66FRIC.js";
|
|
25
|
+
import {
|
|
26
|
+
MAX_JOBS,
|
|
27
|
+
nextDurableFireMs
|
|
28
|
+
} from "./chunk-EKSCLBBF.js";
|
|
29
|
+
import {
|
|
30
|
+
nextFireTime,
|
|
31
|
+
parseCron
|
|
32
|
+
} from "./chunk-IRH27ZC2.js";
|
|
33
|
+
import {
|
|
34
|
+
appendCronRun,
|
|
35
|
+
generateCronTaskId,
|
|
36
|
+
readCronTasks,
|
|
37
|
+
taskHasLegacyCondition,
|
|
38
|
+
updateCronTasks
|
|
39
|
+
} from "./chunk-D5LUXLUH.js";
|
|
40
|
+
import {
|
|
41
|
+
Storage
|
|
42
|
+
} from "./chunk-UHQFIS7N.js";
|
|
43
|
+
import {
|
|
44
|
+
writeStderrLine
|
|
45
|
+
} from "./chunk-7FA2II6K.js";
|
|
46
|
+
import {
|
|
47
|
+
init_esbuild_shims
|
|
48
|
+
} from "./chunk-5O2XNYP6.js";
|
|
49
|
+
import {
|
|
50
|
+
__name
|
|
51
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
52
|
+
|
|
53
|
+
// packages/cli/src/serve/routes/scheduled-tasks.ts
|
|
54
|
+
init_esbuild_shims();
|
|
55
|
+
import { isDeepStrictEqual } from "node:util";
|
|
56
|
+
|
|
57
|
+
// packages/cli/src/serve/workspace-route-runtime.ts
|
|
58
|
+
init_esbuild_shims();
|
|
59
|
+
import * as fs from "node:fs";
|
|
60
|
+
import path from "node:path";
|
|
61
|
+
function resolveWorkspaceEntryFromParam(registry, req, res, paramName = "workspace") {
|
|
62
|
+
const selector = req.params[paramName] ?? "";
|
|
63
|
+
const byId = registry.getEntryByWorkspaceId(selector);
|
|
64
|
+
if (byId) return byId;
|
|
65
|
+
if (!isPortableAbsolutePath(selector)) {
|
|
66
|
+
res.status(400).json({
|
|
67
|
+
error: `\`:${paramName}\` must decode to a workspace id or absolute path`,
|
|
68
|
+
code: "workspace_mismatch"
|
|
69
|
+
});
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const exact = registry.getEntryByWorkspaceCwd(selector);
|
|
73
|
+
if (exact) return exact;
|
|
74
|
+
if (path.isAbsolute(selector) && !isUncPath(selector)) {
|
|
75
|
+
try {
|
|
76
|
+
const canonicalSelector = canonicalizeWorkspace(selector);
|
|
77
|
+
const canonicalMatch = registry.getEntryByWorkspaceCwd(canonicalSelector);
|
|
78
|
+
if (canonicalMatch) return canonicalMatch;
|
|
79
|
+
for (const candidate of registry.listEntries()) {
|
|
80
|
+
if (canonicalizeWorkspace(candidate.workspaceCwd) === canonicalSelector) {
|
|
81
|
+
return candidate;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const normalizedSelector = normalizePortableAbsolutePath(selector);
|
|
88
|
+
const entry = registry.listEntries().find(
|
|
89
|
+
(candidate) => normalizePortableAbsolutePath(candidate.workspaceCwd) === normalizedSelector
|
|
90
|
+
);
|
|
91
|
+
if (!entry) {
|
|
92
|
+
sendWorkspaceMismatch(res, registry);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return entry;
|
|
96
|
+
}
|
|
97
|
+
__name(resolveWorkspaceEntryFromParam, "resolveWorkspaceEntryFromParam");
|
|
98
|
+
function isPortableAbsolutePath(value) {
|
|
99
|
+
return path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || /^\\\\[^\\]+\\[^\\]+/.test(value);
|
|
100
|
+
}
|
|
101
|
+
__name(isPortableAbsolutePath, "isPortableAbsolutePath");
|
|
102
|
+
function isUncPath(value) {
|
|
103
|
+
return /^\\\\[^\\]+\\[^\\]+/.test(value);
|
|
104
|
+
}
|
|
105
|
+
__name(isUncPath, "isUncPath");
|
|
106
|
+
function normalizePortableAbsolutePath(value) {
|
|
107
|
+
if (/^[A-Za-z]:[\\/]/.test(value) || /^\\\\[^\\]+\\[^\\]+/.test(value)) {
|
|
108
|
+
return path.win32.normalize(value).toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
return path.resolve(value);
|
|
111
|
+
}
|
|
112
|
+
__name(normalizePortableAbsolutePath, "normalizePortableAbsolutePath");
|
|
113
|
+
function resolveRegisteredWorkspaceRuntimeByPathSelector(registry, selector) {
|
|
114
|
+
const exact = registry.getByWorkspaceCwd(selector);
|
|
115
|
+
if (exact) return exact;
|
|
116
|
+
if (path.isAbsolute(selector) && !isUncPath(selector)) {
|
|
117
|
+
try {
|
|
118
|
+
const canonicalSelector = canonicalizeWorkspace(selector);
|
|
119
|
+
const canonicalMatch = registry.getByWorkspaceCwd(canonicalSelector);
|
|
120
|
+
if (canonicalMatch) return canonicalMatch;
|
|
121
|
+
for (const runtime of registry.list()) {
|
|
122
|
+
if (canonicalizeWorkspace(runtime.workspaceCwd) === canonicalSelector) {
|
|
123
|
+
return runtime;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const normalizedSelector = normalizePortableAbsolutePath(selector);
|
|
130
|
+
return registry.list().find(
|
|
131
|
+
(runtime) => normalizePortableAbsolutePath(runtime.workspaceCwd) === normalizedSelector
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
__name(resolveRegisteredWorkspaceRuntimeByPathSelector, "resolveRegisteredWorkspaceRuntimeByPathSelector");
|
|
135
|
+
function resolveManagedWorkspaceRuntimeByPathSelector(registry, selector) {
|
|
136
|
+
const exact = registry.getManagedByWorkspaceCwd(selector);
|
|
137
|
+
if (exact && !isInternalWorkspaceRuntime(exact)) return exact;
|
|
138
|
+
if (path.isAbsolute(selector) && !isUncPath(selector)) {
|
|
139
|
+
try {
|
|
140
|
+
const canonicalSelector = canonicalizeWorkspace(selector);
|
|
141
|
+
const canonicalMatch = registry.getManagedByWorkspaceCwd(canonicalSelector);
|
|
142
|
+
if (canonicalMatch && !isInternalWorkspaceRuntime(canonicalMatch)) {
|
|
143
|
+
return canonicalMatch;
|
|
144
|
+
}
|
|
145
|
+
for (const runtime of registry.listManaged()) {
|
|
146
|
+
if (isInternalWorkspaceRuntime(runtime)) continue;
|
|
147
|
+
if (canonicalizeWorkspace(runtime.workspaceCwd) === canonicalSelector) {
|
|
148
|
+
return runtime;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const normalizedSelector = normalizePortableAbsolutePath(selector);
|
|
155
|
+
return registry.listManaged().find(
|
|
156
|
+
(runtime) => !isInternalWorkspaceRuntime(runtime) && normalizePortableAbsolutePath(runtime.workspaceCwd) === normalizedSelector
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
__name(resolveManagedWorkspaceRuntimeByPathSelector, "resolveManagedWorkspaceRuntimeByPathSelector");
|
|
160
|
+
function resolveWorkspaceRuntimeFromParam(registry, req, res, paramName = "workspace") {
|
|
161
|
+
const entry = resolveWorkspaceEntryFromParam(registry, req, res, paramName);
|
|
162
|
+
if (!entry) return null;
|
|
163
|
+
const runtime = entry.state === "active" ? entry.current?.runtime : void 0;
|
|
164
|
+
if (!runtime) {
|
|
165
|
+
sendWorkspaceRuntimeUnavailable(res, entry);
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
return runtime;
|
|
169
|
+
}
|
|
170
|
+
__name(resolveWorkspaceRuntimeFromParam, "resolveWorkspaceRuntimeFromParam");
|
|
171
|
+
function resolveTrustedRuntime(registry, req, res, paramName = "workspace") {
|
|
172
|
+
const runtime = resolveWorkspaceRuntimeFromParam(
|
|
173
|
+
registry,
|
|
174
|
+
req,
|
|
175
|
+
res,
|
|
176
|
+
paramName
|
|
177
|
+
);
|
|
178
|
+
if (!runtime) return null;
|
|
179
|
+
return requireTrustedWorkspaceRuntime(runtime, res) ? runtime : null;
|
|
180
|
+
}
|
|
181
|
+
__name(resolveTrustedRuntime, "resolveTrustedRuntime");
|
|
182
|
+
function resolveWorkspaceRuntimeWithLiveCompatibilityFromParam(registry, req, res, paramName = "workspace") {
|
|
183
|
+
if (typeof registry.getManagedEntryByWorkspaceId !== "function" || typeof registry.getManagedEntryByWorkspaceCwd !== "function") {
|
|
184
|
+
return resolveWorkspaceRuntimeFromParam(registry, req, res, paramName);
|
|
185
|
+
}
|
|
186
|
+
const selector = req.params[paramName] ?? "";
|
|
187
|
+
let entry = registry.getManagedEntryByWorkspaceId(selector);
|
|
188
|
+
if (!entry && isPortableAbsolutePath(selector)) {
|
|
189
|
+
entry = registry.getManagedEntryByWorkspaceCwd(selector);
|
|
190
|
+
}
|
|
191
|
+
if (!entry?.internal) {
|
|
192
|
+
return resolveWorkspaceRuntimeFromParam(registry, req, res, paramName);
|
|
193
|
+
}
|
|
194
|
+
const runtime = entry.state === "active" ? entry.current?.runtime : void 0;
|
|
195
|
+
if (!runtime) {
|
|
196
|
+
sendConversationRuntimeUnavailable(res);
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
return runtime;
|
|
200
|
+
}
|
|
201
|
+
__name(resolveWorkspaceRuntimeWithLiveCompatibilityFromParam, "resolveWorkspaceRuntimeWithLiveCompatibilityFromParam");
|
|
202
|
+
function sendConversationRuntimeUnavailable(res) {
|
|
203
|
+
res.set("Retry-After", "1");
|
|
204
|
+
res.status(503).json({
|
|
205
|
+
error: "The Conversations runtime is temporarily unavailable.",
|
|
206
|
+
code: "conversation_runtime_unavailable",
|
|
207
|
+
retryable: true
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
__name(sendConversationRuntimeUnavailable, "sendConversationRuntimeUnavailable");
|
|
211
|
+
function sendWorkspaceRuntimeUnavailable(res, entry) {
|
|
212
|
+
res.set("Retry-After", "1");
|
|
213
|
+
res.status(503).json({
|
|
214
|
+
error: "Workspace runtime is not active.",
|
|
215
|
+
code: "workspace_runtime_unavailable",
|
|
216
|
+
...entry ? { workspaceCwd: entry.workspaceCwd, workspaceId: entry.workspaceId } : {}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
__name(sendWorkspaceRuntimeUnavailable, "sendWorkspaceRuntimeUnavailable");
|
|
220
|
+
function isGenerationClosedError(error) {
|
|
221
|
+
return Boolean(
|
|
222
|
+
error && typeof error === "object" && "code" in error && error.code === "workspace_generation_closed"
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
__name(isGenerationClosedError, "isGenerationClosedError");
|
|
226
|
+
function sendGenerationClosedError(res, error) {
|
|
227
|
+
if (!isGenerationClosedError(error)) return false;
|
|
228
|
+
sendWorkspaceRuntimeUnavailable(res);
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
__name(sendGenerationClosedError, "sendGenerationClosedError");
|
|
232
|
+
function resolveManagedWorkspaceRuntimeFromParam(registry, req, res, paramName = "workspace") {
|
|
233
|
+
const selector = req.params[paramName] ?? "";
|
|
234
|
+
const byId = registry.getManagedByWorkspaceId(selector);
|
|
235
|
+
if (byId && !isInternalWorkspaceRuntime(byId)) return byId;
|
|
236
|
+
if (!isPortableAbsolutePath(selector)) {
|
|
237
|
+
res.status(400).json({
|
|
238
|
+
error: `\`:${paramName}\` must decode to a workspace id or absolute path`,
|
|
239
|
+
code: "workspace_mismatch"
|
|
240
|
+
});
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
const runtime = resolveManagedWorkspaceRuntimeByPathSelector(
|
|
244
|
+
registry,
|
|
245
|
+
selector
|
|
246
|
+
);
|
|
247
|
+
if (!runtime) {
|
|
248
|
+
res.status(400).json({
|
|
249
|
+
error: "Workspace mismatch: the requested workspace is not registered with this daemon.",
|
|
250
|
+
code: "workspace_mismatch"
|
|
251
|
+
});
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
return runtime;
|
|
255
|
+
}
|
|
256
|
+
__name(resolveManagedWorkspaceRuntimeFromParam, "resolveManagedWorkspaceRuntimeFromParam");
|
|
257
|
+
function requireTrustedWorkspaceRuntime(runtime, res) {
|
|
258
|
+
if (runtime.trusted) return true;
|
|
259
|
+
sendUntrustedWorkspaceResponse(res);
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
__name(requireTrustedWorkspaceRuntime, "requireTrustedWorkspaceRuntime");
|
|
263
|
+
function sendUntrustedWorkspaceResponse(res, extra) {
|
|
264
|
+
res.status(403).json({
|
|
265
|
+
error: "Workspace is not trusted.",
|
|
266
|
+
code: "untrusted_workspace",
|
|
267
|
+
...extra
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
__name(sendUntrustedWorkspaceResponse, "sendUntrustedWorkspaceResponse");
|
|
271
|
+
function getWorkspaceRouteContext(req) {
|
|
272
|
+
return req.workspaceRouteContext;
|
|
273
|
+
}
|
|
274
|
+
__name(getWorkspaceRouteContext, "getWorkspaceRouteContext");
|
|
275
|
+
function setWorkspaceRouteContext(req, context) {
|
|
276
|
+
req.workspaceRouteContext = context;
|
|
277
|
+
}
|
|
278
|
+
__name(setWorkspaceRouteContext, "setWorkspaceRouteContext");
|
|
279
|
+
function sendWorkspaceMismatch(res, registry) {
|
|
280
|
+
res.status(400).json({
|
|
281
|
+
error: "Workspace mismatch: the requested workspace is not registered with this daemon.",
|
|
282
|
+
code: "workspace_mismatch",
|
|
283
|
+
workspaceCount: registry.listEntries().length
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
__name(sendWorkspaceMismatch, "sendWorkspaceMismatch");
|
|
287
|
+
function resolveContainedCwd(req, workspaceCwd) {
|
|
288
|
+
const rawCwd = req.query["cwd"];
|
|
289
|
+
if (typeof rawCwd !== "string" || rawCwd.length === 0) {
|
|
290
|
+
return workspaceCwd;
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const resolved = fs.realpathSync(path.resolve(rawCwd));
|
|
294
|
+
const root = fs.realpathSync(workspaceCwd);
|
|
295
|
+
const rel = path.relative(root, resolved);
|
|
296
|
+
if (!rel.startsWith("..") && !path.isAbsolute(rel)) {
|
|
297
|
+
return resolved;
|
|
298
|
+
}
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
return workspaceCwd;
|
|
302
|
+
}
|
|
303
|
+
__name(resolveContainedCwd, "resolveContainedCwd");
|
|
304
|
+
function resolveContainedCwdOrFail(req, workspaceCwd) {
|
|
305
|
+
const rawCwd = req.query["cwd"];
|
|
306
|
+
if (rawCwd === void 0) {
|
|
307
|
+
return workspaceCwd;
|
|
308
|
+
}
|
|
309
|
+
if (typeof rawCwd !== "string" || rawCwd.length === 0) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const resolved = fs.realpathSync(path.resolve(rawCwd));
|
|
314
|
+
const root = fs.realpathSync(workspaceCwd);
|
|
315
|
+
const rel = path.relative(root, resolved);
|
|
316
|
+
if (!rel.startsWith("..") && !path.isAbsolute(rel)) {
|
|
317
|
+
return resolved;
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
__name(resolveContainedCwdOrFail, "resolveContainedCwdOrFail");
|
|
324
|
+
|
|
325
|
+
// packages/cli/src/serve/routes/scheduled-tasks.ts
|
|
326
|
+
var MAX_SCHEDULED_TASKS = MAX_JOBS;
|
|
327
|
+
var MAX_PROMPT_LENGTH = 1e5;
|
|
328
|
+
var MAX_NAME_LENGTH = 200;
|
|
329
|
+
var MAX_CRON_LENGTH = 200;
|
|
330
|
+
var MAX_SESSION_NAME_LENGTH = 60;
|
|
331
|
+
function scheduledTaskSessionName(label) {
|
|
332
|
+
const cleaned = stripTerminalControlSequences(label).replace(/[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/g, "").trim().replace(/\s+/g, " ");
|
|
333
|
+
let short = cleaned;
|
|
334
|
+
if (cleaned.length > MAX_SESSION_NAME_LENGTH) {
|
|
335
|
+
let cut = MAX_SESSION_NAME_LENGTH - 1;
|
|
336
|
+
const boundary = cleaned.charCodeAt(cut - 1);
|
|
337
|
+
if (boundary >= 55296 && boundary <= 56319) cut -= 1;
|
|
338
|
+
short = `${cleaned.slice(0, cut)}\u2026`;
|
|
339
|
+
}
|
|
340
|
+
return `\u23F0 ${short}`;
|
|
341
|
+
}
|
|
342
|
+
__name(scheduledTaskSessionName, "scheduledTaskSessionName");
|
|
343
|
+
var ExistingSessionScheduledTaskCreateError = class extends Error {
|
|
344
|
+
constructor(status, code, message) {
|
|
345
|
+
super(message);
|
|
346
|
+
this.status = status;
|
|
347
|
+
this.code = code;
|
|
348
|
+
this.name = "ExistingSessionScheduledTaskCreateError";
|
|
349
|
+
}
|
|
350
|
+
static {
|
|
351
|
+
__name(this, "ExistingSessionScheduledTaskCreateError");
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
function assertReusableScheduledTaskSession(target, sessionId, allowActivePrompt, assertCallerPromptActive) {
|
|
355
|
+
const { bridge, workspaceCwd } = target;
|
|
356
|
+
if (!bridge) {
|
|
357
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
358
|
+
409,
|
|
359
|
+
"session_binding_unavailable",
|
|
360
|
+
"Session management is not available for this workspace"
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
assertCallerPromptActive?.();
|
|
364
|
+
let owner;
|
|
365
|
+
try {
|
|
366
|
+
owner = target.resolveLiveSessionOwner?.(sessionId);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
writeStderrLine(
|
|
369
|
+
`qwen serve: failed to resolve scheduled-task session owner '${sessionId}': ${error instanceof Error ? error.message : String(error)}`
|
|
370
|
+
);
|
|
371
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
372
|
+
500,
|
|
373
|
+
"scheduled_tasks_session_failed",
|
|
374
|
+
"Failed to look up the requested session"
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
if (owner?.kind === "unavailable") {
|
|
378
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
379
|
+
503,
|
|
380
|
+
"workspace_runtime_unavailable",
|
|
381
|
+
"The workspace runtime is unavailable"
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
if (owner?.kind === "ambiguous") {
|
|
385
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
386
|
+
500,
|
|
387
|
+
"ambiguous_session_owner",
|
|
388
|
+
`Session owner is ambiguous for "${sessionId}"`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
if (owner?.kind === "found" && owner.runtime.workspaceCwd !== workspaceCwd) {
|
|
392
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
393
|
+
400,
|
|
394
|
+
"session_workspace_mismatch",
|
|
395
|
+
"The requested session belongs to a different workspace; use that workspace's scheduled-task endpoint"
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
let summary;
|
|
399
|
+
try {
|
|
400
|
+
summary = bridge.getSessionSummary(sessionId);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (error instanceof SessionNotFoundError) {
|
|
403
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
404
|
+
404,
|
|
405
|
+
"session_not_found",
|
|
406
|
+
`Session '${sessionId}' was not found`
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
writeStderrLine(
|
|
410
|
+
`qwen serve: failed to look up scheduled-task session '${sessionId}': ${error instanceof Error ? error.message : String(error)}`
|
|
411
|
+
);
|
|
412
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
413
|
+
500,
|
|
414
|
+
"scheduled_tasks_session_failed",
|
|
415
|
+
"Failed to look up the requested session"
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
if (summary.workspaceCwd !== workspaceCwd) {
|
|
419
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
420
|
+
400,
|
|
421
|
+
"session_workspace_mismatch",
|
|
422
|
+
"The requested session belongs to a different workspace; use that workspace's scheduled-task endpoint"
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
if (!allowActivePrompt && summary.hasActivePrompt || (summary.pendingInteractionCount ?? 0) > 0) {
|
|
426
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
427
|
+
409,
|
|
428
|
+
"session_busy",
|
|
429
|
+
allowActivePrompt ? "The caller session has a pending interaction; resolve it before binding the session to a task" : "The requested session is busy; wait for its active prompt or pending interaction to finish before binding it to a task"
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
if (summary.sourceType === "scheduled_task") {
|
|
433
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
434
|
+
409,
|
|
435
|
+
"session_already_bound",
|
|
436
|
+
"The requested session is already reserved for a scheduled task"
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (summary.parentSessionId !== void 0 || summary.sourceId !== void 0 || summary.sourceType !== void 0 && summary.sourceType !== "default") {
|
|
440
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
441
|
+
409,
|
|
442
|
+
"session_source_ineligible",
|
|
443
|
+
"The requested session source cannot own a scheduled task"
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
__name(assertReusableScheduledTaskSession, "assertReusableScheduledTaskSession");
|
|
448
|
+
async function createScheduledTaskWithExistingSession(target, input, options) {
|
|
449
|
+
if (input.cron.length === 0 || input.cron.length > MAX_CRON_LENGTH || validateCron(input.cron) !== null) {
|
|
450
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
451
|
+
400,
|
|
452
|
+
"invalid_cron",
|
|
453
|
+
"The scheduled-task cron expression is invalid"
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
const prompt = input.prompt.trim();
|
|
457
|
+
if (prompt.length === 0 || prompt.length > MAX_PROMPT_LENGTH) {
|
|
458
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
459
|
+
400,
|
|
460
|
+
"invalid_prompt",
|
|
461
|
+
"The scheduled-task prompt is invalid"
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
const allowActivePrompt = options.source === "cron-tool";
|
|
465
|
+
const assertCallerPromptActive = options.source === "cron-tool" ? options.assertCallerPromptActive : void 0;
|
|
466
|
+
assertReusableScheduledTaskSession(
|
|
467
|
+
target,
|
|
468
|
+
input.sessionId,
|
|
469
|
+
allowActivePrompt,
|
|
470
|
+
assertCallerPromptActive
|
|
471
|
+
);
|
|
472
|
+
target.assertGenerationOpen?.();
|
|
473
|
+
if (options.source === "rest") {
|
|
474
|
+
const ensurePersisted = target.bridge?.ensureDefaultSessionPersisted;
|
|
475
|
+
if (!ensurePersisted) {
|
|
476
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
477
|
+
409,
|
|
478
|
+
"session_binding_unavailable",
|
|
479
|
+
"Session persistence is not available for this workspace"
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
try {
|
|
483
|
+
await ensurePersisted.call(target.bridge, input.sessionId);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
target.assertGenerationOpen?.();
|
|
486
|
+
if (error instanceof SessionNotFoundError) {
|
|
487
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
488
|
+
404,
|
|
489
|
+
"session_not_found",
|
|
490
|
+
`Session '${input.sessionId}' was not found`
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
writeStderrLine(
|
|
494
|
+
`qwen serve: failed to persist scheduled-task session '${input.sessionId}': ${error instanceof Error ? error.message : String(error)}`
|
|
495
|
+
);
|
|
496
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
497
|
+
500,
|
|
498
|
+
"session_persistence_failed",
|
|
499
|
+
"Failed to persist the requested session"
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
target.assertGenerationOpen?.();
|
|
503
|
+
}
|
|
504
|
+
const now = Date.now();
|
|
505
|
+
const task = {
|
|
506
|
+
id: generateCronTaskId(),
|
|
507
|
+
cron: input.cron,
|
|
508
|
+
prompt,
|
|
509
|
+
recurring: input.recurring,
|
|
510
|
+
createdAt: now,
|
|
511
|
+
lastFiredAt: now - now % 6e4,
|
|
512
|
+
enabled: input.enabled !== false,
|
|
513
|
+
sessionId: input.sessionId,
|
|
514
|
+
sessionOwnedByTask: false,
|
|
515
|
+
...input.delivery !== void 0 ? { delivery: input.delivery } : {},
|
|
516
|
+
...input.name !== void 0 ? { name: input.name } : {}
|
|
517
|
+
};
|
|
518
|
+
let before;
|
|
519
|
+
let after;
|
|
520
|
+
await runWithScheduledTaskTarget(
|
|
521
|
+
target,
|
|
522
|
+
() => updateCronTasks(
|
|
523
|
+
target.workspaceCwd,
|
|
524
|
+
(tasks) => {
|
|
525
|
+
assertReusableScheduledTaskSession(
|
|
526
|
+
target,
|
|
527
|
+
input.sessionId,
|
|
528
|
+
allowActivePrompt,
|
|
529
|
+
assertCallerPromptActive
|
|
530
|
+
);
|
|
531
|
+
if (tasks.some((candidate) => candidate.sessionId === input.sessionId)) {
|
|
532
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
533
|
+
409,
|
|
534
|
+
"session_already_bound",
|
|
535
|
+
"The requested session is already bound to another scheduled task"
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
if (tasks.length >= MAX_SCHEDULED_TASKS) {
|
|
539
|
+
throw new ExistingSessionScheduledTaskCreateError(
|
|
540
|
+
409,
|
|
541
|
+
"max_tasks_reached",
|
|
542
|
+
`Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
before = tasks;
|
|
546
|
+
after = [...tasks, task];
|
|
547
|
+
return after;
|
|
548
|
+
},
|
|
549
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
try {
|
|
553
|
+
target.assertGenerationOpen?.();
|
|
554
|
+
} catch (error) {
|
|
555
|
+
await rollbackCronMutation(target, before, after, "scheduled-task create");
|
|
556
|
+
throw error;
|
|
557
|
+
}
|
|
558
|
+
return task;
|
|
559
|
+
}
|
|
560
|
+
__name(createScheduledTaskWithExistingSession, "createScheduledTaskWithExistingSession");
|
|
561
|
+
function requireOpenGeneration(target, res) {
|
|
562
|
+
try {
|
|
563
|
+
target.assertGenerationOpen?.();
|
|
564
|
+
return true;
|
|
565
|
+
} catch (error) {
|
|
566
|
+
if (sendGenerationClosedError(res, error)) return false;
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
__name(requireOpenGeneration, "requireOpenGeneration");
|
|
571
|
+
async function rollbackCronMutation(target, before, after, route) {
|
|
572
|
+
if (!before || !after) return;
|
|
573
|
+
await runWithScheduledTaskTarget(
|
|
574
|
+
target,
|
|
575
|
+
() => updateCronTasks(
|
|
576
|
+
target.workspaceCwd,
|
|
577
|
+
(tasks) => isDeepStrictEqual(tasks, after) ? before : tasks
|
|
578
|
+
)
|
|
579
|
+
).catch((error) => {
|
|
580
|
+
writeStderrLine(
|
|
581
|
+
`qwen serve: ${route} failed to roll back a stale task mutation: ${error instanceof Error ? error.message : String(error)}`
|
|
582
|
+
);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
__name(rollbackCronMutation, "rollbackCronMutation");
|
|
586
|
+
async function teardownBoundSession(target, sessionId) {
|
|
587
|
+
if (target.cleanupSession) {
|
|
588
|
+
await target.cleanupSession(sessionId).catch(() => {
|
|
589
|
+
});
|
|
590
|
+
} else if (target.bridge) {
|
|
591
|
+
await target.bridge.closeSession(sessionId).catch(() => {
|
|
592
|
+
});
|
|
593
|
+
const removed = await new SessionService(target.workspaceCwd, {
|
|
594
|
+
runtimeBaseDir: target.runtimeBaseDir
|
|
595
|
+
}).removeSession(sessionId).catch(() => false);
|
|
596
|
+
if (removed) target.bridge.markSessionCatalogChanged?.();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
__name(teardownBoundSession, "teardownBoundSession");
|
|
600
|
+
async function runWithScheduledTaskTarget(target, fn) {
|
|
601
|
+
const result = target.runtimeBaseDir === void 0 ? fn() : Storage.runWithResolvedRuntimeBaseDir(target.runtimeBaseDir, fn);
|
|
602
|
+
return await result;
|
|
603
|
+
}
|
|
604
|
+
__name(runWithScheduledTaskTarget, "runWithScheduledTaskTarget");
|
|
605
|
+
function sendActivityGateError(res, error) {
|
|
606
|
+
if (!error || typeof error !== "object" || error.code !== "daemon_draining") {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
res.status(503).json({
|
|
610
|
+
error: "The daemon is draining and no longer accepts work.",
|
|
611
|
+
code: "daemon_draining"
|
|
612
|
+
});
|
|
613
|
+
return true;
|
|
614
|
+
}
|
|
615
|
+
__name(sendActivityGateError, "sendActivityGateError");
|
|
616
|
+
function computeNextRunAt(task) {
|
|
617
|
+
if (task.enabled === false) return null;
|
|
618
|
+
return nextDurableFireMs(task);
|
|
619
|
+
}
|
|
620
|
+
__name(computeNextRunAt, "computeNextRunAt");
|
|
621
|
+
function toView(task) {
|
|
622
|
+
return {
|
|
623
|
+
id: task.id,
|
|
624
|
+
name: typeof task.name === "string" && task.name.length > 0 ? task.name : null,
|
|
625
|
+
cron: task.cron,
|
|
626
|
+
prompt: task.prompt,
|
|
627
|
+
recurring: task.recurring,
|
|
628
|
+
// Absent enabled defaults to enabled — tool-created tasks never write it.
|
|
629
|
+
// A legacy guarded task (isolated run mode + precondition, both removed) is
|
|
630
|
+
// reported as NOT runnable — `enabled: false` with no `nextRunAt` — so the
|
|
631
|
+
// management UI never shows it as active or offers a Run affordance for a
|
|
632
|
+
// task the scheduler refuses to fire. Fail closed on the read path too, not
|
|
633
|
+
// just the tick. `POST /:id/run` rejects it as a second guard.
|
|
634
|
+
enabled: task.enabled !== false && !taskHasLegacyCondition(task),
|
|
635
|
+
createdAt: task.createdAt,
|
|
636
|
+
lastFiredAt: task.lastFiredAt,
|
|
637
|
+
nextRunAt: taskHasLegacyCondition(task) ? null : computeNextRunAt(task),
|
|
638
|
+
// The task's bound session (its run-history transcript), or null for an
|
|
639
|
+
// unbound tool-created/legacy task.
|
|
640
|
+
sessionId: typeof task.sessionId === "string" && task.sessionId.length > 0 ? task.sessionId : null,
|
|
641
|
+
// Absent runs (tool-created / never-fired) normalizes to [] so the client
|
|
642
|
+
// never special-cases undefined.
|
|
643
|
+
runs: Array.isArray(task.runs) ? task.runs : [],
|
|
644
|
+
...task.delivery !== void 0 ? { delivery: task.delivery } : {}
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
__name(toView, "toView");
|
|
648
|
+
function validateCron(cron) {
|
|
649
|
+
try {
|
|
650
|
+
parseCron(cron);
|
|
651
|
+
nextFireTime(cron, /* @__PURE__ */ new Date());
|
|
652
|
+
return null;
|
|
653
|
+
} catch (err) {
|
|
654
|
+
return err instanceof Error ? err.message : String(err);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
__name(validateCron, "validateCron");
|
|
658
|
+
function canonicalCron(cron) {
|
|
659
|
+
try {
|
|
660
|
+
const f = parseCron(cron);
|
|
661
|
+
const s = /* @__PURE__ */ __name((set) => [...set].sort((a, b) => a - b).join(","), "s");
|
|
662
|
+
return [
|
|
663
|
+
s(f.minute),
|
|
664
|
+
s(f.hour),
|
|
665
|
+
s(f.dayOfMonth),
|
|
666
|
+
s(f.month),
|
|
667
|
+
s(f.dayOfWeek),
|
|
668
|
+
f.domIsWild ? "W" : "",
|
|
669
|
+
f.dowIsWild ? "W" : ""
|
|
670
|
+
].join("|");
|
|
671
|
+
} catch {
|
|
672
|
+
return null;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
__name(canonicalCron, "canonicalCron");
|
|
676
|
+
function registerScheduledTaskCrudRoutes(app, deps) {
|
|
677
|
+
const {
|
|
678
|
+
prefix,
|
|
679
|
+
resolveTarget,
|
|
680
|
+
mutate,
|
|
681
|
+
safeBody,
|
|
682
|
+
channelDeliveryAuthorizations
|
|
683
|
+
} = deps;
|
|
684
|
+
const base = `${prefix}/scheduled-tasks`;
|
|
685
|
+
const withTarget = /* @__PURE__ */ __name((handler) => async (req, res) => {
|
|
686
|
+
const target = resolveTarget(req, res);
|
|
687
|
+
if (!target) return;
|
|
688
|
+
const operation = /* @__PURE__ */ __name(async () => {
|
|
689
|
+
if (!requireOpenGeneration(target, res)) return;
|
|
690
|
+
await handler(req, res, target);
|
|
691
|
+
}, "operation");
|
|
692
|
+
try {
|
|
693
|
+
if (target.activity) {
|
|
694
|
+
await target.activity.run(operation);
|
|
695
|
+
} else {
|
|
696
|
+
await operation();
|
|
697
|
+
}
|
|
698
|
+
} catch (error) {
|
|
699
|
+
if (sendActivityGateError(res, error)) return;
|
|
700
|
+
throw error;
|
|
701
|
+
}
|
|
702
|
+
}, "withTarget");
|
|
703
|
+
app.get(
|
|
704
|
+
base,
|
|
705
|
+
withTarget(async (_req, res, target) => {
|
|
706
|
+
try {
|
|
707
|
+
const tasks = await runWithScheduledTaskTarget(
|
|
708
|
+
target,
|
|
709
|
+
() => readCronTasks(target.workspaceCwd)
|
|
710
|
+
);
|
|
711
|
+
if (!requireOpenGeneration(target, res)) return;
|
|
712
|
+
res.status(200).json({ v: 1, tasks: tasks.map(toView) });
|
|
713
|
+
} catch (err) {
|
|
714
|
+
if (sendActivityGateError(res, err)) return;
|
|
715
|
+
writeStderrLine(
|
|
716
|
+
`qwen serve: GET ${base} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
717
|
+
);
|
|
718
|
+
res.status(500).json({
|
|
719
|
+
error: "Failed to read scheduled tasks (the tasks file may be corrupt)",
|
|
720
|
+
code: "scheduled_tasks_read_failed"
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
})
|
|
724
|
+
);
|
|
725
|
+
app.post(
|
|
726
|
+
base,
|
|
727
|
+
mutate(),
|
|
728
|
+
withTarget(async (req, res, target) => {
|
|
729
|
+
const { workspaceCwd, bridge } = target;
|
|
730
|
+
const body = safeBody(req);
|
|
731
|
+
const cron = typeof body["cron"] === "string" ? body["cron"].trim() : "";
|
|
732
|
+
if (cron.length === 0) {
|
|
733
|
+
res.status(400).json({
|
|
734
|
+
error: "`cron` is required and must be a non-empty string",
|
|
735
|
+
code: "invalid_cron"
|
|
736
|
+
});
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (cron.length > MAX_CRON_LENGTH) {
|
|
740
|
+
res.status(400).json({
|
|
741
|
+
error: `\`cron\` exceeds ${MAX_CRON_LENGTH}-character limit`,
|
|
742
|
+
code: "invalid_cron"
|
|
743
|
+
});
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
const cronError = validateCron(cron);
|
|
747
|
+
if (cronError) {
|
|
748
|
+
res.status(400).json({ error: cronError, code: "invalid_cron" });
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const prompt = typeof body["prompt"] === "string" ? body["prompt"].trim() : "";
|
|
752
|
+
if (prompt.length === 0) {
|
|
753
|
+
res.status(400).json({
|
|
754
|
+
error: "`prompt` is required and must be a non-empty string",
|
|
755
|
+
code: "invalid_prompt"
|
|
756
|
+
});
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (prompt.length > MAX_PROMPT_LENGTH) {
|
|
760
|
+
res.status(400).json({
|
|
761
|
+
error: `\`prompt\` exceeds ${MAX_PROMPT_LENGTH}-character limit`,
|
|
762
|
+
code: "invalid_prompt"
|
|
763
|
+
});
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const nameResult = parseNameField(body["name"]);
|
|
767
|
+
if (nameResult.error) {
|
|
768
|
+
res.status(400).json({ error: nameResult.error, code: "invalid_name" });
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
if (body["recurring"] !== void 0 && typeof body["recurring"] !== "boolean") {
|
|
772
|
+
res.status(400).json({
|
|
773
|
+
error: "`recurring` must be a boolean",
|
|
774
|
+
code: "invalid_recurring"
|
|
775
|
+
});
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (body["enabled"] !== void 0 && typeof body["enabled"] !== "boolean") {
|
|
779
|
+
res.status(400).json({
|
|
780
|
+
error: "`enabled` must be a boolean",
|
|
781
|
+
code: "invalid_enabled"
|
|
782
|
+
});
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const parsedSessionId = parseCallerSuppliedSessionId(body["sessionId"]);
|
|
786
|
+
if (parsedSessionId.kind === "invalid") {
|
|
787
|
+
res.status(400).json({
|
|
788
|
+
error: '`sessionId` must be an RFC UUID v1-v5 (e.g. "550e8400-e29b-41d4-a716-446655440000")',
|
|
789
|
+
code: "invalid_session_id"
|
|
790
|
+
});
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
const providedSessionId = parsedSessionId.kind === "valid" ? parsedSessionId.sessionId : void 0;
|
|
794
|
+
let delivery;
|
|
795
|
+
if (body["delivery"] !== void 0) {
|
|
796
|
+
try {
|
|
797
|
+
delivery = parseChannelDelivery(body["delivery"]);
|
|
798
|
+
} catch (err) {
|
|
799
|
+
if (!isChannelDeliveryError(err)) throw err;
|
|
800
|
+
res.status(400).json({ error: err.message, code: err.code });
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
const removedField = findRemovedTaskField(body);
|
|
805
|
+
if (removedField) {
|
|
806
|
+
res.status(400).json(removedFieldError(removedField));
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
const recurring = body["recurring"] !== false;
|
|
810
|
+
const enabled = body["enabled"] !== false;
|
|
811
|
+
const taskId = generateCronTaskId();
|
|
812
|
+
if (providedSessionId !== void 0) {
|
|
813
|
+
try {
|
|
814
|
+
const task2 = await createScheduledTaskWithExistingSession(
|
|
815
|
+
target,
|
|
816
|
+
{
|
|
817
|
+
sessionId: providedSessionId,
|
|
818
|
+
cron,
|
|
819
|
+
prompt,
|
|
820
|
+
recurring,
|
|
821
|
+
enabled,
|
|
822
|
+
...delivery !== void 0 ? { delivery } : {},
|
|
823
|
+
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
824
|
+
},
|
|
825
|
+
{ source: "rest" }
|
|
826
|
+
);
|
|
827
|
+
if (task2.delivery && task2.sessionId) {
|
|
828
|
+
channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
|
|
829
|
+
sessionId: task2.sessionId,
|
|
830
|
+
taskId: task2.id,
|
|
831
|
+
target: task2.delivery.target,
|
|
832
|
+
recurring: task2.recurring,
|
|
833
|
+
lastFiredAt: task2.lastFiredAt ?? void 0
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
res.status(201).json(toView(task2));
|
|
837
|
+
} catch (error) {
|
|
838
|
+
if (error instanceof ExistingSessionScheduledTaskCreateError) {
|
|
839
|
+
if (error.code === "workspace_runtime_unavailable") {
|
|
840
|
+
res.set("Retry-After", "1");
|
|
841
|
+
}
|
|
842
|
+
res.status(error.status).json({ error: error.message, code: error.code });
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (sendActivityGateError(res, error)) return;
|
|
846
|
+
if (sendGenerationClosedError(res, error)) return;
|
|
847
|
+
writeStderrLine(
|
|
848
|
+
`qwen serve: POST ${base} failed to create a task for session '${providedSessionId}': ${error instanceof Error ? error.message : String(error)}`
|
|
849
|
+
);
|
|
850
|
+
res.status(500).json({
|
|
851
|
+
error: "Failed to create scheduled task",
|
|
852
|
+
code: "scheduled_tasks_write_failed"
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
let boundSessionId;
|
|
858
|
+
let sessionMintedHere = false;
|
|
859
|
+
if (bridge) {
|
|
860
|
+
try {
|
|
861
|
+
const tasks = await runWithScheduledTaskTarget(
|
|
862
|
+
target,
|
|
863
|
+
() => readCronTasks(workspaceCwd)
|
|
864
|
+
);
|
|
865
|
+
if (tasks.length >= MAX_SCHEDULED_TASKS) {
|
|
866
|
+
res.status(409).json({
|
|
867
|
+
error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
|
|
868
|
+
code: "max_tasks_reached"
|
|
869
|
+
});
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
} catch {
|
|
873
|
+
}
|
|
874
|
+
if (!requireOpenGeneration(target, res)) return;
|
|
875
|
+
try {
|
|
876
|
+
const session = await runWithScheduledTaskTarget(
|
|
877
|
+
target,
|
|
878
|
+
() => bridge.spawnOrAttach({
|
|
879
|
+
workspaceCwd,
|
|
880
|
+
sessionScope: "thread",
|
|
881
|
+
sourceType: "scheduled_task",
|
|
882
|
+
sourceId: taskId
|
|
883
|
+
})
|
|
884
|
+
);
|
|
885
|
+
boundSessionId = session.sessionId;
|
|
886
|
+
sessionMintedHere = true;
|
|
887
|
+
if (!requireOpenGeneration(target, res)) {
|
|
888
|
+
await teardownBoundSession(target, boundSessionId);
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
try {
|
|
892
|
+
await runWithScheduledTaskTarget(
|
|
893
|
+
target,
|
|
894
|
+
async () => bridge.updateSessionMetadata(boundSessionId, {
|
|
895
|
+
displayName: scheduledTaskSessionName(
|
|
896
|
+
nameResult.value ?? prompt
|
|
897
|
+
)
|
|
898
|
+
})
|
|
899
|
+
);
|
|
900
|
+
} catch {
|
|
901
|
+
}
|
|
902
|
+
} catch (err) {
|
|
903
|
+
if (sendActivityGateError(res, err)) return;
|
|
904
|
+
if (sendGenerationClosedError(res, err)) return;
|
|
905
|
+
writeStderrLine(
|
|
906
|
+
`qwen serve: POST ${base} failed to create the task's session: ${err instanceof Error ? err.message : String(err)}`
|
|
907
|
+
);
|
|
908
|
+
res.status(500).json({
|
|
909
|
+
error: "Failed to create the task's session",
|
|
910
|
+
code: "scheduled_tasks_session_failed"
|
|
911
|
+
});
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
const now = Date.now();
|
|
916
|
+
const task = {
|
|
917
|
+
id: taskId,
|
|
918
|
+
cron,
|
|
919
|
+
prompt,
|
|
920
|
+
recurring,
|
|
921
|
+
createdAt: now,
|
|
922
|
+
// Pin to the creation minute so the scheduler can't fire during the
|
|
923
|
+
// minute the task was created — same guard cronScheduler.create uses.
|
|
924
|
+
lastFiredAt: now - now % 6e4,
|
|
925
|
+
enabled,
|
|
926
|
+
...delivery !== void 0 ? { delivery } : {},
|
|
927
|
+
...boundSessionId !== void 0 ? {
|
|
928
|
+
sessionId: boundSessionId
|
|
929
|
+
} : {},
|
|
930
|
+
...nameResult.value !== void 0 ? { name: nameResult.value } : {}
|
|
931
|
+
};
|
|
932
|
+
const rollbackSession = /* @__PURE__ */ __name(async () => {
|
|
933
|
+
if (boundSessionId !== void 0 && sessionMintedHere) {
|
|
934
|
+
await teardownBoundSession(target, boundSessionId);
|
|
935
|
+
}
|
|
936
|
+
}, "rollbackSession");
|
|
937
|
+
let overCap = false;
|
|
938
|
+
let rollbackBefore;
|
|
939
|
+
let rollbackAfter;
|
|
940
|
+
try {
|
|
941
|
+
await runWithScheduledTaskTarget(
|
|
942
|
+
target,
|
|
943
|
+
() => updateCronTasks(
|
|
944
|
+
workspaceCwd,
|
|
945
|
+
(tasks) => {
|
|
946
|
+
if (tasks.length >= MAX_SCHEDULED_TASKS) {
|
|
947
|
+
overCap = true;
|
|
948
|
+
return tasks;
|
|
949
|
+
}
|
|
950
|
+
rollbackBefore = tasks;
|
|
951
|
+
rollbackAfter = [...tasks, task];
|
|
952
|
+
return rollbackAfter;
|
|
953
|
+
},
|
|
954
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
955
|
+
)
|
|
956
|
+
);
|
|
957
|
+
} catch (err) {
|
|
958
|
+
await rollbackSession();
|
|
959
|
+
if (sendActivityGateError(res, err)) return;
|
|
960
|
+
if (sendGenerationClosedError(res, err)) return;
|
|
961
|
+
writeStderrLine(
|
|
962
|
+
`qwen serve: POST ${base} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
963
|
+
);
|
|
964
|
+
res.status(500).json({
|
|
965
|
+
error: "Failed to create scheduled task",
|
|
966
|
+
code: "scheduled_tasks_write_failed"
|
|
967
|
+
});
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (rollbackBefore && rollbackAfter) {
|
|
971
|
+
try {
|
|
972
|
+
target.assertGenerationOpen?.();
|
|
973
|
+
} catch (error) {
|
|
974
|
+
await rollbackCronMutation(
|
|
975
|
+
target,
|
|
976
|
+
rollbackBefore,
|
|
977
|
+
rollbackAfter,
|
|
978
|
+
`POST ${base}`
|
|
979
|
+
);
|
|
980
|
+
await rollbackSession();
|
|
981
|
+
if (sendGenerationClosedError(res, error)) return;
|
|
982
|
+
throw error;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (overCap) {
|
|
986
|
+
await rollbackSession();
|
|
987
|
+
res.status(409).json({
|
|
988
|
+
error: `Maximum number of scheduled tasks (${MAX_SCHEDULED_TASKS}) reached`,
|
|
989
|
+
code: "max_tasks_reached"
|
|
990
|
+
});
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
if (task.delivery && task.sessionId) {
|
|
994
|
+
channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
|
|
995
|
+
sessionId: task.sessionId,
|
|
996
|
+
taskId: task.id,
|
|
997
|
+
target: task.delivery.target,
|
|
998
|
+
recurring: task.recurring,
|
|
999
|
+
lastFiredAt: task.lastFiredAt ?? void 0
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
res.status(201).json(toView(task));
|
|
1003
|
+
})
|
|
1004
|
+
);
|
|
1005
|
+
app.patch(
|
|
1006
|
+
`${base}/:id`,
|
|
1007
|
+
mutate(),
|
|
1008
|
+
withTarget(async (req, res, target) => {
|
|
1009
|
+
const { workspaceCwd, bridge } = target;
|
|
1010
|
+
const id = typeof req.params["id"] === "string" ? req.params["id"] : "";
|
|
1011
|
+
if (id.length === 0) {
|
|
1012
|
+
res.status(400).json({ error: "Task id is required", code: "invalid_id" });
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const body = safeBody(req);
|
|
1016
|
+
const patch = {};
|
|
1017
|
+
let clearName = false;
|
|
1018
|
+
let clearDelivery = false;
|
|
1019
|
+
const removedPatchField = findRemovedTaskField(body);
|
|
1020
|
+
if (removedPatchField) {
|
|
1021
|
+
res.status(400).json(removedFieldError(removedPatchField));
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
if ("cron" in body) {
|
|
1025
|
+
const cron = typeof body["cron"] === "string" ? body["cron"].trim() : "";
|
|
1026
|
+
if (cron.length === 0 || cron.length > MAX_CRON_LENGTH) {
|
|
1027
|
+
res.status(400).json({
|
|
1028
|
+
error: "`cron` must be a non-empty string within the length limit",
|
|
1029
|
+
code: "invalid_cron"
|
|
1030
|
+
});
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
const cronError = validateCron(cron);
|
|
1034
|
+
if (cronError) {
|
|
1035
|
+
res.status(400).json({ error: cronError, code: "invalid_cron" });
|
|
1036
|
+
return;
|
|
1037
|
+
}
|
|
1038
|
+
patch.cron = cron;
|
|
1039
|
+
}
|
|
1040
|
+
if ("prompt" in body) {
|
|
1041
|
+
const prompt = typeof body["prompt"] === "string" ? body["prompt"].trim() : "";
|
|
1042
|
+
if (prompt.length === 0 || prompt.length > MAX_PROMPT_LENGTH) {
|
|
1043
|
+
res.status(400).json({
|
|
1044
|
+
error: "`prompt` must be a non-empty string within the length limit",
|
|
1045
|
+
code: "invalid_prompt"
|
|
1046
|
+
});
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
patch.prompt = prompt;
|
|
1050
|
+
}
|
|
1051
|
+
if ("name" in body) {
|
|
1052
|
+
const nameResult = parseNameField(body["name"]);
|
|
1053
|
+
if (nameResult.error) {
|
|
1054
|
+
res.status(400).json({ error: nameResult.error, code: "invalid_name" });
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
1057
|
+
if (nameResult.value === void 0) {
|
|
1058
|
+
clearName = true;
|
|
1059
|
+
} else {
|
|
1060
|
+
patch.name = nameResult.value;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if ("recurring" in body) {
|
|
1064
|
+
if (typeof body["recurring"] !== "boolean") {
|
|
1065
|
+
res.status(400).json({
|
|
1066
|
+
error: "`recurring` must be a boolean",
|
|
1067
|
+
code: "invalid_recurring"
|
|
1068
|
+
});
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
patch.recurring = body["recurring"];
|
|
1072
|
+
}
|
|
1073
|
+
if ("enabled" in body) {
|
|
1074
|
+
if (typeof body["enabled"] !== "boolean") {
|
|
1075
|
+
res.status(400).json({
|
|
1076
|
+
error: "`enabled` must be a boolean",
|
|
1077
|
+
code: "invalid_enabled"
|
|
1078
|
+
});
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
patch.enabled = body["enabled"];
|
|
1082
|
+
}
|
|
1083
|
+
if ("delivery" in body) {
|
|
1084
|
+
if (body["delivery"] === null) {
|
|
1085
|
+
clearDelivery = true;
|
|
1086
|
+
} else {
|
|
1087
|
+
try {
|
|
1088
|
+
patch.delivery = parseChannelDelivery(body["delivery"]);
|
|
1089
|
+
} catch (err) {
|
|
1090
|
+
if (!isChannelDeliveryError(err)) throw err;
|
|
1091
|
+
res.status(400).json({ error: err.message, code: err.code });
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (Object.keys(patch).length === 0 && !clearName && !clearDelivery) {
|
|
1097
|
+
res.status(400).json({
|
|
1098
|
+
error: "No updatable fields provided",
|
|
1099
|
+
code: "empty_patch"
|
|
1100
|
+
});
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
let found = false;
|
|
1104
|
+
let updated;
|
|
1105
|
+
let blockedByArchive = false;
|
|
1106
|
+
let blockedLegacy = false;
|
|
1107
|
+
let rollbackBefore;
|
|
1108
|
+
let rollbackAfter;
|
|
1109
|
+
try {
|
|
1110
|
+
await runWithScheduledTaskTarget(
|
|
1111
|
+
target,
|
|
1112
|
+
() => updateCronTasks(
|
|
1113
|
+
workspaceCwd,
|
|
1114
|
+
(tasks) => {
|
|
1115
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
1116
|
+
if (idx === -1) return tasks;
|
|
1117
|
+
found = true;
|
|
1118
|
+
const current = tasks[idx];
|
|
1119
|
+
if (patch.enabled === true && taskHasLegacyCondition(current)) {
|
|
1120
|
+
blockedLegacy = true;
|
|
1121
|
+
return tasks;
|
|
1122
|
+
}
|
|
1123
|
+
if (patch.enabled === true && current.disabledByArchive === true) {
|
|
1124
|
+
blockedByArchive = true;
|
|
1125
|
+
return tasks;
|
|
1126
|
+
}
|
|
1127
|
+
const next = { ...current, ...patch };
|
|
1128
|
+
if (clearName) delete next.name;
|
|
1129
|
+
if (clearDelivery) delete next.delivery;
|
|
1130
|
+
const justReEnabled = current.enabled === false && patch.enabled === true;
|
|
1131
|
+
const cronChanged = patch.cron !== void 0 && canonicalCron(patch.cron) !== canonicalCron(current.cron);
|
|
1132
|
+
const becameRecurring = patch.recurring === true && current.recurring !== true;
|
|
1133
|
+
const becameOneShot = patch.recurring === false && current.recurring !== false;
|
|
1134
|
+
{
|
|
1135
|
+
const now = Date.now();
|
|
1136
|
+
const minute = now - now % 6e4;
|
|
1137
|
+
if (next.recurring && (justReEnabled || cronChanged || becameRecurring)) {
|
|
1138
|
+
next.lastFiredAt = minute;
|
|
1139
|
+
} else if (!next.recurring && (justReEnabled || cronChanged || becameOneShot)) {
|
|
1140
|
+
next.createdAt = now;
|
|
1141
|
+
next.lastFiredAt = minute;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
updated = next;
|
|
1145
|
+
rollbackBefore = tasks;
|
|
1146
|
+
rollbackAfter = tasks.map((t, i) => i === idx ? next : t);
|
|
1147
|
+
return rollbackAfter;
|
|
1148
|
+
},
|
|
1149
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
1150
|
+
)
|
|
1151
|
+
);
|
|
1152
|
+
} catch (err) {
|
|
1153
|
+
if (sendActivityGateError(res, err)) return;
|
|
1154
|
+
if (sendGenerationClosedError(res, err)) return;
|
|
1155
|
+
writeStderrLine(
|
|
1156
|
+
`qwen serve: PATCH ${base}/${id} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1157
|
+
);
|
|
1158
|
+
res.status(500).json({
|
|
1159
|
+
error: "Failed to update scheduled task",
|
|
1160
|
+
code: "scheduled_tasks_write_failed"
|
|
1161
|
+
});
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (rollbackBefore && rollbackAfter) {
|
|
1165
|
+
try {
|
|
1166
|
+
target.assertGenerationOpen?.();
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
await rollbackCronMutation(
|
|
1169
|
+
target,
|
|
1170
|
+
rollbackBefore,
|
|
1171
|
+
rollbackAfter,
|
|
1172
|
+
`PATCH ${base}/${id}`
|
|
1173
|
+
);
|
|
1174
|
+
if (sendGenerationClosedError(res, error)) return;
|
|
1175
|
+
throw error;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
if (blockedLegacy) {
|
|
1179
|
+
res.status(409).json({
|
|
1180
|
+
error: "This task uses the removed isolated run mode with a precondition and can no longer be enabled or run. Recreate it (and call the `create_sub_session` tool from the prompt if you need per-run isolation).",
|
|
1181
|
+
code: "task_legacy_unsupported"
|
|
1182
|
+
});
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
if (blockedByArchive) {
|
|
1186
|
+
res.status(409).json({
|
|
1187
|
+
error: "This task was disabled by archiving its session; unarchive the session to re-enable it.",
|
|
1188
|
+
code: "task_session_archived"
|
|
1189
|
+
});
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
if (!found || !updated) {
|
|
1193
|
+
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
const effectiveLabelChanged = patch.name !== void 0 || clearName || patch.prompt !== void 0 && updated.name === void 0;
|
|
1197
|
+
if (bridge && updated.sessionId && updated.sessionOwnedByTask !== false && effectiveLabelChanged) {
|
|
1198
|
+
try {
|
|
1199
|
+
bridge.updateSessionMetadata(updated.sessionId, {
|
|
1200
|
+
displayName: scheduledTaskSessionName(
|
|
1201
|
+
updated.name ?? updated.prompt
|
|
1202
|
+
)
|
|
1203
|
+
});
|
|
1204
|
+
} catch {
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
if (updated.delivery && updated.sessionId) {
|
|
1208
|
+
channelDeliveryAuthorizations?.registerScheduledTask(workspaceCwd, {
|
|
1209
|
+
sessionId: updated.sessionId,
|
|
1210
|
+
taskId: updated.id,
|
|
1211
|
+
target: updated.delivery.target,
|
|
1212
|
+
recurring: updated.recurring,
|
|
1213
|
+
lastFiredAt: updated.lastFiredAt ?? void 0
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
if (clearDelivery && updated.sessionId) {
|
|
1217
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
1218
|
+
workspaceCwd,
|
|
1219
|
+
updated.sessionId,
|
|
1220
|
+
updated.id
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
res.status(200).json(toView(updated));
|
|
1224
|
+
})
|
|
1225
|
+
);
|
|
1226
|
+
app.delete(
|
|
1227
|
+
`${base}/:id`,
|
|
1228
|
+
mutate(),
|
|
1229
|
+
withTarget(async (req, res, target) => {
|
|
1230
|
+
const { workspaceCwd, bridge } = target;
|
|
1231
|
+
const id = typeof req.params["id"] === "string" ? req.params["id"] : "";
|
|
1232
|
+
if (id.length === 0) {
|
|
1233
|
+
res.status(400).json({ error: "Task id is required", code: "invalid_id" });
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
let boundSessionId;
|
|
1237
|
+
let sessionOwnedByTask = true;
|
|
1238
|
+
let removed = false;
|
|
1239
|
+
let rollbackBefore;
|
|
1240
|
+
let rollbackAfter;
|
|
1241
|
+
try {
|
|
1242
|
+
await runWithScheduledTaskTarget(
|
|
1243
|
+
target,
|
|
1244
|
+
() => updateCronTasks(
|
|
1245
|
+
workspaceCwd,
|
|
1246
|
+
(tasks) => {
|
|
1247
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
1248
|
+
if (idx === -1) return tasks;
|
|
1249
|
+
const match = tasks[idx].sessionId;
|
|
1250
|
+
if (typeof match === "string" && match.length > 0) {
|
|
1251
|
+
boundSessionId = match;
|
|
1252
|
+
sessionOwnedByTask = tasks[idx].sessionOwnedByTask !== false;
|
|
1253
|
+
}
|
|
1254
|
+
removed = true;
|
|
1255
|
+
rollbackBefore = tasks;
|
|
1256
|
+
rollbackAfter = tasks.filter((_, i) => i !== idx);
|
|
1257
|
+
return rollbackAfter;
|
|
1258
|
+
},
|
|
1259
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
1260
|
+
)
|
|
1261
|
+
);
|
|
1262
|
+
} catch (err) {
|
|
1263
|
+
if (sendActivityGateError(res, err)) return;
|
|
1264
|
+
if (sendGenerationClosedError(res, err)) return;
|
|
1265
|
+
writeStderrLine(
|
|
1266
|
+
`qwen serve: DELETE ${base}/${id} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1267
|
+
);
|
|
1268
|
+
res.status(500).json({
|
|
1269
|
+
error: "Failed to delete scheduled task",
|
|
1270
|
+
code: "scheduled_tasks_write_failed"
|
|
1271
|
+
});
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
if (rollbackBefore && rollbackAfter) {
|
|
1275
|
+
try {
|
|
1276
|
+
target.assertGenerationOpen?.();
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
await rollbackCronMutation(
|
|
1279
|
+
target,
|
|
1280
|
+
rollbackBefore,
|
|
1281
|
+
rollbackAfter,
|
|
1282
|
+
`DELETE ${base}/${id}`
|
|
1283
|
+
);
|
|
1284
|
+
if (sendGenerationClosedError(res, error)) return;
|
|
1285
|
+
throw error;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
if (!removed) {
|
|
1289
|
+
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (boundSessionId && sessionOwnedByTask && bridge) {
|
|
1293
|
+
try {
|
|
1294
|
+
await runWithScheduledTaskTarget(
|
|
1295
|
+
target,
|
|
1296
|
+
() => bridge.closeSession(boundSessionId)
|
|
1297
|
+
);
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
if (sendActivityGateError(res, error)) return;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
if (boundSessionId) {
|
|
1303
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
1304
|
+
workspaceCwd,
|
|
1305
|
+
boundSessionId,
|
|
1306
|
+
id
|
|
1307
|
+
);
|
|
1308
|
+
}
|
|
1309
|
+
res.status(200).json({ deleted: true, id });
|
|
1310
|
+
})
|
|
1311
|
+
);
|
|
1312
|
+
app.post(
|
|
1313
|
+
`${base}/:id/run`,
|
|
1314
|
+
mutate(),
|
|
1315
|
+
withTarget(async (req, res, target) => {
|
|
1316
|
+
const { workspaceCwd } = target;
|
|
1317
|
+
const id = typeof req.params["id"] === "string" ? req.params["id"] : "";
|
|
1318
|
+
if (id.length === 0) {
|
|
1319
|
+
res.status(400).json({ error: "Task id is required", code: "invalid_id" });
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const now = Date.now();
|
|
1323
|
+
let found = false;
|
|
1324
|
+
let blockedDisabled = false;
|
|
1325
|
+
let blockedLegacy = false;
|
|
1326
|
+
let updated;
|
|
1327
|
+
let rollbackBefore;
|
|
1328
|
+
let rollbackAfter;
|
|
1329
|
+
try {
|
|
1330
|
+
await runWithScheduledTaskTarget(
|
|
1331
|
+
target,
|
|
1332
|
+
() => updateCronTasks(
|
|
1333
|
+
workspaceCwd,
|
|
1334
|
+
(tasks) => {
|
|
1335
|
+
const idx = tasks.findIndex((t) => t.id === id);
|
|
1336
|
+
if (idx === -1) return tasks;
|
|
1337
|
+
found = true;
|
|
1338
|
+
const current = tasks[idx];
|
|
1339
|
+
if (taskHasLegacyCondition(current)) {
|
|
1340
|
+
blockedLegacy = true;
|
|
1341
|
+
return tasks;
|
|
1342
|
+
}
|
|
1343
|
+
if (current.enabled === false) {
|
|
1344
|
+
blockedDisabled = true;
|
|
1345
|
+
return tasks;
|
|
1346
|
+
}
|
|
1347
|
+
const next = {
|
|
1348
|
+
...current,
|
|
1349
|
+
lastFiredAt: now,
|
|
1350
|
+
runs: appendCronRun(current.runs, {
|
|
1351
|
+
at: now,
|
|
1352
|
+
kind: "manual",
|
|
1353
|
+
...current.sessionId ? { sessionId: current.sessionId } : {}
|
|
1354
|
+
})
|
|
1355
|
+
};
|
|
1356
|
+
updated = next;
|
|
1357
|
+
rollbackBefore = tasks;
|
|
1358
|
+
const nextTasks = !current.recurring ? tasks.filter((_, i) => i !== idx) : tasks.map((t, i) => i === idx ? next : t);
|
|
1359
|
+
rollbackAfter = nextTasks;
|
|
1360
|
+
return nextTasks;
|
|
1361
|
+
},
|
|
1362
|
+
{ assertCanCommit: target.assertGenerationOpen }
|
|
1363
|
+
)
|
|
1364
|
+
);
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
if (sendActivityGateError(res, err)) return;
|
|
1367
|
+
if (sendGenerationClosedError(res, err)) return;
|
|
1368
|
+
writeStderrLine(
|
|
1369
|
+
`qwen serve: POST ${base}/${id}/run failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1370
|
+
);
|
|
1371
|
+
res.status(500).json({
|
|
1372
|
+
error: "Failed to record scheduled task run",
|
|
1373
|
+
code: "scheduled_tasks_write_failed"
|
|
1374
|
+
});
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (rollbackBefore && rollbackAfter) {
|
|
1378
|
+
try {
|
|
1379
|
+
target.assertGenerationOpen?.();
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
await rollbackCronMutation(
|
|
1382
|
+
target,
|
|
1383
|
+
rollbackBefore,
|
|
1384
|
+
rollbackAfter,
|
|
1385
|
+
`POST ${base}/${id}/run`
|
|
1386
|
+
);
|
|
1387
|
+
if (sendGenerationClosedError(res, error)) return;
|
|
1388
|
+
throw error;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
if (blockedLegacy) {
|
|
1392
|
+
res.status(409).json({
|
|
1393
|
+
error: "This task uses the removed isolated run mode with a precondition and can no longer run. Recreate it (and call the `create_sub_session` tool from the prompt if you need per-run isolation).",
|
|
1394
|
+
code: "task_legacy_unsupported"
|
|
1395
|
+
});
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (blockedDisabled) {
|
|
1399
|
+
res.status(409).json({
|
|
1400
|
+
error: "Cannot run a disabled task; enable it first (unarchive its session if it was archived).",
|
|
1401
|
+
code: "task_disabled"
|
|
1402
|
+
});
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
if (!found || !updated) {
|
|
1406
|
+
res.status(404).json({ error: "Task not found", code: "task_not_found" });
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (!updated.recurring && updated.sessionId) {
|
|
1410
|
+
channelDeliveryAuthorizations?.revokeScheduledTask(
|
|
1411
|
+
workspaceCwd,
|
|
1412
|
+
updated.sessionId,
|
|
1413
|
+
updated.id
|
|
1414
|
+
);
|
|
1415
|
+
}
|
|
1416
|
+
const view = toView(updated);
|
|
1417
|
+
if (!updated.recurring) view.nextRunAt = null;
|
|
1418
|
+
res.status(200).json(view);
|
|
1419
|
+
})
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
__name(registerScheduledTaskCrudRoutes, "registerScheduledTaskCrudRoutes");
|
|
1423
|
+
function registerScheduledTasksRoutes(app, deps) {
|
|
1424
|
+
const {
|
|
1425
|
+
boundWorkspace,
|
|
1426
|
+
mutate,
|
|
1427
|
+
safeBody,
|
|
1428
|
+
bridge,
|
|
1429
|
+
channelDeliveryAuthorizations
|
|
1430
|
+
} = deps;
|
|
1431
|
+
registerScheduledTaskCrudRoutes(app, {
|
|
1432
|
+
prefix: "",
|
|
1433
|
+
resolveTarget: /* @__PURE__ */ __name((_req, res) => {
|
|
1434
|
+
const runtime = deps.getRuntime?.();
|
|
1435
|
+
if (deps.getRuntime && !runtime) {
|
|
1436
|
+
res.set("Retry-After", "1");
|
|
1437
|
+
res.status(503).json({
|
|
1438
|
+
error: "Workspace runtime is not active",
|
|
1439
|
+
code: "workspace_runtime_unavailable"
|
|
1440
|
+
});
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
if (runtime && !requireTrustedWorkspaceRuntime(runtime, res)) return null;
|
|
1444
|
+
return {
|
|
1445
|
+
workspaceCwd: boundWorkspace,
|
|
1446
|
+
...runtime ? {
|
|
1447
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir,
|
|
1448
|
+
...deps.cleanupSession ? {
|
|
1449
|
+
cleanupSession: /* @__PURE__ */ __name((sessionId) => deps.cleanupSession(runtime, sessionId), "cleanupSession")
|
|
1450
|
+
} : {}
|
|
1451
|
+
} : {},
|
|
1452
|
+
// The runtime bridge only refines an ENABLED deps bridge; it must never
|
|
1453
|
+
// re-enable binding when deps `bridge` is undefined. server.ts passes
|
|
1454
|
+
// the bridge only when resident task-session management is on, and a
|
|
1455
|
+
// bound task must always have something to keep it resident + rehydrate
|
|
1456
|
+
// it — the same gate the qualified surface enforces below.
|
|
1457
|
+
bridge: bridge === void 0 ? void 0 : runtime?.bridge ?? bridge,
|
|
1458
|
+
...runtime?.generationGuard ? {
|
|
1459
|
+
assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1460
|
+
} : {},
|
|
1461
|
+
...deps.workspaceRegistry ? {
|
|
1462
|
+
resolveLiveSessionOwner: /* @__PURE__ */ __name((sessionId) => deps.workspaceRegistry.resolveLiveSessionOwner(sessionId), "resolveLiveSessionOwner")
|
|
1463
|
+
} : {}
|
|
1464
|
+
};
|
|
1465
|
+
}, "resolveTarget"),
|
|
1466
|
+
mutate,
|
|
1467
|
+
safeBody,
|
|
1468
|
+
channelDeliveryAuthorizations
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
__name(registerScheduledTasksRoutes, "registerScheduledTasksRoutes");
|
|
1472
|
+
function registerWorkspaceQualifiedScheduledTasksRoutes(app, deps) {
|
|
1473
|
+
const {
|
|
1474
|
+
workspaceRegistry,
|
|
1475
|
+
mutate,
|
|
1476
|
+
safeBody,
|
|
1477
|
+
manageScheduledTaskSessions,
|
|
1478
|
+
channelDeliveryAuthorizations,
|
|
1479
|
+
cleanupSession
|
|
1480
|
+
} = deps;
|
|
1481
|
+
registerScheduledTaskCrudRoutes(app, {
|
|
1482
|
+
prefix: "/workspaces/:workspace",
|
|
1483
|
+
resolveTarget: /* @__PURE__ */ __name((req, res) => {
|
|
1484
|
+
const runtime = resolveWorkspaceRuntimeWithLiveCompatibilityFromParam(
|
|
1485
|
+
workspaceRegistry,
|
|
1486
|
+
req,
|
|
1487
|
+
res
|
|
1488
|
+
);
|
|
1489
|
+
if (!runtime) return null;
|
|
1490
|
+
if (!requireTrustedWorkspaceRuntime(runtime, res)) return null;
|
|
1491
|
+
if (runtime.provenance === "live-conversation" && !deps.conversationRuntimeActivity) {
|
|
1492
|
+
sendConversationRuntimeUnavailable(res);
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
if (runtime.provenance === "live-conversation" && req.method === "POST" && req.params["id"] === void 0 && parseCallerSuppliedSessionId(safeBody(req)["sessionId"]).kind === "absent") {
|
|
1496
|
+
res.status(400).json({
|
|
1497
|
+
error: "Generic scheduled tasks cannot create sessions in the Conversations workspace.",
|
|
1498
|
+
code: "live_session_creation_reserved"
|
|
1499
|
+
});
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
return {
|
|
1503
|
+
workspaceCwd: runtime.workspaceCwd,
|
|
1504
|
+
runtimeBaseDir: runtime.sessionRuntimeBaseDir,
|
|
1505
|
+
...runtime.provenance === "live-conversation" && deps.conversationRuntimeActivity ? { activity: deps.conversationRuntimeActivity } : {},
|
|
1506
|
+
...cleanupSession ? {
|
|
1507
|
+
cleanupSession: /* @__PURE__ */ __name((sessionId) => cleanupSession(runtime, sessionId), "cleanupSession")
|
|
1508
|
+
} : {},
|
|
1509
|
+
// Mirror the primary surface: only bind a session when management is on,
|
|
1510
|
+
// so a bound task always has something to keep it resident + rehydrate it.
|
|
1511
|
+
bridge: manageScheduledTaskSessions ? runtime.bridge : void 0,
|
|
1512
|
+
...runtime.generationGuard ? {
|
|
1513
|
+
assertGenerationOpen: /* @__PURE__ */ __name(() => runtime.generationGuard?.assertOpen(), "assertGenerationOpen")
|
|
1514
|
+
} : {},
|
|
1515
|
+
resolveLiveSessionOwner: /* @__PURE__ */ __name((sessionId) => workspaceRegistry.resolveLiveSessionOwner(sessionId), "resolveLiveSessionOwner")
|
|
1516
|
+
};
|
|
1517
|
+
}, "resolveTarget"),
|
|
1518
|
+
mutate,
|
|
1519
|
+
safeBody,
|
|
1520
|
+
channelDeliveryAuthorizations
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
__name(registerWorkspaceQualifiedScheduledTasksRoutes, "registerWorkspaceQualifiedScheduledTasksRoutes");
|
|
1524
|
+
var REMOVED_TASK_FIELDS = ["runMode", "condition"];
|
|
1525
|
+
function findRemovedTaskField(body) {
|
|
1526
|
+
return REMOVED_TASK_FIELDS.find((field) => field in body);
|
|
1527
|
+
}
|
|
1528
|
+
__name(findRemovedTaskField, "findRemovedTaskField");
|
|
1529
|
+
function removedFieldError(field) {
|
|
1530
|
+
return {
|
|
1531
|
+
error: `\`${field}\` is no longer supported: the isolated scheduled-task run mode was removed. Every task now runs in its bound session; call the \`create_sub_session\` tool from the task prompt for per-run isolation.`,
|
|
1532
|
+
code: "unsupported_field"
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
__name(removedFieldError, "removedFieldError");
|
|
1536
|
+
function parseNameField(raw) {
|
|
1537
|
+
if (raw === void 0 || raw === null) return { value: void 0 };
|
|
1538
|
+
if (typeof raw !== "string") {
|
|
1539
|
+
return { error: "`name` must be a string" };
|
|
1540
|
+
}
|
|
1541
|
+
const trimmed = raw.trim();
|
|
1542
|
+
if (trimmed.length === 0) return { value: void 0 };
|
|
1543
|
+
if (trimmed.length > MAX_NAME_LENGTH) {
|
|
1544
|
+
return { error: `\`name\` exceeds ${MAX_NAME_LENGTH}-character limit` };
|
|
1545
|
+
}
|
|
1546
|
+
return { value: trimmed };
|
|
1547
|
+
}
|
|
1548
|
+
__name(parseNameField, "parseNameField");
|
|
1549
|
+
|
|
1550
|
+
export {
|
|
1551
|
+
resolveWorkspaceEntryFromParam,
|
|
1552
|
+
isPortableAbsolutePath,
|
|
1553
|
+
resolveRegisteredWorkspaceRuntimeByPathSelector,
|
|
1554
|
+
resolveManagedWorkspaceRuntimeByPathSelector,
|
|
1555
|
+
resolveWorkspaceRuntimeFromParam,
|
|
1556
|
+
resolveTrustedRuntime,
|
|
1557
|
+
resolveWorkspaceRuntimeWithLiveCompatibilityFromParam,
|
|
1558
|
+
sendConversationRuntimeUnavailable,
|
|
1559
|
+
sendWorkspaceRuntimeUnavailable,
|
|
1560
|
+
isGenerationClosedError,
|
|
1561
|
+
sendGenerationClosedError,
|
|
1562
|
+
resolveManagedWorkspaceRuntimeFromParam,
|
|
1563
|
+
requireTrustedWorkspaceRuntime,
|
|
1564
|
+
sendUntrustedWorkspaceResponse,
|
|
1565
|
+
getWorkspaceRouteContext,
|
|
1566
|
+
setWorkspaceRouteContext,
|
|
1567
|
+
resolveContainedCwd,
|
|
1568
|
+
resolveContainedCwdOrFail,
|
|
1569
|
+
scheduledTaskSessionName,
|
|
1570
|
+
ExistingSessionScheduledTaskCreateError,
|
|
1571
|
+
createScheduledTaskWithExistingSession,
|
|
1572
|
+
registerScheduledTasksRoutes,
|
|
1573
|
+
registerWorkspaceQualifiedScheduledTasksRoutes
|
|
1574
|
+
};
|
|
1575
|
+
/**
|
|
1576
|
+
* @license
|
|
1577
|
+
* Copyright 2026 Qwen Team
|
|
1578
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1579
|
+
*/
|
|
1580
|
+
/**
|
|
1581
|
+
* @license
|
|
1582
|
+
* Copyright 2025 Qwen Team
|
|
1583
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1584
|
+
*/
|