@qwen-code/qwen-code 0.23.0 → 0.23.1-preview.1
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/new-app/SKILL.md +1 -1
- package/bundled/qc-helper/docs/configuration/auth.md +84 -12
- package/bundled/qc-helper/docs/configuration/settings.md +76 -74
- package/bundled/qc-helper/docs/features/arena.md +15 -20
- package/bundled/qc-helper/docs/features/channels/overview.md +7 -2
- package/bundled/qc-helper/docs/features/code-review.md +22 -19
- package/bundled/qc-helper/docs/features/commands.md +51 -10
- package/bundled/qc-helper/docs/features/followup-suggestions.md +1 -1
- package/bundled/qc-helper/docs/features/goals.md +8 -0
- package/bundled/qc-helper/docs/features/headless.md +2 -2
- package/bundled/qc-helper/docs/features/hooks.md +19 -19
- package/bundled/qc-helper/docs/features/output-styles.md +35 -2
- package/bundled/qc-helper/docs/qwen-serve.md +67 -52
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +3 -1
- package/bundled/qc-helper/docs/support/troubleshooting.md +3 -3
- package/bundled/review/SKILL.md +45 -41
- package/bundled/review/references/aone.md +1 -1
- package/bundled/review/references/posting.md +1 -1
- package/bundled/workflow-creator/SKILL.md +48 -0
- package/bundled/zvec-grep-install/SKILL.md +57 -0
- package/chunks/MaxSizedBox-5ARLO5PR.js +116 -0
- package/chunks/{StandaloneSessionPicker-QUMO4LLQ.js → StandaloneSessionPicker-T6B322CB.js} +87 -82
- package/chunks/{acp-startup-profiler-M4X5F3VK.js → acp-startup-profiler-6ULXXQMS.js} +2 -2
- package/chunks/{acpAgent-2GTFCIEP.js → acpAgent-WTDEY5KD.js} +1041 -364
- package/chunks/{agent-XKF5SZWU.js → agent-NXPUXEVZ.js} +46 -43
- package/chunks/agent-headless-QQZTWOKO.js +88 -0
- package/chunks/{anthropicContentGenerator-L76MR5OR.js → anthropicContentGenerator-6XDHXIII.js} +16 -9
- package/chunks/{artifact-tool-MYCL2QCS.js → artifact-tool-DFVVJXL2.js} +3 -3
- package/chunks/askUserQuestion-GF7VQ44M.js +14 -0
- package/chunks/bridge-OHY5OGOZ.js +123 -0
- package/chunks/{ca-BNU7YNDE.js → ca-KC2AISNS.js} +1 -0
- package/chunks/{channel-management-service-4MTCEGJB.js → channel-management-service-ZDDG3G5S.js} +4 -4
- package/chunks/channel-settings-store-7BJAS2SU.js +126 -0
- package/chunks/{channel-worker-group-47F4ISUZ.js → channel-worker-group-2ISMRENV.js} +6 -6
- package/chunks/{channel-worker-manager-I5Y44GYR.js → channel-worker-manager-VSRPVPRH.js} +6 -6
- package/chunks/{channel-worker-supervisor-6VCLUXFE.js → channel-worker-supervisor-SRJBK72Z.js} +4 -4
- package/chunks/{chunk-5RTTI4GE.js → chunk-2RYWGYB3.js} +4 -3
- package/chunks/{chunk-FUO5V5KI.js → chunk-2UWQX4FP.js} +2 -2
- package/chunks/{chunk-L26ONV2Y.js → chunk-2WGJG2KW.js} +9 -8
- package/chunks/{chunk-JHN7UIDW.js → chunk-2XRE4KE4.js} +1 -1
- package/chunks/chunk-32CM56LO.js +20 -0
- package/chunks/{chunk-SI7WDR3U.js → chunk-32YDNYXP.js} +129 -14
- package/chunks/{chunk-ZHO2CW6D.js → chunk-3CZ2BQV6.js} +1 -1
- package/chunks/{chunk-FD5SJOWT.js → chunk-3K456UJF.js} +9 -4
- package/chunks/{chunk-5M6IDOMF.js → chunk-3K65MUKD.js} +105 -0
- package/chunks/chunk-3UMWOKJC.js +78 -0
- package/chunks/{chunk-UM2FFKXN.js → chunk-43JNQAHO.js} +3 -3
- package/chunks/{chunk-KM3XVTMO.js → chunk-43NOB5NM.js} +112 -12
- package/chunks/{chunk-G5PBOQWI.js → chunk-47BZVBTE.js} +3 -3
- package/chunks/{chunk-32LU3APX.js → chunk-4F2QRVW6.js} +1 -1
- package/chunks/{chunk-KMU3ZHH4.js → chunk-4HC4DYKN.js} +2 -2
- package/chunks/{chunk-22UH7VTP.js → chunk-4HOEU2OR.js} +1 -1
- package/chunks/{chunk-NXKOVOM5.js → chunk-4IQKBLTQ.js} +15 -9
- package/chunks/{chunk-M4KFODIP.js → chunk-4JAGXZR3.js} +1 -1
- package/chunks/{chunk-PDAKFU7M.js → chunk-4LIPOIXS.js} +1 -1
- package/chunks/{chunk-LEPCWS5A.js → chunk-4MCY33Y2.js} +3 -3
- package/chunks/{chunk-U6D2PPMN.js → chunk-4VUVBN3Y.js} +1 -1
- package/chunks/{chunk-37JFWFCD.js → chunk-4VZCORNT.js} +1 -1
- package/chunks/{daemon-RKDGBFLK.js → chunk-537SQ2AI.js} +2216 -1721
- package/chunks/{chunk-VNAYZAFX.js → chunk-54TF2ZIQ.js} +4 -4
- package/chunks/{chunk-OKTNXDVO.js → chunk-565U2ANU.js} +1 -1
- package/chunks/chunk-5ETULJLP.js +74 -0
- package/chunks/{chunk-ADYN7P2Y.js → chunk-5JLQWQK6.js} +8 -6
- package/chunks/{chunk-BFY33IB4.js → chunk-5MTARK4Y.js} +7 -7
- package/chunks/{chunk-BJXCYUGM.js → chunk-5YY5MZT6.js} +1 -1
- package/chunks/{chunk-4PSDSCW3.js → chunk-64MQTIX7.js} +3 -3
- package/chunks/{chunk-54C6PIGT.js → chunk-6UIACMGH.js} +3 -3
- package/chunks/{chunk-ALUYNJPM.js → chunk-7BZS4ZDV.js} +1362 -1140
- package/chunks/{chunk-LB3WQQJK.js → chunk-7OCIQNKX.js} +2 -2
- package/chunks/{chunk-QKDNS6FU.js → chunk-7VEYUF3N.js} +13 -2
- package/chunks/{chunk-AZJLY2XZ.js → chunk-AHBLRVD5.js} +5 -5
- package/chunks/{chunk-VWTSRH6C.js → chunk-AQ5NAGWI.js} +89 -17
- package/chunks/{chunk-MOF6VZN2.js → chunk-AXPOOQAW.js} +2 -2
- package/chunks/{chunk-CVX63TFJ.js → chunk-B44JBZBB.js} +3 -3
- package/chunks/{chunk-AI35S34R.js → chunk-B54PFQS5.js} +3 -3
- package/chunks/{chunk-373DQUVA.js → chunk-BF3RUIVP.js} +5 -4
- package/chunks/{chunk-RJUVTJEZ.js → chunk-BKNY7PDI.js} +1 -1
- package/chunks/{chunk-UKYXYWI2.js → chunk-BUQN5LTI.js} +2 -2
- package/chunks/{chunk-O5CD7T4T.js → chunk-BW4333PP.js} +0 -95
- package/chunks/{chunk-UPFRILIL.js → chunk-CWNC7M73.js} +2 -2
- package/chunks/{chunk-3L724BJ5.js → chunk-CZACBHAW.js} +6 -6
- package/chunks/{chunk-EBDGRBZX.js → chunk-D4CU6DKR.js} +6 -6
- package/chunks/{chunk-G7HBEEX7.js → chunk-D6PIMKY3.js} +9 -9
- package/chunks/{chunk-ENYUKMFK.js → chunk-DJXSOEFB.js} +1 -1
- package/chunks/{chunk-C2VWOXHS.js → chunk-DNPHKA72.js} +8 -8
- package/chunks/{chunk-UUASLXHW.js → chunk-E4L5BM2B.js} +5 -5
- package/chunks/{chunk-HT5S5TRQ.js → chunk-EDIDYZBT.js} +4 -11
- package/chunks/{chunk-5H5S4UY5.js → chunk-EFT7OMDN.js} +1 -1
- package/chunks/{chunk-GB4UKWY5.js → chunk-EJNYBDYC.js} +2 -2
- package/chunks/{chunk-NQ4L2CMD.js → chunk-ER273QE6.js} +53 -9
- package/chunks/{chunk-RKW36UWC.js → chunk-EWNKP4V4.js} +1 -1
- package/chunks/{chunk-UJ4DUYIH.js → chunk-F53KKZUD.js} +2 -2
- package/chunks/{chunk-EFTPIZIC.js → chunk-FDOGGKAA.js} +21 -0
- package/chunks/{chunk-AQ37AY7B.js → chunk-FKJM6JKY.js} +5 -0
- package/chunks/{chunk-KEVYJSI4.js → chunk-G34YLYCS.js} +13 -13
- package/chunks/{chunk-P6UIF2OW.js → chunk-GCFZ2LAX.js} +195 -10
- package/chunks/{chunk-VGHZT6JR.js → chunk-GELRJXE2.js} +1 -1
- package/chunks/{chunk-ZDFQGHZH.js → chunk-GMNLYQOS.js} +1 -1
- package/chunks/{chunk-KOGW3YWJ.js → chunk-GVVCLL2P.js} +12 -12
- package/chunks/{chunk-OSSTATJF.js → chunk-GXZHYPHZ.js} +428 -30
- package/chunks/{chunk-IPATA3T2.js → chunk-GZWW2QWR.js} +2 -2
- package/chunks/{chunk-C4TIXFDZ.js → chunk-H3UDNQLO.js} +6 -4
- package/chunks/chunk-HD7O6WLV.js +18 -0
- package/chunks/{chunk-4UANMABT.js → chunk-HFTB354P.js} +259 -49
- package/chunks/{chunk-LOBDDFYK.js → chunk-HJ34U5J4.js} +5 -5
- package/chunks/{chunk-M4LBBSVP.js → chunk-HY3DXYZK.js} +2 -2
- package/chunks/{chunk-4F7GQGXB.js → chunk-I72PHOKL.js} +1451 -415
- package/chunks/{chunk-YPWZTR7F.js → chunk-IFD3BTEA.js} +3 -3
- package/chunks/{chunk-EWRW2WQC.js → chunk-IKLFS6SC.js} +5 -5
- package/chunks/{chunk-VPSIC437.js → chunk-IQN2CCIE.js} +66 -6
- package/chunks/{chunk-F7NF2IOE.js → chunk-IXSGOSEG.js} +7 -7
- package/chunks/{chunk-ODZF64DM.js → chunk-IZ2U57NY.js} +1 -1
- package/chunks/{chunk-4BGDFKQE.js → chunk-J3O5I5ZD.js} +24 -7
- package/chunks/{chunk-DYTW3QVG.js → chunk-J6MB5ZHZ.js} +1 -1
- package/chunks/{chunk-HJBHMANB.js → chunk-JBTZUFR4.js} +11 -8
- package/chunks/{chunk-SRF4KTAG.js → chunk-JLWFGYXU.js} +4 -4
- package/chunks/{chunk-SX2QIMJV.js → chunk-JOPC3FND.js} +5 -5
- package/chunks/chunk-JPEAQJNS.js +2142 -0
- package/chunks/{chunk-ZTPGUFQV.js → chunk-JRYL3T2O.js} +24 -5
- package/chunks/{chunk-GXUTFQXK.js → chunk-KE3Q4JMY.js} +4 -4
- package/chunks/{chunk-LKODFJRD.js → chunk-KFFCDLKV.js} +1 -1
- package/chunks/{chunk-4M24B5J5.js → chunk-KJJPJYHI.js} +79 -30
- package/chunks/chunk-KK2GZGBK.js +21080 -0
- package/chunks/{chunk-64QH2UC6.js → chunk-KPXRFTT7.js} +12 -1
- package/chunks/{chunk-JZWOCUZ3.js → chunk-L4R7BCVV.js} +1 -1
- package/chunks/{chunk-IG4W5SJR.js → chunk-LDS57224.js} +3 -3
- package/chunks/{chunk-UAKRDON5.js → chunk-LK7S2D6V.js} +4 -4
- package/chunks/{chunk-4HVH57J3.js → chunk-LMJQSPWB.js} +21 -6
- package/chunks/{chunk-ANVG3BVV.js → chunk-LNYV4GXX.js} +13 -3
- package/chunks/{chunk-RM4WT2XB.js → chunk-LPBQODMR.js} +4 -4
- package/chunks/{chunk-XEAAO654.js → chunk-M3JGHRMQ.js} +1 -1
- package/chunks/{chunk-AMDSOFFV.js → chunk-MATEIJZF.js} +1 -0
- package/chunks/{chunk-LHBNR6EU.js → chunk-MNEYUNOE.js} +2 -2
- package/chunks/{chunk-I4NRYS6A.js → chunk-MUZCSTOO.js} +11 -11
- package/chunks/{chunk-I5N4EAS6.js → chunk-MWHY26G3.js} +1 -1
- package/chunks/{chunk-7XL4WRXM.js → chunk-N6VQ37ZZ.js} +2 -2
- package/chunks/{chunk-AHYTURFB.js → chunk-N7EYO2E7.js} +1 -1
- package/chunks/{chunk-LU77UT4D.js → chunk-N7VURC4O.js} +24 -26
- package/chunks/{chunk-DSX7KQPM.js → chunk-NAKALAL4.js} +227 -29
- package/chunks/{chunk-QQD2GART.js → chunk-NGX4NUNP.js} +3 -3
- package/chunks/{chunk-2M3EWQNG.js → chunk-NUQFUXOG.js} +17 -1
- package/chunks/{chunk-E4JNFXNI.js → chunk-NXWYCSPL.js} +3 -3
- package/chunks/{chunk-6A2D4QSO.js → chunk-O2GG7H4C.js} +4 -4
- package/chunks/{chunk-ZKFTS3OV.js → chunk-O45WBTNS.js} +6 -6
- package/chunks/{chunk-KGV55H53.js → chunk-OECNP26L.js} +1 -1
- package/chunks/{chunk-S6H3ELPG.js → chunk-P4RUUG64.js} +1 -1
- package/chunks/{chunk-GH2S4GD5.js → chunk-P5LDR7FI.js} +21 -68
- package/chunks/{chunk-RN3YGDCA.js → chunk-P6LATTDG.js} +4 -4
- package/chunks/{chunk-WP4AX3XD.js → chunk-PTFFWTTO.js} +3 -3
- package/chunks/{chunk-DTVQSSNM.js → chunk-PZUOHCWI.js} +3 -3
- package/chunks/{chunk-VYIUNFEA.js → chunk-PZV2FASB.js} +3 -3
- package/chunks/{chunk-XLXAZLDR.js → chunk-Q2SAQTEJ.js} +1 -1
- package/chunks/{chunk-47RYEQW5.js → chunk-QMFOYPGV.js} +2 -2
- package/chunks/{chunk-SULZPKTA.js → chunk-QSC5YOEC.js} +3 -3
- package/chunks/{chunk-F33GFWPR.js → chunk-QWZOOIR3.js} +58 -18
- package/chunks/{chunk-H43PSPYS.js → chunk-R355CUNQ.js} +4 -4
- package/chunks/{chunk-DQCKVAF5.js → chunk-RDKXZ2LS.js} +3 -3
- package/chunks/{chunk-7JMGTOH7.js → chunk-RPBMP6BN.js} +21 -1
- package/chunks/{chunk-5Q5RC2WE.js → chunk-RVNS7NWN.js} +2 -2
- package/chunks/{chunk-7RB56BRJ.js → chunk-SAZS4IWW.js} +6 -4
- package/chunks/{chunk-5EIOJGCR.js → chunk-SFMCYMVF.js} +4 -4
- package/chunks/{chunk-TMKTOTMQ.js → chunk-SN5FV4FY.js} +5 -5
- package/chunks/{chunk-QJGYU5PG.js → chunk-TDP7UULF.js} +1 -1
- package/chunks/{chunk-EIJT2PQ6.js → chunk-TIGXX4PA.js} +2 -2
- package/chunks/{chunk-PCRBLMIN.js → chunk-TMWB67LS.js} +21 -3
- package/chunks/{chunk-JUARRUMA.js → chunk-UEZOXZNI.js} +1358 -646
- package/chunks/{chunk-KFN2IZYR.js → chunk-UKADFFL2.js} +3 -3
- package/chunks/{chunk-TJYRTS4S.js → chunk-UKKYOIVT.js} +2 -2
- package/chunks/{chunk-EVFDRBUM.js → chunk-URSCX7S7.js} +12 -7
- package/chunks/{chunk-U4DJ5XB3.js → chunk-VDXYYVCD.js} +269 -70
- package/chunks/{chunk-4LIFGNI4.js → chunk-VEFRT7NX.js} +1 -1
- package/chunks/chunk-VFFQAOPR.js +18 -0
- package/chunks/{chunk-3AKCBZVW.js → chunk-VU7O7CGQ.js} +3 -3
- package/chunks/{chunk-RAFQIHN2.js → chunk-VUSSAGKI.js} +76 -5
- package/chunks/{chunk-TQHPVKO6.js → chunk-VY6UVU7G.js} +6 -6
- package/chunks/{chunk-S2T7H5MI.js → chunk-W4LL5RZO.js} +1 -1
- package/chunks/{chunk-ZGCKTAL5.js → chunk-WEXA2DNG.js} +2 -0
- package/chunks/{chunk-NVVJTUSL.js → chunk-WR3SH3EY.js} +136 -85
- package/chunks/{chunk-JR42V4UY.js → chunk-WTW36TJ3.js} +1 -1
- package/chunks/{chunk-TSZSGQ3N.js → chunk-WXC6OAWD.js} +1 -1
- package/chunks/{chunk-ZVP4PWBU.js → chunk-X35VIWWJ.js} +1 -1
- package/chunks/{chunk-KHP66DFN.js → chunk-XFFRI3WM.js} +1 -1
- package/chunks/{chunk-EIY7SUPZ.js → chunk-XHGGYCTA.js} +1 -1
- package/chunks/{chunk-BA4WJC4L.js → chunk-XOVVCGZX.js} +1 -1
- package/chunks/{chunk-VBWD6C27.js → chunk-XUSOYE2I.js} +1 -1
- package/chunks/{chunk-NUHOLAQ6.js → chunk-XWJFDJZK.js} +1 -1
- package/chunks/{chunk-65HWLGA7.js → chunk-XY3USGFE.js} +3 -3
- package/chunks/{chunk-STCVJXQB.js → chunk-Y3ZKI4RQ.js} +56 -26
- package/chunks/{chunk-QAK5475D.js → chunk-Y53DG2HA.js} +1 -1
- package/chunks/{chunk-3JQZVCBI.js → chunk-YCDL2SAS.js} +2 -2
- package/chunks/{chunk-NSUKQ4DN.js → chunk-YHDGABDC.js} +3 -3
- package/chunks/{chunk-FRICLXCZ.js → chunk-Z6WZPXQH.js} +3 -3
- package/chunks/{chunk-EAHOJF6V.js → chunk-ZAFYHRVY.js} +12 -0
- package/chunks/{chunk-MP6YZ4RK.js → chunk-ZAZ3NFL6.js} +852 -309
- package/chunks/{chunk-7TBU7PU2.js → chunk-ZSTCM3MX.js} +1 -1
- package/chunks/{chunk-NRL5CUZT.js → chunk-ZTAVGFKA.js} +1 -1
- package/chunks/config-utils-QXDOTXEQ.js +119 -0
- package/chunks/contextCommand-RN4KARWC.js +112 -0
- package/chunks/{core-runtime-B4UKKIAQ.js → core-runtime-NAZCOKHB.js} +63 -58
- package/chunks/{create-sub-session-NJ24B4US.js → create-sub-session-BCSM4WKB.js} +61 -56
- package/chunks/{create-sub-session-LUPWEUHR.js → create-sub-session-BQ3SE4TX.js} +3 -3
- package/chunks/{cron-create-CRSPET3H.js → cron-create-D6HQ7I7I.js} +4 -4
- package/chunks/{cron-delete-DB77SZTU.js → cron-delete-KK3D2SQV.js} +4 -4
- package/chunks/{cron-list-U2JNYWV6.js → cron-list-VBF3IZMF.js} +4 -4
- package/chunks/daemon-LCUELM6E.js +191 -0
- package/chunks/{daemon-git-worktree-guard-O2HPOBAB.js → daemon-git-worktree-guard-3K5CAU36.js} +62 -57
- package/chunks/daemon-status-provider-4X3ZZQTZ.js +122 -0
- package/chunks/daemon-trust-policy-R45CFUJA.js +118 -0
- package/chunks/{daemon-trust-policy-monitor-JL7F4Y4Q.js → daemon-trust-policy-monitor-DSSFCO3K.js} +69 -64
- package/chunks/{de-T4BLOKEC.js → de-UU2YTO37.js} +1 -0
- package/chunks/deferred-core-runtime-UO2M6WYI.js +120 -0
- package/chunks/{display-image-73C7XNRK.js → display-image-EVVTBVYE.js} +6 -6
- package/chunks/{dist-EDHQIBYD.js → dist-3T5MDUHP.js} +62 -20
- package/chunks/{dist-ZCJLKQSP.js → dist-AFH3BMZZ.js} +18 -10
- package/chunks/{dist-LXFYIJNG.js → dist-MK5PPBRF.js} +40 -9
- package/chunks/{dist-GT64AAUR.js → dist-PH5RSTEA.js} +56 -20
- package/chunks/{dist-62OZ7QXB.js → dist-QUU7TVE3.js} +35 -12
- package/chunks/{dist-JVXT4VUJ.js → dist-R5Y34V6T.js} +11 -2
- package/chunks/{dist-L6URO6CK.js → dist-SB2XRXZA.js} +5 -1
- package/chunks/{dist-QAF5DO3Y.js → dist-SIHF5MU2.js} +326 -131
- package/chunks/{dist-PDGNRVPY.js → dist-UVHW2U56.js} +20 -1
- package/chunks/earlyInputCapture-BXP7V2P3.js +22 -0
- package/chunks/{edit-SUGXY63Y.js → edit-VNBCTRWP.js} +48 -44
- package/chunks/{en-2RATMNX7.js → en-JMR535HP.js} +3 -1
- package/chunks/{enter-worktree-B6USKSIK.js → enter-worktree-CEVK7MQ2.js} +7 -7
- package/chunks/{enterPlanMode-MDX4RVVL.js → enterPlanMode-4KMZMUIA.js} +48 -45
- package/chunks/environment-S2HYQDON.js +135 -0
- package/chunks/errors-DAAN5TL7.js +119 -0
- package/chunks/{exit-worktree-DLQ73SJH.js → exit-worktree-D3YE6MUN.js} +7 -7
- package/chunks/exitPlanMode-HR36HG3D.js +86 -0
- package/chunks/{fast-path-Y73R42LV.js → fast-path-4IWSW3UV.js} +3 -3
- package/chunks/{fast-path-settings-MFUR3IWK.js → fast-path-settings-ISEJPRYE.js} +6 -4
- package/chunks/{fr-BGHGYX6A.js → fr-HKNWVXRJ.js} +1 -0
- package/chunks/{glob-DMGH7EZN.js → glob-IZYB2XH2.js} +46 -43
- package/chunks/{goal-tools-3RF3PXCL.js → goal-tools-VGUPKQDJ.js} +46 -43
- package/chunks/{grep-AJVLCVXC.js → grep-OUVLNXG7.js} +9 -8
- package/chunks/handleAutoUpdate-D56FMDTW.js +115 -0
- package/chunks/i18n-BKE5WO6T.js +130 -0
- package/chunks/{image-gen-VOIDOHOB.js → image-gen-SHVQ3XID.js} +8 -8
- package/chunks/initializer-MS4SGEHF.js +119 -0
- package/chunks/installationInfo-542MGC4S.js +113 -0
- package/chunks/{ja-G3FTD5XE.js → ja-GJS5RZGU.js} +1 -0
- package/chunks/{keychain-token-storage-REZVMJA6.js → keychain-token-storage-NQ5XWIPX.js} +2 -2
- package/chunks/list-H6XTKUWL.js +122 -0
- package/chunks/{list-agents-SBMONIUK.js → list-agents-ULYBGJXC.js} +6 -6
- package/chunks/{llm-K26SUDVK.js → llm-3NUC4EJY.js} +132 -113
- package/chunks/{llm-content-generator-TT6EAUD4.js → llm-content-generator-R4NL3OQN.js} +40 -13
- package/chunks/loadedSettingsAdapter-3XLKYDVT.js +116 -0
- package/chunks/{loggingContentGenerator-EYQBA4M4.js → loggingContentGenerator-ZYSWVNEO.js} +55 -52
- package/chunks/{loop-wakeup-QA6SHCZT.js → loop-wakeup-B27BEYRL.js} +5 -5
- package/chunks/{lowlight-J2OZNPCA.js → lowlight-BTE423KL.js} +3 -6
- package/chunks/{ls-HEJNCEYO.js → ls-3IIMMVKF.js} +5 -4
- package/chunks/{lsp-WOQKNZP6.js → lsp-VJAT7XKS.js} +2 -2
- package/chunks/{managed-npm-update-HIJTODQT.js → managed-npm-update-L2I53ZAI.js} +62 -57
- package/chunks/mcp-4PIXQASW.js +116 -0
- package/chunks/{monitor-DKNZQAB2.js → monitor-O2YQTOZZ.js} +50 -46
- package/chunks/{node-UETAYMMO.js → node-ISQAFKIS.js} +2 -2
- package/chunks/nonInteractiveCli-LV7CDBA2.js +198 -0
- package/chunks/{notebook-edit-MGHTRL2D.js → notebook-edit-4RE2ALH4.js} +48 -44
- package/chunks/{openaiContentGenerator-ZJIEQ3ZJ.js → openaiContentGenerator-7ND7K5CP.js} +30 -25
- package/chunks/pidfile-UFTLQ7NP.js +117 -0
- package/chunks/{processUtils-UY3SAJJZ.js → processUtils-3XBB4FYV.js} +2 -2
- package/chunks/prompt-terminal-ledger-2QASOGMM.js +111 -0
- package/chunks/{pt-D73IFYT7.js → pt-FXMYXEUV.js} +1 -0
- package/chunks/{qwenContentGenerator-VI4KATRY.js → qwenContentGenerator-AELTUTH6.js} +52 -49
- package/chunks/{qwenOAuth2-7AOCKSOQ.js → qwenOAuth2-BS5D2LYV.js} +7 -7
- package/chunks/{read-file-P7F4P7LV.js → read-file-PDWHZPHX.js} +13 -11
- package/chunks/{read-mcp-resource-GLAGB6R7.js → read-mcp-resource-YXJZ75UB.js} +2 -2
- package/chunks/{record-artifact-SWVR7NSU.js → record-artifact-WJDOV6XU.js} +4 -4
- package/chunks/{report-findings-AL5YW3KI.js → report-findings-Q4UACKWR.js} +5 -5
- package/chunks/{request-shutdown-5YK4IZ54.js → request-shutdown-2YZ3E3GH.js} +8 -8
- package/chunks/resumeHistoryUtils-QRXZEEBA.js +124 -0
- package/chunks/ripGrep-KSOOLE6H.js +39 -0
- package/chunks/{ru-QMISLKRH.js → ru-RMHURE5U.js} +1 -0
- package/chunks/{run-qwen-serve-OGTEEUR2.js → run-qwen-serve-RTAREPT6.js} +84 -70
- package/chunks/runtime-ESFSCJRZ.js +154 -0
- package/chunks/scheduled-tasks-6ZHRNBH6.js +133 -0
- package/chunks/{scheduler-73YXGUGW.js → scheduler-DQI6KV7T.js} +63 -58
- package/chunks/{sdk-exporters-http-3JO5TJNU.js → sdk-exporters-http-7R2ARBPV.js} +2 -2
- package/chunks/{sdk-impl-HZAUUTHJ.js → sdk-impl-YOLO7LV4.js} +4 -4
- package/chunks/{send-message-JC7NJTY6.js → send-message-PQCVSVMN.js} +24 -24
- package/chunks/serve-FY7ZEW52.js +124 -0
- package/chunks/{server-AOYZVVOM.js → server-KNDY6K5F.js} +1594 -273
- package/chunks/{session-UAWFNFGI.js → session-MCEPXAZP.js} +113 -105
- package/chunks/session-attachments-root-OLNAE6GF.js +109 -0
- package/chunks/{session-pr-refresh-CT2INROL.js → session-pr-refresh-HKJHQQQK.js} +67 -62
- package/chunks/{settings-BHRGDASJ.js → settings-VXO4WBMK.js} +68 -63
- package/chunks/shell-U263OTES.js +96 -0
- package/chunks/{skill-ZGBKNCHQ.js → skill-SDODGBKL.js} +19 -17
- package/chunks/skill-settings-YEIA22QJ.js +124 -0
- package/chunks/spawnChannel-4WJZVFPP.js +117 -0
- package/chunks/standalone-update-ZWVQUO64.js +124 -0
- package/chunks/{start-opentui-ui-FZ4USOU7.js → start-opentui-ui-BFYCJQRZ.js} +1199 -190
- package/chunks/{startInteractiveUI-E2WQJUOA.js → startInteractiveUI-JYAFCMHL.js} +2977 -2319
- package/chunks/{syntheticOutput-HJNZSEHN.js → syntheticOutput-AUAJBNXR.js} +3 -3
- package/chunks/{task-create-6RSD54S5.js → task-create-LD5ISM3E.js} +12 -12
- package/chunks/{task-list-IQSACPOM.js → task-list-YISJ4RJA.js} +5 -5
- package/chunks/{task-stop-HE2LRQNW.js → task-stop-65ZOVATJ.js} +2 -2
- package/chunks/{task-update-XAJ2NYOA.js → task-update-AAN4ZVEY.js} +15 -15
- package/chunks/{team-create-SOKMYSQU.js → team-create-KU7MABNO.js} +47 -44
- package/chunks/{team-delete-NGNNKGMG.js → team-delete-XFRRTJTT.js} +5 -5
- package/chunks/{team-plan-approval-U7ZWXYAY.js → team-plan-approval-DPB377A3.js} +46 -43
- package/chunks/terminal-image-renderer-WGWRENOF.js +124 -0
- package/chunks/theme-manager-GBUFULSO.js +108 -0
- package/chunks/{todoWrite-5UTVUXHA.js → todoWrite-G7NT4IFP.js} +5 -5
- package/chunks/{tool-search-IAI2RVWT.js → tool-search-6YUXHBPT.js} +19 -17
- package/chunks/total-session-admission-54R2JQ5L.js +118 -0
- package/chunks/trustedFolders-KAJIDJTH.js +128 -0
- package/chunks/{update-relaunch-5RWKZAL3.js → update-relaunch-XM4IWBFD.js} +5 -5
- package/chunks/updateCheck-W6UZFURI.js +124 -0
- package/chunks/useAutoAcceptIndicator-LAWYHY3U.js +126 -0
- package/chunks/{validateNonInterActiveAuth-QPFEKATS.js → validateNonInterActiveAuth-7WCKHRN2.js} +109 -101
- package/chunks/{version-JKNG7YDH.js → version-3ZU43RJ6.js} +1 -1
- package/chunks/{web-fetch-X3AHIIHW.js → web-fetch-QHI2SQL4.js} +16 -14
- package/chunks/{web-search-K2FMOGS5.js → web-search-3KZZKWNY.js} +9 -8
- package/chunks/{workflow-TOLPAK5G.js → workflow-HRW7Y2X4.js} +330 -1667
- package/chunks/workspace-providers-status-KTGCWCPC.js +120 -0
- package/chunks/{workspace-registration-store-KQWVVW4Y.js → workspace-registration-store-LHLPPWNE.js} +1 -1
- package/chunks/workspace-registry-X34MLN52.js +127 -0
- package/chunks/workspace-runtime-coordinator-U4PW4P7K.js +128 -0
- package/chunks/workspace-service-KD7BCGYL.js +132 -0
- package/chunks/workspace-skills-status-YJGO6Y3T.js +119 -0
- package/chunks/{workspace-trust-reconciler-IBDFQBQS.js → workspace-trust-reconciler-EUYHISCH.js} +74 -69
- package/chunks/write-file-EBSB34NJ.js +91 -0
- package/chunks/{zh-25DF7OGK.js → zh-DVFYHRK5.js} +3 -1
- package/chunks/{zh-TW-5EDMZVGK.js → zh-TW-W2GNP2IU.js} +3 -1
- package/chunks/{zoom-image-IFXSN74N.js → zoom-image-UJ5VKWKP.js} +13 -11
- package/cli.js +13 -13
- package/export-transcript-document.js +617 -0
- package/locales/ca.js +1 -0
- package/locales/de.js +1 -0
- package/locales/en.js +5 -2
- package/locales/fr.js +1 -0
- package/locales/ja.js +1 -0
- package/locales/pt.js +1 -0
- package/locales/ru.js +1 -0
- package/locales/zh-TW.js +5 -2
- package/locales/zh.js +5 -2
- package/package.json +5 -4
- package/web-shell/assets/{abnfDiagram-VCTEODGH-Cxf7xE_Z.js → abnfDiagram-VCTEODGH-Dur--luQ.js} +1 -1
- package/web-shell/assets/{arc-ESi1eNkE.js → arc-tYLobxFi.js} +1 -1
- package/web-shell/assets/{architectureDiagram-5GKGNRK7-D9l7-bDo.js → architectureDiagram-5GKGNRK7-IG6aXD03.js} +1 -1
- package/web-shell/assets/{blockDiagram-NRAW4CY4-Bc8DEasw.js → blockDiagram-NRAW4CY4-C6eBSkfA.js} +1 -1
- package/web-shell/assets/{c4Diagram-UCG6FXSJ-Dimb2Hmh.js → c4Diagram-UCG6FXSJ-BrX3HJqB.js} +1 -1
- package/web-shell/assets/channel-uEkvKckd.js +1 -0
- package/web-shell/assets/{chunk-2Q5K7J3B-jVDmOpAQ.js → chunk-2Q5K7J3B-B3fcJ8ee.js} +1 -1
- package/web-shell/assets/{chunk-5VM5RSS4-DbG_SwdB.js → chunk-5VM5RSS4-CeC90yKM.js} +1 -1
- package/web-shell/assets/{chunk-F27PBJKO-QEc4cY1v.js → chunk-F27PBJKO-CW44RVki.js} +1 -1
- package/web-shell/assets/{chunk-G27WJ6UU-iJ36lQ3X.js → chunk-G27WJ6UU-D1PAMukD.js} +1 -1
- package/web-shell/assets/{chunk-JWPE2WC7-DuArnVtF.js → chunk-JWPE2WC7-Dt3Y2Fvx.js} +1 -1
- package/web-shell/assets/{chunk-LCL6LL3I-DxOf1zwL.js → chunk-LCL6LL3I-CZHw2lLI.js} +1 -1
- package/web-shell/assets/{chunk-POPQ4Y6H-lVLu9Ild.js → chunk-POPQ4Y6H-ysNAdTGx.js} +1 -1
- package/web-shell/assets/{chunk-SVP7TREG-C6XYlIer.js → chunk-SVP7TREG-BdNXW6YQ.js} +1 -1
- package/web-shell/assets/{chunk-XXDRQBXY-CiG2j2Ji.js → chunk-XXDRQBXY-DgqQ9UA8.js} +1 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DuPsnhWS.js +1 -0
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DuPsnhWS.js +1 -0
- package/web-shell/assets/{cose-bilkent-JH36ORCC-DGVHMMVm.js → cose-bilkent-JH36ORCC-BILImXzJ.js} +1 -1
- package/web-shell/assets/{cynefin-OW5HDTMX-D6cgpCnH.js → cynefin-OW5HDTMX-DR88Pund.js} +1 -1
- package/web-shell/assets/{cynefinDiagram-5FMLGOSQ-BKv4Z-UX.js → cynefinDiagram-5FMLGOSQ-BYFbfkA6.js} +1 -1
- package/web-shell/assets/{dagre-3AP2YEHR-B4ABMIG-.js → dagre-3AP2YEHR-rfpyc6sX.js} +1 -1
- package/web-shell/assets/{diagram-S7CK7UJ4-DgCkp_Lm.js → diagram-S7CK7UJ4-BJxLmEwH.js} +1 -1
- package/web-shell/assets/{diagram-UQ7AKVKN-FG0FNokz.js → diagram-UQ7AKVKN-H34xm7k3.js} +1 -1
- package/web-shell/assets/{diagram-VSXAHHWV-JgkP9qg-.js → diagram-VSXAHHWV-HYxhwNLx.js} +1 -1
- package/web-shell/assets/{diagram-VX7I27RA-ADh2x83l.js → diagram-VX7I27RA-BJazso8F.js} +1 -1
- package/web-shell/assets/{diagram-Z3DM3KII-yXqoYF1J.js → diagram-Z3DM3KII-Clje1aNy.js} +1 -1
- package/web-shell/assets/{ebnfDiagram-PWID7BFC-Duk83Ek_.js → ebnfDiagram-PWID7BFC-M93YBkFh.js} +1 -1
- package/web-shell/assets/{erDiagram-SSCWMZ5O-DMdvxySG.js → erDiagram-SSCWMZ5O-DY8XzSHU.js} +1 -1
- package/web-shell/assets/{flowDiagram-A5DVABFB-DHjVgSji.js → flowDiagram-A5DVABFB-CE6Aylcq.js} +1 -1
- package/web-shell/assets/{ganttDiagram-EL5Y4UJY-DMM9DkCE.js → ganttDiagram-EL5Y4UJY-DI-5LL22.js} +1 -1
- package/web-shell/assets/{gitGraphDiagram-WWUBYQGX-t_ug9vO8.js → gitGraphDiagram-WWUBYQGX-C7BZWElk.js} +1 -1
- package/web-shell/assets/index-CVyqwW7y.js +2142 -0
- package/web-shell/assets/{index-zqvnpGHv.js → index-DclFHns9.js} +1 -1
- package/web-shell/assets/index-FO7JXPnH.css +36 -0
- package/web-shell/assets/{infoDiagram-RXCK75RN-eT1fANNm.js → infoDiagram-RXCK75RN-CGUSy4Pc.js} +1 -1
- package/web-shell/assets/{ishikawaDiagram-5VMMS53U-k3evzZNn.js → ishikawaDiagram-5VMMS53U-B5BVks9q.js} +1 -1
- package/web-shell/assets/{journeyDiagram-EYS64GPL-CGim3EAi.js → journeyDiagram-EYS64GPL-CFh6Tf7h.js} +1 -1
- package/web-shell/assets/{kanban-definition-3QL26DDD-WHfJo-22.js → kanban-definition-3QL26DDD-B7TlxP7c.js} +1 -1
- package/web-shell/assets/{layout-DkqIaFlJ.js → layout-Br_pZq2Q.js} +1 -1
- package/web-shell/assets/{linear-Bdkd3mCz.js → linear-BVlP6fte.js} +1 -1
- package/web-shell/assets/{mermaid.core-CGw0LkT_.js → mermaid.core-TrcYWoiF.js} +6 -6
- package/web-shell/assets/{mindmap-definition-FBJOCRG2-C9V4rBvo.js → mindmap-definition-FBJOCRG2-BJ4LzqjZ.js} +1 -1
- package/web-shell/assets/{pegDiagram-XKGWAZYB-CwoI2T5G.js → pegDiagram-XKGWAZYB-1b_MxlOl.js} +1 -1
- package/web-shell/assets/{pieDiagram-E7YTZNPT-DaTmBmPG.js → pieDiagram-E7YTZNPT-B8zl0YhY.js} +1 -1
- package/web-shell/assets/{quadrantDiagram-AXDQQJYC-plh6MyGI.js → quadrantDiagram-AXDQQJYC-CIZO8ukl.js} +1 -1
- package/web-shell/assets/{railroadDiagram-O6MQD6OU-D_b-S0iK.js → railroadDiagram-O6MQD6OU-CepHSbCj.js} +1 -1
- package/web-shell/assets/{requirementDiagram-EFPCY7ZU-zUzTN7VE.js → requirementDiagram-EFPCY7ZU-BCgxkcSW.js} +1 -1
- package/web-shell/assets/{sankeyDiagram-P5KCCOFB-m6AhoD0l.js → sankeyDiagram-P5KCCOFB-CE5CcoMM.js} +1 -1
- package/web-shell/assets/{sequenceDiagram-WJ2MYXX4-Cwhzsine.js → sequenceDiagram-WJ2MYXX4-DvgHi-d5.js} +1 -1
- package/web-shell/assets/{sizeCapture-X5ZJPWSS-CcZuKIae.js → sizeCapture-X5ZJPWSS-T-fAsCPX.js} +1 -1
- package/web-shell/assets/{stateDiagram-HBIQ2CUA-CFoiJwD_.js → stateDiagram-HBIQ2CUA-DYHaul-5.js} +1 -1
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V-BcYho9a4.js +1 -0
- package/web-shell/assets/{swimlanes-XN3QIQJK-CgS9hcaV.js → swimlanes-XN3QIQJK-Dbz3Qiej.js} +1 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-D6HsOIgX.js +8 -0
- package/web-shell/assets/{timeline-definition-24CTP7MA-Dzzc05t9.js → timeline-definition-24CTP7MA-9NVRts3N.js} +1 -1
- package/web-shell/assets/{vennDiagram-4TSXK5OY-DemK0f7Y.js → vennDiagram-4TSXK5OY-C7cb7vnH.js} +1 -1
- package/web-shell/assets/{wardleyDiagram-VM6X3IG4-CquLxtMr.js → wardleyDiagram-VM6X3IG4-CG-8Ddjm.js} +1 -1
- package/web-shell/assets/{xychartDiagram-S5SC5T6Z-BTBKTM5g.js → xychartDiagram-S5SC5T6Z-iGeYAcP4.js} +1 -1
- package/web-shell/index.html +2 -2
- package/chunks/MaxSizedBox-B3D7545A.js +0 -111
- package/chunks/agent-headless-OC2IB55D.js +0 -85
- package/chunks/askUserQuestion-THQZMG44.js +0 -322
- package/chunks/bridge-IHSBI2YJ.js +0 -118
- package/chunks/channel-settings-store-BVKWAI2T.js +0 -121
- package/chunks/chunk-I2TMJPCV.js +0 -448
- package/chunks/chunk-QI27MKNQ.js +0 -4008
- package/chunks/config-utils-LVSYDLHZ.js +0 -114
- package/chunks/contextCommand-TZD7UAJK.js +0 -107
- package/chunks/daemon-status-provider-GRRVCJFW.js +0 -117
- package/chunks/daemon-trust-policy-YJL442BK.js +0 -113
- package/chunks/deferred-core-runtime-S32AYVZI.js +0 -115
- package/chunks/earlyInputCapture-BBPCIVZG.js +0 -108
- package/chunks/environment-VN6RXDVN.js +0 -130
- package/chunks/errors-UEY36PIT.js +0 -114
- package/chunks/exitPlanMode-EPHIEDAA.js +0 -83
- package/chunks/handleAutoUpdate-HVWQT2AU.js +0 -110
- package/chunks/i18n-5OR7NTRZ.js +0 -125
- package/chunks/initializer-JE5RQSOE.js +0 -114
- package/chunks/installationInfo-KO3CCSCK.js +0 -108
- package/chunks/list-3IORSFIY.js +0 -117
- package/chunks/loadedSettingsAdapter-KLLFZF3M.js +0 -111
- package/chunks/mcp-A2UEHETW.js +0 -111
- package/chunks/nonInteractiveCli-YA47F2F4.js +0 -190
- package/chunks/pidfile-ETHAZNMY.js +0 -112
- package/chunks/prompt-terminal-ledger-GZ747VYE.js +0 -106
- package/chunks/resumeHistoryUtils-DPZKFW24.js +0 -119
- package/chunks/ripGrep-C7LJKUPZ.js +0 -37
- package/chunks/runtime-LNBLEMZS.js +0 -149
- package/chunks/scheduled-tasks-FLDYZQOF.js +0 -128
- package/chunks/serve-3UR2H4CV.js +0 -119
- package/chunks/session-attachments-root-ZCGXQQTR.js +0 -104
- package/chunks/shell-YHOGC7TO.js +0 -93
- package/chunks/skill-settings-AKSP665O.js +0 -119
- package/chunks/spawnChannel-N25MBB6F.js +0 -112
- package/chunks/standalone-update-XGPWJDRN.js +0 -119
- package/chunks/terminal-image-renderer-KKM4OBLO.js +0 -117
- package/chunks/theme-manager-GQHF3A7T.js +0 -103
- package/chunks/total-session-admission-G4CGCSTG.js +0 -113
- package/chunks/trustedFolders-D2I3FDPB.js +0 -123
- package/chunks/updateCheck-ZXOQDFEI.js +0 -119
- package/chunks/useAutoAcceptIndicator-6EK4QGAH.js +0 -121
- package/chunks/workspace-providers-status-PCJK3RC7.js +0 -115
- package/chunks/workspace-registry-YNIOB6HJ.js +0 -122
- package/chunks/workspace-runtime-coordinator-WG2RNEN7.js +0 -123
- package/chunks/workspace-service-G4ZNBOFH.js +0 -127
- package/chunks/workspace-skills-status-FMTPPMWC.js +0 -114
- package/chunks/write-file-YTLFY2S5.js +0 -88
- package/web-shell/assets/channel-B7ohGDil.js +0 -1
- package/web-shell/assets/classDiagram-DTDB5LWJ-DdFpqpfD.js +0 -1
- package/web-shell/assets/classDiagram-v2-JRS7N3AN-DdFpqpfD.js +0 -1
- package/web-shell/assets/index-BGZRqbRo.css +0 -36
- package/web-shell/assets/index-DRri_6_x.js +0 -2067
- package/web-shell/assets/stateDiagram-v2-4QOOHH4V--H8HdEmk.js +0 -1
- package/web-shell/assets/swimlanesDiagram-VK2B7HYN-ShE9OIgf.js +0 -8
|
@@ -0,0 +1,2142 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
isActiveWorkflowStatus,
|
|
5
|
+
isTerminalWorkflowStatus,
|
|
6
|
+
isWorkflowRunPersistenceActive
|
|
7
|
+
} from "./chunk-I72PHOKL.js";
|
|
8
|
+
import {
|
|
9
|
+
atomicWriteFile
|
|
10
|
+
} from "./chunk-XFFRI3WM.js";
|
|
11
|
+
import {
|
|
12
|
+
stripAnsiAndControl
|
|
13
|
+
} from "./chunk-7VEYUF3N.js";
|
|
14
|
+
import {
|
|
15
|
+
Storage,
|
|
16
|
+
createDebugLogger
|
|
17
|
+
} from "./chunk-ZAFYHRVY.js";
|
|
18
|
+
import {
|
|
19
|
+
init_esbuild_shims
|
|
20
|
+
} from "./chunk-5O2XNYP6.js";
|
|
21
|
+
import {
|
|
22
|
+
__name
|
|
23
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
24
|
+
|
|
25
|
+
// packages/core/src/agents/runtime/workflow-sandbox.ts
|
|
26
|
+
init_esbuild_shims();
|
|
27
|
+
import * as vm from "node:vm";
|
|
28
|
+
|
|
29
|
+
// packages/core/src/agents/runtime/workflow-meta-literal.ts
|
|
30
|
+
init_esbuild_shims();
|
|
31
|
+
var WorkflowMetaSyntaxError = class extends Error {
|
|
32
|
+
static {
|
|
33
|
+
__name(this, "WorkflowMetaSyntaxError");
|
|
34
|
+
}
|
|
35
|
+
index;
|
|
36
|
+
constructor(message, index) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "WorkflowMetaSyntaxError";
|
|
39
|
+
this.index = index;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
function parseWorkflowMetaLiteral(source) {
|
|
43
|
+
const parser = new MetaLiteralParser(source);
|
|
44
|
+
parser.skipTrivia();
|
|
45
|
+
const value = parser.parseValue(0);
|
|
46
|
+
parser.skipTrivia();
|
|
47
|
+
if (parser.index < source.length) {
|
|
48
|
+
throw parser.fail("unexpected trailing content");
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
__name(parseWorkflowMetaLiteral, "parseWorkflowMetaLiteral");
|
|
53
|
+
var MAX_DEPTH = 32;
|
|
54
|
+
var WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\r", "\f", "\v", "\xA0", "\uFEFF"]);
|
|
55
|
+
var ID_START = /[A-Za-z_$]/;
|
|
56
|
+
var ID_PART = /[A-Za-z0-9_$]/;
|
|
57
|
+
var MetaLiteralParser = class {
|
|
58
|
+
constructor(src) {
|
|
59
|
+
this.src = src;
|
|
60
|
+
}
|
|
61
|
+
static {
|
|
62
|
+
__name(this, "MetaLiteralParser");
|
|
63
|
+
}
|
|
64
|
+
index = 0;
|
|
65
|
+
fail(message) {
|
|
66
|
+
const from = Math.max(0, this.index - 24);
|
|
67
|
+
const snippet = this.src.slice(from, this.index + 24).replace(/\s+/g, " ").trim();
|
|
68
|
+
return new WorkflowMetaSyntaxError(
|
|
69
|
+
`${message} at position ${this.index} (near "${snippet}"). meta must be a plain object literal \u2014 strings, numbers, booleans, null, arrays and objects only, with no variables, function calls, spreads, accessors or template substitutions.`,
|
|
70
|
+
this.index
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
skipTrivia() {
|
|
74
|
+
for (; ; ) {
|
|
75
|
+
while (this.index < this.src.length && WHITESPACE.has(this.src[this.index])) {
|
|
76
|
+
this.index++;
|
|
77
|
+
}
|
|
78
|
+
if (this.src.startsWith("//", this.index)) {
|
|
79
|
+
let end = this.index + 2;
|
|
80
|
+
while (end < this.src.length && !"\n\r\u2028\u2029".includes(this.src[end])) {
|
|
81
|
+
end++;
|
|
82
|
+
}
|
|
83
|
+
if (this.src[end] === "\r" && this.src[end + 1] === "\n") end++;
|
|
84
|
+
this.index = end < this.src.length ? end + 1 : this.src.length;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (this.src.startsWith("/*", this.index)) {
|
|
88
|
+
const end = this.src.indexOf("*/", this.index + 2);
|
|
89
|
+
if (end === -1) throw this.fail("unterminated comment");
|
|
90
|
+
this.index = end + 2;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
parseValue(depth) {
|
|
97
|
+
if (depth > MAX_DEPTH) throw this.fail("meta literal is nested too deeply");
|
|
98
|
+
this.skipTrivia();
|
|
99
|
+
const c = this.src[this.index];
|
|
100
|
+
if (c === void 0) throw this.fail("unexpected end of meta literal");
|
|
101
|
+
if (c === "{") return this.parseObject(depth);
|
|
102
|
+
if (c === "[") return this.parseArray(depth);
|
|
103
|
+
if (c === '"' || c === "'" || c === "`") return this.parseString();
|
|
104
|
+
if (c === "-" || c >= "0" && c <= "9") return this.parseNumber();
|
|
105
|
+
if (this.src.startsWith("true", this.index)) return this.word("true", true);
|
|
106
|
+
if (this.src.startsWith("false", this.index)) {
|
|
107
|
+
return this.word("false", false);
|
|
108
|
+
}
|
|
109
|
+
if (this.src.startsWith("null", this.index)) return this.word("null", null);
|
|
110
|
+
if (c === "/")
|
|
111
|
+
throw this.fail("regular expressions are not allowed in meta");
|
|
112
|
+
throw this.fail("unsupported value");
|
|
113
|
+
}
|
|
114
|
+
word(literal, value) {
|
|
115
|
+
const after = this.src[this.index + literal.length];
|
|
116
|
+
if (after !== void 0 && ID_PART.test(after)) {
|
|
117
|
+
throw this.fail("unsupported value");
|
|
118
|
+
}
|
|
119
|
+
this.index += literal.length;
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
parseObject(depth) {
|
|
123
|
+
this.index++;
|
|
124
|
+
const out = /* @__PURE__ */ Object.create(null);
|
|
125
|
+
for (; ; ) {
|
|
126
|
+
this.skipTrivia();
|
|
127
|
+
const c = this.src[this.index];
|
|
128
|
+
if (c === "}") {
|
|
129
|
+
this.index++;
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
if (c === void 0) throw this.fail("unterminated object");
|
|
133
|
+
if (this.src.startsWith("...", this.index)) {
|
|
134
|
+
throw this.fail("spread is not allowed in meta");
|
|
135
|
+
}
|
|
136
|
+
if (c === "[") throw this.fail("computed keys are not allowed in meta");
|
|
137
|
+
const key = this.parseKey();
|
|
138
|
+
this.skipTrivia();
|
|
139
|
+
if (this.src[this.index] === "(") {
|
|
140
|
+
throw this.fail("methods are not allowed in meta");
|
|
141
|
+
}
|
|
142
|
+
if (this.src[this.index] !== ":")
|
|
143
|
+
throw this.fail('expected ":" after key');
|
|
144
|
+
this.index++;
|
|
145
|
+
out[key] = this.parseValue(depth + 1);
|
|
146
|
+
this.skipTrivia();
|
|
147
|
+
if (this.src[this.index] === ",") {
|
|
148
|
+
this.index++;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (this.src[this.index] === "}") {
|
|
152
|
+
this.index++;
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
throw this.fail('expected "," or "}"');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
parseKey() {
|
|
159
|
+
const c = this.src[this.index];
|
|
160
|
+
if (c === '"' || c === "'" || c === "`") return this.parseString();
|
|
161
|
+
if (c !== void 0 && ID_START.test(c)) {
|
|
162
|
+
const start = this.index;
|
|
163
|
+
while (this.index < this.src.length && ID_PART.test(this.src[this.index])) {
|
|
164
|
+
this.index++;
|
|
165
|
+
}
|
|
166
|
+
const word = this.src.slice(start, this.index);
|
|
167
|
+
if (word === "get" || word === "set" || word === "async") {
|
|
168
|
+
const save = this.index;
|
|
169
|
+
this.skipTrivia();
|
|
170
|
+
const next = this.src[this.index];
|
|
171
|
+
const startsPropertyName = next !== void 0 && (ID_START.test(next) || next === '"' || next === "'" || next === "[");
|
|
172
|
+
this.index = save;
|
|
173
|
+
if (startsPropertyName) {
|
|
174
|
+
throw this.fail(
|
|
175
|
+
word === "async" ? "async members are not allowed in meta" : `${word}ters are not allowed in meta`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return word;
|
|
180
|
+
}
|
|
181
|
+
throw this.fail("expected a property name");
|
|
182
|
+
}
|
|
183
|
+
parseArray(depth) {
|
|
184
|
+
this.index++;
|
|
185
|
+
const out = [];
|
|
186
|
+
for (; ; ) {
|
|
187
|
+
this.skipTrivia();
|
|
188
|
+
const c = this.src[this.index];
|
|
189
|
+
if (c === "]") {
|
|
190
|
+
this.index++;
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
if (c === void 0) throw this.fail("unterminated array");
|
|
194
|
+
if (this.src.startsWith("...", this.index)) {
|
|
195
|
+
throw this.fail("spread is not allowed in meta");
|
|
196
|
+
}
|
|
197
|
+
if (c === ",") throw this.fail("missing array element");
|
|
198
|
+
out.push(this.parseValue(depth + 1));
|
|
199
|
+
this.skipTrivia();
|
|
200
|
+
if (this.src[this.index] === ",") {
|
|
201
|
+
this.index++;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (this.src[this.index] === "]") {
|
|
205
|
+
this.index++;
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
throw this.fail('expected "," or "]"');
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
parseString() {
|
|
212
|
+
const quote = this.src[this.index++];
|
|
213
|
+
let out = "";
|
|
214
|
+
for (; ; ) {
|
|
215
|
+
const c = this.src[this.index];
|
|
216
|
+
if (c === void 0) throw this.fail("unterminated string");
|
|
217
|
+
if (c === quote) {
|
|
218
|
+
this.index++;
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
if (c === "\n" || c === "\r") {
|
|
222
|
+
if (quote !== "`") throw this.fail("unterminated string");
|
|
223
|
+
if (c === "\r") {
|
|
224
|
+
this.index++;
|
|
225
|
+
if (this.src[this.index] === "\n") this.index++;
|
|
226
|
+
out += "\n";
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (quote === "`" && c === "$" && this.src[this.index + 1] === "{") {
|
|
231
|
+
throw this.fail("template substitutions are not allowed in meta");
|
|
232
|
+
}
|
|
233
|
+
if (c === "\\") {
|
|
234
|
+
out += this.parseEscape();
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
out += c;
|
|
238
|
+
this.index++;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
parseEscape() {
|
|
242
|
+
this.index++;
|
|
243
|
+
const c = this.src[this.index++];
|
|
244
|
+
switch (c) {
|
|
245
|
+
case "n":
|
|
246
|
+
return "\n";
|
|
247
|
+
case "t":
|
|
248
|
+
return " ";
|
|
249
|
+
case "r":
|
|
250
|
+
return "\r";
|
|
251
|
+
case "b":
|
|
252
|
+
return "\b";
|
|
253
|
+
case "f":
|
|
254
|
+
return "\f";
|
|
255
|
+
case "v":
|
|
256
|
+
return "\v";
|
|
257
|
+
case "0":
|
|
258
|
+
if (/[0-9]/.test(this.src[this.index] ?? "")) {
|
|
259
|
+
throw this.fail("octal escapes are not allowed in meta");
|
|
260
|
+
}
|
|
261
|
+
return "\0";
|
|
262
|
+
case "x": {
|
|
263
|
+
const hex = this.src.slice(this.index, this.index + 2);
|
|
264
|
+
if (!/^[0-9a-fA-F]{2}$/.test(hex)) {
|
|
265
|
+
throw this.fail("invalid \\x escape");
|
|
266
|
+
}
|
|
267
|
+
this.index += 2;
|
|
268
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
269
|
+
}
|
|
270
|
+
case "u": {
|
|
271
|
+
if (this.src[this.index] === "{") {
|
|
272
|
+
const end = this.src.indexOf("}", this.index);
|
|
273
|
+
const hex2 = end === -1 ? "" : this.src.slice(this.index + 1, end);
|
|
274
|
+
if (!/^[0-9a-fA-F]{1,6}$/.test(hex2)) {
|
|
275
|
+
throw this.fail("invalid \\u{...} escape");
|
|
276
|
+
}
|
|
277
|
+
const code = parseInt(hex2, 16);
|
|
278
|
+
if (code > 1114111) throw this.fail("invalid \\u{...} escape");
|
|
279
|
+
this.index = end + 1;
|
|
280
|
+
return String.fromCodePoint(code);
|
|
281
|
+
}
|
|
282
|
+
const hex = this.src.slice(this.index, this.index + 4);
|
|
283
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
284
|
+
throw this.fail("invalid \\u escape");
|
|
285
|
+
}
|
|
286
|
+
this.index += 4;
|
|
287
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
288
|
+
}
|
|
289
|
+
case "\n":
|
|
290
|
+
return "";
|
|
291
|
+
// line continuation
|
|
292
|
+
case "\r":
|
|
293
|
+
if (this.src[this.index] === "\n") this.index++;
|
|
294
|
+
return "";
|
|
295
|
+
case "\u2028":
|
|
296
|
+
case "\u2029":
|
|
297
|
+
return "";
|
|
298
|
+
case void 0:
|
|
299
|
+
throw this.fail("unterminated escape sequence");
|
|
300
|
+
default:
|
|
301
|
+
return c;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
parseNumber() {
|
|
305
|
+
const start = this.index;
|
|
306
|
+
if (this.src[this.index] === "-") this.index++;
|
|
307
|
+
while (this.index < this.src.length && /[0-9]/.test(this.src[this.index])) {
|
|
308
|
+
this.index++;
|
|
309
|
+
}
|
|
310
|
+
if (this.src[this.index] === ".") {
|
|
311
|
+
this.index++;
|
|
312
|
+
while (this.index < this.src.length && /[0-9]/.test(this.src[this.index])) {
|
|
313
|
+
this.index++;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (this.src[this.index] === "e" || this.src[this.index] === "E") {
|
|
317
|
+
this.index++;
|
|
318
|
+
if (this.src[this.index] === "+" || this.src[this.index] === "-") {
|
|
319
|
+
this.index++;
|
|
320
|
+
}
|
|
321
|
+
while (this.index < this.src.length && /[0-9]/.test(this.src[this.index])) {
|
|
322
|
+
this.index++;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const after = this.src[this.index];
|
|
326
|
+
if (after !== void 0 && ID_PART.test(after)) {
|
|
327
|
+
throw this.fail("unsupported numeric literal");
|
|
328
|
+
}
|
|
329
|
+
const text = this.src.slice(start, this.index);
|
|
330
|
+
const value = Number(text);
|
|
331
|
+
if (text.length === 0 || !Number.isFinite(value)) {
|
|
332
|
+
throw this.fail("unsupported numeric literal");
|
|
333
|
+
}
|
|
334
|
+
return value;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// packages/core/src/agents/runtime/workflow-sandbox.ts
|
|
339
|
+
function findMetaBlockBounds(source) {
|
|
340
|
+
const re = /^\s*export\s+const\s+meta\s*=\s*\{/;
|
|
341
|
+
const match = re.exec(source);
|
|
342
|
+
if (!match) return null;
|
|
343
|
+
const exportIdx = match.index;
|
|
344
|
+
const startBrace = source.indexOf("{", exportIdx);
|
|
345
|
+
let depth = 1;
|
|
346
|
+
let i = startBrace + 1;
|
|
347
|
+
while (i < source.length && depth > 0) {
|
|
348
|
+
const ch = source[i];
|
|
349
|
+
const next = source[i + 1];
|
|
350
|
+
if (ch === "/" && next === "/") {
|
|
351
|
+
i += 2;
|
|
352
|
+
while (i < source.length && source[i] !== "\n") i++;
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (ch === "/" && next === "*") {
|
|
356
|
+
i += 2;
|
|
357
|
+
while (i < source.length && !(source[i] === "*" && source[i + 1] === "/"))
|
|
358
|
+
i++;
|
|
359
|
+
i += 2;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (ch === "/" && isRegexContext(source, i)) {
|
|
363
|
+
i++;
|
|
364
|
+
let inClass = false;
|
|
365
|
+
while (i < source.length && (inClass || source[i] !== "/") && source[i] !== "\n") {
|
|
366
|
+
if (source[i] === "\\") i += 2;
|
|
367
|
+
else if (source[i] === "[") {
|
|
368
|
+
inClass = true;
|
|
369
|
+
i++;
|
|
370
|
+
} else if (source[i] === "]") {
|
|
371
|
+
inClass = false;
|
|
372
|
+
i++;
|
|
373
|
+
} else {
|
|
374
|
+
i++;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
i++;
|
|
378
|
+
while (i < source.length && /[gimsuy]/.test(source[i])) i++;
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
382
|
+
const q = ch;
|
|
383
|
+
i++;
|
|
384
|
+
while (i < source.length && source[i] !== q) {
|
|
385
|
+
if (source[i] === "\\") i++;
|
|
386
|
+
i++;
|
|
387
|
+
}
|
|
388
|
+
i++;
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (ch === "{") depth++;
|
|
392
|
+
else if (ch === "}") depth--;
|
|
393
|
+
i++;
|
|
394
|
+
}
|
|
395
|
+
if (depth !== 0) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
"unbalanced braces in export const meta declaration \u2014 the workflow script cannot be safely stripped. Check the meta block syntax."
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const endBraceIncl = i - 1;
|
|
401
|
+
while (i < source.length && /[\s;]/.test(source[i])) i++;
|
|
402
|
+
return { exportIdx, startBrace, endBraceIncl, afterMeta: i };
|
|
403
|
+
}
|
|
404
|
+
__name(findMetaBlockBounds, "findMetaBlockBounds");
|
|
405
|
+
function extractAndStripMeta(source) {
|
|
406
|
+
const bounds = findMetaBlockBounds(source);
|
|
407
|
+
if (!bounds) return { stripped: source, meta: null };
|
|
408
|
+
const metaSource = source.slice(bounds.startBrace, bounds.endBraceIncl + 1);
|
|
409
|
+
const stripped = source.slice(0, bounds.exportIdx) + source.slice(bounds.afterMeta);
|
|
410
|
+
let raw;
|
|
411
|
+
try {
|
|
412
|
+
raw = parseWorkflowMetaLiteral(metaSource);
|
|
413
|
+
} catch (e) {
|
|
414
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
415
|
+
throw new Error(`invalid meta object literal: ${msg}`);
|
|
416
|
+
}
|
|
417
|
+
const meta = validateMeta(raw);
|
|
418
|
+
return { stripped, meta };
|
|
419
|
+
}
|
|
420
|
+
__name(extractAndStripMeta, "extractAndStripMeta");
|
|
421
|
+
var WORKFLOW_SCRIPT_FILENAME = "workflow.js";
|
|
422
|
+
function wrapWorkflowBody(strippedSource) {
|
|
423
|
+
return `(async () => {'use strict';
|
|
424
|
+
${strippedSource}
|
|
425
|
+
})()`;
|
|
426
|
+
}
|
|
427
|
+
__name(wrapWorkflowBody, "wrapWorkflowBody");
|
|
428
|
+
function compileWorkflowScript(scriptSource) {
|
|
429
|
+
const { stripped, meta } = extractAndStripMeta(scriptSource);
|
|
430
|
+
const bounds = findMetaBlockBounds(scriptSource);
|
|
431
|
+
const compilable = bounds ? scriptSource.slice(0, bounds.exportIdx) + scriptSource.slice(bounds.exportIdx, bounds.afterMeta).replace(/[^\r\n\u2028\u2029]/g, " ") + scriptSource.slice(bounds.afterMeta) : stripped;
|
|
432
|
+
const script = new vm.Script(wrapWorkflowBody(compilable), {
|
|
433
|
+
filename: WORKFLOW_SCRIPT_FILENAME
|
|
434
|
+
});
|
|
435
|
+
return { script, meta };
|
|
436
|
+
}
|
|
437
|
+
__name(compileWorkflowScript, "compileWorkflowScript");
|
|
438
|
+
function workflowCancelledError() {
|
|
439
|
+
const error = new Error("Workflow run was aborted (cancelled).");
|
|
440
|
+
error.name = "AbortError";
|
|
441
|
+
return error;
|
|
442
|
+
}
|
|
443
|
+
__name(workflowCancelledError, "workflowCancelledError");
|
|
444
|
+
var COMPILE_ERROR_LINE_WIDTH = 80;
|
|
445
|
+
function describeWorkflowCompileError(error, authorLineCount) {
|
|
446
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
447
|
+
const stack = typeof err.stack === "string" ? err.stack : "";
|
|
448
|
+
const frame = [];
|
|
449
|
+
for (const line of stack.split("\n")) {
|
|
450
|
+
if (frame.length >= 3 && /^\s+at\s/.test(line)) break;
|
|
451
|
+
frame.push(line);
|
|
452
|
+
}
|
|
453
|
+
const header = frame[0] ?? "";
|
|
454
|
+
const match = /^.*?:(\d+)$/.exec(header);
|
|
455
|
+
if (frame.length < 3 || !match) {
|
|
456
|
+
return err.message;
|
|
457
|
+
}
|
|
458
|
+
const bodyLine = Number(match[1]) - 1;
|
|
459
|
+
if (bodyLine < 1) return err.message;
|
|
460
|
+
if (bodyLine > authorLineCount) {
|
|
461
|
+
return "The script ends with unmatched or incomplete syntax. Check parentheses, brackets, braces, quotes, and template literals near the end.";
|
|
462
|
+
}
|
|
463
|
+
const rendered = clampSourceFrame(frame[1] ?? "", frame[2] ?? "");
|
|
464
|
+
const tail = frame.slice(3).filter((l) => l.trim().length > 0).join("\n");
|
|
465
|
+
return [`line ${bodyLine}`, rendered, tail].filter(Boolean).join("\n");
|
|
466
|
+
}
|
|
467
|
+
__name(describeWorkflowCompileError, "describeWorkflowCompileError");
|
|
468
|
+
function clampSourceFrame(sourceLine, caretLine) {
|
|
469
|
+
if (sourceLine.length <= COMPILE_ERROR_LINE_WIDTH) {
|
|
470
|
+
return `${sourceLine}
|
|
471
|
+
${caretLine}`;
|
|
472
|
+
}
|
|
473
|
+
const caret = /\^+/.exec(caretLine);
|
|
474
|
+
if (!caret) return "";
|
|
475
|
+
const caretCol = caret.index;
|
|
476
|
+
const start = Math.max(
|
|
477
|
+
0,
|
|
478
|
+
Math.min(
|
|
479
|
+
caretCol - Math.floor(COMPILE_ERROR_LINE_WIDTH / 2),
|
|
480
|
+
sourceLine.length - COMPILE_ERROR_LINE_WIDTH
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
const prefix = start > 0 ? "\u2026" : "";
|
|
484
|
+
const window = sourceLine.slice(start, start + COMPILE_ERROR_LINE_WIDTH);
|
|
485
|
+
const suffix = start + COMPILE_ERROR_LINE_WIDTH < sourceLine.length ? "\u2026" : "";
|
|
486
|
+
const visibleCaretStart = Math.max(caretCol, start);
|
|
487
|
+
const visibleCaretEnd = Math.min(
|
|
488
|
+
caretCol + caret[0].length,
|
|
489
|
+
start + COMPILE_ERROR_LINE_WIDTH
|
|
490
|
+
);
|
|
491
|
+
const shiftedCaret = " ".repeat(prefix.length + visibleCaretStart - start) + "^".repeat(visibleCaretEnd - visibleCaretStart);
|
|
492
|
+
return `${prefix}${window}${suffix}
|
|
493
|
+
${shiftedCaret}`;
|
|
494
|
+
}
|
|
495
|
+
__name(clampSourceFrame, "clampSourceFrame");
|
|
496
|
+
function validateMeta(value) {
|
|
497
|
+
if (value === null || typeof value !== "object") {
|
|
498
|
+
throw new Error("meta must be an object");
|
|
499
|
+
}
|
|
500
|
+
const obj = value;
|
|
501
|
+
if (typeof obj["name"] !== "string" || obj["name"].length === 0) {
|
|
502
|
+
throw new Error("meta.name must be a non-empty string");
|
|
503
|
+
}
|
|
504
|
+
if (typeof obj["description"] !== "string" || obj["description"].length === 0) {
|
|
505
|
+
throw new Error("meta.description must be a non-empty string");
|
|
506
|
+
}
|
|
507
|
+
if (obj["whenToUse"] !== void 0 && typeof obj["whenToUse"] !== "string") {
|
|
508
|
+
throw new Error("meta.whenToUse must be a string");
|
|
509
|
+
}
|
|
510
|
+
let phases;
|
|
511
|
+
if (obj["phases"] !== void 0) {
|
|
512
|
+
if (!Array.isArray(obj["phases"])) {
|
|
513
|
+
throw new Error("meta.phases must be an array");
|
|
514
|
+
}
|
|
515
|
+
phases = [];
|
|
516
|
+
for (const p of obj["phases"]) {
|
|
517
|
+
if (p === null || typeof p !== "object") {
|
|
518
|
+
throw new Error("meta.phases entries must be objects");
|
|
519
|
+
}
|
|
520
|
+
const ph = p;
|
|
521
|
+
if (typeof ph["title"] !== "string" || ph["title"].length === 0) {
|
|
522
|
+
throw new Error("meta.phases[].title must be a non-empty string");
|
|
523
|
+
}
|
|
524
|
+
const phase = {
|
|
525
|
+
title: ph["title"]
|
|
526
|
+
};
|
|
527
|
+
if (ph["detail"] !== void 0) {
|
|
528
|
+
if (typeof ph["detail"] !== "string") {
|
|
529
|
+
throw new Error("meta.phases[].detail must be a string");
|
|
530
|
+
}
|
|
531
|
+
phase.detail = ph["detail"];
|
|
532
|
+
}
|
|
533
|
+
if (ph["model"] !== void 0) {
|
|
534
|
+
if (typeof ph["model"] !== "string") {
|
|
535
|
+
throw new Error("meta.phases[].model must be a string");
|
|
536
|
+
}
|
|
537
|
+
phase.model = ph["model"];
|
|
538
|
+
}
|
|
539
|
+
phases.push(phase);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const out = {
|
|
543
|
+
name: obj["name"],
|
|
544
|
+
description: obj["description"]
|
|
545
|
+
};
|
|
546
|
+
if (obj["whenToUse"] !== void 0) {
|
|
547
|
+
out.whenToUse = obj["whenToUse"];
|
|
548
|
+
}
|
|
549
|
+
if (phases !== void 0) {
|
|
550
|
+
out.phases = phases;
|
|
551
|
+
}
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
554
|
+
__name(validateMeta, "validateMeta");
|
|
555
|
+
function isRegexContext(source, i) {
|
|
556
|
+
let j = i - 1;
|
|
557
|
+
while (j >= 0 && /\s/.test(source[j])) j--;
|
|
558
|
+
if (j < 0) return true;
|
|
559
|
+
const prev = source[j];
|
|
560
|
+
return /[{[(,;:=!&|?+\-*/%^~<>]/.test(prev);
|
|
561
|
+
}
|
|
562
|
+
__name(isRegexContext, "isRegexContext");
|
|
563
|
+
var debugLogger = createDebugLogger("WORKFLOW");
|
|
564
|
+
var MAX_LOG_LINES = 1e4;
|
|
565
|
+
var MAX_PHASE_ENTRIES = 1e4;
|
|
566
|
+
var ARGS_MAX_DEPTH = 64;
|
|
567
|
+
var DEFAULT_MAX_WALL_CLOCK_MS = 30 * 60 * 1e3;
|
|
568
|
+
function resolveMaxWallClockMs(opts) {
|
|
569
|
+
if (typeof opts.maxWallClockMs === "number" && opts.maxWallClockMs > 0) {
|
|
570
|
+
return opts.maxWallClockMs;
|
|
571
|
+
}
|
|
572
|
+
const envSec = Number(process.env["QWEN_CODE_MAX_WORKFLOW_SECONDS"]);
|
|
573
|
+
if (Number.isFinite(envSec) && envSec > 0) return envSec * 1e3;
|
|
574
|
+
return DEFAULT_MAX_WALL_CLOCK_MS;
|
|
575
|
+
}
|
|
576
|
+
__name(resolveMaxWallClockMs, "resolveMaxWallClockMs");
|
|
577
|
+
var WallClockWatchdog = class {
|
|
578
|
+
constructor(budgetMs, onFire) {
|
|
579
|
+
this.onFire = onFire;
|
|
580
|
+
this.remainingMs = budgetMs;
|
|
581
|
+
this.arm();
|
|
582
|
+
}
|
|
583
|
+
static {
|
|
584
|
+
__name(this, "WallClockWatchdog");
|
|
585
|
+
}
|
|
586
|
+
timer;
|
|
587
|
+
remainingMs;
|
|
588
|
+
armedAt = 0;
|
|
589
|
+
paused = false;
|
|
590
|
+
stopped = false;
|
|
591
|
+
pause() {
|
|
592
|
+
if (this.stopped || this.paused || this.timer === void 0) return;
|
|
593
|
+
this.paused = true;
|
|
594
|
+
clearTimeout(this.timer);
|
|
595
|
+
this.timer = void 0;
|
|
596
|
+
this.remainingMs = Math.max(
|
|
597
|
+
0,
|
|
598
|
+
this.remainingMs - (performance.now() - this.armedAt)
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
resume() {
|
|
602
|
+
if (this.stopped || !this.paused) return;
|
|
603
|
+
this.paused = false;
|
|
604
|
+
this.arm();
|
|
605
|
+
}
|
|
606
|
+
stop() {
|
|
607
|
+
this.stopped = true;
|
|
608
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
609
|
+
this.timer = void 0;
|
|
610
|
+
}
|
|
611
|
+
arm() {
|
|
612
|
+
this.armedAt = performance.now();
|
|
613
|
+
this.timer = setTimeout(() => {
|
|
614
|
+
this.stopped = true;
|
|
615
|
+
this.timer = void 0;
|
|
616
|
+
this.onFire();
|
|
617
|
+
}, this.remainingMs);
|
|
618
|
+
this.timer.unref?.();
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
function validateArgs(val, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
622
|
+
if (depth > ARGS_MAX_DEPTH) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`WorkflowSandbox: args exceeded max nesting depth of ${ARGS_MAX_DEPTH}`
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
if (val === null) return;
|
|
628
|
+
const t = typeof val;
|
|
629
|
+
if (t === "function") {
|
|
630
|
+
throw new Error(
|
|
631
|
+
"WorkflowSandbox: args must be JSON-serializable (functions are not allowed)."
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
if (t === "bigint") {
|
|
635
|
+
throw new Error(
|
|
636
|
+
"WorkflowSandbox: args must be JSON-serializable (BigInt is not allowed \u2014 pass as string)."
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
if (t !== "object") return;
|
|
640
|
+
const obj = val;
|
|
641
|
+
if (seen.has(obj)) {
|
|
642
|
+
throw new Error(
|
|
643
|
+
"WorkflowSandbox: args must be JSON-serializable (circular reference detected)."
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
seen.add(obj);
|
|
647
|
+
if (Array.isArray(val)) {
|
|
648
|
+
for (const item of val) validateArgs(item, depth + 1, seen);
|
|
649
|
+
} else {
|
|
650
|
+
for (const v of Object.values(val)) {
|
|
651
|
+
validateArgs(v, depth + 1, seen);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
__name(validateArgs, "validateArgs");
|
|
656
|
+
function createWorkflowSandbox(opts) {
|
|
657
|
+
const phases = [];
|
|
658
|
+
const logs = [];
|
|
659
|
+
const emitLog = /* @__PURE__ */ __name((line) => {
|
|
660
|
+
try {
|
|
661
|
+
opts.emitter?.logAppended?.(line);
|
|
662
|
+
} catch (e) {
|
|
663
|
+
debugLogger.warn("emitter.logAppended threw:", e);
|
|
664
|
+
}
|
|
665
|
+
}, "emitLog");
|
|
666
|
+
const safeLog = /* @__PURE__ */ __name((msg, notify = true) => {
|
|
667
|
+
if (logs.length < MAX_LOG_LINES) {
|
|
668
|
+
const line = String(msg);
|
|
669
|
+
logs.push(line);
|
|
670
|
+
if (notify) emitLog(line);
|
|
671
|
+
} else if (logs.length === MAX_LOG_LINES) {
|
|
672
|
+
const line = `[workflow log truncated at ${MAX_LOG_LINES} lines]`;
|
|
673
|
+
logs.push(line);
|
|
674
|
+
if (notify) emitLog(line);
|
|
675
|
+
}
|
|
676
|
+
}, "safeLog");
|
|
677
|
+
const safePhase = /* @__PURE__ */ __name((title) => {
|
|
678
|
+
if (phases.length < MAX_PHASE_ENTRIES) {
|
|
679
|
+
const t = stripAnsiAndControl(String(title)).slice(0, 200) || "phase";
|
|
680
|
+
if (phases[phases.length - 1] === t) return;
|
|
681
|
+
phases.push(t);
|
|
682
|
+
try {
|
|
683
|
+
opts.emitter?.phaseStarted?.(t);
|
|
684
|
+
} catch (e) {
|
|
685
|
+
debugLogger.warn("emitter.phaseStarted threw:", e);
|
|
686
|
+
}
|
|
687
|
+
} else if (phases.length === MAX_PHASE_ENTRIES) {
|
|
688
|
+
phases.push(
|
|
689
|
+
`[workflow phases truncated at ${MAX_PHASE_ENTRIES} entries]`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
}, "safePhase");
|
|
693
|
+
if (opts.args !== void 0) validateArgs(opts.args);
|
|
694
|
+
const argsJson = opts.args === void 0 ? null : JSON.stringify(opts.args);
|
|
695
|
+
const unconsumedRoots = /* @__PURE__ */ new Map();
|
|
696
|
+
const unconsumedRejections = /* @__PURE__ */ new Map();
|
|
697
|
+
let nextUnconsumedId = 1;
|
|
698
|
+
let unconsumedSettled = false;
|
|
699
|
+
let mirroredEscapeKeys = /* @__PURE__ */ new Set();
|
|
700
|
+
const unconsumedRejectionLine = /* @__PURE__ */ __name((rec) => {
|
|
701
|
+
if (rec.dispatchFailed) {
|
|
702
|
+
return rec.isRoot ? "dispatch failed (result not consumed): " + rec.msg : "dispatch failed (rejection not handled): " + rec.msg;
|
|
703
|
+
}
|
|
704
|
+
return "script handler failed (rejection not handled): " + rec.msg;
|
|
705
|
+
}, "unconsumedRejectionLine");
|
|
706
|
+
const bridge = {
|
|
707
|
+
argsJson,
|
|
708
|
+
pushPhase: safePhase,
|
|
709
|
+
pushLog: safeLog,
|
|
710
|
+
lastPhase: /* @__PURE__ */ __name(() => phases[phases.length - 1], "lastPhase"),
|
|
711
|
+
hostAgent: opts.dispatch,
|
|
712
|
+
// PR #4947 R2 T7 (qwen-code-ci-bot): host-side log hook for reviveInRealm's
|
|
713
|
+
// catch path. Mirrors the rejection-logging in settleToNullArray so an
|
|
714
|
+
// operator running with debug logging can distinguish "thunk rejected"
|
|
715
|
+
// (settleToNullArray.warn) from "thunk resolved to a non-JSON-serializable
|
|
716
|
+
// value" (this warn). Receives only primitive strings/numbers — the bridge
|
|
717
|
+
// contract forbids host objects crossing back to the script.
|
|
718
|
+
logRevivalFailure: /* @__PURE__ */ __name((idx, reason) => {
|
|
719
|
+
debugLogger.warn(
|
|
720
|
+
`Workflow result revival failed at index ${idx}: ${reason}; slot set to null (non-JSON-serializable thunk return).`
|
|
721
|
+
);
|
|
722
|
+
}, "logRevivalFailure"),
|
|
723
|
+
// --- Unconsumed-rejection mirror bookkeeping ---
|
|
724
|
+
wfRegisterRoot: /* @__PURE__ */ __name(() => {
|
|
725
|
+
const id = nextUnconsumedId++;
|
|
726
|
+
unconsumedRoots.set(id, { rejectionHandled: false, adoptedOut: false });
|
|
727
|
+
return id;
|
|
728
|
+
}, "wfRegisterRoot"),
|
|
729
|
+
wfMarkRejectionHandled: /* @__PURE__ */ __name((rootId) => {
|
|
730
|
+
const root = unconsumedRoots.get(rootId);
|
|
731
|
+
if (root) root.rejectionHandled = true;
|
|
732
|
+
}, "wfMarkRejectionHandled"),
|
|
733
|
+
wfIsRootHandled: /* @__PURE__ */ __name((rootId) => unconsumedRoots.get(rootId)?.rejectionHandled === true, "wfIsRootHandled"),
|
|
734
|
+
wfMarkAdopted: /* @__PURE__ */ __name((rootId) => {
|
|
735
|
+
const root = unconsumedRoots.get(rootId);
|
|
736
|
+
if (root) root.adoptedOut = true;
|
|
737
|
+
}, "wfMarkAdopted"),
|
|
738
|
+
runId: opts.runId ?? "",
|
|
739
|
+
wfReportUnconsumed: /* @__PURE__ */ __name((rootId, isRoot, dispatchFailed, msg) => {
|
|
740
|
+
if (unconsumedSettled) {
|
|
741
|
+
const rec = {
|
|
742
|
+
rootId,
|
|
743
|
+
isRoot,
|
|
744
|
+
dispatchFailed,
|
|
745
|
+
msg
|
|
746
|
+
};
|
|
747
|
+
const rootState = unconsumedRoots.get(rootId);
|
|
748
|
+
if (!rootState?.rejectionHandled && !(dispatchFailed && rootState?.adoptedOut)) {
|
|
749
|
+
safeLog(unconsumedRejectionLine(rec));
|
|
750
|
+
}
|
|
751
|
+
return 0;
|
|
752
|
+
}
|
|
753
|
+
const id = nextUnconsumedId++;
|
|
754
|
+
unconsumedRejections.set(id, { rootId, isRoot, dispatchFailed, msg });
|
|
755
|
+
return id;
|
|
756
|
+
}, "wfReportUnconsumed"),
|
|
757
|
+
wfClearUnconsumed: /* @__PURE__ */ __name((id) => {
|
|
758
|
+
unconsumedRejections.delete(id);
|
|
759
|
+
}, "wfClearUnconsumed"),
|
|
760
|
+
// R10-1: teardown discrimination cannot key on the error name alone.
|
|
761
|
+
// The dominant in-flight cancellation path (controller.abort() →
|
|
762
|
+
// subagent returns terminateMode=CANCELLED → runSingleDispatch throws
|
|
763
|
+
// a PLAIN Error) never produces an 'AbortError', so the mirror would
|
|
764
|
+
// log a spurious dispatch failure for a correctly-cancelled run. Once
|
|
765
|
+
// the run's abort signal has fired, the run is already settling as
|
|
766
|
+
// cancelled / timed-out — every rejection still crossing the boundary
|
|
767
|
+
// is teardown noise regardless of its shape.
|
|
768
|
+
isRunAborted: /* @__PURE__ */ __name(() => opts.abortOnTimeout?.signal.aborted === true, "isRunAborted"),
|
|
769
|
+
// The truthy flags distinguish "injected" from "default stub" inside the
|
|
770
|
+
// init script without leaking the host function itself when not used.
|
|
771
|
+
hasParallel: !!opts.parallel,
|
|
772
|
+
hasPipeline: !!opts.pipeline,
|
|
773
|
+
hasWorkflow: !!opts.workflow,
|
|
774
|
+
hasBudget: !!opts.budget,
|
|
775
|
+
hostParallel: opts.parallel,
|
|
776
|
+
hostPipeline: opts.pipeline,
|
|
777
|
+
hostWorkflow: opts.workflow,
|
|
778
|
+
budgetTotal: opts.budget ? opts.budget.total : null,
|
|
779
|
+
hostBudgetSpent: opts.budget ? opts.budget.spent.bind(opts.budget) : null,
|
|
780
|
+
hostBudgetRemaining: opts.budget ? opts.budget.remaining.bind(opts.budget) : null
|
|
781
|
+
};
|
|
782
|
+
Object.setPrototypeOf(bridge, null);
|
|
783
|
+
const sandboxGlobals = Object.assign(
|
|
784
|
+
/* @__PURE__ */ Object.create(null),
|
|
785
|
+
{ __workflowBridge: bridge }
|
|
786
|
+
);
|
|
787
|
+
const ctx = vm.createContext(sandboxGlobals);
|
|
788
|
+
vm.runInContext(
|
|
789
|
+
`(() => {
|
|
790
|
+
const __b = globalThis.__workflowBridge;
|
|
791
|
+
delete globalThis.__workflowBridge;
|
|
792
|
+
|
|
793
|
+
// --- Math (vm-realm, random throws) ---
|
|
794
|
+
const realMath = Math;
|
|
795
|
+
const safeMath = Object.create(null);
|
|
796
|
+
for (const k of Object.getOwnPropertyNames(realMath)) {
|
|
797
|
+
if (k === 'random' || k === 'constructor') continue;
|
|
798
|
+
safeMath[k] = realMath[k];
|
|
799
|
+
}
|
|
800
|
+
safeMath.random = () => {
|
|
801
|
+
throw new Error(
|
|
802
|
+
'Math.random() is unavailable in workflow scripts (breaks resume). ' +
|
|
803
|
+
'For N independent samples, include the index in the agent label or prompt.'
|
|
804
|
+
);
|
|
805
|
+
};
|
|
806
|
+
globalThis.Math = safeMath;
|
|
807
|
+
|
|
808
|
+
// --- Date (vm-realm function that throws on any access) ---
|
|
809
|
+
const dateMsg = 'Date.now() / new Date() are unavailable in workflow ' +
|
|
810
|
+
'scripts (breaks resume). Stamp results after the workflow returns, ' +
|
|
811
|
+
'or pass timestamps via args.';
|
|
812
|
+
const safeDate = function Date() { throw new Error(dateMsg); };
|
|
813
|
+
safeDate.now = () => { throw new Error(dateMsg); };
|
|
814
|
+
safeDate.UTC = () => { throw new Error(dateMsg); };
|
|
815
|
+
safeDate.parse = () => { throw new Error(dateMsg); };
|
|
816
|
+
Object.setPrototypeOf(safeDate, null);
|
|
817
|
+
Object.defineProperty(safeDate, 'constructor', {
|
|
818
|
+
value: undefined, writable: false, configurable: false,
|
|
819
|
+
});
|
|
820
|
+
globalThis.Date = safeDate;
|
|
821
|
+
|
|
822
|
+
// --- args (parsed via vm-realm JSON \u2192 vm-realm objects/arrays) ---
|
|
823
|
+
// FIX-Round1-T2: vm-realm arrays keep their vm-realm Array.prototype,
|
|
824
|
+
// so for...of, .map, .forEach, spread, destructuring all work \u2014 and
|
|
825
|
+
// their inherited methods' constructors are vm-realm Function, which
|
|
826
|
+
// cannot reach host process.
|
|
827
|
+
globalThis.args = __b.argsJson === null ? undefined : JSON.parse(__b.argsJson);
|
|
828
|
+
|
|
829
|
+
// --- Wrap a host async function so it returns a vm-realm Promise ---
|
|
830
|
+
// FIX-Round1-T1/T8/T14: success and failure both cross the boundary
|
|
831
|
+
// as vm-realm values: resolve with the host's value (a primitive
|
|
832
|
+
// string for dispatch; vm-realm arrays for parallel/pipeline because
|
|
833
|
+
// those wrappers will produce vm-realm results); reject with a
|
|
834
|
+
// freshly-constructed vm-realm Error so e.constructor.constructor
|
|
835
|
+
// stays in the vm realm.
|
|
836
|
+
// Dispatch promises are ObservedPromise instances (a vm-realm
|
|
837
|
+
// Promise subclass). Its then override marks the result consumed
|
|
838
|
+
// and re-attaches the teardown observer to the derived promise, so
|
|
839
|
+
// script-derived chains (agent(...).then(...), await, and the
|
|
840
|
+
// ELEMENTS of static-combinator aggregates \u2014 everything that
|
|
841
|
+
// funnels through then) stay observed at every depth. The
|
|
842
|
+
// AGGREGATES of Promise.all/race/any are built by the native
|
|
843
|
+
// statics and never pass through the observed then, so those
|
|
844
|
+
// statics are wrapped explicitly below (observeAggregate).
|
|
845
|
+
// Without this, a correctly-cancelled run holding a pending derived
|
|
846
|
+
// chain fired a process-level unhandledRejection even though the
|
|
847
|
+
// bare dispatch promise was observed.
|
|
848
|
+
//
|
|
849
|
+
// Unconsumed rejections of an observed node are recorded through
|
|
850
|
+
// the bridge and mirrored into the run log at run settlement (a
|
|
851
|
+
// later consumption clears the record first) \u2014 a dispatch refused
|
|
852
|
+
// at the entry gate (budget / agent cap) or failing mid-run reaches
|
|
853
|
+
// no other surface, so without the mirror the failure leaves no
|
|
854
|
+
// log, alarm, or telemetry.
|
|
855
|
+
function mapDispatchError(hostErr) {
|
|
856
|
+
var msg;
|
|
857
|
+
try {
|
|
858
|
+
msg = (hostErr && hostErr.message != null)
|
|
859
|
+
? String(hostErr.message)
|
|
860
|
+
: String(hostErr);
|
|
861
|
+
} catch (e) {
|
|
862
|
+
msg = '[unserializable rejection value]';
|
|
863
|
+
}
|
|
864
|
+
const vmErr = new Error(msg);
|
|
865
|
+
// Teardown discrimination at the host boundary \u2014 before the error
|
|
866
|
+
// is flattened into a vm-realm Error. Two shapes count as
|
|
867
|
+
// teardown: an error NAMED 'AbortError' (the scheduler's
|
|
868
|
+
// abortError() DOMException), and ANY rejection that crosses
|
|
869
|
+
// after the run's abort signal has fired \u2014 the dominant
|
|
870
|
+
// cancellation path rejects with a plain Error ('did not complete
|
|
871
|
+
// (terminate mode: CANCELLED).'), which a name-only match would
|
|
872
|
+
// mirror as a spurious dispatch failure on a correctly-cancelled
|
|
873
|
+
// run. Matching the name here (rather than the message text)
|
|
874
|
+
// still suppresses teardown noise without swallowing genuine
|
|
875
|
+
// failures whose message merely contains 'aborted' (e.g. a
|
|
876
|
+
// network-layer 'connection aborted by peer').
|
|
877
|
+
var isAbort = false;
|
|
878
|
+
try {
|
|
879
|
+
isAbort = !!(hostErr && hostErr.name === 'AbortError');
|
|
880
|
+
} catch (e) {
|
|
881
|
+
isAbort = false;
|
|
882
|
+
}
|
|
883
|
+
if (isAbort || __b.isRunAborted()) vmErr.__wfAbort = true;
|
|
884
|
+
vmErr.__wfDispatchFailed = true;
|
|
885
|
+
return vmErr;
|
|
886
|
+
}
|
|
887
|
+
function readFlag(value, name) {
|
|
888
|
+
try {
|
|
889
|
+
return !!(value && value[name]);
|
|
890
|
+
} catch (e) {
|
|
891
|
+
return false;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
function observeDispatch(promise) {
|
|
895
|
+
// Direct native-then call: routing through ObservedPromise.then
|
|
896
|
+
// would mark the promise consumed and recurse the observer. The
|
|
897
|
+
// observer body must be exception-safe on ANY rejection value:
|
|
898
|
+
// a script handler can throw an exotic value (a message getter
|
|
899
|
+
// that throws, a Proxy with throwing traps), and an observer
|
|
900
|
+
// killed mid-body would turn the very rejection it watches into
|
|
901
|
+
// a process-level unhandledRejection \u2014 the exact failure class
|
|
902
|
+
// the observer exists to remove.
|
|
903
|
+
Promise.prototype.then.call(promise, undefined, function (err) {
|
|
904
|
+
if (promise.__wfConsumed) return;
|
|
905
|
+
// R11-30: also suppress on the run-level abort state, not just
|
|
906
|
+
// the rejection's own marker \u2014 a wrapped Promise.any aggregate
|
|
907
|
+
// rejects with a natively built AggregateError that carries
|
|
908
|
+
// neither marker, so teardown rejections of a correctly-
|
|
909
|
+
// cancelled run would still be mirrored when it is unconsumed.
|
|
910
|
+
if (readFlag(err, '__wfAbort') || __b.isRunAborted()) return;
|
|
911
|
+
var dispatchFailed = readFlag(err, '__wfDispatchFailed');
|
|
912
|
+
var errors = null;
|
|
913
|
+
try {
|
|
914
|
+
if (err && Array.isArray(err.errors)) errors = err.errors;
|
|
915
|
+
} catch (e) {
|
|
916
|
+
errors = null;
|
|
917
|
+
}
|
|
918
|
+
if (!dispatchFailed && errors) {
|
|
919
|
+
// R11-4: Promise.any rejects with a fresh vm-realm
|
|
920
|
+
// AggregateError carrying no flags; the element errors are
|
|
921
|
+
// reachable on .errors with their markers preserved. Derive
|
|
922
|
+
// the attribution from the causes instead of blaming the
|
|
923
|
+
// script for a dispatch failure.
|
|
924
|
+
for (var i = 0; i < errors.length; i++) {
|
|
925
|
+
if (readFlag(errors[i], '__wfDispatchFailed')) {
|
|
926
|
+
dispatchFailed = true;
|
|
927
|
+
break;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
// R11-15: cross-root suppression \u2014 aggregate roots track
|
|
932
|
+
// rejectionHandled independently of their elements' roots, so
|
|
933
|
+
// a forwarded dispatch failure whose originating element root
|
|
934
|
+
// the script already handled must not mirror from the
|
|
935
|
+
// aggregate. The element rootId is stamped in vmAsync;
|
|
936
|
+
// Promise.all/race forward the element's own reason,
|
|
937
|
+
// Promise.any surfaces them on .errors.
|
|
938
|
+
try {
|
|
939
|
+
var sourceIds = [];
|
|
940
|
+
if (err && err.__wfRootId) {
|
|
941
|
+
sourceIds.push(err.__wfRootId);
|
|
942
|
+
} else if (errors) {
|
|
943
|
+
for (var j = 0; j < errors.length; j++) {
|
|
944
|
+
if (errors[j] && errors[j].__wfRootId) {
|
|
945
|
+
sourceIds.push(errors[j].__wfRootId);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
for (var k = 0; k < sourceIds.length; k++) {
|
|
950
|
+
if (
|
|
951
|
+
sourceIds[k] !== promise.__wfRootId &&
|
|
952
|
+
__b.wfIsRootHandled(sourceIds[k])
|
|
953
|
+
) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
} catch (e) {
|
|
958
|
+
// A throwing exotic value must not kill the observer; fall
|
|
959
|
+
// through and mirror conservatively.
|
|
960
|
+
}
|
|
961
|
+
var msg;
|
|
962
|
+
try {
|
|
963
|
+
msg = String(err && err.message != null ? err.message : err);
|
|
964
|
+
} catch (e) {
|
|
965
|
+
msg = '[unserializable rejection value]';
|
|
966
|
+
}
|
|
967
|
+
promise.__wfUnconsumedId = __b.wfReportUnconsumed(
|
|
968
|
+
promise.__wfRootId,
|
|
969
|
+
promise.__wfIsRoot === true,
|
|
970
|
+
dispatchFailed,
|
|
971
|
+
msg,
|
|
972
|
+
);
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
// R11-3: await / Promise.resolve / returning a thenable from a
|
|
976
|
+
// handler adopts an ObservedPromise through this then with the
|
|
977
|
+
// adopting promise's capability (resolve, reject) pair \u2014 native
|
|
978
|
+
// functions, indistinguishable from real handlers by arity. They
|
|
979
|
+
// are detected by the native toString signature. Adoption
|
|
980
|
+
// CONSUMES the result (a delayed adoption clears a recorded
|
|
981
|
+
// verdict exactly like a delayed await) but is NOT a rejection
|
|
982
|
+
// handler: the rejection transfers into the adopting promise \u2014
|
|
983
|
+
// typically an async wrapper's implicit promise, which is a plain
|
|
984
|
+
// vm-realm Promise the mirror cannot observe. Marking adoption as
|
|
985
|
+
// handling would silently disarm the mirror for the forgotten-
|
|
986
|
+
// await failure class; the run-level escape hook in the host
|
|
987
|
+
// surfaces those escapes instead. Bound script functions also
|
|
988
|
+
// stringify as native code; misreading one as adoption only
|
|
989
|
+
// forgoes the rejectionHandled marking, never native semantics.
|
|
990
|
+
function isAdoptionAttach(handler) {
|
|
991
|
+
try {
|
|
992
|
+
return (
|
|
993
|
+
typeof handler === 'function' &&
|
|
994
|
+
Function.prototype.toString
|
|
995
|
+
.call(handler)
|
|
996
|
+
.indexOf('[native code]') !== -1
|
|
997
|
+
);
|
|
998
|
+
} catch (e) {
|
|
999
|
+
return false;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
class ObservedPromise extends Promise {
|
|
1003
|
+
then(onFulfilled, onRejected) {
|
|
1004
|
+
// R11-26: introspect the handler BEFORE any state mutation.
|
|
1005
|
+
// The read is guarded because a script-supplied handler can
|
|
1006
|
+
// be exotic (a revoked Proxy wrapping a function, a throwing
|
|
1007
|
+
// accessor) \u2014 an unguarded read made .then() throw
|
|
1008
|
+
// synchronously, something native then never does, leaving
|
|
1009
|
+
// the promise marked consumed with no handler attached.
|
|
1010
|
+
var rethrows = false;
|
|
1011
|
+
try {
|
|
1012
|
+
rethrows = !!(onRejected && onRejected.__wfRethrows);
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
rethrows = false;
|
|
1015
|
+
}
|
|
1016
|
+
this.__wfConsumed = true;
|
|
1017
|
+
// An attached rejection handler means the script can surface the
|
|
1018
|
+
// root rejection itself; the mirror stays silent for it. The
|
|
1019
|
+
// finally override below routes through this then with marked
|
|
1020
|
+
// rethrow combinators \u2014 those re-raise the rejection instead of
|
|
1021
|
+
// handling it, so they must NOT set the flag (marking them
|
|
1022
|
+
// handled would silently drop a fire-and-forget
|
|
1023
|
+
// agent(...).finally(...) failure). Adoption attaches count
|
|
1024
|
+
// as consumption only, never handling (see isAdoptionAttach):
|
|
1025
|
+
// they mark adoptedOut so forwarded sibling entries defer to
|
|
1026
|
+
// the adopting chain / escape hook instead of mirroring.
|
|
1027
|
+
if (isAdoptionAttach(onRejected)) {
|
|
1028
|
+
__b.wfMarkAdopted(this.__wfRootId);
|
|
1029
|
+
} else if (typeof onRejected === 'function' && !rethrows) {
|
|
1030
|
+
__b.wfMarkRejectionHandled(this.__wfRootId);
|
|
1031
|
+
}
|
|
1032
|
+
// A delayed consumption clears a verdict recorded at
|
|
1033
|
+
// rejection-settlement time, so a late-but-real await is not
|
|
1034
|
+
// misreported as unconsumed.
|
|
1035
|
+
if (this.__wfUnconsumedId !== undefined) {
|
|
1036
|
+
__b.wfClearUnconsumed(this.__wfUnconsumedId);
|
|
1037
|
+
this.__wfUnconsumedId = undefined;
|
|
1038
|
+
}
|
|
1039
|
+
const derived = super.then(onFulfilled, onRejected);
|
|
1040
|
+
derived.__wfRootId = this.__wfRootId;
|
|
1041
|
+
observeDispatch(derived);
|
|
1042
|
+
return derived;
|
|
1043
|
+
}
|
|
1044
|
+
finally(onFinally) {
|
|
1045
|
+
// Native Promise.prototype.finally calls the observed then with
|
|
1046
|
+
// two function combinators, indistinguishable there from a real
|
|
1047
|
+
// then(f, g) \u2014 which would mark the root rejection handled even
|
|
1048
|
+
// though finally rethrows it. Implement finally through the
|
|
1049
|
+
// observed then with an explicitly-marked rethrow combinator so
|
|
1050
|
+
// the mirror stays armed for finally-only chains.
|
|
1051
|
+
if (typeof onFinally !== 'function') {
|
|
1052
|
+
return this.then(undefined, undefined);
|
|
1053
|
+
}
|
|
1054
|
+
const onRethrow = function (err) {
|
|
1055
|
+
return Promise.resolve(onFinally()).then(function () {
|
|
1056
|
+
throw err;
|
|
1057
|
+
});
|
|
1058
|
+
};
|
|
1059
|
+
onRethrow.__wfRethrows = true;
|
|
1060
|
+
return this.then(
|
|
1061
|
+
function (value) {
|
|
1062
|
+
return Promise.resolve(onFinally()).then(function () {
|
|
1063
|
+
return value;
|
|
1064
|
+
});
|
|
1065
|
+
},
|
|
1066
|
+
onRethrow,
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
// --- Static combinators: observe the aggregate promise ---
|
|
1071
|
+
// Promise.all/race/any build their aggregate via the native static;
|
|
1072
|
+
// it never passes through the observed then, so a fire-and-forget
|
|
1073
|
+
// aggregate holding a failed dispatch would escape the run-log
|
|
1074
|
+
// mirror. While the run is live the host's adoption-escape hook
|
|
1075
|
+
// (R11-3) still catches and mirrors the process-level
|
|
1076
|
+
// unhandledRejection \u2014 a round-14 A/B confirmed that hook, not
|
|
1077
|
+
// this wrap, is the live-run backstop \u2014 but only with the coarse
|
|
1078
|
+
// '(rejection not handled)' wording, and once the run's hook is
|
|
1079
|
+
// detached nothing in the sandbox catches the escape. R14-A:
|
|
1080
|
+
// wrapping the statics gives each aggregate its own observer, so
|
|
1081
|
+
// consumption tracking works through the aggregate's own observed
|
|
1082
|
+
// then (await / .catch / .then marks it handled) and the mirror
|
|
1083
|
+
// itself classifies the rejection; the elements still funnel
|
|
1084
|
+
// through the then override via the native static's internal
|
|
1085
|
+
// attach, so they stay marked consumed.
|
|
1086
|
+
function observeAggregate(nativeAggregate) {
|
|
1087
|
+
const rootId = __b.wfRegisterRoot();
|
|
1088
|
+
const observed = new ObservedPromise(function (resolve, reject) {
|
|
1089
|
+
Promise.prototype.then.call(nativeAggregate, resolve, reject);
|
|
1090
|
+
});
|
|
1091
|
+
observed.__wfRootId = rootId;
|
|
1092
|
+
observed.__wfIsRoot = true;
|
|
1093
|
+
observeDispatch(observed);
|
|
1094
|
+
return observed;
|
|
1095
|
+
}
|
|
1096
|
+
const nativePromiseAll = Promise.all;
|
|
1097
|
+
const nativePromiseRace = Promise.race;
|
|
1098
|
+
const nativePromiseAny = Promise.any;
|
|
1099
|
+
// R11-16: a static called on a script-defined Promise subclass
|
|
1100
|
+
// must honor the species contract and return a subclass instance,
|
|
1101
|
+
// so non-default receivers bypass observation (their elements
|
|
1102
|
+
// still funnel through the observed then, and a fire-and-forget
|
|
1103
|
+
// dispatch failure escaping such an aggregate is still caught by
|
|
1104
|
+
// the host's adoption-escape hook via its stamped markers).
|
|
1105
|
+
Promise.all = function (items) {
|
|
1106
|
+
if (this !== Promise) return nativePromiseAll.call(this, items);
|
|
1107
|
+
return observeAggregate(nativePromiseAll.call(this, items));
|
|
1108
|
+
};
|
|
1109
|
+
Promise.race = function (items) {
|
|
1110
|
+
if (this !== Promise) return nativePromiseRace.call(this, items);
|
|
1111
|
+
return observeAggregate(nativePromiseRace.call(this, items));
|
|
1112
|
+
};
|
|
1113
|
+
Promise.any = function (items) {
|
|
1114
|
+
if (this !== Promise) return nativePromiseAny.call(this, items);
|
|
1115
|
+
return observeAggregate(nativePromiseAny.call(this, items));
|
|
1116
|
+
};
|
|
1117
|
+
function vmAsync(hostFn) {
|
|
1118
|
+
return function (...vmArgs) {
|
|
1119
|
+
const rootId = __b.wfRegisterRoot();
|
|
1120
|
+
const p = new ObservedPromise(function (resolve, reject) {
|
|
1121
|
+
function rejectMapped(hostErr) {
|
|
1122
|
+
const vmErr = mapDispatchError(hostErr);
|
|
1123
|
+
// Stamp the originating root and run BEFORE the error can
|
|
1124
|
+
// be forwarded into aggregate promises: the observer's
|
|
1125
|
+
// cross-root suppression (R11-15) reads __wfRootId and
|
|
1126
|
+
// the host's adoption-escape hook (R11-3) attributes by
|
|
1127
|
+
// __wfRunId.
|
|
1128
|
+
try {
|
|
1129
|
+
vmErr.__wfRootId = rootId;
|
|
1130
|
+
vmErr.__wfRunId = __b.runId;
|
|
1131
|
+
} catch (e) {}
|
|
1132
|
+
reject(vmErr);
|
|
1133
|
+
}
|
|
1134
|
+
try {
|
|
1135
|
+
const hostPromise = hostFn.apply(null, vmArgs);
|
|
1136
|
+
hostPromise.then(
|
|
1137
|
+
function (value) { resolve(value); },
|
|
1138
|
+
rejectMapped
|
|
1139
|
+
);
|
|
1140
|
+
} catch (hostErr) {
|
|
1141
|
+
rejectMapped(hostErr);
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1144
|
+
p.__wfRootId = rootId;
|
|
1145
|
+
p.__wfIsRoot = true;
|
|
1146
|
+
observeDispatch(p);
|
|
1147
|
+
return p;
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// --- phase / log ---
|
|
1152
|
+
globalThis.phase = function phase(title) {
|
|
1153
|
+
__b.pushPhase(String(title));
|
|
1154
|
+
};
|
|
1155
|
+
globalThis.log = function log(msg) {
|
|
1156
|
+
__b.pushLog(msg);
|
|
1157
|
+
};
|
|
1158
|
+
|
|
1159
|
+
// --- console (object with hardened methods, all in vm-realm) ---
|
|
1160
|
+
const safeConsole = Object.create(null);
|
|
1161
|
+
safeConsole.log = function () {
|
|
1162
|
+
const parts = [];
|
|
1163
|
+
for (let i = 0; i < arguments.length; i++) parts.push(String(arguments[i]));
|
|
1164
|
+
__b.pushLog(parts.join(' '));
|
|
1165
|
+
};
|
|
1166
|
+
safeConsole.warn = safeConsole.log;
|
|
1167
|
+
safeConsole.error = safeConsole.log;
|
|
1168
|
+
globalThis.console = safeConsole;
|
|
1169
|
+
|
|
1170
|
+
// --- agent (with runtime allowlist + named throws, all vm-realm) ---
|
|
1171
|
+
// FIX-Round1-T13: throw on any opts key not in the allowlist \u2014 catches
|
|
1172
|
+
// typos like { scema: ... } that previously slipped through the
|
|
1173
|
+
// [key:string]: unknown index signature.
|
|
1174
|
+
const KNOWN_AGENT_OPTS = ['label', 'phase', 'schema', 'model', 'isolation', 'agentType', 'stallMs', 'workingDir'];
|
|
1175
|
+
globalThis.agent = vmAsync(function (prompt, agentOpts) {
|
|
1176
|
+
agentOpts = agentOpts || {};
|
|
1177
|
+
const keys = Object.keys(agentOpts);
|
|
1178
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1179
|
+
const k = keys[i];
|
|
1180
|
+
if (KNOWN_AGENT_OPTS.indexOf(k) === -1) {
|
|
1181
|
+
throw new Error(
|
|
1182
|
+
"agent({" + k + "}): unknown option. " +
|
|
1183
|
+
"Known options are: " + KNOWN_AGENT_OPTS.join(', ') + "."
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
// P3: schema + model + agentType + isolation are all wired through
|
|
1188
|
+
// createProductionDispatch \u2192 SubagentManager.createAgentHeadless.
|
|
1189
|
+
// The dispatch surfaces descriptive errors for "agent type not found",
|
|
1190
|
+
// "isolation:'remote' is not available in this build", parent-dirty
|
|
1191
|
+
// refuse, worktree creation failures, and StructuredOutput contract
|
|
1192
|
+
// violations ("completed without calling StructuredOutput after 2
|
|
1193
|
+
// in-conversation nudges").
|
|
1194
|
+
if (
|
|
1195
|
+
agentOpts.isolation !== undefined &&
|
|
1196
|
+
agentOpts.isolation !== 'worktree' &&
|
|
1197
|
+
agentOpts.isolation !== 'remote'
|
|
1198
|
+
) {
|
|
1199
|
+
throw new Error(
|
|
1200
|
+
"agent({isolation: '" + agentOpts.isolation + "'}): unknown isolation mode. " +
|
|
1201
|
+
"Known modes are: 'worktree', 'remote'."
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
// NOTE: this init script is a host-side template literal \u2014 no
|
|
1205
|
+
// backticks anywhere below, in code or comments.
|
|
1206
|
+
//
|
|
1207
|
+
// A non-number stallMs is silently dropped downstream and the
|
|
1208
|
+
// default watchdog applies, contradicting "0 disables the watchdog"
|
|
1209
|
+
// \u2014 refuse it loudly like the other option gates.
|
|
1210
|
+
if (agentOpts.stallMs !== undefined && (typeof agentOpts.stallMs !== 'number' || !Number.isFinite(agentOpts.stallMs))) {
|
|
1211
|
+
throw new Error("agent({stallMs}): must be a finite number of milliseconds (0 disables the watchdog).");
|
|
1212
|
+
}
|
|
1213
|
+
// workingDir pins the agent to a worktree the CALLER already owns;
|
|
1214
|
+
// isolation creates and reaps one. Asking for both is a contradiction
|
|
1215
|
+
// about who owns the directory's lifetime, so name it here rather than
|
|
1216
|
+
// silently letting one win.
|
|
1217
|
+
if (agentOpts.workingDir !== undefined) {
|
|
1218
|
+
if (typeof agentOpts.workingDir !== 'string' || agentOpts.workingDir.trim().length === 0) {
|
|
1219
|
+
throw new Error(
|
|
1220
|
+
"agent({workingDir}): must be a non-empty string naming an existing " +
|
|
1221
|
+
"git worktree of this repository."
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
if (agentOpts.isolation !== undefined) {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"agent({workingDir, isolation}): incompatible options. workingDir " +
|
|
1227
|
+
"pins the agent to a worktree you already own; isolation creates " +
|
|
1228
|
+
"a fresh one and removes it afterwards. Pass one."
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
if (typeof agentOpts.phase === 'string' && agentOpts.phase.length > 0) {
|
|
1233
|
+
if (__b.lastPhase() !== agentOpts.phase) {
|
|
1234
|
+
__b.pushPhase(agentOpts.phase);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
// SECURITY (P3 R2 self-review): user-script-controlled agentOpts
|
|
1238
|
+
// cross the vm/host boundary verbatim via vmAsync's hostFn.apply.
|
|
1239
|
+
// A Proxy / inherited-getter / non-plain object in agentOpts.schema
|
|
1240
|
+
// would let host-side code (SyntheticOutputTool constructor + AJV
|
|
1241
|
+
// compile) trigger user-controlled trap handlers that execute with
|
|
1242
|
+
// the host realm's full surface. Revive agentOpts through JSON
|
|
1243
|
+
// round-trip BEFORE crossing so the host only ever sees vm-realm
|
|
1244
|
+
// plain objects with vm-realm prototypes. Same mechanism that
|
|
1245
|
+
// makes args + parallel/pipeline results safe.
|
|
1246
|
+
var safeOpts;
|
|
1247
|
+
try {
|
|
1248
|
+
safeOpts = JSON.parse(JSON.stringify(agentOpts));
|
|
1249
|
+
} catch (e) {
|
|
1250
|
+
throw new Error(
|
|
1251
|
+
"agent() opts contain a non-JSON-serializable value: " +
|
|
1252
|
+
String(e && e.message != null ? e.message : e)
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
// SECURITY (PR #4947 R1 wenshao, extended for P3): vmAsync's resolve
|
|
1256
|
+
// path is verbatim (no re-wrap of resolved values). Host-realm
|
|
1257
|
+
// strings cross the boundary harmlessly because primitives have no
|
|
1258
|
+
// prototype identity. But P3's schema-mode dispatch returns the
|
|
1259
|
+
// validated structured_output args as a host-realm OBJECT --
|
|
1260
|
+
// handing that to the script reopens the T1/T8/T14 escape:
|
|
1261
|
+
// result.constructor.constructor("return process")() would walk
|
|
1262
|
+
// the host Object.prototype chain to the host Function
|
|
1263
|
+
// constructor. Per-call JSON revival inside this vm runInContext
|
|
1264
|
+
// block makes the returned object carry vm-realm prototypes (same
|
|
1265
|
+
// mechanism as parallel/pipeline reviveInRealm and the args
|
|
1266
|
+
// global revival). The fallback to null on a non-serializable
|
|
1267
|
+
// resolve mirrors the errors-as-data convention parallel/pipeline
|
|
1268
|
+
// already use for individual slot failures.
|
|
1269
|
+
// R3 review (wenshao T3 [Suggestion]): the null fallback below is
|
|
1270
|
+
// a SECURITY backstop, not a contract path. In schema mode the
|
|
1271
|
+
// host return is the validated args of a structured_output tool
|
|
1272
|
+
// call -- LLM tool_call payloads are always JSON-serializable
|
|
1273
|
+
// (the model sends them through the OpenAI tool-call protocol
|
|
1274
|
+
// which serializes through JSON itself) and SyntheticOutputTool's
|
|
1275
|
+
// AJV validation runs over the parsed JSON, so a non-serializable
|
|
1276
|
+
// host return is unreachable in production schema mode. The
|
|
1277
|
+
// sentinel preserves the errors-as-data convention parallel /
|
|
1278
|
+
// pipeline already use for individual slot failures, and stays as
|
|
1279
|
+
// residual defense for any future dispatch path whose return
|
|
1280
|
+
// value isn't a tool_call payload. logRevivalFailure surfaces
|
|
1281
|
+
// the actionable detail (slot 0 + the error string) to operators
|
|
1282
|
+
// so a real trigger in production isn't silent.
|
|
1283
|
+
return __b.hostAgent(prompt, safeOpts).then(function (value) {
|
|
1284
|
+
if (value === null || typeof value !== 'object') {
|
|
1285
|
+
return value;
|
|
1286
|
+
}
|
|
1287
|
+
try {
|
|
1288
|
+
return JSON.parse(JSON.stringify(value));
|
|
1289
|
+
} catch (e) {
|
|
1290
|
+
__b.logRevivalFailure(0, String(e && e.message != null ? e.message : e));
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
});
|
|
1295
|
+
|
|
1296
|
+
// --- parallel / pipeline ---
|
|
1297
|
+
// SECURITY (PR #4732 P2): the host impl resolves with a HOST-realm array.
|
|
1298
|
+
// vmAsync's resolve path is verbatim (it does NOT re-wrap resolved
|
|
1299
|
+
// values), so handing that host array to the script would reopen the
|
|
1300
|
+
// T1/T8/T14 escape: result.constructor.constructor('return process')()
|
|
1301
|
+
// walks the host Array.prototype chain to the host Function constructor.
|
|
1302
|
+
// We revive the array INSIDE the vm realm with JSON.parse(JSON.stringify)
|
|
1303
|
+
// -- the same mechanism that makes the args global safe (see the args
|
|
1304
|
+
// revival above) -- so the value the script sees has vm-realm prototypes
|
|
1305
|
+
// whose constructors can't reach host process. Agent results are JSON
|
|
1306
|
+
// strings (and null slots), so the round-trip is lossless for P2.
|
|
1307
|
+
//
|
|
1308
|
+
// EAD-1 (P2 self-review): revive PER-ELEMENT, not the whole array in one
|
|
1309
|
+
// JSON.stringify. A single slot whose VALUE is non-serializable (a thunk
|
|
1310
|
+
// that returns a BigInt or a circular object) must become null at its
|
|
1311
|
+
// index -- it must NOT throw on the whole array and destroy every sibling
|
|
1312
|
+
// result, which would defeat errors-as-data for return values. The outer
|
|
1313
|
+
// [] is built in-realm here, so the result keeps vm-realm prototypes.
|
|
1314
|
+
//
|
|
1315
|
+
// SECURITY (PR #4947 R1 wenshao): reviveInRealm MUST remain inside this
|
|
1316
|
+
// vm init runInContext block. JSON, Array, Object here are vm-realm
|
|
1317
|
+
// globals; extracting this function to a host-side utility (e.g. a
|
|
1318
|
+
// shared utils/jsonRevive.ts) would resolve those references against
|
|
1319
|
+
// the HOST realm, silently reopening the T1/T8/T14 escape that the
|
|
1320
|
+
// revival is designed to prevent. The textual identity to a host-side
|
|
1321
|
+
// util is exactly the trap.
|
|
1322
|
+
function reviveInRealm(hostArr) {
|
|
1323
|
+
const out = [];
|
|
1324
|
+
for (let i = 0; i < hostArr.length; i++) {
|
|
1325
|
+
try {
|
|
1326
|
+
out[i] = JSON.parse(JSON.stringify(hostArr[i]));
|
|
1327
|
+
} catch (e) {
|
|
1328
|
+
// Cross to host realm for debug logging. The bridge function
|
|
1329
|
+
// accepts only primitive strings/numbers; the error message is
|
|
1330
|
+
// coerced to a String here so no vm-realm Error object crosses.
|
|
1331
|
+
__b.logRevivalFailure(i, String(e?.message ?? e));
|
|
1332
|
+
out[i] = null;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
return out;
|
|
1336
|
+
}
|
|
1337
|
+
if (__b.hasParallel) {
|
|
1338
|
+
const callParallel = vmAsync(function (thunks) {
|
|
1339
|
+
return __b.hostParallel(thunks);
|
|
1340
|
+
});
|
|
1341
|
+
globalThis.parallel = function parallel(thunks) {
|
|
1342
|
+
return callParallel(thunks).then(reviveInRealm);
|
|
1343
|
+
};
|
|
1344
|
+
} else {
|
|
1345
|
+
globalThis.parallel = function parallel() {
|
|
1346
|
+
return new Promise(function (_, reject) {
|
|
1347
|
+
reject(new Error(
|
|
1348
|
+
'parallel() is unavailable: this sandbox was created without a ' +
|
|
1349
|
+
'parallel implementation. The orchestrator injects one; a bare ' +
|
|
1350
|
+
'sandbox has no concurrent-dispatch capability.'
|
|
1351
|
+
));
|
|
1352
|
+
});
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
if (__b.hasPipeline) {
|
|
1356
|
+
const callPipeline = vmAsync(function (items) {
|
|
1357
|
+
const stages = [];
|
|
1358
|
+
for (let i = 1; i < arguments.length; i++) stages.push(arguments[i]);
|
|
1359
|
+
return __b.hostPipeline.apply(null, [items].concat(stages));
|
|
1360
|
+
});
|
|
1361
|
+
globalThis.pipeline = function pipeline() {
|
|
1362
|
+
return callPipeline.apply(null, arguments).then(reviveInRealm);
|
|
1363
|
+
};
|
|
1364
|
+
} else {
|
|
1365
|
+
globalThis.pipeline = function pipeline() {
|
|
1366
|
+
return new Promise(function (_, reject) {
|
|
1367
|
+
reject(new Error(
|
|
1368
|
+
'pipeline() is unavailable: this sandbox was created without a ' +
|
|
1369
|
+
'pipeline implementation. The orchestrator injects one; a bare ' +
|
|
1370
|
+
'sandbox has no staggered multi-stage capability.'
|
|
1371
|
+
));
|
|
1372
|
+
});
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
// --- workflow (nested, single-level) ---
|
|
1376
|
+
// Mirrors agent(): args cross vm\u2192host verbatim (safe direction), the
|
|
1377
|
+
// single result is revived back into the vm realm via JSON round-trip
|
|
1378
|
+
// (same T1/T8/T14 escape defense as agent / parallel / pipeline). The
|
|
1379
|
+
// host impl resolves a saved workflow and runs it sharing this run's
|
|
1380
|
+
// agent-count cap + token budget. When __b.hasWorkflow is false, the
|
|
1381
|
+
// sandbox is either bare (no resolver wired) OR is itself a nested
|
|
1382
|
+
// workflow \u2014 in both cases workflow() must throw, which is how the
|
|
1383
|
+
// single-level nesting limit is enforced (a nested sandbox is created
|
|
1384
|
+
// without a workflow impl, so its workflow() lands in the else branch).
|
|
1385
|
+
if (__b.hasWorkflow) {
|
|
1386
|
+
const callWorkflow = vmAsync(function (nameOrRef, wfArgs) {
|
|
1387
|
+
// Sanitize args through a JSON round-trip BEFORE crossing so the
|
|
1388
|
+
// host only ever sees vm-realm plain objects (same defense as
|
|
1389
|
+
// agent()'s safeOpts). nameOrRef may be a string or {scriptPath}.
|
|
1390
|
+
var safeRef;
|
|
1391
|
+
var safeArgs;
|
|
1392
|
+
try {
|
|
1393
|
+
safeRef = nameOrRef === undefined
|
|
1394
|
+
? undefined
|
|
1395
|
+
: JSON.parse(JSON.stringify(nameOrRef));
|
|
1396
|
+
safeArgs = wfArgs === undefined
|
|
1397
|
+
? undefined
|
|
1398
|
+
: JSON.parse(JSON.stringify(wfArgs));
|
|
1399
|
+
} catch (e) {
|
|
1400
|
+
throw new Error(
|
|
1401
|
+
'workflow() received a non-JSON-serializable argument: ' +
|
|
1402
|
+
String(e && e.message != null ? e.message : e)
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
return __b.hostWorkflow(safeRef, safeArgs).then(function (value) {
|
|
1406
|
+
if (value === null || typeof value !== 'object') {
|
|
1407
|
+
return value;
|
|
1408
|
+
}
|
|
1409
|
+
try {
|
|
1410
|
+
return JSON.parse(JSON.stringify(value));
|
|
1411
|
+
} catch (e) {
|
|
1412
|
+
__b.logRevivalFailure(0, String(e && e.message != null ? e.message : e));
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
});
|
|
1417
|
+
globalThis.workflow = function workflow(nameOrRef, wfArgs) {
|
|
1418
|
+
return callWorkflow(nameOrRef, wfArgs);
|
|
1419
|
+
};
|
|
1420
|
+
} else {
|
|
1421
|
+
globalThis.workflow = function workflow() {
|
|
1422
|
+
return new Promise(function (_, reject) {
|
|
1423
|
+
reject(new Error(
|
|
1424
|
+
"workflow() is unavailable here. Either this sandbox was created " +
|
|
1425
|
+
"without a saved-workflow resolver, or this script is already " +
|
|
1426
|
+
"running as a nested workflow \u2014 workflow() nesting is limited to " +
|
|
1427
|
+
"a single level (a workflow cannot call another workflow that " +
|
|
1428
|
+
"itself calls workflow())."
|
|
1429
|
+
));
|
|
1430
|
+
});
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// --- budget ---
|
|
1435
|
+
const safeBudget = Object.create(null);
|
|
1436
|
+
Object.defineProperty(safeBudget, 'total', {
|
|
1437
|
+
value: __b.budgetTotal,
|
|
1438
|
+
writable: false, configurable: false,
|
|
1439
|
+
});
|
|
1440
|
+
if (__b.hasBudget) {
|
|
1441
|
+
Object.defineProperty(safeBudget, 'spent', {
|
|
1442
|
+
value: function spent() { return __b.hostBudgetSpent(); },
|
|
1443
|
+
writable: false, configurable: false,
|
|
1444
|
+
});
|
|
1445
|
+
Object.defineProperty(safeBudget, 'remaining', {
|
|
1446
|
+
value: function remaining() { return __b.hostBudgetRemaining(); },
|
|
1447
|
+
writable: false, configurable: false,
|
|
1448
|
+
});
|
|
1449
|
+
} else {
|
|
1450
|
+
Object.defineProperty(safeBudget, 'spent', {
|
|
1451
|
+
value: function spent() {
|
|
1452
|
+
throw new Error(
|
|
1453
|
+
'budget.spent() is not supported in P1. Token tracking is scheduled for P5.'
|
|
1454
|
+
);
|
|
1455
|
+
},
|
|
1456
|
+
writable: false, configurable: false,
|
|
1457
|
+
});
|
|
1458
|
+
Object.defineProperty(safeBudget, 'remaining', {
|
|
1459
|
+
value: function remaining() {
|
|
1460
|
+
throw new Error(
|
|
1461
|
+
'budget.remaining() is not supported in P1. Token tracking is scheduled for P5.'
|
|
1462
|
+
);
|
|
1463
|
+
},
|
|
1464
|
+
writable: false, configurable: false,
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
globalThis.budget = safeBudget;
|
|
1468
|
+
})();`,
|
|
1469
|
+
ctx,
|
|
1470
|
+
{ filename: "workflow-sandbox-init.js" }
|
|
1471
|
+
);
|
|
1472
|
+
const maxWallClockMs = resolveMaxWallClockMs(opts);
|
|
1473
|
+
const flushUnconsumedRejections = /* @__PURE__ */ __name(async () => {
|
|
1474
|
+
unconsumedSettled = true;
|
|
1475
|
+
if (nextUnconsumedId === 1) return;
|
|
1476
|
+
await new Promise((resolve2) => {
|
|
1477
|
+
setImmediate(resolve2);
|
|
1478
|
+
});
|
|
1479
|
+
for (const rec of unconsumedRejections.values()) {
|
|
1480
|
+
const rootState = unconsumedRoots.get(rec.rootId);
|
|
1481
|
+
if (rootState?.rejectionHandled) {
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
if (rec.dispatchFailed && rootState?.adoptedOut) {
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
const key = rec.rootId + "\0" + rec.msg;
|
|
1488
|
+
if (mirroredEscapeKeys.has(key)) continue;
|
|
1489
|
+
mirroredEscapeKeys.add(key);
|
|
1490
|
+
safeLog(unconsumedRejectionLine(rec));
|
|
1491
|
+
}
|
|
1492
|
+
unconsumedRejections.clear();
|
|
1493
|
+
}, "flushUnconsumedRejections");
|
|
1494
|
+
const hookRunId = opts.runId ?? "";
|
|
1495
|
+
const adoptionEscapeHook = /* @__PURE__ */ __name((reason, _promise) => {
|
|
1496
|
+
try {
|
|
1497
|
+
if (!reason || typeof reason !== "object") return;
|
|
1498
|
+
const marked = reason;
|
|
1499
|
+
if (marked.__wfDispatchFailed !== true) return;
|
|
1500
|
+
if (String(marked.__wfRunId ?? "") !== hookRunId) return;
|
|
1501
|
+
const rootId = typeof marked.__wfRootId === "number" ? marked.__wfRootId : void 0;
|
|
1502
|
+
if (rootId !== void 0 && unconsumedRoots.get(rootId)?.rejectionHandled) {
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
let msg;
|
|
1506
|
+
try {
|
|
1507
|
+
msg = marked.message != null ? String(marked.message) : String(reason);
|
|
1508
|
+
} catch {
|
|
1509
|
+
msg = "[unserializable rejection value]";
|
|
1510
|
+
}
|
|
1511
|
+
const key = String(rootId ?? "") + "\0" + msg;
|
|
1512
|
+
if (mirroredEscapeKeys.has(key)) return;
|
|
1513
|
+
mirroredEscapeKeys.add(key);
|
|
1514
|
+
safeLog("dispatch failed (rejection not handled): " + msg);
|
|
1515
|
+
} catch (e) {
|
|
1516
|
+
debugLogger.warn("adoptionEscapeHook failed:", e);
|
|
1517
|
+
}
|
|
1518
|
+
}, "adoptionEscapeHook");
|
|
1519
|
+
let extractedMeta = null;
|
|
1520
|
+
return {
|
|
1521
|
+
async run(scriptSource) {
|
|
1522
|
+
unconsumedSettled = false;
|
|
1523
|
+
unconsumedRoots.clear();
|
|
1524
|
+
unconsumedRejections.clear();
|
|
1525
|
+
nextUnconsumedId = 1;
|
|
1526
|
+
mirroredEscapeKeys = /* @__PURE__ */ new Set();
|
|
1527
|
+
let watchdog;
|
|
1528
|
+
let stopWatchingState;
|
|
1529
|
+
let rearmWatchdogOnAbort;
|
|
1530
|
+
let settleOnAbort;
|
|
1531
|
+
let wallClockFired = false;
|
|
1532
|
+
process.on("unhandledRejection", adoptionEscapeHook);
|
|
1533
|
+
try {
|
|
1534
|
+
const { script, meta } = compileWorkflowScript(scriptSource);
|
|
1535
|
+
extractedMeta = meta;
|
|
1536
|
+
if (opts.abortOnTimeout?.signal.aborted) {
|
|
1537
|
+
throw workflowCancelledError();
|
|
1538
|
+
}
|
|
1539
|
+
const runOpts = {
|
|
1540
|
+
timeout: 3e4
|
|
1541
|
+
};
|
|
1542
|
+
const result = script.runInContext(ctx, runOpts);
|
|
1543
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1544
|
+
watchdog = new WallClockWatchdog(maxWallClockMs, () => {
|
|
1545
|
+
wallClockFired = true;
|
|
1546
|
+
opts.abortOnTimeout?.abort();
|
|
1547
|
+
reject(
|
|
1548
|
+
new Error(
|
|
1549
|
+
`Workflow execution exceeded ${maxWallClockMs} ms of active time (paused time is not counted). Override via SandboxOptions.maxWallClockMs or QWEN_CODE_MAX_WORKFLOW_SECONDS env var.`
|
|
1550
|
+
)
|
|
1551
|
+
);
|
|
1552
|
+
});
|
|
1553
|
+
});
|
|
1554
|
+
const aborted = /* @__PURE__ */ __name(() => opts.abortOnTimeout?.signal.aborted === true, "aborted");
|
|
1555
|
+
stopWatchingState = opts.scheduler?.onStateChange(({ state }) => {
|
|
1556
|
+
if (state === "paused" && !aborted()) watchdog?.pause();
|
|
1557
|
+
else watchdog?.resume();
|
|
1558
|
+
});
|
|
1559
|
+
if (opts.scheduler?.snapshot().state === "paused" && !aborted()) {
|
|
1560
|
+
watchdog?.pause();
|
|
1561
|
+
}
|
|
1562
|
+
rearmWatchdogOnAbort = /* @__PURE__ */ __name(() => watchdog?.resume(), "rearmWatchdogOnAbort");
|
|
1563
|
+
opts.abortOnTimeout?.signal.addEventListener(
|
|
1564
|
+
"abort",
|
|
1565
|
+
rearmWatchdogOnAbort,
|
|
1566
|
+
{ once: true }
|
|
1567
|
+
);
|
|
1568
|
+
const abortPromise = new Promise((_, reject) => {
|
|
1569
|
+
const signal = opts.abortOnTimeout?.signal;
|
|
1570
|
+
if (!signal) return;
|
|
1571
|
+
settleOnAbort = /* @__PURE__ */ __name(() => {
|
|
1572
|
+
if (!wallClockFired) reject(workflowCancelledError());
|
|
1573
|
+
}, "settleOnAbort");
|
|
1574
|
+
signal.addEventListener("abort", settleOnAbort, { once: true });
|
|
1575
|
+
});
|
|
1576
|
+
return await Promise.race([result, timeoutPromise, abortPromise]);
|
|
1577
|
+
} finally {
|
|
1578
|
+
if (rearmWatchdogOnAbort) {
|
|
1579
|
+
opts.abortOnTimeout?.signal.removeEventListener(
|
|
1580
|
+
"abort",
|
|
1581
|
+
rearmWatchdogOnAbort
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
if (settleOnAbort) {
|
|
1585
|
+
opts.abortOnTimeout?.signal.removeEventListener(
|
|
1586
|
+
"abort",
|
|
1587
|
+
settleOnAbort
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
stopWatchingState?.();
|
|
1591
|
+
watchdog?.stop();
|
|
1592
|
+
await flushUnconsumedRejections();
|
|
1593
|
+
process.off("unhandledRejection", adoptionEscapeHook);
|
|
1594
|
+
}
|
|
1595
|
+
},
|
|
1596
|
+
getPhases: /* @__PURE__ */ __name(() => [...phases], "getPhases"),
|
|
1597
|
+
getLogs: /* @__PURE__ */ __name(() => [...logs], "getLogs"),
|
|
1598
|
+
appendLog: /* @__PURE__ */ __name((line) => safeLog(line, false), "appendLog"),
|
|
1599
|
+
getMeta: /* @__PURE__ */ __name(() => extractedMeta, "getMeta")
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
__name(createWorkflowSandbox, "createWorkflowSandbox");
|
|
1603
|
+
|
|
1604
|
+
// packages/core/src/agents/runtime/workflow-saved.ts
|
|
1605
|
+
init_esbuild_shims();
|
|
1606
|
+
import { promises as fs } from "node:fs";
|
|
1607
|
+
import * as path from "node:path";
|
|
1608
|
+
var debugLogger2 = createDebugLogger("WORKFLOW_SAVED");
|
|
1609
|
+
var WORKFLOW_NAME_PATTERN = /^[a-z][a-z0-9-]{0,40}$/;
|
|
1610
|
+
function validateWorkflowName(name) {
|
|
1611
|
+
if (!name) return "Workflow name is required.";
|
|
1612
|
+
if (!WORKFLOW_NAME_PATTERN.test(name)) {
|
|
1613
|
+
return `Invalid workflow name "${name}". Use lower-case letters, digits, and hyphens only (must start with a letter, max 41 chars).`;
|
|
1614
|
+
}
|
|
1615
|
+
return null;
|
|
1616
|
+
}
|
|
1617
|
+
__name(validateWorkflowName, "validateWorkflowName");
|
|
1618
|
+
function getSavedWorkflowDirs(config) {
|
|
1619
|
+
return [
|
|
1620
|
+
{ dir: config.storage.getProjectWorkflowsDir(), source: "project" },
|
|
1621
|
+
{ dir: Storage.getUserWorkflowsDir(), source: "user" }
|
|
1622
|
+
];
|
|
1623
|
+
}
|
|
1624
|
+
__name(getSavedWorkflowDirs, "getSavedWorkflowDirs");
|
|
1625
|
+
function getWorkflowScriptRoots(config) {
|
|
1626
|
+
return [
|
|
1627
|
+
...getSavedWorkflowDirs(config).map(({ dir }) => dir),
|
|
1628
|
+
config.storage.getGeneratedWorkflowsDir()
|
|
1629
|
+
];
|
|
1630
|
+
}
|
|
1631
|
+
__name(getWorkflowScriptRoots, "getWorkflowScriptRoots");
|
|
1632
|
+
async function isSymlinkedRoot(dir) {
|
|
1633
|
+
return fs.lstat(dir).then((st) => st.isSymbolicLink()).catch(() => false);
|
|
1634
|
+
}
|
|
1635
|
+
__name(isSymlinkedRoot, "isSymlinkedRoot");
|
|
1636
|
+
async function listJsFiles(dir) {
|
|
1637
|
+
if (await isSymlinkedRoot(dir)) {
|
|
1638
|
+
debugLogger2.warn(`refusing symlinked saved-workflow dir: ${dir}`);
|
|
1639
|
+
return [];
|
|
1640
|
+
}
|
|
1641
|
+
try {
|
|
1642
|
+
const names = await fs.readdir(dir);
|
|
1643
|
+
const out = [];
|
|
1644
|
+
for (const n of names) {
|
|
1645
|
+
if (!n.endsWith(".js")) continue;
|
|
1646
|
+
const st = await fs.lstat(path.join(dir, n)).catch(() => null);
|
|
1647
|
+
if (!st || st.isSymbolicLink()) continue;
|
|
1648
|
+
out.push(n);
|
|
1649
|
+
}
|
|
1650
|
+
return out;
|
|
1651
|
+
} catch (e) {
|
|
1652
|
+
const code = e?.code;
|
|
1653
|
+
if (code !== "ENOENT") {
|
|
1654
|
+
debugLogger2.warn(`listJsFiles failed for ${dir}: ${e}`);
|
|
1655
|
+
}
|
|
1656
|
+
return [];
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
__name(listJsFiles, "listJsFiles");
|
|
1660
|
+
async function readWorkflowFileSecurely(filePath, config) {
|
|
1661
|
+
const real = await fs.realpath(filePath);
|
|
1662
|
+
const roots = await Promise.all(
|
|
1663
|
+
getWorkflowScriptRoots(config).map(async (dir) => {
|
|
1664
|
+
if (await isSymlinkedRoot(dir)) return { dir, real: null };
|
|
1665
|
+
try {
|
|
1666
|
+
return { dir, real: await fs.realpath(dir) };
|
|
1667
|
+
} catch {
|
|
1668
|
+
return { dir, real: path.resolve(dir) };
|
|
1669
|
+
}
|
|
1670
|
+
})
|
|
1671
|
+
);
|
|
1672
|
+
const dirs = roots.flatMap((r) => r.real === null ? [] : [r.real]);
|
|
1673
|
+
const inside = dirs.some((d) => real === d || real.startsWith(d + path.sep));
|
|
1674
|
+
if (!inside) {
|
|
1675
|
+
const refused = roots.flatMap((r) => r.real === null ? [r.dir] : []);
|
|
1676
|
+
const refusedNote = refused.length > 0 ? `; refused symlinked ${refused.length === 1 ? "root" : "roots"}: ${refused.join(", ")}` : "";
|
|
1677
|
+
throw new Error(
|
|
1678
|
+
`refusing to load a workflow file outside the workflow script roots (checked: ${dirs.join(", ")}${refusedNote}): '${filePath}'.`
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
return fs.readFile(real, "utf8");
|
|
1682
|
+
}
|
|
1683
|
+
__name(readWorkflowFileSecurely, "readWorkflowFileSecurely");
|
|
1684
|
+
async function resolveSavedWorkflowNameForPath(scriptPath, config) {
|
|
1685
|
+
const realScriptPath = await fs.realpath(scriptPath);
|
|
1686
|
+
for (const { dir } of getSavedWorkflowDirs(config)) {
|
|
1687
|
+
if (await isSymlinkedRoot(dir)) continue;
|
|
1688
|
+
let realDir;
|
|
1689
|
+
try {
|
|
1690
|
+
realDir = await fs.realpath(dir);
|
|
1691
|
+
} catch {
|
|
1692
|
+
continue;
|
|
1693
|
+
}
|
|
1694
|
+
if (realScriptPath !== realDir && !realScriptPath.startsWith(realDir + path.sep)) {
|
|
1695
|
+
continue;
|
|
1696
|
+
}
|
|
1697
|
+
const name = path.basename(realScriptPath).replace(/\.js$/, "");
|
|
1698
|
+
return WORKFLOW_NAME_PATTERN.test(name) ? name : void 0;
|
|
1699
|
+
}
|
|
1700
|
+
return void 0;
|
|
1701
|
+
}
|
|
1702
|
+
__name(resolveSavedWorkflowNameForPath, "resolveSavedWorkflowNameForPath");
|
|
1703
|
+
async function listSavedWorkflows(config) {
|
|
1704
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1705
|
+
for (const { dir, source } of [...getSavedWorkflowDirs(config)].reverse()) {
|
|
1706
|
+
for (const file of await listJsFiles(dir)) {
|
|
1707
|
+
const name = file.slice(0, -".js".length);
|
|
1708
|
+
if (!WORKFLOW_NAME_PATTERN.test(name)) continue;
|
|
1709
|
+
byName.set(name, { name, scriptPath: path.join(dir, file), source });
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return Array.from(byName.values()).sort(
|
|
1713
|
+
(a, b) => a.name.localeCompare(b.name)
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
__name(listSavedWorkflows, "listSavedWorkflows");
|
|
1717
|
+
async function resolveSavedWorkflowScript(nameOrRef, config) {
|
|
1718
|
+
if (typeof nameOrRef === "object" && nameOrRef !== null) {
|
|
1719
|
+
const scriptPath = nameOrRef.scriptPath;
|
|
1720
|
+
if (typeof scriptPath !== "string" || scriptPath.length === 0) {
|
|
1721
|
+
throw new Error(
|
|
1722
|
+
"workflow() expects a workflow name (string) or {scriptPath: string}."
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
let script;
|
|
1726
|
+
try {
|
|
1727
|
+
script = await readWorkflowFileSecurely(scriptPath, config);
|
|
1728
|
+
} catch (e) {
|
|
1729
|
+
throw new Error(
|
|
1730
|
+
`workflow({scriptPath: '${scriptPath}'}): ${e instanceof Error ? e.message : String(e)}`
|
|
1731
|
+
);
|
|
1732
|
+
}
|
|
1733
|
+
const name2 = path.basename(scriptPath).replace(/\.js$/, "");
|
|
1734
|
+
const savedWorkflowName = await resolveSavedWorkflowNameForPath(
|
|
1735
|
+
scriptPath,
|
|
1736
|
+
config
|
|
1737
|
+
);
|
|
1738
|
+
return {
|
|
1739
|
+
name: name2,
|
|
1740
|
+
scriptPath,
|
|
1741
|
+
script,
|
|
1742
|
+
...savedWorkflowName ? { savedWorkflowName } : {}
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
if (typeof nameOrRef !== "string") {
|
|
1746
|
+
throw new Error(
|
|
1747
|
+
"workflow() expects a workflow name (string) or {scriptPath: string}."
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
const name = nameOrRef;
|
|
1751
|
+
const nameError = validateWorkflowName(name);
|
|
1752
|
+
if (nameError) {
|
|
1753
|
+
throw new Error(`workflow('${name}'): ${nameError}`);
|
|
1754
|
+
}
|
|
1755
|
+
for (const { dir } of getSavedWorkflowDirs(config)) {
|
|
1756
|
+
const scriptPath = path.join(dir, `${name}.js`);
|
|
1757
|
+
try {
|
|
1758
|
+
const script = await readWorkflowFileSecurely(scriptPath, config);
|
|
1759
|
+
return { name, scriptPath, script, savedWorkflowName: name };
|
|
1760
|
+
} catch {
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
const available = (await listSavedWorkflows(config)).map((e) => e.name);
|
|
1764
|
+
throw new Error(
|
|
1765
|
+
`workflow('${name}'): no workflow with that name. Available: ${available.length > 0 ? available.join(", ") : "(none)"}.`
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
__name(resolveSavedWorkflowScript, "resolveSavedWorkflowScript");
|
|
1769
|
+
async function saveWorkflowScript(config, opts) {
|
|
1770
|
+
const { name, scope, script, overwrite = false } = opts;
|
|
1771
|
+
const nameError = validateWorkflowName(name);
|
|
1772
|
+
if (nameError) return { status: "invalid-name", error: nameError };
|
|
1773
|
+
if (!script || script.trim().length === 0) {
|
|
1774
|
+
return {
|
|
1775
|
+
status: "empty-script",
|
|
1776
|
+
error: "This run has no script source to save."
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
const dir = scope === "project" ? config.storage.getProjectWorkflowsDir() : Storage.getUserWorkflowsDir();
|
|
1780
|
+
if (await isSymlinkedRoot(dir)) {
|
|
1781
|
+
throw new Error(
|
|
1782
|
+
`refusing to save into a symlinked saved-workflow directory: '${dir}'.`
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
const filePath = path.join(dir, `${name}.js`);
|
|
1786
|
+
if (!overwrite) {
|
|
1787
|
+
try {
|
|
1788
|
+
await fs.access(filePath);
|
|
1789
|
+
return { status: "exists", name, scope, path: filePath };
|
|
1790
|
+
} catch {
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1794
|
+
await fs.writeFile(filePath, script, "utf8");
|
|
1795
|
+
return { status: "saved", name, scope, path: filePath };
|
|
1796
|
+
}
|
|
1797
|
+
__name(saveWorkflowScript, "saveWorkflowScript");
|
|
1798
|
+
var INLINE_RUN_ID_PATTERN = /^wf_[0-9a-f]+$/;
|
|
1799
|
+
async function persistInlineWorkflowScript(config, runId, script) {
|
|
1800
|
+
if (!INLINE_RUN_ID_PATTERN.test(runId)) {
|
|
1801
|
+
debugLogger2.warn(`refusing to persist a script for run id: ${runId}`);
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
const storage = config.storage;
|
|
1805
|
+
if (!storage) return null;
|
|
1806
|
+
try {
|
|
1807
|
+
const filePath = storage.getInlineWorkflowScriptPath(runId);
|
|
1808
|
+
const dir = path.dirname(filePath);
|
|
1809
|
+
if (await isSymlinkedRoot(storage.getGeneratedWorkflowsDir()) || await isSymlinkedRoot(dir)) {
|
|
1810
|
+
debugLogger2.warn(
|
|
1811
|
+
`refusing to persist an inline workflow script into a symlinked root: '${dir}'.`
|
|
1812
|
+
);
|
|
1813
|
+
return null;
|
|
1814
|
+
}
|
|
1815
|
+
await fs.mkdir(dir, { recursive: true });
|
|
1816
|
+
await atomicWriteFile(filePath, script, {
|
|
1817
|
+
encoding: "utf8",
|
|
1818
|
+
mode: 384,
|
|
1819
|
+
forceMode: true,
|
|
1820
|
+
noFollow: true
|
|
1821
|
+
});
|
|
1822
|
+
return filePath;
|
|
1823
|
+
} catch (error) {
|
|
1824
|
+
debugLogger2.warn(
|
|
1825
|
+
`failed to persist inline workflow script for ${runId}: ${error}`
|
|
1826
|
+
);
|
|
1827
|
+
return null;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
__name(persistInlineWorkflowScript, "persistInlineWorkflowScript");
|
|
1831
|
+
async function deleteInlineWorkflowScript(config, runId) {
|
|
1832
|
+
if (!INLINE_RUN_ID_PATTERN.test(runId)) return false;
|
|
1833
|
+
const storage = config.storage;
|
|
1834
|
+
if (!storage) return false;
|
|
1835
|
+
try {
|
|
1836
|
+
await fs.rm(storage.getInlineWorkflowScriptPath(runId), { force: true });
|
|
1837
|
+
return true;
|
|
1838
|
+
} catch (error) {
|
|
1839
|
+
debugLogger2.warn(
|
|
1840
|
+
`failed to delete inline workflow script for ${runId}: ${error}`
|
|
1841
|
+
);
|
|
1842
|
+
return false;
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
__name(deleteInlineWorkflowScript, "deleteInlineWorkflowScript");
|
|
1846
|
+
|
|
1847
|
+
// packages/core/src/agents/workflow-snapshot.ts
|
|
1848
|
+
init_esbuild_shims();
|
|
1849
|
+
import { promises as fs2 } from "node:fs";
|
|
1850
|
+
import path2 from "node:path";
|
|
1851
|
+
var debugLogger3 = createDebugLogger("WORKFLOW_SNAPSHOT");
|
|
1852
|
+
var MAX_RETAINED_SNAPSHOTS = 30;
|
|
1853
|
+
function toSnapshot(task) {
|
|
1854
|
+
if (!isTerminalWorkflowStatus(task.status)) {
|
|
1855
|
+
throw new Error(`Cannot snapshot active workflow ${task.runId}.`);
|
|
1856
|
+
}
|
|
1857
|
+
return {
|
|
1858
|
+
runId: task.runId,
|
|
1859
|
+
...task.toolUseId ? { toolUseId: task.toolUseId } : {},
|
|
1860
|
+
description: task.description,
|
|
1861
|
+
...task.workflowName ? { workflowName: task.workflowName } : {},
|
|
1862
|
+
sourceRunId: task.sourceRunId,
|
|
1863
|
+
startMode: task.startMode,
|
|
1864
|
+
meta: task.meta,
|
|
1865
|
+
status: task.status,
|
|
1866
|
+
script: task.script ?? "",
|
|
1867
|
+
scriptPath: task.scriptPath,
|
|
1868
|
+
phases: [...task.phases],
|
|
1869
|
+
phaseVisits: task.phaseVisits.map((visit) => ({ ...visit })),
|
|
1870
|
+
dispatches: task.dispatches.map((dispatch) => ({
|
|
1871
|
+
...dispatch,
|
|
1872
|
+
dependsOn: [...dispatch.dependsOn]
|
|
1873
|
+
})),
|
|
1874
|
+
agentsDispatched: task.agentsDispatched,
|
|
1875
|
+
agentsCompleted: task.agentsCompleted,
|
|
1876
|
+
tokensSpent: task.tokensSpent,
|
|
1877
|
+
tokenBudgetTotal: task.tokenBudgetTotal,
|
|
1878
|
+
perPhaseTokens: Array.from(task.perPhaseTokens.entries()),
|
|
1879
|
+
recentLogs: [...task.recentLogs],
|
|
1880
|
+
events: task.events.map((event) => ({ ...event })),
|
|
1881
|
+
startTime: task.startTime,
|
|
1882
|
+
endTime: task.endTime,
|
|
1883
|
+
result: safeResult(task.result),
|
|
1884
|
+
error: task.error
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
__name(toSnapshot, "toSnapshot");
|
|
1888
|
+
function safeResult(result) {
|
|
1889
|
+
if (result === void 0) return void 0;
|
|
1890
|
+
try {
|
|
1891
|
+
JSON.stringify(result);
|
|
1892
|
+
return result;
|
|
1893
|
+
} catch {
|
|
1894
|
+
return `(non-JSON-serializable ${typeof result})`;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
__name(safeResult, "safeResult");
|
|
1898
|
+
async function writeWorkflowSnapshot(config, task) {
|
|
1899
|
+
const storage = config.storage;
|
|
1900
|
+
if (!storage) return false;
|
|
1901
|
+
try {
|
|
1902
|
+
const snapshot = toSnapshot(task);
|
|
1903
|
+
const dir = storage.getWorkflowRunsDir();
|
|
1904
|
+
await fs2.mkdir(dir, { recursive: true });
|
|
1905
|
+
await fs2.writeFile(
|
|
1906
|
+
storage.getWorkflowRunSnapshotPath(task.runId),
|
|
1907
|
+
JSON.stringify(snapshot, null, 2),
|
|
1908
|
+
"utf8"
|
|
1909
|
+
);
|
|
1910
|
+
await pruneSnapshots(config, dir);
|
|
1911
|
+
return true;
|
|
1912
|
+
} catch (e) {
|
|
1913
|
+
debugLogger3.warn(`writeWorkflowSnapshot failed for ${task.runId}: ${e}`);
|
|
1914
|
+
return false;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
__name(writeWorkflowSnapshot, "writeWorkflowSnapshot");
|
|
1918
|
+
async function listWorkflowSnapshots(config) {
|
|
1919
|
+
const storage = config.storage;
|
|
1920
|
+
if (!storage) return [];
|
|
1921
|
+
const dir = storage.getWorkflowRunsDir();
|
|
1922
|
+
let files;
|
|
1923
|
+
try {
|
|
1924
|
+
files = (await fs2.readdir(dir)).filter((f) => f.endsWith(".json"));
|
|
1925
|
+
} catch {
|
|
1926
|
+
return [];
|
|
1927
|
+
}
|
|
1928
|
+
const snapshots = [];
|
|
1929
|
+
for (const file of files) {
|
|
1930
|
+
try {
|
|
1931
|
+
const raw = await fs2.readFile(`${dir}/${file}`, "utf8");
|
|
1932
|
+
const parsed = JSON.parse(raw);
|
|
1933
|
+
if (!isWorkflowSnapshot(parsed)) {
|
|
1934
|
+
debugLogger3.warn(`skipping invalid workflow snapshot ${file}`);
|
|
1935
|
+
continue;
|
|
1936
|
+
}
|
|
1937
|
+
snapshots.push(parsed);
|
|
1938
|
+
} catch (e) {
|
|
1939
|
+
debugLogger3.warn(`skipping unparseable snapshot ${file}: ${e}`);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
snapshots.sort((a, b) => (b.startTime ?? 0) - (a.startTime ?? 0));
|
|
1943
|
+
return snapshots;
|
|
1944
|
+
}
|
|
1945
|
+
__name(listWorkflowSnapshots, "listWorkflowSnapshots");
|
|
1946
|
+
async function deleteWorkflowSnapshot(config, runId) {
|
|
1947
|
+
const storage = config.storage;
|
|
1948
|
+
if (!storage || !/^wf_[0-9a-f]+$/.test(runId)) return false;
|
|
1949
|
+
try {
|
|
1950
|
+
await fs2.rm(path2.dirname(storage.getWorkflowRunJournalPath(runId)), {
|
|
1951
|
+
recursive: true,
|
|
1952
|
+
force: true
|
|
1953
|
+
});
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
debugLogger3.warn(`delete workflow journal failed for ${runId}: ${error}`);
|
|
1956
|
+
return false;
|
|
1957
|
+
}
|
|
1958
|
+
if (!await deleteInlineWorkflowScript(config, runId)) return false;
|
|
1959
|
+
try {
|
|
1960
|
+
await fs2.unlink(storage.getWorkflowRunSnapshotPath(runId));
|
|
1961
|
+
} catch (error) {
|
|
1962
|
+
if (error.code !== "ENOENT") {
|
|
1963
|
+
debugLogger3.warn(`deleteWorkflowSnapshot failed for ${runId}: ${error}`);
|
|
1964
|
+
return false;
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
return true;
|
|
1968
|
+
}
|
|
1969
|
+
__name(deleteWorkflowSnapshot, "deleteWorkflowSnapshot");
|
|
1970
|
+
function isRecord(value) {
|
|
1971
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1972
|
+
}
|
|
1973
|
+
__name(isRecord, "isRecord");
|
|
1974
|
+
function isFiniteNumber(value) {
|
|
1975
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
1976
|
+
}
|
|
1977
|
+
__name(isFiniteNumber, "isFiniteNumber");
|
|
1978
|
+
function isOptionalString(value) {
|
|
1979
|
+
return value === void 0 || typeof value === "string";
|
|
1980
|
+
}
|
|
1981
|
+
__name(isOptionalString, "isOptionalString");
|
|
1982
|
+
function isStringArray(value) {
|
|
1983
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
1984
|
+
}
|
|
1985
|
+
__name(isStringArray, "isStringArray");
|
|
1986
|
+
function isWorkflowMeta(value) {
|
|
1987
|
+
if (value === null) return true;
|
|
1988
|
+
if (!isRecord(value)) return false;
|
|
1989
|
+
if (typeof value["name"] !== "string" || typeof value["description"] !== "string" || !isOptionalString(value["whenToUse"])) {
|
|
1990
|
+
return false;
|
|
1991
|
+
}
|
|
1992
|
+
const phases = value["phases"];
|
|
1993
|
+
return phases === void 0 || Array.isArray(phases) && phases.every(
|
|
1994
|
+
(phase) => isRecord(phase) && typeof phase["title"] === "string" && isOptionalString(phase["detail"]) && isOptionalString(phase["model"])
|
|
1995
|
+
);
|
|
1996
|
+
}
|
|
1997
|
+
__name(isWorkflowMeta, "isWorkflowMeta");
|
|
1998
|
+
function isWorkflowPhaseVisit(value) {
|
|
1999
|
+
return isRecord(value) && typeof value["id"] === "string" && isFiniteNumber(value["index"]) && typeof value["title"] === "string" && isFiniteNumber(value["startedAt"]) && (value["endedAt"] === void 0 || isFiniteNumber(value["endedAt"]));
|
|
2000
|
+
}
|
|
2001
|
+
__name(isWorkflowPhaseVisit, "isWorkflowPhaseVisit");
|
|
2002
|
+
function isWorkflowDispatch(value) {
|
|
2003
|
+
if (!isRecord(value)) return false;
|
|
2004
|
+
const status = value["status"];
|
|
2005
|
+
return typeof value["id"] === "string" && (value["phaseVisitId"] === null || typeof value["phaseVisitId"] === "string") && typeof value["label"] === "string" && typeof value["prompt"] === "string" && isOptionalString(value["subagentId"]) && (status === "queued" || status === "running" || status === "completed" || status === "failed" || status === "cancelled" || status === "cached") && isStringArray(value["dependsOn"]) && isFiniteNumber(value["queuedAt"]) && (value["startedAt"] === void 0 || isFiniteNumber(value["startedAt"])) && (value["endedAt"] === void 0 || isFiniteNumber(value["endedAt"])) && isOptionalString(value["error"]);
|
|
2006
|
+
}
|
|
2007
|
+
__name(isWorkflowDispatch, "isWorkflowDispatch");
|
|
2008
|
+
function hasOnlyKeys(value, keys) {
|
|
2009
|
+
const allowed = new Set(keys);
|
|
2010
|
+
return Object.keys(value).every((key) => allowed.has(key));
|
|
2011
|
+
}
|
|
2012
|
+
__name(hasOnlyKeys, "hasOnlyKeys");
|
|
2013
|
+
function isWorkflowEvent(value) {
|
|
2014
|
+
if (!isRecord(value) || typeof value["id"] !== "string" || !isFiniteNumber(value["at"]) || typeof value["type"] !== "string") {
|
|
2015
|
+
return false;
|
|
2016
|
+
}
|
|
2017
|
+
const base = ["id", "type", "at"];
|
|
2018
|
+
switch (value["type"]) {
|
|
2019
|
+
case "phase-started":
|
|
2020
|
+
return hasOnlyKeys(value, [...base, "phaseVisitId", "title"]) && typeof value["phaseVisitId"] === "string" && typeof value["title"] === "string";
|
|
2021
|
+
case "phase-completed":
|
|
2022
|
+
return hasOnlyKeys(value, [...base, "phaseVisitId"]) && typeof value["phaseVisitId"] === "string";
|
|
2023
|
+
case "dispatch-queued":
|
|
2024
|
+
case "dispatch-started":
|
|
2025
|
+
case "dispatch-completed":
|
|
2026
|
+
case "dispatch-cancelled":
|
|
2027
|
+
case "dispatch-cached":
|
|
2028
|
+
return hasOnlyKeys(value, [...base, "dispatchId"]) && typeof value["dispatchId"] === "string";
|
|
2029
|
+
case "dispatch-failed":
|
|
2030
|
+
return hasOnlyKeys(value, [...base, "dispatchId", "error"]) && typeof value["dispatchId"] === "string" && typeof value["error"] === "string";
|
|
2031
|
+
case "log":
|
|
2032
|
+
return hasOnlyKeys(value, [...base, "message"]) && typeof value["message"] === "string";
|
|
2033
|
+
case "approval-requested":
|
|
2034
|
+
case "approval-settled":
|
|
2035
|
+
return hasOnlyKeys(value, [...base, "name", "dispatchId"]) && typeof value["name"] === "string" && isOptionalString(value["dispatchId"]);
|
|
2036
|
+
case "workflow-completed":
|
|
2037
|
+
case "workflow-cancelled":
|
|
2038
|
+
return hasOnlyKeys(value, base);
|
|
2039
|
+
case "workflow-failed":
|
|
2040
|
+
return hasOnlyKeys(value, [...base, "error"]) && typeof value["error"] === "string";
|
|
2041
|
+
default:
|
|
2042
|
+
return false;
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
__name(isWorkflowEvent, "isWorkflowEvent");
|
|
2046
|
+
function isWorkflowSnapshot(value) {
|
|
2047
|
+
if (!isRecord(value)) return false;
|
|
2048
|
+
const status = value["status"];
|
|
2049
|
+
const phaseVisits = value["phaseVisits"];
|
|
2050
|
+
const dispatches = value["dispatches"];
|
|
2051
|
+
const events = value["events"];
|
|
2052
|
+
const perPhaseTokens = value["perPhaseTokens"];
|
|
2053
|
+
return typeof value["runId"] === "string" && value["runId"].length > 0 && isOptionalString(value["toolUseId"]) && isOptionalString(value["description"]) && isOptionalString(value["workflowName"]) && isOptionalString(value["sourceRunId"]) && (value["startMode"] === void 0 || value["startMode"] === "retry" || value["startMode"] === "rerun") && isWorkflowMeta(value["meta"]) && (status === "completed" || status === "failed" || status === "cancelled") && typeof value["script"] === "string" && isOptionalString(value["scriptPath"]) && isStringArray(value["phases"]) && (phaseVisits === void 0 || Array.isArray(phaseVisits) && phaseVisits.every(isWorkflowPhaseVisit)) && (dispatches === void 0 || Array.isArray(dispatches) && dispatches.every(isWorkflowDispatch)) && (events === void 0 || Array.isArray(events) && events.every(isWorkflowEvent)) && isFiniteNumber(value["agentsDispatched"]) && isFiniteNumber(value["agentsCompleted"]) && isFiniteNumber(value["tokensSpent"]) && (value["tokenBudgetTotal"] === null || isFiniteNumber(value["tokenBudgetTotal"])) && Array.isArray(perPhaseTokens) && perPhaseTokens.every(
|
|
2054
|
+
(entry) => Array.isArray(entry) && entry.length === 2 && (entry[0] === null || typeof entry[0] === "string") && isFiniteNumber(entry[1])
|
|
2055
|
+
) && isStringArray(value["recentLogs"]) && isFiniteNumber(value["startTime"]) && (value["endTime"] === void 0 || isFiniteNumber(value["endTime"])) && isOptionalString(value["error"]);
|
|
2056
|
+
}
|
|
2057
|
+
__name(isWorkflowSnapshot, "isWorkflowSnapshot");
|
|
2058
|
+
async function pruneSnapshots(config, dir) {
|
|
2059
|
+
let files;
|
|
2060
|
+
try {
|
|
2061
|
+
files = (await fs2.readdir(dir)).filter((f) => f.endsWith(".json"));
|
|
2062
|
+
} catch {
|
|
2063
|
+
return;
|
|
2064
|
+
}
|
|
2065
|
+
if (files.length <= MAX_RETAINED_SNAPSHOTS) return;
|
|
2066
|
+
const stats = await Promise.all(
|
|
2067
|
+
files.map(async (f) => {
|
|
2068
|
+
try {
|
|
2069
|
+
const s = await fs2.stat(`${dir}/${f}`);
|
|
2070
|
+
return { f, mtime: s.mtimeMs };
|
|
2071
|
+
} catch {
|
|
2072
|
+
return { f, mtime: 0 };
|
|
2073
|
+
}
|
|
2074
|
+
})
|
|
2075
|
+
);
|
|
2076
|
+
stats.sort((a, b) => a.mtime - b.mtime);
|
|
2077
|
+
const toPrune = stats.slice(0, stats.length - MAX_RETAINED_SNAPSHOTS);
|
|
2078
|
+
const registry = config.getWorkflowRunRegistry?.();
|
|
2079
|
+
const protectedRunIds = /* @__PURE__ */ new Set([
|
|
2080
|
+
...(registry?.list() ?? []).filter((entry) => isActiveWorkflowStatus(entry.status)).map((entry) => entry.runId),
|
|
2081
|
+
...registry?.listStartingRunIds() ?? []
|
|
2082
|
+
]);
|
|
2083
|
+
await Promise.all(
|
|
2084
|
+
toPrune.map((s) => {
|
|
2085
|
+
const runId = s.f.replace(/\.json$/, "");
|
|
2086
|
+
const isRunDir = /^wf_[0-9a-f]+$/.test(runId);
|
|
2087
|
+
const deleteArtifacts = isRunDir && !protectedRunIds.has(runId) && !isWorkflowRunPersistenceActive(config, runId);
|
|
2088
|
+
return Promise.all([
|
|
2089
|
+
fs2.unlink(`${dir}/${s.f}`).catch(
|
|
2090
|
+
(e) => debugLogger3.warn(`prune unlink failed for ${s.f}: ${e}`)
|
|
2091
|
+
),
|
|
2092
|
+
...deleteArtifacts ? [
|
|
2093
|
+
fs2.rm(
|
|
2094
|
+
path2.dirname(config.storage.getWorkflowRunJournalPath(runId)),
|
|
2095
|
+
{ recursive: true, force: true }
|
|
2096
|
+
).catch(
|
|
2097
|
+
(e) => debugLogger3.warn(
|
|
2098
|
+
`prune journal dir failed for ${runId}: ${e}`
|
|
2099
|
+
)
|
|
2100
|
+
),
|
|
2101
|
+
deleteInlineWorkflowScript(config, runId)
|
|
2102
|
+
] : []
|
|
2103
|
+
]);
|
|
2104
|
+
})
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
__name(pruneSnapshots, "pruneSnapshots");
|
|
2108
|
+
|
|
2109
|
+
export {
|
|
2110
|
+
extractAndStripMeta,
|
|
2111
|
+
compileWorkflowScript,
|
|
2112
|
+
describeWorkflowCompileError,
|
|
2113
|
+
debugLogger,
|
|
2114
|
+
createWorkflowSandbox,
|
|
2115
|
+
validateWorkflowName,
|
|
2116
|
+
isSymlinkedRoot,
|
|
2117
|
+
listSavedWorkflows,
|
|
2118
|
+
resolveSavedWorkflowScript,
|
|
2119
|
+
saveWorkflowScript,
|
|
2120
|
+
persistInlineWorkflowScript,
|
|
2121
|
+
deleteInlineWorkflowScript,
|
|
2122
|
+
MAX_RETAINED_SNAPSHOTS,
|
|
2123
|
+
toSnapshot,
|
|
2124
|
+
writeWorkflowSnapshot,
|
|
2125
|
+
listWorkflowSnapshots,
|
|
2126
|
+
deleteWorkflowSnapshot
|
|
2127
|
+
};
|
|
2128
|
+
/**
|
|
2129
|
+
* @license
|
|
2130
|
+
* Copyright 2025 Google LLC
|
|
2131
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2132
|
+
*/
|
|
2133
|
+
/**
|
|
2134
|
+
* @license
|
|
2135
|
+
* Copyright 2025 Qwen
|
|
2136
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2137
|
+
*/
|
|
2138
|
+
/**
|
|
2139
|
+
* @license
|
|
2140
|
+
* Copyright 2026 Qwen Team
|
|
2141
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
2142
|
+
*/
|