sootsim 0.1.295 → 0.1.297
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/README.md +13 -4
- package/detox/index.ts +380 -28
- package/detox/motion-change.cjs +109 -0
- package/detox/motion-change.d.cts +35 -0
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-ASAYE5YY.js → agent-EYT6T2IB.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-K2D4Q5AA.js → agent-wrapper-UU4WV5UG.js} +2 -2
- package/dist-cli/chunks/app-fonts-6SO36STZ.js +4 -0
- package/dist-cli/chunks/{assert-4FKHHDY7.js → assert-M4AVODJW.js} +2 -2
- package/dist-cli/chunks/{auth-BQPOPEFK.js → auth-JJNP2L7C.js} +2 -2
- package/dist-cli/chunks/{beta-3LNYONDF.js → beta-BIJ5MU6X.js} +2 -2
- package/dist-cli/chunks/{camera-Y5MZ5V4L.js → camera-FGQGSHG5.js} +2 -2
- package/dist-cli/chunks/{chunk-RV67EC7L.js → chunk-2JCUNWU2.js} +2 -2
- package/dist-cli/chunks/chunk-3QVML26F.js +4 -0
- package/dist-cli/chunks/{chunk-XCCDO6I2.js → chunk-445FUUZC.js} +1 -1
- package/dist-cli/chunks/{chunk-T2DHHOWE.js → chunk-4EAJWGB4.js} +2 -2
- package/dist-cli/chunks/chunk-63UBXHOB.js +4 -0
- package/dist-cli/chunks/{chunk-Y6FJ5FCY.js → chunk-6YIHNXMZ.js} +1 -1
- package/dist-cli/chunks/{chunk-DKS75M2I.js → chunk-74ATIHUI.js} +2 -2
- package/dist-cli/chunks/{chunk-UBIGBHUM.js → chunk-7O6HJRGX.js} +2 -2
- package/dist-cli/chunks/{chunk-UWFAWMPE.js → chunk-7XXIMTJR.js} +2 -2
- package/dist-cli/chunks/{chunk-I4QJVACX.js → chunk-AC2HNBEI.js} +1 -1
- package/dist-cli/chunks/chunk-BAFDYXCM.js +9 -0
- package/dist-cli/chunks/chunk-DMJN3NC3.js +12 -0
- package/dist-cli/chunks/{chunk-JPPGM6RZ.js → chunk-E4O5A2QP.js} +2 -2
- package/dist-cli/chunks/{chunk-FH7DQ2HB.js → chunk-EKA2DXOV.js} +2 -2
- package/dist-cli/chunks/{chunk-S6BEA6OC.js → chunk-ERRHAM2H.js} +1 -1
- package/dist-cli/chunks/{chunk-MEYVMDZR.js → chunk-FC2ULGKP.js} +2 -2
- package/dist-cli/chunks/{chunk-RNW36VM5.js → chunk-H6RQAFD5.js} +4 -4
- package/dist-cli/chunks/{chunk-2RI6RC6I.js → chunk-HNQ2FYAG.js} +2 -2
- package/dist-cli/chunks/{chunk-CVDC2ER2.js → chunk-HRPE3IND.js} +2 -2
- package/dist-cli/chunks/chunk-HTX6BHJZ.js +4 -0
- package/dist-cli/chunks/{chunk-6VF477QO.js → chunk-I4G2BKZB.js} +1 -1
- package/dist-cli/chunks/chunk-I6HFNMYG.js +125 -0
- package/dist-cli/chunks/{chunk-L7V46673.js → chunk-IKQSTS2U.js} +1 -1
- package/dist-cli/chunks/{chunk-7GZ6XF2B.js → chunk-IMXVXXWX.js} +2 -2
- package/dist-cli/chunks/{chunk-E6DZD6JD.js → chunk-IVV2KJTY.js} +1 -1
- package/dist-cli/chunks/{chunk-WFYQNZTT.js → chunk-K36T5764.js} +3 -3
- package/dist-cli/chunks/{chunk-SU5WQ4SQ.js → chunk-KQ7WHS3C.js} +1 -1
- package/dist-cli/chunks/{chunk-TNKZWHD2.js → chunk-LGU5JGT6.js} +1 -1
- package/dist-cli/chunks/{chunk-U2QPKFOY.js → chunk-O4IGQ7XT.js} +2 -2
- package/dist-cli/chunks/{chunk-UAZ3NVKO.js → chunk-OBKNUUIF.js} +2 -2
- package/dist-cli/chunks/chunk-OTYWESTV.js +4 -0
- package/dist-cli/chunks/chunk-QDL6YYL4.js +4 -0
- package/dist-cli/chunks/{chunk-XQRUWC3F.js → chunk-QRFC2ZZC.js} +2 -2
- package/dist-cli/chunks/chunk-RZQ7SBBQ.js +4 -0
- package/dist-cli/chunks/chunk-SDHGPSEC.js +4 -0
- package/dist-cli/chunks/{chunk-X5FTDIHQ.js → chunk-U37NEIQF.js} +1 -1
- package/dist-cli/chunks/chunk-V4N34AOX.js +15 -0
- package/dist-cli/chunks/{chunk-K7LQB4IF.js → chunk-VTYVJJHN.js} +1 -1
- package/dist-cli/chunks/chunk-VVSQCLBU.js +6 -0
- package/dist-cli/chunks/chunk-W2QIWNCW.js +6 -0
- package/dist-cli/chunks/{chunk-QPA44BZC.js → chunk-WDZ4PVKV.js} +11 -11
- package/dist-cli/chunks/chunk-WFXFYXUA.js +30 -0
- package/dist-cli/chunks/chunk-X5J5A63F.js +23 -0
- package/dist-cli/chunks/chunk-XKACQ3MD.js +4 -0
- package/dist-cli/chunks/{chunk-ETDZQUGI.js → chunk-XLT6Y654.js} +3 -3
- package/dist-cli/chunks/{chunk-4NJIXTVJ.js → chunk-Y7TQDOU5.js} +1 -1
- package/dist-cli/chunks/{chunk-7FYIMLU4.js → chunk-YNN2AELC.js} +17 -17
- package/dist-cli/chunks/{chunk-BX2NUJGR.js → chunk-YTTBKONB.js} +1 -1
- package/dist-cli/chunks/{chunk-3WQISFAK.js → chunk-Z3VP4WF6.js} +1 -1
- package/dist-cli/chunks/cleanup-Q4GUW4DU.js +25 -0
- package/dist-cli/chunks/{cli-version-I6BOBK57.js → cli-version-Y74RBK4R.js} +2 -2
- package/dist-cli/chunks/compat-CSFBMTVO.js +20 -0
- package/dist-cli/chunks/config-4ZW7VYBV.js +13 -0
- package/dist-cli/chunks/control-BFFHTY4I.js +4 -0
- package/dist-cli/chunks/daemon-746DWYWS.js +4 -0
- package/dist-cli/chunks/{debug-VG2JOF6H.js → debug-EEYUHHSR.js} +3 -3
- package/dist-cli/chunks/{desktop-GH2POW6X.js → desktop-Q4NXGDCY.js} +3 -3
- package/dist-cli/chunks/{detox-X6T265L5.js → detox-UMSQ33AB.js} +2 -2
- package/dist-cli/chunks/{device-VDOOSAXO.js → device-7STN6X5G.js} +2 -2
- package/dist-cli/chunks/{diagnose-6D6WNAGL.js → diagnose-7L67FGJY.js} +2 -2
- package/dist-cli/chunks/disk-cleanup-IISQYADA.js +4 -0
- package/dist-cli/chunks/drivers-RD6OW2D5.js +4 -0
- package/dist-cli/chunks/{film-UZWYISAB.js → film-2MP5BL6J.js} +3 -3
- package/dist-cli/chunks/flow-MKSEPFWS.js +4 -0
- package/dist-cli/chunks/help-4ADSAOGD.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-UGMJ4LJX.js → hidden-runtime-alias-HTJVTEHX.js} +2 -2
- package/dist-cli/chunks/home-paths-KOZFBUVS.js +4 -0
- package/dist-cli/chunks/inspect-6D7Q27PN.js +4 -0
- package/dist-cli/chunks/install-desktop-WZBAUSKT.js +4 -0
- package/dist-cli/chunks/{login-K43TRKUC.js → login-XWITDS34.js} +4 -4
- package/dist-cli/chunks/{logout-L43CR6M2.js → logout-C6EVSNGO.js} +2 -2
- package/dist-cli/chunks/{maestro-7VZFYLNS.js → maestro-Y3RDSX5X.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-PMYHUVH4.js → maestro-generate-WHUYPFMX.js} +3 -3
- package/dist-cli/chunks/{mode-QQS5XFFX.js → mode-3D6W3Y2Y.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-2V327HDG.js → optional-demo-registry-MRBZKL5R.js} +2 -2
- package/dist-cli/chunks/{perf-CL5P3JVP.js → perf-CRMSVQX4.js} +2 -2
- package/dist-cli/chunks/{permissions-RGVCEC2B.js → permissions-RFASUZIH.js} +2 -2
- package/dist-cli/chunks/{record-ASW6UFQT.js → record-SKX3SUNS.js} +3 -3
- package/dist-cli/chunks/report-issue-I7VXCIGQ.js +29 -0
- package/dist-cli/chunks/runtime-OJ26HJM7.js +4 -0
- package/dist-cli/chunks/{screenshot-command-FEJGQMQF.js → screenshot-command-PIMVRGAW.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-3JPZ5WMX.js → screenshots-capture-RRZUJDIO.js} +2 -2
- package/dist-cli/chunks/serve-JHBXNJ77.js +44 -0
- package/dist-cli/chunks/setup-A3I3R4FB.js +32 -0
- package/dist-cli/chunks/{skills-T6EEX5P6.js → skills-7KS6HD4G.js} +2 -2
- package/dist-cli/chunks/{storage-ZFUK4EQA.js → storage-H2ODISXF.js} +2 -2
- package/dist-cli/chunks/store-ARKALTX7.js +4 -0
- package/dist-cli/chunks/telemetry-ZMRUVMCZ.js +4 -0
- package/dist-cli/chunks/{timeline-EIURYQVC.js → timeline-5N5AUCOX.js} +2 -2
- package/dist-cli/chunks/upgrade-UM4K5PH4.js +7 -0
- package/dist-cli/chunks/upload-WGPI5XX6.js +4 -0
- package/dist-cli/chunks/version-B2MBTUMC.js +6 -0
- package/dist-cli/chunks/web-ZM5Y5GRE.js +4 -0
- package/dist-cli/chunks/{what-happened-L5ZN7S5G.js → what-happened-K443NB2H.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +3 -2
- package/dist-lib/detox/index.cjs +312 -27
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +41 -14
- package/dist-lib/host/bridge-host.cjs +215 -84
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2 -2
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +2 -3
- package/dist-lib/menu.mjs +2 -3
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +2 -2
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +366 -154
- package/dist-lib/vite.cjs +2 -2
- package/package.json +2 -1
- package/scripts/postinstall.cjs +2 -78
- package/skills/contrast/SKILL.md +1 -0
- package/skills/sootsim-setup/SKILL.md +25 -0
- package/src/config.ts +4 -0
- package/src/disk-cleanup.ts +5 -26
- package/src/home-paths.ts +58 -23
- package/src/host/bridge-host.ts +152 -57
- package/src/menu.ts +0 -1
- package/src/runtime-assets.ts +35 -0
- package/src/runtime-delivery.ts +5 -8
- package/src/skills/builtin/compat-check.ts +32 -65
- package/dist-cli/chunks/app-fonts-36N7AVQ3.js +0 -4
- package/dist-cli/chunks/chunk-4ODQVUBH.js +0 -6
- package/dist-cli/chunks/chunk-4V2KYK5T.js +0 -4
- package/dist-cli/chunks/chunk-7GVBNEQ3.js +0 -9
- package/dist-cli/chunks/chunk-COEKUTWV.js +0 -4
- package/dist-cli/chunks/chunk-D2DU3ROC.js +0 -6
- package/dist-cli/chunks/chunk-DXCQP3VE.js +0 -12
- package/dist-cli/chunks/chunk-HT6WYHQL.js +0 -6
- package/dist-cli/chunks/chunk-I7AWRAXM.js +0 -125
- package/dist-cli/chunks/chunk-OQ7SSRYK.js +0 -4
- package/dist-cli/chunks/chunk-QKZVANQG.js +0 -31
- package/dist-cli/chunks/chunk-TGYZYSDB.js +0 -15
- package/dist-cli/chunks/chunk-TXURXDZN.js +0 -4
- package/dist-cli/chunks/chunk-ZJZYGLJ2.js +0 -4
- package/dist-cli/chunks/cleanup-SMCA44QC.js +0 -25
- package/dist-cli/chunks/compat-FCM2ZQLV.js +0 -35
- package/dist-cli/chunks/config-PZSANSAI.js +0 -13
- package/dist-cli/chunks/control-PM554MHE.js +0 -4
- package/dist-cli/chunks/daemon-5KXEZZLJ.js +0 -4
- package/dist-cli/chunks/disk-cleanup-HTOIDDKK.js +0 -4
- package/dist-cli/chunks/drivers-CKLBQDXG.js +0 -4
- package/dist-cli/chunks/flow-VOS3RKB3.js +0 -4
- package/dist-cli/chunks/help-LVMDERFQ.js +0 -4
- package/dist-cli/chunks/home-paths-3LYT47SY.js +0 -4
- package/dist-cli/chunks/inspect-FHCSOWGQ.js +0 -4
- package/dist-cli/chunks/install-desktop-KLMCVDGZ.js +0 -4
- package/dist-cli/chunks/runtime-GB3ZE27C.js +0 -4
- package/dist-cli/chunks/serve-SYXRHRQO.js +0 -44
- package/dist-cli/chunks/setup-QLGL6MC6.js +0 -99
- package/dist-cli/chunks/store-WCDTSWJC.js +0 -4
- package/dist-cli/chunks/telemetry-D7SL4WW7.js +0 -4
- package/dist-cli/chunks/upgrade-Q7ZGWMCJ.js +0 -6
- package/dist-cli/chunks/upload-7XEICYJX.js +0 -4
- package/dist-cli/chunks/version-PDG4V26R.js +0 -6
- package/dist-cli/chunks/web-AMW2TRWB.js +0 -4
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{a as k}from"./chunk-SDHGPSEC.js";import{createHash as j}from"node:crypto";import D from"node:fs";import{createRequire as L}from"node:module";import x from"node:path";var P=/(^|\/)expo-splash-screen$/,A=/(^|\/)react-native-bootsplash$/;function w(n,e){let r=e.replace(/\/+$/,""),s=n.replace(/^\.\//,"").replace(/^\/+/,"");if(s)return`${r}/assets/${s}`}function d(n,e,r){return r?r(n):w(n,e)}function y(n){if(n==="cover")return"cover";if(n==="contain"||n==="native")return"contain"}function p(n){return typeof n=="string"&&n.length>0?n:void 0}function m(n){return typeof n=="number"&&Number.isFinite(n)?n:void 0}function R(n,e,r){if(!n||typeof n!="object")return null;let s=n,o={source:"expo-splash-screen",backgroundColor:p(s.backgroundColor)??"#ffffff"},i=p(s.image);i&&(o.imageUrl=d(i,e,r));let t=m(s.imageWidth);t!=null&&(o.imageWidthPx=t);let l=y(s.resizeMode);l&&(o.resizeMode=l);let a=s.dark;if(a&&typeof a=="object"){let u=a,g=p(u.backgroundColor),f=p(u.image);(g||f)&&(o.dark={},g&&(o.dark.backgroundColor=g),f&&(o.dark.imageUrl=d(f,e,r)))}return o}function U(n,e,r,s){let c=n[e],o=c&&typeof c=="object"?c.splash:void 0,i=n.splash,t=o&&typeof o=="object"?o:i;if(!t||typeof t!="object")return null;let a={source:"expo-legacy",backgroundColor:p(t.backgroundColor)??"#ffffff",imageWidthPx:m(t.imageWidth)??200,resizeMode:y(t.resizeMode)??"contain"},u=p(t.image);u&&(a.imageUrl=d(u,r,s));let g=t.dark;if(g&&typeof g=="object"){let f=g,h=p(f.backgroundColor),S=p(f.image);(h||S)&&(a.dark={},h&&(a.dark.backgroundColor=h),S&&(a.dark.imageUrl=d(S,r,s)))}return a}function v(n,e,r){if(!n||typeof n!="object")return null;let s=n,c=p(s.logo);if(!c)return null;let o={source:"react-native-bootsplash",backgroundColor:p(s.background)??"#fff",imageUrl:d(c,e,r),imageWidthPx:m(s.logoWidth)??100,resizeMode:"contain"},i=p(s.darkBackground),t=p(s.darkLogo);return(i||t)&&(o.dark={},i&&(o.dark.backgroundColor=i),t&&(o.dark.imageUrl=d(t,e,r))),o}function C(n,e,r,s={}){if(!n||typeof n!="object")return null;let c=n,o=c.plugins,i=null,t=null;if(Array.isArray(o))for(let l of o){let a=Array.isArray(l)?l[0]:l;if(typeof a!="string")continue;let u=Array.isArray(l)?l[1]??{}:{};!i&&P.test(a)?i=R(u,r,s.resolveAssetUrl):!t&&A.test(a)&&(t=v(u,r,s.resolveAssetUrl))}return t||i||U(c,e,r,s.resolveAssetUrl)}var b=L(import.meta.url);function E(n){try{let e=new URL(n),r=e.hostname.replace(/^\[|\]$/g,"").toLowerCase();if(r==="localhost"||r.endsWith(".localhost")||r==="0.0.0.0"||r==="::1"||/^127(?:\.\d{1,3}){3}$/.test(r))return e.origin}catch{}return null}function I(n){try{return D.statSync(x.join(n,"package.json")).isFile()}catch{return!1}}function G(n){let e=E(n.bundleUrl);if(!e)return null;let r=n.repoDir||process.env.CONTRAST_REPO_DIR,s=r?x.resolve(r):process.cwd();if(!r&&!I(s))return null;let o=k(s,{trustStart:n.exactProjectDir})?.appDir??null;if(!o)return null;let i=(n.platform||process.env.CONTRAST_PLATFORM||"ios").toLowerCase(),t=null;try{let a=b.resolve("@expo/config",{paths:[o,s]}),u=b(a);typeof u.getConfig=="function"&&(t=u.getConfig)}catch{}if(!t)return null;let l;try{let a=t(o,{skipSDKVersionRequirement:!0});a?.exp&&typeof a.exp=="object"&&(l=a.exp)}catch{}return!l||typeof l!="object"?null:C(l,i==="android"?"android":"ios",e)}function q(n){return encodeURIComponent(JSON.stringify(n))}function z(n){if(!n)return null;try{let e=JSON.parse(decodeURIComponent(n));if(!e||typeof e!="object")return null;let r=e;return r.source!=="expo-splash-screen"&&r.source!=="expo-legacy"&&r.source!=="react-native-bootsplash"||typeof r.backgroundColor!="string"?null:e}catch{return null}}function M(n){let e=new Set;return n.imageUrl&&e.add(n.imageUrl),n.dark?.imageUrl&&e.add(n.dark.imageUrl),[...e]}function F(n){let e=(n.split("?")[0].split(".").pop()||"").toLowerCase();return e==="png"?"image/png":e==="jpg"||e==="jpeg"?"image/jpeg":e==="webp"?"image/webp":e==="gif"?"image/gif":e==="svg"?"image/svg+xml":"application/octet-stream"}async function H(n,e){let r=z(n);if(!r)return[];let s=[],c=new Set;for(let o of M(r)){let i=j("sha256").update(o).digest("hex");if(!c.has(i)){c.add(i);try{let t=await fetch(o);if(!t.ok){e?.onError?.(o,new Error(`${t.status} ${t.statusText}`));continue}let l=new Uint8Array(await t.arrayBuffer());s.push({url:o,urlhash:i,contentType:F(o),bytes:l}),e?.onStaged?.({url:o,byteLength:l.byteLength})}catch(t){e?.onError?.(o,t)}}}return s}export{G as a,q as b,H as c};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
var p={"--help":{type:"boolean",short:"-h"},"--version":{type:"boolean",short:"-V"},"--verbose":{type:"boolean",short:"-v"},"--port":{type:"number",short:"-p"},"--device":{type:"string",short:"-d"},"--theme":{type:"string",short:"-t"},"--headless":{type:"boolean"},"--driver":{type:"string"},"--sim":{type:"string"},"--session":{type:"string"},"--tab":{type:"string"}},m=new Set(["list","describe","find","get","do","wait","network","logs","shell"]),d=new Set(["do","get","wait","shell","debug"]),b=new Set(["detox","maestro","record","film","storage","permissions","perf","screenshot","mode","inspect","debug","timeline","what-happened","shell","assert","device","open","list","use","claim","close","compat","report-issue","desktop","login","logout","auth","setup","serve","daemon","runtime","upgrade","update","version","skill","config","cleanup","app-fonts","agent-wrapper","agent",...m]);function u(c){let r=c.slice(2),e={command:null,commandArgs:[],globalFlags:{},help:!1,version:!1,verbose:!1},s=0;for(;s<r.length;){let o=r[s];if(o==="--"){e.commandArgs.push(...r.slice(s+1));break}let i=Object.entries(p).find(([a,t])=>a===o||t.short===o);if(i){let[a,t]=i,l=a.replace(/^--/,"");if(t.type==="boolean")e.globalFlags[l]=!0,s++;else{let n=r[s+1];if(n===void 0||n.startsWith("-")){console.error(` warning: ${o} requires a value`),s++;continue}if(t.type==="number"){let g=Number(n);if(Number.isNaN(g)){console.error(` warning: ${o} requires a number, got "${n}"`),s+=2;continue}e.globalFlags[l]=g}else e.globalFlags[l]=n;s+=2}continue}if(!e.command&&!o.startsWith("-")){let a=o.indexOf("-");if(a>0){let t=o.slice(0,a),l=o.slice(a+1);if(d.has(t)&&l.length>0){e.command=t;let n=r.slice(s+1);e.commandArgs=[l,...n[0]==="--"?n.slice(1):n];break}}if(b.has(o)){e.command=o;let t=r.slice(s+1);e.commandArgs=t[0]==="--"?t.slice(1):t;break}e.commandArgs=r.slice(s);break}e.commandArgs.push(o),s++}return e.help=!!e.globalFlags.help,e.version=!!e.globalFlags.version,e.verbose=!!e.globalFlags.verbose,e}export{m as a,u as b};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
3
|
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
-
import{
|
|
4
|
+
import{l as n}from"./chunk-XLT6Y654.js";var i=[];for(let[t,e]of Object.entries(n))e.cliFlag&&i.push({name:`--${e.cliFlag}`,short:e.cliFlagShort?`-${e.cliFlagShort}`:void 0,key:t,type:e.type==="enum"?"string":e.type,description:e.description,options:e.options,default:e.default});var a=i;function g(){let t=[];for(let e of a){let s=e.short?`${e.short}, ${e.name}`:` ${e.name}`,o=e.options?` [${e.options.join("|")}]`:"",r=e.default!==void 0?` (default: ${e.default})`:"";t.push(` ${s.padEnd(24)}${e.description}${o}${r}`)}return t.join(`
|
|
5
5
|
`)}export{g as a};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{c as P,k as m,l as S,m as R,n as _,o as v}from"./chunk-XLT6Y654.js";var k="sootsim:settings",d=["productAnalytics","crashReports","colorScheme","reduceMotion","boldText","fontSize","largerAccessibilitySizes","a11yMode","a11yDepth","screenshotCanvas","screenshotBackground","screenshotText","screenshotPose","screenshotDynamicSize","alwaysShowLiveWebViews","showFrame","showMenuBar","showRail","solidWindow","ambientGlow","agentProvider"];function p(){if(typeof window>"u")return null;let e=window.sootsimElectron;return e&&typeof e=="object"?e:null}function l(e){let t={};for(let n of d){if(!(n in e))continue;let o=e[n],i=S[n];i.validate&&!i.validate(o)||i.options&&!i.options.includes(o)||(t[n]=o)}return t}function K(e){let t={};for(let n of d)t[n]=e[n];return t}function M(){if(typeof localStorage>"u")return{};try{let e=localStorage.getItem(k);return e?l(JSON.parse(e)):{}}catch{return{}}}function T(e){if(!(typeof localStorage>"u"))try{localStorage.setItem(k,JSON.stringify(e))}catch{}}function x(){let t=p()?.sharedConfig?.settings;return!t||typeof t!="object"?{}:l(t)}function A(e){let t=p();if(t?.writeSharedConfig)try{t.writeSharedConfig({settings:e})}catch{}}async function L(e){let t=p();return t?.writeSharedConfig?(await t.writeSharedConfig({settings:e}),!0):!1}function b(){if(typeof window>"u")return null;let e=window.__sootsimSharedConfig;return e&&typeof e=="object"?e:null}function O(){let e=b()?.settings;return!e||typeof e!="object"?{}:l(e)}function B(e){if(!b())return;let t={settings:e};try{if(globalThis.__sootsimBridgeRequest?.writeSharedConfig?.(t))return}catch{}if(!(typeof fetch>"u"))try{fetch("/__sootsim/shared-config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),keepalive:!0}).catch(()=>{})}catch{}}async function F(e){if(!b()||typeof fetch>"u")return!1;let t=await fetch("/__sootsim/shared-config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({settings:e}),keepalive:!0});if(!t.ok)throw new Error(`shared settings reset failed with HTTP ${t.status}`);return await t.text(),!0}function D(){let e=M(),t=O(),n=x();return{...e,...t,...n}}function V(e,t={}){let n=K(e);for(let o of d)t[o]!==void 0&&(n[o]=t[o]);T(n),A(n),B(n)}async function I(e,t={}){let n=K(e);for(let o of d)t[o]!==void 0&&(n[o]=t[o]);T(n),!await L(n)&&await F(n)}function j(e){if(typeof window>"u")return()=>{};let t=r=>{if(!(r.key!==k||r.newValue==null))try{e(l(JSON.parse(r.newValue)))}catch{}};window.addEventListener("storage",t);let n=p(),o;n?.onSharedConfigChanged&&(o=n.onSharedConfigChanged(r=>{let f=r?.settings;!f||typeof f!="object"||e(l(f))}));let a=globalThis.__sootsimBridgeRequest?.subscribeSharedConfig?.(r=>{let f=r?.settings;!f||typeof f!="object"||e(l(f))});return()=>{window.removeEventListener("storage",t),o?.(),a?.()}}var N=_(),q=v(),y=D(),c=new Set,g={};for(let e of d)N[e]!==void 0&&(c.add(e),y[e]!==void 0&&(g[e]=y[e]),delete y[e]);var s={...q,...y},w=[],u=null;function h(){for(let e of w)e()}function E(){h(),V(s,g)}function C(e,t){let n=S[e];return n.validate&&!n.validate(t)||n.options&&!n.options.includes(t)||s[e]===t?!1:(s={...s,[e]:t},e==="deviceModel"&&(u=null),!0)}j(e=>{let t={...s},n=!1;for(let[o,i]of Object.entries(e)){let a=o;if(c.has(a)){g[a]=i;continue}t[a]!==i&&(t[a]=i,n=!0)}n&&(s=t,u=null,h())});var z={get(e){return s[e]},set(e,t){C(e,t)&&E()},setRuntime(e,t){c.has(e)||(c.add(e),d.includes(e)&&(g[e]=s[e])),C(e,t)&&h()},isRuntimeControlled(e){return c.has(e)},getAll(){return s},apply(e){let t=!1,n={...s};for(let[o,i]of Object.entries(e)){if(i===void 0)continue;let a=o,r=S[a];r&&(r.validate&&!r.validate(i)||r.options&&!r.options.includes(i)||n[a]!==i&&(n[a]=i,t=!0))}t&&(s=n,u=null,E())},applyRuntime(e){let t=!1;for(let n of Object.keys(e)){let o=e[n];o!==void 0&&(c.has(n)||(c.add(n),d.includes(n)&&(g[n]=s[n])),C(n,o)&&(t=!0))}t&&h()},reset(){s=v(),u=null,E()},async resetDeviceContent(){let e=m.filter(n=>!c.has(n)).map(n=>[n,R[n]]),t=e.some(([n,o])=>s[n]!==o);s={...s,...Object.fromEntries(e)};for(let n of m)c.has(n)&&(g[n]=R[n]);t&&h(),await I(s,g)},subscribe(e){return w.push(e),()=>{w=w.filter(t=>t!==e)}},getDeviceSpec(){return u||(u=P(s.deviceModel)),u},getA11yMode(){return s.a11yMode},setA11yMode(e){this.set("a11yMode",e)},getInspectMode(){return s.inspectMode},setInspectMode(e){this.set("inspectMode",e)}};export{z as a};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import g from"node:fs";import l from"node:path";var k=["app.config.js","app.config.ts","app.config.cjs","app.config.mjs","app.json"],b=["sootsim.config.ts","sootsim.config.js","sootsim.config.mjs","sootsim.config.cjs"],D=new Set(["node_modules","artifacts","dist","build","out","coverage","tmp","public","ios","android","macos","windows","__fixtures__","__tests__","fixtures","fixture","examples","example"]),d=256,A=4,y=50;function _(o,c){for(let t of c){let n=l.join(o,t);try{if(g.statSync(n).isFile())return n}catch{}}return null}function S(o){return _(o,k)}function m(o){return _(o,b)}function j(o){try{let c=JSON.parse(g.readFileSync(l.join(o,"package.json"),"utf8"));if(!c||typeof c!="object")return[];let t=Reflect.get(c,"workspaces");if(Array.isArray(t))return t.filter(s=>typeof s=="string");if(!t||typeof t!="object")return[];let n=Reflect.get(t,"packages");return Array.isArray(n)?n.filter(s=>typeof s=="string"):[]}catch{return[]}}function w(o){let c=Date.now(),t=new Set,n=0,s=!0;for(let a of j(o)){if(n>=d||Date.now()-c>=y){s=!1;break}if(!a||l.isAbsolute(a))continue;let f=a.split(/[\\/]+/).filter(Boolean);if(f.length===0||f.length>A||f.some(e=>e===".."||e==="**"))continue;let r=[o];for(let e of f){let i=[];for(let u of r){if(n>=d||Date.now()-c>=y){s=!1;break}if(n++,e==="*"){let h;try{h=g.readdirSync(u,{withFileTypes:!0})}catch{continue}for(let p of h)!p.isDirectory()||p.isSymbolicLink()||p.name.startsWith(".")||D.has(p.name)||i.push(l.join(u,p.name))}else if(!e.includes("*")){let h=l.join(u,e);try{let p=g.lstatSync(h);p.isDirectory()&&!p.isSymbolicLink()&&i.push(h)}catch{}}}r=i,r.length>d&&(r.length=d,s=!1)}for(let e of r)t.add(e)}return{directories:[...t],complete:s}}function x(o){let c=Date.now(),t=[{dir:o,depth:0}],n=[],s=0,a=0,f=!0;for(;a<t.length&&s<d&&Date.now()-c<y;){let r=t[a++];if(!r)break;if(s++,r.depth>0&&S(r.dir)&&(n.push(r.dir),n.length>1))return{directories:n,complete:!0};if(r.depth>=A)continue;let e;try{e=g.readdirSync(r.dir,{withFileTypes:!0})}catch{continue}for(let i of e)if(!(!i.isDirectory()||i.isSymbolicLink())&&!(i.name.startsWith(".")||D.has(i.name))){if(t.length>=d){f=!1;break}t.push({dir:l.join(r.dir,i.name),depth:r.depth+1})}}return{directories:n,complete:f&&a===t.length}}function C(o,c={}){let t=l.resolve(o),n=m(t);if(S(t)||c.trustStart&&g.existsSync(t)){let e=n;if(!e&&c.trustStart){let i=l.dirname(t);for(let u=0;u<A&&i!==l.dirname(i)&&(e=m(i),!e);u++)i=l.dirname(i)}return{appDir:t,configPath:e}}let s=w(t),a=s.directories.filter(e=>S(e));if(a.length>1||!s.complete)return null;if(a.length===1){let e=a[0];return{appDir:e,configPath:n??m(e)}}let f=x(t),r=f.directories;if(r.length>1||!f.complete)return null;if(r.length===1){let e=r[0];return{appDir:e,configPath:n??m(e)}}return n?{appDir:t,configPath:n}:null}export{C as a};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
3
|
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
4
|
import{readFileSync as i}from"node:fs";import{fileURLToPath as e}from"node:url";var r=null;function l(){if(r!=null)return r;let o=[()=>e(import.meta.resolve("sootsim/package.json")),()=>e(new URL("../package.json",import.meta.url))];for(let n of o)try{let t=JSON.parse(i(n(),"utf8")).version;if(typeof t=="string"&&t)return r=t,r}catch{}return r="0.0.0",r}export{l as a};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{a as Ne,b as q,c as de,d as ue,e as Fe,f as je,h as x,i as We,j as Ke}from"./chunk-DMJN3NC3.js";import{m as O}from"./chunk-7O6HJRGX.js";import{m as _e,p as Oe}from"./chunk-ERRHAM2H.js";import{b as He,l as he}from"./chunk-4EAJWGB4.js";import{a as B,b as pe}from"./chunk-AC2HNBEI.js";import{a as Ge,b as Je}from"./chunk-OTYWESTV.js";import{a as qe,b as z,c as ze}from"./chunk-3QVML26F.js";import{d as fe}from"./chunk-LGU5JGT6.js";import{a as Ve}from"./chunk-X5J5A63F.js";import{a as me}from"./chunk-SDHGPSEC.js";import{b as Be,c as De,d as ce,f as Ae,g as Le,h as M,i as v,j as E}from"./chunk-IMXVXXWX.js";import{f as Ee}from"./chunk-VVSQCLBU.js";import{b as le,d as Ue}from"./chunk-XLT6Y654.js";import{d as Te,e as T,f as b,g as _}from"./chunk-VTYVJJHN.js";import{H as Re,K as ae,M as V,O as Me,l as ie}from"./chunk-BAFDYXCM.js";import{spawn as ot,spawnSync as nt}from"node:child_process";import U from"node:fs";import Ct from"node:os";import C from"node:path";import{WebSocket as Rt}from"ws";function Qe(e){return new Error(`could not resolve a native bundle for ${e}. pass an explicit bundle URL or open Connect and choose the app there.`)}function vt(e,o){return e?.includes("/one/metro-entry.bundle")?"one":typeof o=="string"&&o?"expo":"unknown"}function Ze(e,o,t){return`${e}//${o}:${t}`}function St(e){if(typeof window>"u")return!1;try{let o=new URL(e);return x(o.hostname)&&x(window.location.hostname)&&o.origin!==window.location.origin}catch{return!1}}async function Ye(e,o){let t={...o,cache:o?.cache??"no-store"};return St(e)?fetch(`/__fetch-proxy?url=${encodeURIComponent(e)}`,t):fetch(e,t)}function $t(e){return e==="https:"?443:80}function xt(e){let o=e.pathname||"/";return(o==="/"||o==="")&&!e.search&&!e.hash}async function Pt(e){try{let o=await fetch("/__server-scan",{cache:"no-store"});if(!o.ok||!(o.headers.get("content-type")||"").toLowerCase().includes("json"))return null;let t=await o.json();if(!Array.isArray(t))return null;let n=t.find(r=>!!r&&typeof r=="object"&&r.port===e&&typeof r.bundleUrl=="string");return n?{bundleUrl:ue(n.bundleUrl),port:e,framework:typeof n.framework=="string"?n.framework:"unknown",projectName:typeof n.projectName=="string"?n.projectName:void 0}:null}catch{return null}}async function Xe(e,o){let t=e.replace(/\/+$/,"");try{if(x(new URL(t).hostname)){let n=await Pt(o);if(n)return n}}catch{}try{let n=await Ye(`${t}/`,{headers:{"expo-platform":"ios"}});if(n.ok){let r=await n.json(),s=r?.extra?.expoClient||r?.extra||{},i=typeof r?.launchAsset?.url=="string"?r.launchAsset.url:void 0;if(i||s.name)return{bundleUrl:ue(i||`${t}${de}`),port:o,framework:vt(i,s.sdkVersion),projectName:s.name}}}catch{}try{let n=await Ye(`${t}/status`);if(n.ok&&(await n.text()).includes("packager-status:running"))return{bundleUrl:`${t}${de}`,port:o,framework:"metro"}}catch{}return null}async function kt(e){return Xe(Ze("http:","localhost",e),e)}async function et(e){let o=e.trim();if(/^\d+$/.test(o)){let a=parseInt(o,10),l=await kt(a);if(l)return l;throw Qe(`localhost:${a}`)}let t=o.startsWith("http")?o:`http://${o}`,n;try{n=new URL(t)}catch{throw new Error(`could not parse "${e}". pass a dev-server port, a dev-server base URL, or a full bundle URL.`)}let r=n.protocol||"http:",s=n.port?parseInt(n.port,10):$t(r),i=Ze(r,n.hostname,s);if(xt(n)){let a=await Xe(i,s);if(a)return a;throw Qe(i)}return{bundleUrl:n.toString(),port:s,framework:"unknown"}}function Po(){console.error(" no sootsim desktop companion found."),console.error(""),console.error(" install the desktop app:"),console.error(" sootsim desktop install"),console.error(""),console.error(" or run setup to install the background daemon:"),console.error(" sootsim setup"),console.error("")}function tt(e){let o=B();if(console.log(` note: no sootsim bridge detected on port ${e}`),o){console.log(" launch the installed companion with:"),console.log(" sootsim desktop");return}console.log(""),console.log(" run `sootsim setup` to install the background daemon,"),console.log(" or run `sootsim serve` in another shell for a foreground bridge.")}function It(e){console.error(""),console.error(` no sim is connected to the sootsim bridge on port ${e}.`),console.error(""),console.error(" start your app dev server, then open it in sootsim:"),console.error(" npx expo start --localhost --port 8081"),console.error(" sootsim open 8081"),console.error(""),console.error(" then inspect the live app:"),console.error(" sootsim describe")}async function ko(e,o,t){let n=[];try{n=await e.listSims()}catch{}if(console.error(""),n.length===0){It(o);return}console.error(` no sim with id "${t}" is connected to the bridge on port ${o}.`),console.error(""),console.error(" connected sims:");for(let r of n){let s=[r.isPrimary?"primary":null,r.readyState,r.userVisible===!1?"hidden":r.userVisible===!0?"visible":null,r.userFocused?"focused":null].filter(Boolean).join(", ");console.error(` ${r.id} (${s})`)}console.error(""),console.error(" pass a valid --sim id, or run `sootsim list` to see all sessions.")}var Mt=12e4,rt=100,Et=5e3,st=1e4,Ut={rn:"/rn",connectrn:"/rn","connect-rn":"/rn",clock:"/app/clock","native-ui":"/app/native-ui",tamagui:"/app/tamagui",settings:"/app/settings",photos:"/app/photos",camera:"/app/camera"};function $(e){return new Promise(o=>setTimeout(o,e))}function it(e){let o=process.env[e]?.trim();if(!o)return null;let t=Number(o);return Number.isInteger(t)&&t>0?t:null}function Tt(){let e=it("SOOTSIM_DRIVER_CONNECT_TIMEOUT_MS")??it("SOOTSIM_PW_CONNECT_TIMEOUT_MS")??Mt;return{timeoutMs:e,hostTimeoutMs:e+Et,intervalMs:rt,attempts:Math.max(1,Math.ceil(e/rt))}}function _t(e){return e==="chromium"||e==="electron"||e==="playwright"||e==="system"}function Ot(e,o){return e.includes("--headless")?!0:e.includes("--headed")?!1:o==="playwright"&&process.platform==="linux"&&!process.env.DISPLAY&&!process.env.WAYLAND_DISPLAY?(console.error(" no display detected \u2192 running playwright headless (override with --headed)"),!0):!1}function Q(e){return e.trim()}var dt=/^[A-Za-z][A-Za-z0-9+.-]*:/;function Bt(e){let o=e.trim();if(!o)throw new Error("expected <url-or-route>");return dt.test(o)||o.startsWith("/")?o:`/${o}`}function Dt(e){return e!==null&&typeof e=="object"}function At(e){let o=e.trim();return o?o.startsWith("/")?!0:dt.test(o)?!/^https?:\/\//i.test(o):!1:!1}async function Lt(e){if(await G(e,250))return e;let o=ae();if(o&&V(o)&&await G(o.bridgePort,500))return o.bridgePort;if(o&&V(o))throw new Error(`sootsim bridge lockfile is fresh (port ${o.bridgePort}) but the bridge is not reachable. run \`sootsim daemon restart\` or \`sootsim daemon uninstall\`.`);await Nt();let t=Ft(["serve","--quiet","--port",String(e)]),n=null;t.once("exit",(s,i)=>{n=String(s??i??"unknown")}),t.unref();let r=Date.now()+st;for(;Date.now()<r;){let s=ae();if(s&&V(s)&&await G(s.bridgePort,250))return console.error(` started local bridge on port ${s.bridgePort}; run \`sootsim setup\` to install the background daemon`),s.bridgePort;if(await G(e,250))return console.error(` started local bridge on port ${e}; run \`sootsim setup\` to install the background daemon`),e;if(n)throw new Error(`sootsim bridge exited before becoming ready (exit ${n})`);await $(150)}throw new Error(`sootsim bridge did not start within ${Math.round(st/1e3)}s`)}async function Nt(){let e=Re();if(e&&U.existsSync(ie(e)))return;console.error(" installing sootsim engine runtime...");let{runRuntime:o}=await import("./runtime-OJ26HJM7.js");await o(["install"],{})}function Ft(e){let o=process.argv[1];return o&&U.existsSync(o)?ot(process.execPath,[o,...e],{detached:!0,stdio:"ignore",env:process.env}):ot("sootsim",e,{detached:!0,stdio:"ignore",env:process.env})}function G(e,o){return new Promise(t=>{let n=new Rt(`ws://127.0.0.1:${e}`,{handshakeTimeout:o}),r=!1,s=i=>{if(!r){r=!0;try{n.close()}catch{}t(i)}};n.once("open",()=>s(!0)),n.once("error",()=>s(!1)),setTimeout(()=>s(!1),o)})}function be(e){try{let o=new URL(e),t=o.pathname.replace(/\/+$/,"")||"/";return o.searchParams.has("open")||o.searchParams.has("port")||o.searchParams.has("bundle")||o.searchParams.has("demo")||o.pathname.includes("/sootsim/index.html")||t==="/sootsim"||o.pathname==="/__soot"||o.pathname==="/__soot/"||t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function jt(e){try{let o=new URL(e,"http://sootsim.local");if(o.origin!=="http://sootsim.local")return!1;let t=o.pathname.replace(/\/+$/,"")||"/";return t==="/rn"||/^\/rn\/[^/]+$/i.test(t)||/^\/app\/[^/]+$/i.test(t)||t==="/__soot/rn"||/^\/__soot\/rn\/[^/]+$/i.test(t)||/^\/__soot\/app\/[^/]+$/i.test(t)}catch{return!1}}function Ht(e,o){let t=new URL(e,"http://sootsim.local"),n=new URL(o),r=Y(n.pathname),s=t.pathname.startsWith("/__soot/")?t.pathname.slice(7):t.pathname;return n.pathname=`${r}${s}`,n.search=t.search,n.hash=t.hash,n.toString()}function Wt(e){try{let o=new URL(e).pathname.replace(/\/+$/,"")||"/";return/^\/preview\/[^/]+$/.test(o)||/^\/build\/.+/.test(o)}catch{return!1}}async function en(e){let o=Q(e);return(await ve(o)).bundleUrl}function Kt(e){try{let o=new URL(e.startsWith("http")?e:`http://${e}`),t=o.pathname||"/";if(t!=="/"&&t!==""||o.search||o.hash||!x(o.hostname))return null;let n=o.port?Number(o.port):o.protocol==="https:"?443:80;return Number.isFinite(n)&&n>0?n:null}catch{return null}}async function ve(e){let o=Q(e),t=/^\d+$/.test(o)?Number(o):Kt(o);if(t&&t>0){let n=await je(t);if(n)return{bundleUrl:n.bundleUrl,port:n.port,framework:n.framework,projectName:n.projectName}}return et(o)}function Y(e){let o=e.replace(/\/+$/,"")||"/";return o==="/__soot"||o.startsWith("/__soot/")?"/__soot":""}function Vt(e,o){let t=Q(e),n=new URL(o),r=Y(n.pathname);return n.pathname=`${r}/rn`,n.searchParams.delete("bundle"),n.searchParams.delete("demo"),n.searchParams.delete("app"),n.searchParams.delete("open"),n.searchParams.delete("port"),/^\d+$/.test(t)?n.pathname=`${r}/rn/${t}`:(n.pathname=`${r}/rn`,n.searchParams.set("open",t)),n.toString()}function ut(e){let o=Q(e);return/^\d+$/.test(o)||/^https?:\/\//i.test(o)?!0:/^(localhost|127\.0\.0\.1|\[::1\]|[^/]+\.localhost):\d+(?:\/.*)?$/i.test(o)}async function qt(e,o,t={}){let n=t.resolvedBundle??await ve(e),r=new URL(o),s=Y(r.pathname);r.pathname=`${s}/rn`,r.searchParams.delete("open"),r.searchParams.delete("port"),r.searchParams.delete("demo"),r.searchParams.delete("app");let i=t.hot===void 0?n.bundleUrl:Fe(n.bundleUrl,t.hot);return r.searchParams.set("bundle",i),r.toString()}function zt(e){return e.startsWith("~/")?C.join(Ct.homedir(),e.slice(2)):C.isAbsolute(e)?e:C.resolve(process.cwd(),e)}function Gt(e){let o={},t={};for(let r=0;r<e.length;r++){if(e[r]==="--replace"){let s=e[r+1];s||(console.error(" sootsim open: --replace expects <module>=<file>"),process.exit(1));let i=s.indexOf("=");(i<=0||i===s.length-1)&&(console.error(" sootsim open: --replace expects <module>=<file>"),process.exit(1));let a=s.slice(0,i).trim(),l=zt(s.slice(i+1).trim());U.existsSync(l)||(console.error(` sootsim open: replacement file not found: ${l}`),process.exit(1)),o[a]={file:l},r++;continue}if(e[r]==="--remap"){let s=e[r+1],i=s?s.indexOf("="):-1;(!s||i<=0||i===s.length-1)&&(console.error(" sootsim open: --remap expects <host:port>=<host:port>"),process.exit(1)),t[s.slice(0,i).trim()]=s.slice(i+1).trim(),r++;continue}}let n={};return Object.keys(o).length>0&&(n.modules=o),Object.keys(t).length>0&&(n.network={remap:t}),n.modules||n.network?n:void 0}async function Jt(e){if(e){let o=await z(e.bundleUrl);if(o)return me(o,{trustStart:!0})}return me(process.env.CONTRAST_REPO_DIR||process.cwd())}async function Qt(e){if(U.existsSync(C.join(ie(e),"index.html")))return;console.error(` installing configured engine runtime ${e}...`);let o=await Ee.install({version:e,setActive:!1,protectVersions:Me()});console.error(` installed engine runtime ${o.version}`)}function Yt(e,o){if(!o)return e;let t=new URL(e);if(!x(t.hostname))throw new Error(`runtimeVersion ${o} requires a local SootSim host; got ${t.origin}`);return t.hostname=Ke(o),t.toString()}function mt(){return Be().shellBaseUrl}async function Zt(e,o){try{let t=new URL(e),n=t.searchParams.get("bundle")||"";if(!n)return e;let r=o?.appDir??await z(n)??void 0,s=qe({bundleUrl:n,repoDir:r,exactProjectDir:!!o||!!r});if(s.length===0)return e;let i=await Xt(s);return i.length===0?e:(t.searchParams.set("appFonts",ze(i)),t.toString())}catch{return e}}async function Xt(e){let o=await Promise.all(e.map(async n=>{let r=new AbortController,s=setTimeout(()=>r.abort(),1500);try{let i=await fetch(n.url,{method:"HEAD",signal:r.signal});return i.status>=200&&i.status<400?n:null}catch{return null}finally{clearTimeout(s)}})),t=[];for(let n of o)n!==null&&t.push(n);return t}async function eo(e,o,t={}){if(!e)return new URL(o).toString();if(be(e))return new URL(e).toString();if(jt(e))return Ht(e,o);let n=Ut[e.toLowerCase()];if(n){let r=new URL(o),s=Y(r.pathname);return r.pathname=`${s}${n}`,r.toString()}return ut(e)?qt(e,o,t):Vt(e,o)}async function to(e,o){try{let t=new URL(e),n=t.searchParams.get("bundle")||"";if(!n)return e;let r=o?.appDir??await z(n)??void 0,s=Ge({bundleUrl:n,repoDir:r,exactProjectDir:!!o||!!r});return!s||s.imageUrl&&!await oo(s.imageUrl)?e:(t.searchParams.set("appSplash",Je(s)),t.toString())}catch{return e}}async function oo(e){let o=new AbortController,t=setTimeout(()=>o.abort(),1500);try{let n=await fetch(e,{method:"HEAD",signal:o.signal});return n.status>=200&&n.status<400}catch{return!1}finally{clearTimeout(t)}}async function J(e,o=mt(),t={}){let n=await eo(e,o,t),r=await to(await Zt(n,t.project),t.project);if(!t.device)return r;let s=new URL(r);return s.searchParams.set("device",t.device),s.toString()}function at(e,o){let t=e?.url||e?.origin||o;try{let n=new URL(t);return n.searchParams.delete("bundle"),n.searchParams.delete("demo"),n.searchParams.delete("app"),n.searchParams.delete("open"),n.searchParams.delete("port"),n.searchParams.delete("inspectOpen"),n.searchParams.delete("appFonts"),n.searchParams.delete("appSplash"),n.toString()}catch{return o}}async function no(e,o,t,n={}){let r=new URL(await J(e,o,n));return r.searchParams.set("inspectOpen",t),r.toString()}async function ro(e,o,t,n={}){let r=n.attempts??30,s=n.intervalMs??500,i=n.minNodeCount??10;for(let a=0;a<r;a++){let l=v(e,{commandTimeoutMs:o,simId:t,simIdSource:"flag"});try{let d=await l.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount()) || 0)()"});if(typeof d=="number"&&d>i)return{bridge:l,count:d}}catch{}l.close(),await $(s)}return null}function so(e){if(!e)return null;try{let o=new URL(e);if(o.searchParams.has("bundle")){let t=o.searchParams.get("bundle")||"";try{let n=new URL(t),r=n.pathname.length>36?`...${n.pathname.slice(-36)}`:n.pathname;return`bundle ${n.host}${r}`}catch{return"bundle"}}return o.searchParams.has("port")?`connect :${o.searchParams.get("port")||""}`:o.searchParams.has("open")?`connect ${o.searchParams.get("open")||""}`:o.searchParams.has("demo")?`demo ${o.searchParams.get("demo")||"default"}`:o.pathname.includes("/sootsim/index.html")||o.pathname==="/sootsim/"||o.pathname==="/sootsim"?"embedded sootsim":null}catch{return null}}function io(e){let o=e.indexOf(":");if(o<=0)return e.length>24?`${e.slice(0,21)}\u2026`:e;let t=e.slice(0,o),n=e.slice(o+1),r=n.length>12?`${n.slice(0,8)}\u2026`:n;return t==="TM_SESSION"||t==="CLAUDE_CODE_SESSION_ID"||t==="CODEX_THREAD_ID"?`agent ${r}`:`${t} ${r}`}function tn(e,o){if(e.length===0){console.log(" no sims connected");return}console.log(` connected sims (${e.length}):
|
|
5
|
+
`);for(let t of e){let n=t.lockedBy&&t.lockExpiresAt?`locked by ${io(t.lockedBy)} (${Math.max(0,Math.round((t.lockExpiresAt-Date.now())/1e3))}s)`:"",r=[t.isPrimary?"primary":"",t.id===o?"selected":"",t.readyState,t.userVisible===!1?"hidden":t.userVisible===!0?"visible":"",t.attachedCliCount&&t.attachedCliCount>0?"in use":"",t.userFocused?"focused":"",n].filter(Boolean);console.log(` ${t.id}${r.length?` [${r.join(", ")}]`:""}`);let s=so(t.url);if(s)console.log(` loaded: ${s}`);else if(t.url){let a=t.url.length>96?`${t.url.slice(0,93)}\u2026`:t.url;console.log(` url: ${a}`)}else t.origin&&console.log(` origin: ${t.origin}`);let i=ao(t);i&&console.log(` engine: ${i}`),t.title&&console.log(` title: ${t.title}`),t.visibilityState&&t.visibilityState!=="visible"&&console.log(` visibility: ${t.visibilityState}`),console.log(` connected: ${lt(Date.now()-t.connectedAt)}`),t.lastActiveAt&&t.lastActiveAt>0&&console.log(` last active: ${lt(Date.now()-t.lastActiveAt)}`)}}function ao(e){let o=e.url||e.origin||"";if(!o)return null;try{let t=new URL(o).port;return t==="5173"?"dev \u2014 local source (:5173)":t==="3000"?"Contrast app embedded (:3000)":We()?`dev \u2014 local build (:${t||"?"})`:`runtime \u2014 published engine (:${t||"?"})`}catch{return null}}function lt(e){let o=Math.max(0,Math.round(e/1e3));return o<60?`${o}s ago`:o<3600?`${Math.round(o/60)}m ago`:o<86400?`${Math.round(o/3600)}h ago`:`${Math.round(o/86400)}d ago`}async function ge(e,o,t,n={}){let r=n.attempts??30,s=n.intervalMs??500;for(let i=0;i<r;i++){let a=v(e,{commandTimeoutMs:o});try{let d=(await a.listSims()).find(t);if(d)return d}catch{}finally{a.close()}await $(s)}return null}async function lo(e,o,t,n,r={}){let s=r.attempts??30,i=r.intervalMs??500,a=!!n&&Number.isInteger(n)&&n>1,l=()=>a&&n!==void 0&&!ye(n);for(let d=0;d<s;d++){if(l())return{kind:"host-exit"};let p=v(e,{commandTimeoutMs:o});try{let w=(await p.listSims()).find(t);if(w)return l()?{kind:"host-exit"}:{kind:"match",sim:w}}catch{}finally{p.close()}if(l())return{kind:"host-exit"};await $(i)}return{kind:"timeout"}}async function co(e,o,t,n={}){let r=n.attempts??20,s=n.intervalMs??250;for(let i=0;i<r;i++){let a=v(e,{commandTimeoutMs:o});try{let d=(await a.listSims()).find(p=>p.id===t);if(!d||d.readyState!=="open")return!0}catch{return!0}finally{a.close()}await $(s)}return!1}function uo(e){let o=e.meta;if(!o||o.sootsimHostDriver!=="playwright")return null;let t=Number(o.sootsimHostPid);return!Number.isInteger(t)||t<=1||t===process.pid?null:t}function mo(e){if(!e.connectAckFile)return!1;try{return U.writeFileSync(e.connectAckFile,`${JSON.stringify({connectedAt:Date.now(),pid:e.pid??null})}
|
|
6
|
+
`,{flag:"w"}),!0}catch{return!1}}function ct(e){if(e.diagnosticLogPath)try{let o=U.readFileSync(e.diagnosticLogPath,"utf8").trim();if(!o){console.error(` ${C.basename(e.diagnosticLogPath)} was empty`);return}let t=o.length>4e3?`\u2026
|
|
7
|
+
${o.slice(-4e3)}`:o;console.error(` ${C.basename(e.diagnosticLogPath)}:`),console.error(t)}catch(o){let t=o instanceof Error?o.message:String(o);console.error(` failed to read ${C.basename(e.diagnosticLogPath)}: ${t}`)}}function ye(e){try{return process.kill(e,0),!0}catch(o){return o?.code==="EPERM"}}async function po(e,o=2500){let t=Date.now()+o;for(;Date.now()<t;){if(!ye(e))return!0;await $(100)}return!ye(e)}function fo(e){let o=nt("ps",["-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),t=nt("ps",["eww","-o","command=","-p",String(e)],{encoding:"utf8",stdio:["ignore","pipe","pipe"]});if(o.status!==0||t.status!==0)return!1;let n=(o.stdout||"").trimEnd(),r=(t.stdout||"").trimEnd();return(r.startsWith(n)?r.slice(n.length):r).includes("SOOTSIM_PW_URL=")}async function we(e,o){let t=new Set(o),n=new Set;for(let r of e){if(!t.has(r.id))continue;let s=uo(r);s&&n.add(s)}for(let r of n){if(!fo(r)){console.log(` skipped pid ${r}: not a sootsim playwright host (stale sim record)`);continue}try{process.kill(r,"SIGTERM")}catch{}if(await po(r)){console.log(` closed playwright host process ${r}`);continue}try{process.kill(r,"SIGKILL"),console.log(` force-closed playwright host process ${r}`)}catch{}}}function Z(e,o){if(o){let r=o.trim(),s=e.find(i=>i.id===r);if(!s)throw new Error(`no sim connected with id ${r}`);return s}let t=e.find(r=>r.isPrimary&&r.readyState==="open");if(t)return t;let n=e.find(r=>r.readyState==="open");if(n)return n;throw new Error("no sim connected")}function D(e,o,t){console.log(` ${t==="current sim"?"loaded":"opened"}: ${e} [${t}]`),console.log(` current sim: ${o.id}`),console.log(JSON.stringify({simId:o.id,url:o.url},null,2))}async function A(e,o,t){if(t.includes("--no-describe"))return;let n=process.env.SOOTSIM_QUIET_TARGET_NOTICE;process.env.SOOTSIM_QUIET_TARGET_NOTICE="1";try{await ho(e,o,{stableMs:150,maxMs:400});let r=v(e,{commandTimeoutMs:3e3,simId:o,cliLabel:"open --describe",simIdSource:"flag"});try{let s=null;try{s=await r.send({type:"evaluate",code:_e})}catch{}if(s&&!(s.flag===!0&&!s.loadingText&&Oe(s))){let p=s.loadingText?`still showing "${s.loadingText}"`:s.flag!==!0?"guest ready event has not fired":s.targets<=0?"no visible app content is inspectable yet":"app tree is still stabilizing";console.log(` app still loading: ${p} (nodes: ${s.nodes}, targets: ${s.targets})`),console.log(" before interacting, run: sootsim wait ready --max-ms 120000")}let a=`(async () => {
|
|
8
|
+
const t = window.__sootsimTest
|
|
9
|
+
const ms = window.SootSim?.bridges?.mainShell
|
|
10
|
+
if (!t) return null
|
|
11
|
+
let shell = null
|
|
12
|
+
try { shell = ms?.getState ? await ms.getState() : null } catch {}
|
|
13
|
+
const tree = await t.dumpTree(12, ${JSON.stringify({describe:!0,verbose:!1,filter:""})})
|
|
14
|
+
return { tree, shell }
|
|
15
|
+
})()`,l=await r.send({type:"evaluate",code:a});if(!l?.tree)return;if(console.log(""),l.shell?.state){let d=[`state=${l.shell.state}`,l.shell.activeApp?`app=${l.shell.activeApp}`:null].filter(Boolean);console.log(` shell: ${d.join(" ")}`)}console.log(l.tree)}finally{r.close()}}catch{}finally{n===void 0?delete process.env.SOOTSIM_QUIET_TARGET_NOTICE:process.env.SOOTSIM_QUIET_TARGET_NOTICE=n}}async function ho(e,o,t){let n=Date.now()+t.maxMs,r="(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()",s=v(e,{commandTimeoutMs:2e3,simId:o,simIdSource:"flag"});try{let i=-1,a=0;for(;Date.now()<n;){let l=-1;try{let d=await s.send({type:"evaluate",code:r});typeof d=="number"&&(l=d)}catch{}if(l>=0&&l===i){if(Date.now()-a>=t.stableMs)return}else i=l,a=Date.now();await $(50)}}finally{s.close()}}async function go(e,o={}){let t=M(e,{port:o.port,commandTimeoutMs:o.timeoutMs});t.positional.length!==1&&(console.error(" sootsim open: expected exactly one <url-or-route>"),console.error(" examples: sootsim open /settings | sootsim open myapp://settings"),process.exit(1));let n;try{n=Bt(t.positional[0]??"")}catch(i){console.error(` sootsim open: ${i instanceof Error?i.message:String(i)}`),process.exit(1)}let r=E(t),s=t.simId?` --sim ${t.simId}`:"";try{let i=await r.send({type:"call",path:"SootSim.bridges.test.openDeepLink",args:[n]});if(Dt(i)&&i.ok===!1)throw new Error(typeof i.error=="string"?i.error:"deep-link dispatch failed");console.log(` opened deep link: ${n}`)}catch(i){console.error(` link failed: ${i instanceof Error?i.message:String(i)}`),await O(r,{errorsCommand:`sootsim get errors 5${s}`,warningsCommand:`sootsim get warnings 5${s}`,requestsCommand:`sootsim get requests 5${s}`}),process.exit(1)}finally{r.close()}}async function on(e,o={}){let t=M(e,{port:o.port,commandTimeoutMs:o.timeoutMs,stripBooleanFlags:["--new","--headless","--headed","--ephemeral","--hot","--no-hmr","--no-describe"],stripValueFlags:["--base-url","--replace","--driver","--profile","--cdp-port","--browser","--device"]}),n=e.find((c,m)=>e[m-1]==="--profile"),r=e.includes("--ephemeral"),s=e.find((c,m)=>e[m-1]==="--cdp-port"),i=s?Number(s):void 0;s&&(!Number.isFinite(i)||i<=0)&&(console.error(` sootsim open: --cdp-port must be a positive port number, got "${s}"`),process.exit(1)),n&&r&&(console.error(" sootsim open: --profile cannot be combined with --ephemeral"),process.exit(1));let a=n?He(n).id:void 0,l=!!a||r,d=e.includes("--new")||l,p=Gt(e);d&&t.simIdSource==="flag"&&(console.error(" sootsim open: --new, --profile, and --ephemeral cannot be combined with --sim"),process.exit(1));let u=t.positional[0]||"";if(At(u)){d&&(console.error(" sootsim open: deep links target the current app; remove --new, --profile, or --ephemeral"),process.exit(1)),await go(e,o);return}if(Wt(u)){let c=(()=>{try{return x(new URL(u).hostname)}catch{return!1}})();console.log(" that\u2019s a SootSim preview/build link \u2014 a full player page, not a driveable sim."),console.log(" opening it in your browser for viewing\u2026");try{await fe(u,{background:!1})}catch(m){console.error(` could not launch a browser: ${m instanceof Error?m.message:String(m)}`),console.error(` open it yourself: ${u}`),process.exit(1)}console.log(c?" to drive it under the CLI, point `sootsim open` at the app\u2019s dev port instead (e.g. `sootsim open 8081`).":" the CLI can\u2019t drive a remote preview (the engine only attaches to the local bridge from localhost). to drive the app, run it locally and `sootsim open <port>`.");return}let w=ut(u)?await ve(u):void 0,L=await Jt(w),X=await Ve(L),N=X?.runtimeVersion,ee=Ne(X?{...X,runtimeVersion:void 0}:void 0,p);N&&await Qt(N);let te=e.find((c,m)=>e[m-1]==="--base-url"),ft=o.port!==void 0||e.some(c=>c==="--port"||c==="-p"||c.startsWith("--port="));if(te&&!ft){let c=ce(te);c&&(t.wsPort=c)}t.wsPort=await Lt(t.wsPort);let y=e.find((c,m)=>e[m-1]==="--driver")||"",ht=Ot(e,y);i&&y!=="playwright"&&(console.error(" sootsim open: --cdp-port is only honored by the playwright driver \u2014 add `--driver playwright`"),process.exit(1));let P=e.find((c,m)=>e[m-1]==="--browser");P&&y!=="playwright"&&(console.error(" sootsim open: --browser is only honored by the playwright driver \u2014 add `--driver playwright`"),process.exit(1));let F=P==="chromium"||P==="webkit"||P==="firefox"?P:void 0;P&&!F&&(console.error(` sootsim open: --browser must be chromium, webkit, or firefox \u2014 got "${P}"`),process.exit(1)),i&&F&&F!=="chromium"&&(console.error(" sootsim open: --cdp-port requires the chromium engine"),process.exit(1));let Se=e.includes("--hot"),$e=e.includes("--no-hmr");Se&&$e&&(console.error(" sootsim open: --hot and --no-hmr cannot be combined"),process.exit(1));let gt=Se?!0:$e?!1:y!=="playwright",k=e.find((c,m)=>e[m-1]==="--device");k&&!(k in le)&&(console.error(` sootsim open: unknown device "${k}"`),console.error(` known devices: ${Ue().join(", ")}`),process.exit(1));let oe=k?le[k]:void 0,j={hot:gt,device:k,resolvedBundle:w,project:L},wt=De(t.wsPort),bt=N?`http://localhost:${t.wsPort}/`:te||wt?.shellBaseUrl||mt(),I=Yt(bt,N),xe=e.includes("--base-url");Ae(t.wsPort,I);let Pe=T();if(!y&&!d&&(t.simIdSource==="flag"||t.simIdSource==="saved"&&!!Pe)){let c=E(t),m=t.simId?` --sim ${t.simId}`:"",f=!1;try{let h=null;try{let g=await c.listSims();if(t.simIdSource==="saved"?(h=g.find(R=>R.id===Pe&&R.readyState==="open")??null,h||_()):h=Z(g,t.simId),!h)if(t.simIdSource==="saved")f=!0;else throw new Error("no sim connected");if(!f&&h){let R=xe||be(u)?I:at(h,I),K=await J(u,q(R,ee),j);c.send({type:"evaluate",simId:h.id,code:`window.location.href = ${JSON.stringify(K)}`}).catch(()=>{})}}catch(g){console.error(` open failed: ${g instanceof Error?g.message:String(g)}`),await O(c,{errorsCommand:`sootsim get errors 5${m}`,warningsCommand:`sootsim get warnings 5${m}`,requestsCommand:`sootsim get requests 5${m}`}),process.exit(1)}if(!f&&h){await $(1500);let g=await ro(t.wsPort,t.commandTimeoutMs,h.id);g||(console.error(" timed out waiting for current sim to load target"),process.exit(1)),g.bridge.close(),b(h.id);let R=xe||be(u)?I:at(h,I),K=await J(u,q(R,ee),j);D(K,{...h,url:K},"current sim"),await A(t.wsPort,h.id,e);return}}finally{c.close()}}let ke=q(I,ee),yt=await J(u,ke,j),Ie=`cli-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,S=await no(u,ke,Ie,j),Ce=Te()??void 0,ne={newWindow:!0},H=c=>c.url?.includes(`inspectOpen=${Ie}`)??!1;if(y){_t(y)||(console.error(` unknown driver "${y}" \u2014 run \`sootsim list --drivers\``),process.exit(1));let c=he(y);c||(console.error(` unknown driver "${y}" \u2014 run \`sootsim list --drivers\``),process.exit(1));let m=Tt(),f=await c.launch({url:S,bridgePort:ce(I)??t.wsPort,headless:ht,newWindow:ne.newWindow,profileId:a,ephemeralProfile:r,cdpPort:i,browser:F,device:k,ownerPid:Ce,viewport:oe?{width:oe.width+120,height:oe.height+60}:void 0,connectTimeoutMs:m.hostTimeoutMs});f.launched||(console.error(` ${c.name} driver: ${f.message}`),process.exit(1));let h=await lo(t.wsPort,t.commandTimeoutMs,H,f.pid,{attempts:m.attempts,intervalMs:m.intervalMs});if(h.kind==="host-exit"&&(ct(f),console.error(` ${c.name} host crashed \u2014 sim is no longer attached`),process.exit(1)),h.kind==="timeout"){if(f.pid)try{process.kill(f.pid,"SIGTERM"),console.error(` closed ${c.name} host process ${f.pid}`)}catch{}ct(f),console.error(` timed out after ${m.timeoutMs}ms waiting for opened sim to connect`),process.exit(1)}let g=h.sim;b(g.id),mo(f),D(S,g,`${c.name} driver`),await A(t.wsPort,g.id,e);return}if(l){let c=B();c||(console.error(" profiles require electron or playwright; install the desktop companion or use `--driver playwright`"),process.exit(1));try{(await pe(S,c,{profileId:a,ephemeralProfile:r,ownerPid:Ce})).launched||(console.error(" desktop companion failed to start"),process.exit(1))}catch(f){console.error(` desktop companion failed: ${f instanceof Error?f.message:String(f)}`),process.exit(1)}let m=await ge(t.wsPort,t.commandTimeoutMs,H,{attempts:40,intervalMs:500});m||(console.error(" timed out waiting for profiled sim to connect"),process.exit(1)),b(m.id),D(S,m,"desktop companion"),await A(t.wsPort,m.id,e);return}let re=!1,se=!1;try{let c=v(t.wsPort,{commandTimeoutMs:2e3});try{await c.listSims(),re=!0}finally{c.close()}}catch{}if(re)try{let c=v(t.wsPort,{commandTimeoutMs:3e3});try{await c.openUrl(S,ne),se=!0}finally{c.close()}}catch{}if(!se){let c=B();if(c)try{if((await pe(S,c)).launched){let f=await ge(t.wsPort,t.commandTimeoutMs,H,{attempts:20,intervalMs:500});if(f){b(f.id),D(S,f,"desktop companion"),await A(t.wsPort,f.id,e);return}}}catch{}try{await fe(S,ne)}catch(m){console.error(` open failed: ${m instanceof Error?m.message:String(m)}`),he("playwright")?.availability().available?console.error(" no system browser found \u2014 retry with `sootsim open \u2026 --driver playwright` for a headless sim."):console.error(" run `sootsim list --drivers` to see available drivers."),process.exit(1)}if(!re){console.log(` opened: ${yt}`),tt(t.wsPort);return}}let W=await ge(t.wsPort,t.commandTimeoutMs,H,{attempts:30,intervalMs:500});W||(console.error(" timed out waiting for opened sim to connect"),process.exit(1)),b(W.id),D(S,W,se?"bridge":"direct shell open"),await A(t.wsPort,W.id,e)}async function pt(e,o={}){let t=M(e,{port:o.port,commandTimeoutMs:o.timeoutMs,stripBooleanFlags:["--force"]}),n=e.includes("--force"),r=E(t),s=t.simId?` --sim ${t.simId}`:"";try{try{let i=await r.listSims(),a=Z(i,t.positional[0]||t.simId);if(a.lockedBy&&a.lockExpiresAt&&a.lockExpiresAt>Date.now()){let l=Math.max(0,Math.round((a.lockExpiresAt-Date.now())/1e3));a.lockedByKind==="user-active"&&(console.error(` refused: ${a.id} is locked by the active user (${l}s) \u2014 that's a live human tab`),console.error(" run `sootsim open --new` for a fresh investigation sim"),process.exit(1)),n||(console.error(` refused: ${a.id} is leased by ${a.lockedBy} (${l}s)`),console.error(` \`sootsim use ${a.id} --force\` to take it, or \`sootsim open --new\` for a fresh sim`),process.exit(1))}await r.focusSim(a.id),b(a.id),console.log(` using: ${a.id}`)}catch(i){console.error(` use failed: ${i instanceof Error?i.message:String(i)}`),await O(r,{errorsCommand:`sootsim get errors 5${s}`,warningsCommand:`sootsim get warnings 5${s}`,requestsCommand:`sootsim get requests 5${s}`}),process.exit(1)}}finally{r.close()}}async function nn(e,o={}){await pt(e,o)}async function rn(e,o={}){await pt(e,o)}async function sn(e,o={}){let t=M(e,{port:o.port,commandTimeoutMs:o.timeoutMs,stripBooleanFlags:["--force"]}),n=e.includes("--force"),r=E(t);try{try{let s=await r.listSims(),i=Z(s,t.positional[0]||t.simId),a=n&&i.lockedBy&&i.lockedByKind!=="user-active"?i.lockedBy:null,l=await r.claim(i.id,{force:n});b(i.id);let d=Math.max(0,Math.round((l.lockExpiresAt-Date.now())/1e3)),p=l.bootedCount>0?` (booted ${l.bootedCount})`:"";console.log(` claimed: ${l.simId} [${d}s]${p}`),a&&console.log(` took over from: ${a}`)}catch(s){if(s instanceof Le){let i=Math.max(0,Math.round(s.lock.expiresInMs/1e3));console.error(` claim failed: locked by ${s.lock.by} for ${i}s more`),console.error(" use --force to take it, or `sootsim open --new` for a fresh sim"),process.exit(1)}console.error(` claim failed: ${s instanceof Error?s.message:String(s)}`),process.exit(1)}}finally{r.close()}}async function wo(e,o,t,n){if(n.length===0)return{closed:[],remaining:[]};await Promise.all(n.map(s=>e.closeSim(s).catch(()=>{})));let r=new Set(n);for(let s=0;s<40;s++){let i=[];try{let a=v(o,{commandTimeoutMs:t});try{i=(await a.listSims()).filter(d=>r.has(d.id)&&d.readyState==="open").map(d=>d.id)}finally{a.close()}}catch{i=[]}if(i.length===0)return{closed:[...r],remaining:[]};if(s===39)return{closed:[...r].filter(a=>!i.includes(a)),remaining:i};await $(250)}return{closed:[...r],remaining:[]}}function bo(e,o){let t=e.filter(u=>u.readyState==="open"),n=t.map(u=>u.id),r=o.explicitKeepId?.trim()||"",s=o.savedKeepId?.trim()||"",i=s?t.some(u=>u.id===s):!1,a=s&&!i?s:null,l=null,d=null,p=null;if(o.closeOthers)if(r){let u=t.find(w=>w.id===r);u?l=u.id:d=r}else if(s&&i)l=s;else{let u=t.find(w=>w.isPrimary)??t[0]??null;u&&(l=u.id,s&&!i&&(p=u.id))}return{openIds:n,keepId:l,targets:d?[]:n.filter(u=>u!==l),staleSavedId:a,missingExplicitKeepId:d,fallbackKeepId:p}}async function an(e,o={}){let t=M(e,{port:o.port,commandTimeoutMs:o.timeoutMs,stripBooleanFlags:["--all","--others"]}),n=E(t),r=t.simId?` --sim ${t.simId}`:"",s=e.includes("--all"),i=e.includes("--others");if(s||i){try{let a=await n.listSims(),l=T(),d=t.positional[0]||(t.simIdSource==="flag"?t.simId:void 0),p=bo(a,{closeOthers:i,explicitKeepId:d,savedKeepId:l});if(p.staleSavedId&&_(),p.fallbackKeepId&&(b(p.fallbackKeepId),console.log(` saved sim ${p.staleSavedId} is gone \u2014 keeping primary ${p.fallbackKeepId}`)),p.missingExplicitKeepId&&(console.error(` close failed: keep sim ${p.missingExplicitKeepId} is not connected; not closing other sims`),process.exit(1)),p.targets.length===0){console.log(p.keepId?` nothing to close \u2014 only the kept sim ${p.keepId} is connected`:p.staleSavedId?` nothing to close \u2014 no sims connected (cleared stale current sim ${p.staleSavedId})`:" nothing to close \u2014 no sims connected");return}let u=await wo(n,t.wsPort,t.commandTimeoutMs,p.targets);await we(a,p.targets);let w=T();w&&u.closed.includes(w)&&(p.keepId?b(p.keepId):_());let L=` closed ${u.closed.length} sim(s)${p.keepId?` (kept ${p.keepId})`:""}`;console.log(L),u.remaining.length>0&&(console.error(` close failed: still connected: ${u.remaining.join(", ")}`),process.exit(1))}catch(a){console.error(` close failed: ${a instanceof Error?a.message:String(a)}`),process.exit(1)}finally{n.close()}return}try{try{let a=await n.listSims(),l=Z(a,t.positional[0]||t.simId),d=a.find(u=>u.id!==l.id&&u.readyState==="open");await n.closeSim(l.id),await co(t.wsPort,t.commandTimeoutMs,l.id)||(await we(a,[l.id]),console.error(` close failed: ${l.id} is still connected`),process.exit(1)),await we(a,[l.id]),T()===l.id&&(d?b(d.id):_()),console.log(` closed: ${l.id}`)}catch(a){console.error(` close failed: ${a instanceof Error?a.message:String(a)}`),await O(n,{errorsCommand:`sootsim get errors 5${r}`,warningsCommand:`sootsim get warnings 5${r}`,requestsCommand:`sootsim get requests 5${r}`}),process.exit(1)}}finally{n.close()}}export{Po as a,It as b,ko as c,Tt as d,Bt as e,en as f,Yt as g,mt as h,J as i,no as j,so as k,tn as l,ge as m,lo as n,uo as o,mo as p,we as q,go as r,on as s,nn as t,rn as u,sn as v,wo as w,bo as x,an as y};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
3
|
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
4
|
import{existsSync as M,mkdirSync as A,readFileSync as v,rmSync as f,writeFileSync as h}from"fs";import{tmpdir as w}from"os";import{dirname as B,join as $,resolve as V}from"path";import{execFileSync as _}from"child_process";import{readFileSync as b}from"fs";import{createRequire as y}from"module";var c=null,p=null;function m(r){c||(c=E());try{return c(r)}catch{return null}}function C(r){p||(p=T());try{return p(r)}catch{return null}}function T(){if(process.platform==="linux")return r=>{try{return b(`/proc/${r}/comm`,"utf8").trim()||null}catch{return null}};if(process.platform==="darwin"){let r=x();return r||F()}return()=>null}function E(){let r=Number(process.env.PPID);if(Number.isFinite(r)&&r>1&&r!==process.ppid)return()=>r;if(process.platform==="linux")return D();if(process.platform==="darwin"){let n=R();return n||k()}return()=>null}function D(){return r=>{try{let n=b(`/proc/${r}/stat`,"utf8"),t=n.lastIndexOf(")");if(t<0)return null;let e=n.slice(t+1).trim().split(/\s+/),i=Number(e[1]);return Number.isFinite(i)&&i>0?i:null}catch{return null}}}var g=3,l=216,P=16,S=48,L=16;function R(){if(!process.versions?.bun)return null;try{let r=y(import.meta.url),{dlopen:n,FFIType:t}=r("bun:ffi"),e=n("/usr/lib/libproc.dylib",{proc_pidinfo:{args:[t.i32,t.i32,t.u64,t.ptr,t.i32],returns:t.i32}}),i=Buffer.alloc(l);return o=>{if(Number(e.symbols.proc_pidinfo(o,g,0n,i,l))<=0)return null;let u=i.readUInt32LE(P);return u>0?u:null}}catch{return null}}function x(){if(!process.versions?.bun)return null;try{let r=y(import.meta.url),{dlopen:n,FFIType:t}=r("bun:ffi"),e=n("/usr/lib/libproc.dylib",{proc_pidinfo:{args:[t.i32,t.i32,t.u64,t.ptr,t.i32],returns:t.i32}}),i=Buffer.alloc(l);return o=>{if(Number(e.symbols.proc_pidinfo(o,g,0n,i,l))<=0)return null;let u=i.subarray(S,S+L),I=u.indexOf(0);return u.subarray(0,I<0?u.length:I).toString("utf8")||null}}catch{return null}}function F(){return r=>{try{let t=_("lsof",["-R","-p",String(r),"-d","cwd","-a"],{encoding:"utf8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).split(`
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{G as E,H as F,I as j,k as L,l as N,u as U,x as _}from"./chunk-BAFDYXCM.js";import z from"node:fs";import G from"node:path";function A(e){return e.length<=100&&/^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(e)}function M(e){try{return z.readdirSync(e.runtimesDir(),{withFileTypes:!0}).filter(c=>c.isDirectory()).map(c=>c.name).sort(k)}catch{return[]}}function T(e,c){return G.posix.basename(e.tarballPath(c))}function k(e,c){let l=f=>{let v=f.indexOf("-"),V=v>=0?f.slice(0,v):f,$=v>=0?f.slice(v+1):"",D=V.split(".").map(I=>Number.parseInt(I,10));return D.some(I=>!Number.isFinite(I))?[[Number.POSITIVE_INFINITY],f]:[D,$]},[m,u]=l(e),[R,x]=l(c);for(let f=0;f<Math.max(m.length,R.length);f++){let v=m[f]??0,V=R[f]??0;if(v!==V)return v-V}return u===x?0:u?x?u<x?-1:1:-1:1}import{spawn as Z}from"node:child_process";import J from"node:crypto";import o from"node:fs";import Y from"node:os";import y from"node:path";import{Readable as q}from"node:stream";import{pipeline as B}from"node:stream/promises";var K=2;function H(e){function c(){try{let n=JSON.parse(o.readFileSync(e.configFile(),"utf8"));return n&&typeof n=="object"?n:{}}catch{return{}}}function l(n){let t=c();return(n||process.env[e.env.cdnOrigin]||t.cdnOrigin||e.defaultCdnOrigin).replace(/\/+$/,"")}function m(n){let t=c();return n||process.env[e.env.channel]||t.runtimeChannel||"stable"}function u(){if(!e.env.pin)return null;let n=process.env[e.env.pin];if(n&&n.trim())return n.trim();let t=c();return typeof t.runtimeVersion=="string"&&t.runtimeVersion.trim()?t.runtimeVersion.trim():null}function R(n){let t=new URL(`${l(n)}${e.manifestPath}`);return t.searchParams.set("t",String(Date.now())),t.toString()}function x(n,t){return`${l(t)}${e.tarballPath(n)}`}async function f(n){let t=R(n),r=await fetch(t,{headers:{Accept:"application/json"}});if(!r.ok)throw new Error(`manifest fetch failed: ${r.status} ${r.statusText} (${t})`);return await r.json()}function v(n,t={}){let r=m(t.channel),i=t.version||u()||n.channels[r]?.latest;if(!i)throw new Error(`no version specified and channel '${r}' has no latest entry in the manifest`);if(!A(i))throw new Error(`invalid runtime version: ${i}`);let h=n.versions[i];if(!h)throw new Error(`version ${i} not found in manifest; available: ${Object.keys(n.versions).slice(-10).join(", ")||"(none)"}`);return{version:i,channel:r,entry:h}}async function V(n={}){e.ensureHome();let t=l(n.cdnOrigin),r=await f(t),{version:i,channel:h,entry:a}=v(r,n),d=e.runtimeDir(i),g=n.setActive!==!1,O=[i,...n.protectVersions??[]];if(b({protectVersions:O}),!n.force&&o.existsSync(y.join(d,e.installedMarker)))return g&&e.writeActiveRuntime(i),b({protectVersions:O}),{version:i,channel:h,cdnOrigin:t,runtimeDir:d,installed:!1,activated:g,manifest:r};let P=a.tarball||x(i,t),S=o.mkdtempSync(y.join(Y.tmpdir(),`${e.id}-runtime-download-`)),w=y.join(S,T(e,i)),p=y.join(y.dirname(d),`.installing-${i}-${process.pid}`);o.rmSync(p,{recursive:!0,force:!0});try{process.stderr.write(`${e.id}: downloading runtime ${i}\u2026
|
|
5
|
+
`),await Q(P,w),process.stderr.write(`${e.id}: extracting runtime ${i}\u2026
|
|
6
|
+
`);let s=await X(w);if(s!==a.sha256)throw new Error(`sha256 mismatch for runtime ${i}: expected ${a.sha256}, actual ${s}`);if(o.mkdirSync(p,{recursive:!0}),await ee(w,p),!o.existsSync(y.join(p,e.installedMarker)))throw new Error(`extracted tarball for runtime ${i} is missing ${e.installedMarker}`);o.rmSync(d,{recursive:!0,force:!0}),o.renameSync(p,d)}catch(s){throw o.rmSync(p,{recursive:!0,force:!0}),s}finally{o.rmSync(S,{recursive:!0,force:!0})}return g&&e.writeActiveRuntime(i),b({protectVersions:O}),{version:i,channel:h,cdnOrigin:t,runtimeDir:d,installed:!0,activated:g,manifest:r}}async function $(n={}){e.ensureHome(),b({protectVersions:n.protectVersions});let t=l(n.cdnOrigin),r=m(n.channel),i=u();if(i){let p=e.readActiveRuntime(),s=o.existsSync(y.join(e.runtimeDir(i),e.installedMarker));if(p===i&&s)return{checked:!0,updated:!1,reason:`runtime is pinned to ${i}`,activeVersion:p,latestVersion:i};let C=await V({version:i,channel:r,cdnOrigin:t,setActive:!1,protectVersions:n.protectVersions});return{checked:!0,updated:!0,reason:`runtime is pinned to ${i}`,activeVersion:i,latestVersion:i,install:C}}let h=await f(t),a=h.channels[r]?.latest;if(!a)return{checked:!0,updated:!1,reason:`channel '${r}' has no latest runtime`,activeVersion:e.readActiveRuntime()};if(!h.versions[a])return{checked:!0,updated:!1,reason:`manifest is missing version ${a}`,activeVersion:e.readActiveRuntime(),latestVersion:a};let g=e.readActiveRuntime(),O=g?e.runtimeDir(g):null,P=O?o.existsSync(y.join(O,e.installedMarker)):!1;if(!(!g||!P||k(a,g)>0))return{checked:!0,updated:!1,reason:"active runtime is current",activeVersion:g,latestVersion:a};let w=await V({version:a,channel:r,cdnOrigin:t,setActive:!1,protectVersions:n.protectVersions});return{checked:!0,updated:!0,activeVersion:a,latestVersion:a,install:w}}async function D(n={}){let t=e.readActiveRuntime(),r=u();if(r)return{active:t,latest:r,pinned:r,outdated:t!==r};try{let i=await f(l(n.cdnOrigin)),h=m(n.channel),a=i.channels[h]?.latest??null,d=!!(a&&(!t||k(a,t)>0));return{active:t,latest:a,pinned:null,outdated:d}}catch{return{active:t,latest:null,pinned:null,outdated:!1}}}function I(n={}){e.ensureHome();let t=Math.max(1,Math.floor(n.retainVersions??K)),r=M(e),i=new Set(r),h=e.readActiveRuntime(),a=u(),d=new Set;for(let s of[h,a,...n.protectVersions??[]])s&&i.has(s)&&d.add(s);for(let s of[...r].reverse()){if(d.size>=t)break;d.add(s)}let g="__RUNTIME_VERSION__",O=T(e,g),P=O.indexOf(g),S=O.slice(0,P),w=O.slice(P+g.length),p=[];if(P>=0)try{p=o.readdirSync(e.cacheDir(),{withFileTypes:!0}).filter(s=>{if(!s.isFile())return!1;let C=s.name.startsWith(S)&&s.name.endsWith(w),W=s.name.startsWith(S)&&s.name.endsWith(`${w}.partial`);return C||W}).map(s=>y.join(e.cacheDir(),s.name)).sort()}catch{}return{activeVersion:h,pinnedVersion:a,keepVersions:r.filter(s=>d.has(s)),removeVersions:r.filter(s=>!d.has(s)),removeCacheFiles:p}}function b(n={}){let t=I(n);for(let r of t.removeVersions)o.rmSync(e.runtimeDir(r),{recursive:!0,force:!0});for(let r of t.removeCacheFiles)o.rmSync(r,{force:!0});return t}return{product:e,resolveCdnOrigin:l,resolveChannel:m,resolvePin:u,manifestUrl:R,tarballUrl:x,fetchManifest:f,resolveVersion:v,install:V,updateToLatest:$,checkUpToDate:D,planLocalRetention:I,pruneLocalRetention:b,listInstalled:()=>M(e)}}async function Q(e,c){let l=await fetch(e);if(!l.ok||!l.body)throw new Error(`download failed: ${l.status} ${l.statusText} (${e})`);o.mkdirSync(y.dirname(c),{recursive:!0});let m=`${c}.partial`;try{await B(q.fromWeb(l.body),o.createWriteStream(m)),o.renameSync(m,c)}catch(u){try{o.unlinkSync(m)}catch{}throw u}}function X(e){return new Promise((c,l)=>{let m=J.createHash("sha256"),u=o.createReadStream(e);u.on("data",R=>m.update(R)),u.on("error",l),u.on("end",()=>c(m.digest("hex")))})}function ee(e,c){return new Promise((l,m)=>{let u=Z("tar",["-xzf",e,"-C",c],{stdio:["ignore","inherit","inherit"]});u.on("error",m),u.on("exit",R=>{R===0?l():m(new Error(`tar exited with code ${R}`))})})}var ne="https://contrast.dev",ve="https://sootsim.com/changelog",Oe="https://contrast.dev/api/changelog/sootsim",te={id:"sootsim",defaultCdnOrigin:ne,manifestPath:"/runtimes/manifest.json",tarballPath:e=>`/runtimes/sootsim-runtime-${e}.tar.gz`,installedMarker:"index.html",env:{cdnOrigin:"SOOTSIM_CDN_ORIGIN",channel:"SOOTSIM_RUNTIME_CHANNEL"},ensureHome:E,configFile:_,runtimesDir:L,runtimeDir:N,cacheDir:U,readActiveRuntime:F,writeActiveRuntime:j},ye=H(te);export{A as a,k as b,ne as c,ve as d,Oe as e,ye as f};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{b as C}from"./chunk-6YIHNXMZ.js";import{f as h}from"./chunk-VVSQCLBU.js";import{G as B,O as b,g as S}from"./chunk-BAFDYXCM.js";import a from"node:fs";import c from"node:path";var g=1,k=`automatic-cleanup-v${g}.json`,A=`automatic-cleanup-v${g}.lock`,P=360*60*1e3;function w(){let i=c.join(S(),k);try{return JSON.parse(a.readFileSync(i,"utf8")).generation===g}catch{return!1}}function N(i){if(i<1024)return`${i} B`;let e=["KiB","MiB","GiB","TiB"],n=i/1024,s=e[0];for(let r=1;r<e.length&&n>=1024;r++)n/=1024,s=e[r];return`${n.toFixed(n>=10?1:2)} ${s}`}function p(i){let e;try{e=a.lstatSync(i)}catch{return 0}let n=e.blocks>0?e.blocks*512:e.size;if(!e.isDirectory()||e.isSymbolicLink())return n;let s=n;try{for(let r of a.readdirSync(i))s+=p(c.join(i,r))}catch{}return s}function E(i){for(let e of["SingletonLock","SingletonSocket","lockfile"])try{if(a.lstatSync(c.join(i,e)))return!0}catch{}return!1}function v(i,e){let n;try{n=a.readdirSync(i,{withFileTypes:!0})}catch{return[]}let s=E(e),r=[];for(let t of n){if(!t.isDirectory()||t.isSymbolicLink())continue;let o=c.join(i,t.name);if(C(t.name)){r.push({path:o,bytes:p(o),kind:"browser-cache",state:s?"in-use":"safe",selected:!s,detail:s?"browser profile is open; close it before cleanup":"disposable browser HTTP, bytecode, or GPU cache"});continue}r.push(...v(o,e))}return r}function L(i){let e=c.join(i,"profiles","playwright"),n;try{n=a.readdirSync(e,{withFileTypes:!0})}catch{return[]}return n.flatMap(s=>{if(!s.isDirectory()||s.isSymbolicLink())return[];let r=c.join(e,s.name);return v(r,r)})}function R(i){let e=c.join(i,"electron","userData");return v(e,e)}function U(i,e){let n=c.join(i,"recordings"),s;try{s=a.readdirSync(n,{withFileTypes:!0})}catch{return[]}return s.map(r=>{let t=c.join(n,r.name);return{path:t,bytes:p(t),kind:"recording",state:"aggressive",selected:e,detail:"user-created recording or captured-frame output"}})}function x(i){let e=new Set(b()),n=[...e],s=h.planLocalRetention({retainVersions:2,protectVersions:n}),r=h.planLocalRetention({retainVersions:1,protectVersions:n}),t=new Set(s.removeVersions),o=new Set(r.removeVersions),l=new Set([...s.keepVersions,...s.removeVersions,...r.keepVersions,...r.removeVersions]),m=[];for(let u of[...l].sort()){let d=h.product.runtimeDir(u),y="retained",f="retained runtime";e.has(u)&&u!==s.activeVersion?(y="in-use",f="runtime is serving a connected simulator"):t.has(u)?(y="safe",f="inactive runtime outside the two-version rollback window"):o.has(u)?(y="aggressive",f="most recent rollback runtime"):u===s.activeVersion&&(f="active runtime; always protected"),m.push({path:d,bytes:p(d),kind:"runtime-version",state:y,selected:y==="safe"||y==="aggressive"&&i,detail:f})}for(let u of s.removeCacheFiles)m.push({path:u,bytes:p(u),kind:"runtime-archive",state:"safe",selected:!0,detail:"downloaded archive is unnecessary after successful extraction"});return{activeRuntime:s.activeVersion,entries:m}}function T(i={}){let e=i.aggressive===!0,n=S(),s=x(e),r=[...s.entries,...L(n),...R(n),...U(n,e)].sort((t,o)=>o.bytes-t.bytes||t.path.localeCompare(o.path));return{home:n,activeRuntime:s.activeRuntime,entries:r,reclaimableBytes:r.reduce((t,o)=>t+(o.selected?o.bytes:0),0),protectedBytes:r.reduce((t,o)=>t+(o.selected?0:o.bytes),0),totalBytes:p(n)}}function D(i,e){let n=c.relative(i,e);if(!n||n.startsWith("..")||c.isAbsolute(n))throw new Error(`refusing cleanup target outside the SootSim home: ${e}`)}function I(i={}){let e=T(i),n=i.aggressive===!0?1:2;h.pruneLocalRetention({retainVersions:n,protectVersions:b()});for(let t of e.entries)if(t.selected&&!(t.kind==="runtime-archive"||t.kind==="runtime-version")){if(t.kind==="browser-cache"){let l=c.relative(e.home,t.path).split(c.sep),m=l[0]==="profiles"&&l[1]==="playwright"&&l[2]?c.join(e.home,"profiles","playwright",l[2]):l[0]==="electron"&&l[1]==="userData"?c.join(e.home,"electron","userData"):null;if(m&&E(m)){t.state="in-use",t.selected=!1,t.detail="browser profile opened while cleanup was starting";continue}}D(e.home,t.path),a.rmSync(t.path,{recursive:!0,force:!0})}let s=e.entries.filter(t=>t.selected&&!a.existsSync(t.path)).map(t=>t.path),r=p(e.home);return{...e,removedPaths:s,reclaimedBytes:Math.max(0,e.totalBytes-r),remainingBytes:r}}function $(){B();let i=S(),e=c.join(i,k),n=c.join(i,A);if(w())return{status:"already-complete",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};let s=null;for(let r=0;r<2&&s===null;r++)try{let t=a.openSync(n,"wx");try{a.writeFileSync(t,`${JSON.stringify({pid:process.pid,startedAt:Date.now()})}
|
|
5
|
+
`,"utf8"),s=t}catch(o){a.closeSync(t);try{a.unlinkSync(n)}catch{}throw o}}catch(t){if((t instanceof Error&&"code"in t?t.code:null)!=="EEXIST")throw t;let l=0,m=0,u=null;try{u=a.lstatSync(n);let d=JSON.parse(a.readFileSync(n,"utf8"));l=typeof d.pid=="number"?d.pid:0,m=typeof d.startedAt=="number"?d.startedAt:0}catch{}if(l>0&&m>0&&Date.now()-m<P)try{return process.kill(l,0),{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0}}catch{}if(!u)continue;try{let d=a.lstatSync(n);if(d.dev!==u.dev||d.ino!==u.ino)return{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};a.unlinkSync(n)}catch{}}if(s===null)return{status:"busy",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};try{if(w())return{status:"already-complete",reclaimedBytes:0,remainingBytes:0,deferredInUseBytes:0};let r=I(),t=r.entries.reduce((l,m)=>l+(m.state==="in-use"?m.bytes:0),0);if(t>0)return{status:"deferred",reclaimedBytes:r.reclaimedBytes,remainingBytes:r.remainingBytes,deferredInUseBytes:t};let o=`${e}.${process.pid}.tmp`;return a.writeFileSync(o,`${JSON.stringify({generation:g,completedAt:Date.now(),reclaimedBytes:r.reclaimedBytes})}
|
|
6
|
+
`,"utf8"),a.renameSync(o,e),{status:"complete",reclaimedBytes:r.reclaimedBytes,remainingBytes:r.remainingBytes,deferredInUseBytes:0}}finally{a.closeSync(s);try{a.unlinkSync(n)}catch{}}}export{w as a,N as b,T as c,I as d,$ as e};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
3
|
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
-
import{a as at}from"./chunk-
|
|
4
|
+
import{a as at}from"./chunk-HNQ2FYAG.js";import{a as ot}from"./chunk-445FUUZC.js";import{a as pe,c as ge,d as we,e as ze,f as ye,g as be,h as Ye,i as Se,j as it}from"./chunk-YNN2AELC.js";import{a as qe}from"./chunk-E4O5A2QP.js";import{e as st}from"./chunk-H6RQAFD5.js";import{i as et,q as tt,s as rt,w as nt}from"./chunk-V4N34AOX.js";import{g as Xe}from"./chunk-DMJN3NC3.js";import{h as Ge,m as Ke}from"./chunk-7O6HJRGX.js";import{J as he,m as He,n as Ue,o as We,p as je,q as Ve}from"./chunk-ERRHAM2H.js";import{a as Qe}from"./chunk-AC2HNBEI.js";import{a as Ze}from"./chunk-IVV2KJTY.js";import{h as fe,i as me,j as Je}from"./chunk-IMXVXXWX.js";import{c as De,d as ce}from"./chunk-HTX6BHJZ.js";import{a as Be,b as Le,c as Ne}from"./chunk-XLT6Y654.js";import{e as ue,f as Ce}from"./chunk-VTYVJJHN.js";import*as $ from"fs";import{createHash as qt,randomUUID as zt}from"node:crypto";import{tmpdir as z}from"os";import*as w from"path";import*as v from"fs";import*as S from"path";var Pt="inset 0 0 0 0.5px #000, inset 0 0 0 2px #757575, inset 0 0 0 5px #212121",dt=1;function At(i){let e=Ne(i),t=e.scale,r=e.statusBarHeight>0&&!e.dynamicIsland&&e.homeIndicatorHeight===0&&e.cornerRadius===0,n=e.width,o=e.height,a=Be(e),s=r?e.width+58:a.frameWidth,l=r?e.height+111+111:a.frameHeight,p=9.5,u=dt,g=s+p*2,b=l+dt*2,m=p+(r?29:a.screenLeft),k=r?111:a.screenTop,P=r?52:a.frameRadius,H=[{side:e.hardwareButtons.lock.side,top:e.hardwareButtons.lock.top,height:e.hardwareButtons.lock.height,width:e.hardwareButtons.width},{side:e.hardwareButtons.ringToggle.side,top:e.hardwareButtons.ringToggle.top,height:e.hardwareButtons.ringToggle.height,width:e.hardwareButtons.width},{side:e.hardwareButtons.volumeUp.side,top:e.hardwareButtons.volumeUp.top,height:e.hardwareButtons.volumeUp.height,width:e.hardwareButtons.width},{side:e.hardwareButtons.volumeDown.side,top:e.hardwareButtons.volumeDown.top,height:e.hardwareButtons.volumeDown.height,width:e.hardwareButtons.width}];return{model:i,renderScale:t,outerWidth:Math.round(g*t),outerHeight:Math.round(b*t),logicalOuterWidth:g,logicalOuterHeight:b,logicalFrameWidth:s,logicalFrameHeight:l,logicalFrameLeft:p,logicalFrameTop:u,logicalScreenWidth:n,logicalScreenHeight:o,logicalScreenLeft:m,logicalScreenTop:k,logicalScreenRadius:r?0:a.screenRadius,logicalFrameRadius:P,frameBackground:r?"linear-gradient(180deg, #1b1c20 0%, #0f1012 42%, #050608 100%)":"#000000",frameOutline:r?"0 0 0 1px #1f2125":"0 0 0 1px #333",metallicRingShadow:r?null:Pt,buttons:H,legacyHomeButton:r?{top:111+e.height+47/2,left:e.width/2-64/2+29,size:64,ring:1.5}:null,showHomeIndicator:e.homeIndicatorHeight>0,logicalHomeIndicatorStripHeight:e.homeIndicatorHeight}}function Mt(i){let e=i.side==="right",t=e?"inset(-3px -3px -3px 0)":"inset(-3px 0 -3px -3px)";return`
|
|
5
5
|
<div
|
|
6
6
|
aria-hidden="true"
|
|
7
7
|
style="
|
|
@@ -212,7 +212,7 @@ process.stdin.on('end', async () => {
|
|
|
212
212
|
var yPercent = Math.ceil(y * 100) + '%'
|
|
213
213
|
return xPercent + ',' + yPercent
|
|
214
214
|
}
|
|
215
|
-
`,this.context);for(let[n,o]of Object.entries(process.env))o!==void 0&&this.envBinding.set(n,o)}putEnv(e,t){this.envBinding.set(e,t)}setCopiedText(e){this.maestro.copiedText=e}enterEnvScope(){this.envScopeStack.push(new Map(this.envBinding))}leaveEnvScope(){let e=this.envScopeStack.pop();if(e){this.envBinding.clear();for(let[t,r]of e)this.envBinding.set(t,r)}}evaluate(e,t={}){let r=t.env;if(r&&Object.keys(r).length>0){this.enterEnvScope();try{for(let[n,o]of Object.entries(r))this.envBinding.set(n,o);return this.evalRaw(e)}finally{this.leaveEnvScope()}}return this.evalRaw(e)}evalRaw(e){this.syncEnvToContext();let t=e.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${");return N.runInContext(`(function(){ with(__maestroScope){ return eval(\`${t}\`) } })()`,this.context)}syncEnvToContext(){let e=N.runInContext("globalThis",this.context);for(let t of this.syncedEnvKeys)this.envBinding.has(t)||delete e[t];this.syncedEnvKeys=new Set;for(let[t,r]of this.envBinding)try{e[t]=r,this.syncedEnvKeys.add(t)}catch{}}evaluateStringTemplate(e){return e.replace(Lt,(r,n)=>{if(n.trim().length===0)return"";let o=this.evaluate(n);if(o===void 0&&Ct.test(n.trim()))throw new Error(`missing variable for flow placeholder: ${n.trim()}`);return ut(o)}).replace(Nt,(r,n)=>n)}interpolateStep(e){return this.interpolateValue(e,null)}interpolateValue(e,t){return typeof e=="string"?t==="evalScript"?e:this.evaluateStringTemplate(e):Array.isArray(e)?t==="commands"||t==="onFlowStart"||t==="onFlowComplete"?e:e.map(r=>this.interpolateValue(r,t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([r,n])=>[r,this.interpolateValue(n,r)])):e}};function ut(i){if(i===void 0)return"undefined";if(i===null)return"null";if(typeof i=="object")try{return JSON.stringify(i)}catch{return String(i)}return String(i)}function pt(i){if(i==null)return!1;if(typeof i=="boolean")return i;let e=String(i);if(e.trim().length===0||e.toLowerCase()==="false"||e==="undefined"||e==="null")return!1;let t=Number(e);return!(!Number.isNaN(t)&&t===0)}var ee=1e4,Ht=Math.min(10,Math.max(1,Number(process.env.SOOTSIM_FLOW_TIMEOUT_SCALE)||1)),K=i=>Math.round(i*Ht),re=393,C=852;function f(i){return new Promise(e=>setTimeout(e,i))}function Ee(i){return!!(i&&typeof i=="object"&&!Array.isArray(i))}function q(i,e){if(!Ee(i))return null;let t=i[e];return typeof t=="string"&&t.length>0?t:null}function Ut(i,e){return Ee(i)?i[e]===!0:!1}function Wt(i){if(!i)return null;let e=i.recentApps;if(Array.isArray(e))for(let r of e){let n=q(r,"id");if(n)return n}let t=i.surfaceBindings;return q(t,"app:one")||q(t,"app:two")||null}function jt(i){return i?S.basename(i)===".maestro"?S.dirname(i):i:process.cwd()}function Vt(i,e,t){let r=e.endsWith(".png")?e:`${e}.png`;if(S.isAbsolute(r))return r;if(t.mode==="flow"&&/[\\/]/.test(r)){let n=r.startsWith("./")||r.startsWith("../")?t.flowDir??process.cwd():jt(t.flowDir);return S.resolve(n,r)}return S.join(i,r)}function Jt(i){if(typeof i=="string")return{path:i,withFrame:!1};let e=i.path?.trim()||i.name?.trim();if(!e)throw new Error("takeScreenshot object form requires path or name");return{path:e,withFrame:i.withFrame===!0,layers:i.layers}}function te(i,e){let[t,r]=i.split(",").map(s=>s.trim()),n=(s,l)=>s.endsWith("%")?Number.parseFloat(s)/100*l:Number.parseFloat(s),o=e?.x??0,a=e?.y??0;return{x:o+n(t,e?.width??re),y:a+n(r,e?.height??C)}}function ht(i){switch(i){case"back":return{back:!0};case"hideKeyboard":return{hideKeyboard:!0};case"waitForAnimationToEnd":return{waitForAnimationToEnd:!0};case"stopApp":return{stopApp:!0};case"clearState":return{clearState:!0};case"clearKeychain":return{clearKeychain:!0};case"eraseText":return{eraseText:50};case"scroll":case"scrollDown":return{scroll:{direction:"DOWN"}};case"scrollUp":return{scroll:{direction:"UP"}};default:return{[i]:!0}}}function Gt(i){let e=i.split(/^---$/m),t=e.length>1?e[e.length-1]:i,r=
|
|
215
|
+
`,this.context);for(let[n,o]of Object.entries(process.env))o!==void 0&&this.envBinding.set(n,o)}putEnv(e,t){this.envBinding.set(e,t)}setCopiedText(e){this.maestro.copiedText=e}enterEnvScope(){this.envScopeStack.push(new Map(this.envBinding))}leaveEnvScope(){let e=this.envScopeStack.pop();if(e){this.envBinding.clear();for(let[t,r]of e)this.envBinding.set(t,r)}}evaluate(e,t={}){let r=t.env;if(r&&Object.keys(r).length>0){this.enterEnvScope();try{for(let[n,o]of Object.entries(r))this.envBinding.set(n,o);return this.evalRaw(e)}finally{this.leaveEnvScope()}}return this.evalRaw(e)}evalRaw(e){this.syncEnvToContext();let t=e.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${");return N.runInContext(`(function(){ with(__maestroScope){ return eval(\`${t}\`) } })()`,this.context)}syncEnvToContext(){let e=N.runInContext("globalThis",this.context);for(let t of this.syncedEnvKeys)this.envBinding.has(t)||delete e[t];this.syncedEnvKeys=new Set;for(let[t,r]of this.envBinding)try{e[t]=r,this.syncedEnvKeys.add(t)}catch{}}evaluateStringTemplate(e){return e.replace(Lt,(r,n)=>{if(n.trim().length===0)return"";let o=this.evaluate(n);if(o===void 0&&Ct.test(n.trim()))throw new Error(`missing variable for flow placeholder: ${n.trim()}`);return ut(o)}).replace(Nt,(r,n)=>n)}interpolateStep(e){return this.interpolateValue(e,null)}interpolateValue(e,t){return typeof e=="string"?t==="evalScript"?e:this.evaluateStringTemplate(e):Array.isArray(e)?t==="commands"||t==="onFlowStart"||t==="onFlowComplete"?e:e.map(r=>this.interpolateValue(r,t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([r,n])=>[r,this.interpolateValue(n,r)])):e}};function ut(i){if(i===void 0)return"undefined";if(i===null)return"null";if(typeof i=="object")try{return JSON.stringify(i)}catch{return String(i)}return String(i)}function pt(i){if(i==null)return!1;if(typeof i=="boolean")return i;let e=String(i);if(e.trim().length===0||e.toLowerCase()==="false"||e==="undefined"||e==="null")return!1;let t=Number(e);return!(!Number.isNaN(t)&&t===0)}var ee=1e4,Ht=Math.min(10,Math.max(1,Number(process.env.SOOTSIM_FLOW_TIMEOUT_SCALE)||1)),K=i=>Math.round(i*Ht),re=393,C=852;function f(i){return new Promise(e=>setTimeout(e,i))}function Ee(i){return!!(i&&typeof i=="object"&&!Array.isArray(i))}function q(i,e){if(!Ee(i))return null;let t=i[e];return typeof t=="string"&&t.length>0?t:null}function Ut(i,e){return Ee(i)?i[e]===!0:!1}function Wt(i){if(!i)return null;let e=i.recentApps;if(Array.isArray(e))for(let r of e){let n=q(r,"id");if(n)return n}let t=i.surfaceBindings;return q(t,"app:one")||q(t,"app:two")||null}function jt(i){return i?S.basename(i)===".maestro"?S.dirname(i):i:process.cwd()}function Vt(i,e,t){let r=e.endsWith(".png")?e:`${e}.png`;if(S.isAbsolute(r))return r;if(t.mode==="flow"&&/[\\/]/.test(r)){let n=r.startsWith("./")||r.startsWith("../")?t.flowDir??process.cwd():jt(t.flowDir);return S.resolve(n,r)}return S.join(i,r)}function Jt(i){if(typeof i=="string")return{path:i,withFrame:!1};let e=i.path?.trim()||i.name?.trim();if(!e)throw new Error("takeScreenshot object form requires path or name");return{path:e,withFrame:i.withFrame===!0,layers:i.layers}}function te(i,e){let[t,r]=i.split(",").map(s=>s.trim()),n=(s,l)=>s.endsWith("%")?Number.parseFloat(s)/100*l:Number.parseFloat(s),o=e?.x??0,a=e?.y??0;return{x:o+n(t,e?.width??re),y:a+n(r,e?.height??C)}}function ht(i){switch(i){case"back":return{back:!0};case"hideKeyboard":return{hideKeyboard:!0};case"waitForAnimationToEnd":return{waitForAnimationToEnd:!0};case"stopApp":return{stopApp:!0};case"clearState":return{clearState:!0};case"clearKeychain":return{clearKeychain:!0};case"eraseText":return{eraseText:50};case"scroll":case"scrollDown":return{scroll:{direction:"DOWN"}};case"scrollUp":return{scroll:{direction:"UP"}};default:return{[i]:!0}}}function Gt(i){let e=i.split(/^---$/m),t=e.length>1?e[e.length-1]:i,r=qe.parse(t);return Array.isArray(r)?r:[]}var ne=class{constructor(e,t){this.bridge=e;this.opts=t}stepDelay=0;js=new Q({platform:"ios",onLog:e=>console.log(`[flow] js: ${e}`)});firstLaunchDone=!1;profilingEnabled=!1;recordingEnabled=!1;recordingAccessChecked=!1;recordingStartedAtMs=null;lastRecordingStartedAtMs=null;lastRecordingDurationMs=null;lastRecordingFrameStats=null;flowTraceSteps=[];lastVisualSettledAtMs=0;simRouteHint=null;lastFailedStep=null;get simId(){return this.opts.simId}setSimRouteHint(e){this.simRouteHint=this.normalizeSimRoute(e)}normalizeSimRoute(e){if(!e)return null;try{let t=new URL(e);t.searchParams.delete("inspectOpen");let r=t.searchParams.toString();return`${t.origin}${t.pathname}${r?`?${r}`:""}`}catch{return e}}async refreshSimId(){if(this.opts.simId)try{let e=await this.bridge.listSims(),t=e.find(l=>l.id===this.opts.simId);if(t&&(this.simRouteHint=this.normalizeSimRoute(t.url||t.origin)),e.find(l=>l.id===this.opts.simId&&l.readyState==="open")||!this.simRouteHint)return;let n=this.simRouteHint&&e.find(l=>l.readyState==="open"&&this.normalizeSimRoute(l.url||l.origin)===this.simRouteHint);if(!n)return;let o=e.find(l=>l.isPrimary&&l.readyState==="open"),a=e.find(l=>l.readyState==="open"),s=n??o??a;s&&(this.opts.simId=s.id,console.log(` [flow] sim rotated to ${s.id}`))}catch{}}async evaluate(e,t){return this.bridge.send({type:"evaluate",simId:this.opts.simId,code:e},t?{timeoutMs:t}:void 0)}async callTest(e,...t){return this.bridge.send({type:"call",simId:this.opts.simId,path:`__sootsimTest.${e}`,args:t})}async waitForTree(e=ee){let t=Date.now()+K(e),r=Date.now(),n=null,o=0,a=0,s=-1,l=r;for(;Date.now()<t;){try{let u=await this.evaluate(He,8e3);if(o=0,u?.externalError)throw new Error(`app failed to load: ${u.externalError}`);if(u){let g=Date.now();u.nodes!==s&&(s=u.nodes,l=g);let b=u.flag===!0&&je(u),m=u.flag!==!0&&Ve(u);if((b||m)&&u.externalReady!==!1&&!u.externalError&&!u.loadingText&&g-l>=Ue)return}}catch(u){if(n=u instanceof Error?u:new Error(String(u)),n.message.startsWith("app failed to load:"))throw n;if(o++,o>=4)throw new Error(`target sim is not responding to the bridge (${n.message}). it is likely a stale orphan \u2014 run \`sootsim list\`, then close it with \`sootsim close <id>\` or start a fresh one with \`sootsim open --new <port>\`.`);await this.refreshSimId()}let p=Date.now()-r;p-a>=5e3&&(a=p,console.log(` [flow] waiting for app to be ready\u2026 (${Math.round(p/1e3)}s)`)),await f(We)}throw n?.message.startsWith("app failed to load:")?n:new Error(`app not ready after ${e}ms`)}async ensureRecordingStarted(){if(!this.opts.recordingOutputDir)throw new Error("recording output directory not configured");this.recordingAccessChecked||(this.opts.requireRecordingEntitlement&&await at("flow --video",{originOverride:this.opts.billingOriginOverride,allowGitHubAuth:this.opts.allowGitHubRecording}),this.recordingAccessChecked=!0);let e=Date.now(),t=await this.evaluate(`(() => {
|
|
216
216
|
const rec = window.__sootsimRecorder
|
|
217
217
|
if (!rec) return { ok: false, error: 'recorder unavailable on this page' }
|
|
218
218
|
const format = ${JSON.stringify(this.opts.recordingFormat??"webm")}
|
|
@@ -443,7 +443,7 @@ process.stdin.on('end', async () => {
|
|
|
443
443
|
${e.steps||12}, ${e.stepMs||16}
|
|
444
444
|
)
|
|
445
445
|
return { ok: !!ok, reason: ok ? null : 'pinch returned false' }
|
|
446
|
-
})()`);if(!t?.ok)throw new Error(`pinch failed: ${t?.reason||"unknown error"}`);await f(250)}async dumpTree(e=6){let t=await this.bridge.send({type:"tree",simId:this.opts.simId,depth:e});return console.log("[flow] tree:"),console.log(typeof t=="string"?t:JSON.stringify(t,null,2)),typeof t=="string"?t:JSON.stringify(t)}async assertTreeContains(e){if(!(await this.dumpTree(8)).includes(e))throw new Error(`assertTreeContains: "${e}" not in tree`)}async waitForAnimationToEnd(e=2e3){let t=Math.max(0,Math.round(e));if(t<=0)return;(await Se({bridge:this.bridge,simId:this.opts.simId,maxMs:t,pollMs:32,stablePolls:2,strict:!0})).settled&&this.markVisualSettled()}async back(){try{await this.tapOn("\u2039")}catch{await this.tapOn("<")}}async scrollUntilVisible(e){let t=Date.now()+(e.timeout||15e3),r=e.direction?.toUpperCase()||"DOWN",n=r==="DOWN"?"UP":r==="UP"?"DOWN":r;for(;Date.now()<t;){let o=await this.findElement({text:e.element});if(o&&o.absolutePosition.y>=0&&o.absolutePosition.y+o.layout.height>0&&o.absolutePosition.y<C-50){if(e.centerElement){let a=C/2,s=o.absolutePosition.y-a;if(Math.abs(s)>100){let l=Math.min(150,Math.abs(s)*.5),p=s>0?a-l:a+l;await this.drag(re/2,a,re/2,p,10,16)}}return}await this.swipe(n,250),await f(500)}throw new Error(`scrollUntilVisible: "${e.element}" not found`)}async extendedWaitUntil(e){let t=Date.now()+K(e.timeout||ee);for(;Date.now()<t;){let r=e.visible?await this.isElementVisible(typeof e.visible=="string"?{text:e.visible}:e.visible):!0,n=e.notVisible?!await this.isElementVisible(typeof e.notVisible=="string"?{text:e.notVisible}:e.notVisible):!0;if(r&&n)return;await f(200)}throw new Error("extendedWaitUntil timed out")}async reloadGuestApp(e){if(e){let n=!1;for(let o=0;o<3&&!n;o++)try{n=await this.evaluate(
|
|
446
|
+
})()`);if(!t?.ok)throw new Error(`pinch failed: ${t?.reason||"unknown error"}`);await f(250)}async dumpTree(e=6){let t=await this.bridge.send({type:"tree",simId:this.opts.simId,depth:e});return console.log("[flow] tree:"),console.log(typeof t=="string"?t:JSON.stringify(t,null,2)),typeof t=="string"?t:JSON.stringify(t)}async assertTreeContains(e){if(!(await this.dumpTree(8)).includes(e))throw new Error(`assertTreeContains: "${e}" not in tree`)}async waitForAnimationToEnd(e=2e3){let t=Math.max(0,Math.round(e));if(t<=0)return;(await Se({bridge:this.bridge,simId:this.opts.simId,maxMs:t,pollMs:32,stablePolls:2,strict:!0})).settled&&this.markVisualSettled()}async back(){try{await this.tapOn("\u2039")}catch{await this.tapOn("<")}}async scrollUntilVisible(e){let t=Date.now()+(e.timeout||15e3),r=e.direction?.toUpperCase()||"DOWN",n=r==="DOWN"?"UP":r==="UP"?"DOWN":r;for(;Date.now()<t;){let o=await this.findElement({text:e.element});if(o&&o.absolutePosition.y>=0&&o.absolutePosition.y+o.layout.height>0&&o.absolutePosition.y<C-50){if(e.centerElement){let a=C/2,s=o.absolutePosition.y-a;if(Math.abs(s)>100){let l=Math.min(150,Math.abs(s)*.5),p=s>0?a-l:a+l;await this.drag(re/2,a,re/2,p,10,16)}}return}await this.swipe(n,250),await f(500)}throw new Error(`scrollUntilVisible: "${e.element}" not found`)}async extendedWaitUntil(e){let t=Date.now()+K(e.timeout||ee);for(;Date.now()<t;){let r=e.visible?await this.isElementVisible(typeof e.visible=="string"?{text:e.visible}:e.visible):!0,n=e.notVisible?!await this.isElementVisible(typeof e.notVisible=="string"?{text:e.notVisible}:e.notVisible):!0;if(r&&n)return;await f(200)}throw new Error("extendedWaitUntil timed out")}async reloadGuestApp(e){if(e){let n=!1;for(let o=0;o<3&&!n;o++)try{n=await this.evaluate(pe(!0),2e4)}catch{await f(1e3)}n||console.warn(" warn: tenant storage clear did not ack \u2014 hard-reloading anyway (worker reset follows)")}await this.evaluate("window.location.reload()").catch(()=>{}),await f(500),await this.refreshSimId()}async softReloadGuestApp(e){if(!await this.evaluate(pe(e),12e4))throw new Error("guest app soft reload bridge unavailable")}async rearmCaptureAfterRuntimeReload(){if(!this.recordingEnabled&&!this.profilingEnabled)return;let e=Date.now()+1e4,t=null;for(;Date.now()<e;){await this.refreshSimId();try{this.recordingEnabled&&await this.ensureRecordingStarted(),this.profilingEnabled&&await this.startProfile();return}catch(r){t=r,await f(250)}}throw new Error(`capture re-arm failed after app reload: ${t instanceof Error?t.message:String(t)}`)}async launchApp(e){await this.refreshSimId(),e&&typeof e=="object"&&e.arguments&&console.log("[flow] launchApp.arguments ignored (sootsim has no native process)");let t=!!(e&&typeof e=="object"&&e.clearState),r=Ut(e,"resetRuntime");if(!this.firstLaunchDone&&!t)this.firstLaunchDone=!0,r?(await this.launchShellAppFromHomeIfNeeded(e)&&await this.waitForTree(12e4),await this.softReloadGuestApp(!1),await this.waitForTree(12e4)):await this.launchShellAppFromHomeIfNeeded(e),await this.waitForTree(3e4);else if(this.firstLaunchDone=!0,await this.reloadGuestApp(t),await this.waitForTree(12e4),this.opts.onAfterLaunch)try{await this.opts.onAfterLaunch()}catch(n){console.warn(` warn: onAfterLaunch hook threw: ${n instanceof Error?n.message:n}`)}this.profilingEnabled&&await this.startProfile(),this.recordingEnabled&&(await this.waitForVisualSettle(),await this.ensureRecordingStarted())}async waitForVisualSettle(){try{await this.evaluate(`new Promise((resolve) => {
|
|
447
447
|
requestAnimationFrame(() => {
|
|
448
448
|
requestAnimationFrame(() => {
|
|
449
449
|
requestAnimationFrame(() => {
|
|
@@ -451,7 +451,7 @@ process.stdin.on('end', async () => {
|
|
|
451
451
|
})
|
|
452
452
|
})
|
|
453
453
|
})
|
|
454
|
-
})`),this.markVisualSettled()}catch{await f(180),this.markVisualSettled()}}markVisualSettled(){this.lastVisualSettledAtMs=Date.now()}hasFreshVisualSettle(){return Date.now()-this.lastVisualSettledAtMs<750}resolveShellLaunchAppId(e,t){if(typeof e=="string"&&e.length>0)return e;if(Ee(e)){let r=q(e,"appId")||q(e,"id");if(r)return r}return Wt(t)||"connect"}async waitForShellAppLaunched(e,t){let r=Date.now()+t,n=null;for(;Date.now()<r;){try{n=await
|
|
454
|
+
})`),this.markVisualSettled()}catch{await f(180),this.markVisualSettled()}}markVisualSettled(){this.lastVisualSettledAtMs=Date.now()}hasFreshVisualSettle(){return Date.now()-this.lastVisualSettledAtMs<750}resolveShellLaunchAppId(e,t){if(typeof e=="string"&&e.length>0)return e;if(Ee(e)){let r=q(e,"appId")||q(e,"id");if(r)return r}return Wt(t)||"connect"}async waitForShellAppLaunched(e,t){let r=Date.now()+t,n=null;for(;Date.now()<r;){try{n=await he(this.bridge)}catch{n=null}if(n?.state==="app"&&n.activeApp===e&&n.showSwitcher===!1&&typeof n.launchProgress=="number"&&n.launchProgress>=.98)return;await f(16)}}async launchShellAppFromHomeIfNeeded(e){let t=null;try{t=await he(this.bridge)}catch{return!1}if(t?.state!=="home"||t.activeApp!=null)return!1;let r=this.resolveShellLaunchAppId(e,t);return this.recordingEnabled&&await this.ensureRecordingStarted(),await Ge(this.bridge,"launchApp",1e3,r),await this.waitForShellAppLaunched(r,1e3),!0}async startProfile(){let e=await this.evaluate(`(() => {
|
|
455
455
|
if (!window.__sootsimShellPerf) {
|
|
456
456
|
return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
|
|
457
457
|
}
|
|
@@ -462,7 +462,7 @@ process.stdin.on('end', async () => {
|
|
|
462
462
|
return { error: "shell frame profile unavailable (__sootsimShellPerf missing on the page)" }
|
|
463
463
|
}
|
|
464
464
|
return await window.__sootsimShellPerf.stop()
|
|
465
|
-
})()`);if(this.profilingEnabled=!1,e?.error)throw new Error(e.error);return e}async stopApp(){await this.reloadGuestApp(!1),await this.rearmCaptureAfterRuntimeReload()}async clearState(){await this.reloadGuestApp(!0),await this.rearmCaptureAfterRuntimeReload()}clearKeychain(){console.warn("[flow] clearKeychain: sootsim has no keychain surface \u2014 no-op (warning)")}async copyTextFrom(e){let t=typeof e=="string"?{id:e}:e,r=await this.findElement(t);if(!r)throw new Error(`copyTextFrom: element not found: ${JSON.stringify(t)}`);let n=r.text??r.testID??"";this.js.setCopiedText(n),this.js.putEnv("maestroCopiedText",n),console.log(`[flow] copied text: ${JSON.stringify(n)}`)}evalScript(e){let r=/(?<!\\)\$\{[^$]*\}/.test(e)?this.js.evaluateStringTemplate(e):this.js.evaluate(e);r!==void 0&&r!==""&&console.log("[flow] evalScript ->",r)}runScript(e){let t=typeof e=="string"?{file:e}:e;if(!t.file)throw new Error("runScript requires a file");let r=S.resolve(this.opts.flowDir,t.file),n=v.readFileSync(r,"utf8");this.js.evaluate(n,{env:t.env}),console.log(`[flow] runScript: ${t.file} done`)}async openLink(e){let t=typeof e=="string"?e:e.link;if(!t)throw new Error("openLink: missing link");let r=await this.callTest("openDeepLink",t);if(!r?.ok)throw new Error(`openLink failed: ${r?.error||"no test bridge"}`);await f(300)}async evaluateWhen(e){if(e.visible!==void 0){let t=typeof e.visible=="string"?{text:e.visible}:e.visible;return!!await this.findElement(t)}if(e.notVisible!==void 0){let t=typeof e.notVisible=="string"?{text:e.notVisible}:e.notVisible;return!await this.findElement(t)}return e.platform!==void 0?e.platform.toLowerCase()===this.js.maestro.platform.toLowerCase():e.true!==void 0?pt(e.true):!0}isOptional(e){if(e.optional===!0)return!0;let r=Object.entries(e).find(([o])=>o!=="when"&&o!=="optional"),n=r?r[1]:void 0;return!!(n&&typeof n=="object"&&"optional"in n&&n.optional)}async runStep(e,t){let r=typeof e=="string"?ht(e):e,n=Object.keys(r).find(l=>l!=="when")||Object.keys(r)[0];console.log(`[flow] step ${t+1}: ${n}`);let o=Date.now(),a=this.flowStepTargetLabel(r,n),s;try{s=this.js.interpolateStep(r),a=this.flowStepTargetLabel(s,n)??a}catch(l){if(this.isOptional(r)){console.log(`[flow] (optional, skipped: ${l.message.slice(0,80)})`),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped",error:l});return}throw this.lastFailedStep={index:t,kind:n,target:r[n]},this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"failure",error:l}),l}if(s.when&&!await this.evaluateWhen(s.when)){console.log("[flow] (when: predicate false, skipped)"),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped"});return}try{let l=!!(s.extendedWaitUntil||s.waitFor||s.scrollUntilVisible||s.launchApp||s.runFlow||s.runScript),p=1e4,u=this.runStepInner(s),g;if(l){let m=await u;typeof m=="string"&&(g=m)}else{let m=null,k=new Promise((P,H)=>{m=setTimeout(()=>{H(new Error(`step watchdog: ${n} made no progress in ${p}ms \u2014 bridge or bundle probably hung`))},p)});try{let P=await Promise.race([u,k]);typeof P=="string"&&(g=P)}finally{m&&clearTimeout(m)}}let b=!!(s.assertVisible||s.assertNotVisible||s.extendedWaitUntil||s.waitFor);this.stepDelay>0&&!b&&await f(this.stepDelay),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"success",screenshotPath:g})}catch(l){if(this.isOptional(s)){console.log(`[flow] (optional, skipped: ${l.message.slice(0,80)})`),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped",error:l});return}throw this.lastFailedStep={index:t,kind:n,target:s[n]},this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"failure",error:l}),l}}async runStepInner(e){if(e.tapOn)await this.tapOn(e.tapOn);else if(e.longPressOn)await this.longPressOn(e.longPressOn);else if(e.scrollUntilVisible)await this.scrollUntilVisible(e.scrollUntilVisible);else if(e.extendedWaitUntil)await this.extendedWaitUntil(e.extendedWaitUntil);else if(e.assertVisible)await this.assertVisible(e.assertVisible);else if(e.assertNotVisible)await this.assertNotVisible(e.assertNotVisible);else if(e.inputText)await this.inputText(e.inputText);else if(e.pressKey)await this.pressKey(e.pressKey);else if(e.dispatchKey)await this.dispatchKey(e.dispatchKey);else if(e.waitFor)await this.waitFor(e.waitFor);else{if(e.takeScreenshot)return this.takeScreenshot(e.takeScreenshot);if(e.swipe)e.swipe.start&&e.swipe.end?await this.swipeCoords(e.swipe.start,e.swipe.end,e.swipe.duration):e.swipe.from?await this.swipeFrom(e.swipe.from,e.swipe.direction,e.swipe.duration):await this.swipe(e.swipe.direction,e.swipe.duration);else if(e.scroll)await this.swipe(e.scroll.direction==="DOWN"?"UP":"DOWN");else if(e.scrollTo){let t=typeof e.scrollTo.nodeId=="number"?{nodeId:e.scrollTo.nodeId}:e.scrollTo.id;if(!t)throw new Error("scrollTo requires id or nodeId");await this.scrollTo(t,e.scrollTo.x,e.scrollTo.y)}else if(e.pinch)await this.pinch(e.pinch);else if(e.waitForAnimationToEnd){let t=e.waitForAnimationToEnd;await this.waitForAnimationToEnd(typeof t=="number"?t:typeof t=="object"&&typeof t.timeout=="number"?t.timeout:2e3)}else if(e.back)await this.back();else if(e.hideKeyboard)await this.hideKeyboard();else if(e.launchApp)await this.launchApp(e.launchApp);else if(typeof e.wait=="number")await f(e.wait);else if(e.dumpTree)await this.dumpTree(e.dumpTree);else if(e.tapAtCoords)await this.tapAtCoords(e.tapAtCoords.x,e.tapAtCoords.y);else if(e.doubleTapAtCoords)await this.doubleTapAtCoords(e.doubleTapAtCoords.x,e.doubleTapAtCoords.y,e.doubleTapAtCoords.gapMs);else if(e.assertTreeContains)await this.assertTreeContains(e.assertTreeContains);else if(typeof e.eraseText=="number")await this.eraseText(e.eraseText);else if(e.repeat&&Array.isArray(e.repeat.commands)){let t=e.repeat.times,r=t==null||t===""?Number.MAX_SAFE_INTEGER:Number(t);if(!Number.isFinite(r))throw new Error(`repeat.times is not a number: ${t}`);let n=e.repeat.when??e.repeat.condition,o=async()=>n?this.evaluateWhen(n):!0,a=n?r:Math.min(r,1e3),s=0;for(;s<a&&await o();){for(let l=0;l<e.repeat.commands.length;l++)await this.runStep(e.repeat.commands[l],l);s++}}else if(e.stopApp!==void 0)await this.stopApp();else if(e.clearState!==void 0)await this.clearState();else if(e.clearKeychain!==void 0)this.clearKeychain();else if(e.copyTextFrom!==void 0)await this.copyTextFrom(e.copyTextFrom);else if(typeof e.evalScript=="string")this.evalScript(e.evalScript);else if(e.runScript){let t=e.runScript,r=typeof t=="string"?void 0:t.when;if(r&&!await this.evaluateWhen(r)){console.log("[flow] runScript skipped (when predicate false)");return}this.runScript(t)}else if(e.openLink!==void 0)await this.openLink(e.openLink);else if(e.runFlow){let t=e.runFlow,r=typeof t=="string"?t:t.file,n=typeof t=="string"?void 0:t.commands,o=typeof t=="string"?void 0:t.env,a=typeof t=="string"?void 0:t.when;if(a&&!await this.evaluateWhen(a)){console.log(`[flow] runFlow skipped (when predicate false): ${r??"inline commands"}`);return}if(!r&&!n)throw new Error("runFlow requires either file or commands");this.js.enterEnvScope();try{if(o)for(let[s,l]of Object.entries(o))this.js.putEnv(s,l);if(r){let s=S.resolve(this.opts.flowDir,r),l=v.readFileSync(s,"utf8"),p=this.opts.flowDir;this.opts.flowDir=S.dirname(s);try{await this.runFlow(Gt(l))}finally{this.opts.flowDir=p}}else if(n)for(let s=0;s<n.length;s++)await this.runStep(n[s],s)}finally{this.js.leaveEnvScope()}}else throw new Error(`unsupported flow step: ${JSON.stringify(e)}`)}}liveStatus=null;async runFlow(e){let t=[],r=[],n=[];for(let a of e){let s=Object.keys(a);if(s.length===1&&s[0]==="onFlowStart"&&Array.isArray(a.onFlowStart)){t.push(...a.onFlowStart);continue}if(s.length===1&&s[0]==="onFlowComplete"&&Array.isArray(a.onFlowComplete)){r.push(...a.onFlowComplete);continue}n.push(a)}if(this.liveStatus&&await this.liveStatus.plan(n.map((a,s)=>{let l=typeof a=="string"?ht(a):a,p=Object.keys(l).find(u=>u!=="when")??Object.keys(l)[0];return{index:s,name:p,target:this.flowStepTargetLabel(l,p)}})),t.length>0){console.log(`[flow] onFlowStart (${t.length} steps)`);for(let a=0;a<t.length;a++)await this.runStep(t[a],a)}let o=null;try{await this.runFlowBody(n)}catch(a){o=a instanceof Error?a:new Error(String(a))}if(r.length>0){console.log(`[flow] onFlowComplete (${r.length} steps)`);for(let a=0;a<r.length;a++)try{await this.runStep(r[a],a)}catch(s){console.warn(`[flow] onFlowComplete step ${a+1} failed: ${s instanceof Error?s.message:s}`)}}if(o)throw o}async runFlowBody(e){for(let t=0;t<e.length;t++){let r=e[t],n=typeof r.wait=="number"?r.wait:0,o=typeof r.waitFor?.timeout=="number"?r.waitFor.timeout:0,a=typeof r.extendedWaitUntil?.timeout=="number"?r.extendedWaitUntil.timeout:0,s=Math.max(6e4,n+15e3,K(o)+15e3,K(a)+15e3);this.liveStatus&&(await this.liveStatus.waitWhilePaused(),await this.liveStatus.step(t,"running"));let l=Date.now(),p=async(u,g)=>{if(!this.liveStatus)return;let b=this.flowTraceSteps[this.flowTraceSteps.length-1],m=b&&b.stepIndex===t&&b.startedAtMs>=l;await this.liveStatus.step(t,u?"failure":m&&b.status==="skipped"?"skipped":"success",{durationMs:Date.now()-l,error:u?g instanceof Error?g.message.slice(0,300):String(g).slice(0,300):m&&b.error||void 0})};try{r.runFlow||r.launchApp?await this.runStep(r,t):await Promise.race([this.runStep(r,t),new Promise((u,g)=>setTimeout(()=>g(new Error(`step ${t+1} (${Object.keys(r)[0]}) exceeded ${s}ms deadline`)),s))])}catch(u){let g=this.flowTraceSteps[this.flowTraceSteps.length-1];if(!(g&&g.stepIndex===t&&g.startedAtMs>=l)){let b=Object.keys(r)[0];this.lastFailedStep={index:t,kind:b,target:r[b]},this.recordFlowTraceStep({stepIndex:t,stepName:b,targetLabel:this.flowStepTargetLabel(r,b),startedAtMs:l,status:"failure",error:u})}throw await p(!0,u),u}await p(!1)}}};function Kt(i){if(typeof i!="object"||i==null||!("control"in i))return!1;let e=i.control;return typeof e=="object"&&e!=null&&"paused"in e&&e.paused===!0}var ie=class{constructor(e,t,r){this.bridge=e;this.flowName=t;this.getSimId=r}disabled=!1;paused=!1;lastSimId;plannedSteps=null;completedSteps=new Map;runId=`flr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`;async send(e,t){let r=await this.bridge.send({type:"flowStatus",simId:t,status:{runId:this.runId,flowName:this.flowName,...e}});this.paused=Kt(r)}async push(e){if(!this.disabled)try{let t=this.getSimId?.();if(t!==this.lastSimId&&this.lastSimId!=null&&this.plannedSteps&&e.phase!=="plan"){await this.send({phase:"plan",state:"running",steps:this.plannedSteps},t);for(let r of this.completedSteps.values())await this.send({phase:"step",state:"running",step:r},t)}this.lastSimId=t,await this.send(e,t)}catch(t){this.disabled=!0,console.log(`[flow] live status unavailable (${t instanceof Error?t.message.slice(0,120):t}) \u2014 continuing without the devtools rail`)}}async plan(e){this.plannedSteps=e.map(t=>({...t})),this.completedSteps.clear(),await this.push({phase:"plan",state:"running",steps:e})}async step(e,t,r){let n={index:e,status:t,...r};await this.push({phase:"step",state:"running",step:n}),this.completedSteps.set(e,n)}async end(e){await this.push({phase:"end",state:e})}async waitWhilePaused(){if(!this.disabled)for(;this.paused;){for(console.log("[flow] paused from devtools \u2014 waiting\u2026");this.paused&&!this.disabled;)await new Promise(e=>setTimeout(e,400)),await this.push({phase:"heartbeat",state:"paused"});this.disabled||console.log("[flow] resumed")}}};var Ie=null;function Ur(){return Ie}var Fe=[];function Wr(){return Fe}async function Yt(i){if(!i)return"";let e=i.trim();if(!e)return"";if(/^\d+$/.test(e)||e.startsWith("http://")||e.startsWith("https://"))return e;let r=(await He()).find(n=>n.name.toLowerCase()===e.toLowerCase());return r?String(r.preferredPort):e}async function Zt(){let i=await Ue(),e=i.find(r=>r.patched);if(e)return`http://localhost:${e.port}/__soot/`;let t=i[0];return t?`http://localhost:${t.port}/__soot/`:null}async function mt(i){Ie=null,Fe=[],(i.length===0||i.includes("--help")||i.includes("-h"))&&(console.log(`
|
|
465
|
+
})()`);if(this.profilingEnabled=!1,e?.error)throw new Error(e.error);return e}async stopApp(){await this.reloadGuestApp(!1),await this.rearmCaptureAfterRuntimeReload()}async clearState(){await this.reloadGuestApp(!0),await this.rearmCaptureAfterRuntimeReload()}clearKeychain(){console.warn("[flow] clearKeychain: sootsim has no keychain surface \u2014 no-op (warning)")}async copyTextFrom(e){let t=typeof e=="string"?{id:e}:e,r=await this.findElement(t);if(!r)throw new Error(`copyTextFrom: element not found: ${JSON.stringify(t)}`);let n=r.text??r.testID??"";this.js.setCopiedText(n),this.js.putEnv("maestroCopiedText",n),console.log(`[flow] copied text: ${JSON.stringify(n)}`)}evalScript(e){let r=/(?<!\\)\$\{[^$]*\}/.test(e)?this.js.evaluateStringTemplate(e):this.js.evaluate(e);r!==void 0&&r!==""&&console.log("[flow] evalScript ->",r)}runScript(e){let t=typeof e=="string"?{file:e}:e;if(!t.file)throw new Error("runScript requires a file");let r=S.resolve(this.opts.flowDir,t.file),n=v.readFileSync(r,"utf8");this.js.evaluate(n,{env:t.env}),console.log(`[flow] runScript: ${t.file} done`)}async openLink(e){let t=typeof e=="string"?e:e.link;if(!t)throw new Error("openLink: missing link");let r=await this.callTest("openDeepLink",t);if(!r?.ok)throw new Error(`openLink failed: ${r?.error||"no test bridge"}`);await f(300)}async evaluateWhen(e){if(e.visible!==void 0){let t=typeof e.visible=="string"?{text:e.visible}:e.visible;return!!await this.findElement(t)}if(e.notVisible!==void 0){let t=typeof e.notVisible=="string"?{text:e.notVisible}:e.notVisible;return!await this.findElement(t)}return e.platform!==void 0?e.platform.toLowerCase()===this.js.maestro.platform.toLowerCase():e.true!==void 0?pt(e.true):!0}isOptional(e){if(e.optional===!0)return!0;let r=Object.entries(e).find(([o])=>o!=="when"&&o!=="optional"),n=r?r[1]:void 0;return!!(n&&typeof n=="object"&&"optional"in n&&n.optional)}async runStep(e,t){let r=typeof e=="string"?ht(e):e,n=Object.keys(r).find(l=>l!=="when")||Object.keys(r)[0];console.log(`[flow] step ${t+1}: ${n}`);let o=Date.now(),a=this.flowStepTargetLabel(r,n),s;try{s=this.js.interpolateStep(r),a=this.flowStepTargetLabel(s,n)??a}catch(l){if(this.isOptional(r)){console.log(`[flow] (optional, skipped: ${l.message.slice(0,80)})`),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped",error:l});return}throw this.lastFailedStep={index:t,kind:n,target:r[n]},this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"failure",error:l}),l}if(s.when&&!await this.evaluateWhen(s.when)){console.log("[flow] (when: predicate false, skipped)"),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped"});return}try{let l=!!(s.extendedWaitUntil||s.waitFor||s.scrollUntilVisible||s.launchApp||s.runFlow||s.runScript),p=1e4,u=this.runStepInner(s),g;if(l){let m=await u;typeof m=="string"&&(g=m)}else{let m=null,k=new Promise((P,H)=>{m=setTimeout(()=>{H(new Error(`step watchdog: ${n} made no progress in ${p}ms \u2014 bridge or bundle probably hung`))},p)});try{let P=await Promise.race([u,k]);typeof P=="string"&&(g=P)}finally{m&&clearTimeout(m)}}let b=!!(s.assertVisible||s.assertNotVisible||s.extendedWaitUntil||s.waitFor);this.stepDelay>0&&!b&&await f(this.stepDelay),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"success",screenshotPath:g})}catch(l){if(this.isOptional(s)){console.log(`[flow] (optional, skipped: ${l.message.slice(0,80)})`),this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"skipped",error:l});return}throw this.lastFailedStep={index:t,kind:n,target:s[n]},this.recordFlowTraceStep({stepIndex:t,stepName:n,targetLabel:a,startedAtMs:o,status:"failure",error:l}),l}}async runStepInner(e){if(e.tapOn)await this.tapOn(e.tapOn);else if(e.longPressOn)await this.longPressOn(e.longPressOn);else if(e.scrollUntilVisible)await this.scrollUntilVisible(e.scrollUntilVisible);else if(e.extendedWaitUntil)await this.extendedWaitUntil(e.extendedWaitUntil);else if(e.assertVisible)await this.assertVisible(e.assertVisible);else if(e.assertNotVisible)await this.assertNotVisible(e.assertNotVisible);else if(e.inputText)await this.inputText(e.inputText);else if(e.pressKey)await this.pressKey(e.pressKey);else if(e.dispatchKey)await this.dispatchKey(e.dispatchKey);else if(e.waitFor)await this.waitFor(e.waitFor);else{if(e.takeScreenshot)return this.takeScreenshot(e.takeScreenshot);if(e.swipe)e.swipe.start&&e.swipe.end?await this.swipeCoords(e.swipe.start,e.swipe.end,e.swipe.duration):e.swipe.from?await this.swipeFrom(e.swipe.from,e.swipe.direction,e.swipe.duration):await this.swipe(e.swipe.direction,e.swipe.duration);else if(e.scroll)await this.swipe(e.scroll.direction==="DOWN"?"UP":"DOWN");else if(e.scrollTo){let t=typeof e.scrollTo.nodeId=="number"?{nodeId:e.scrollTo.nodeId}:e.scrollTo.id;if(!t)throw new Error("scrollTo requires id or nodeId");await this.scrollTo(t,e.scrollTo.x,e.scrollTo.y)}else if(e.pinch)await this.pinch(e.pinch);else if(e.waitForAnimationToEnd){let t=e.waitForAnimationToEnd;await this.waitForAnimationToEnd(typeof t=="number"?t:typeof t=="object"&&typeof t.timeout=="number"?t.timeout:2e3)}else if(e.back)await this.back();else if(e.hideKeyboard)await this.hideKeyboard();else if(e.launchApp)await this.launchApp(e.launchApp);else if(typeof e.wait=="number")await f(e.wait);else if(e.dumpTree)await this.dumpTree(e.dumpTree);else if(e.tapAtCoords)await this.tapAtCoords(e.tapAtCoords.x,e.tapAtCoords.y);else if(e.doubleTapAtCoords)await this.doubleTapAtCoords(e.doubleTapAtCoords.x,e.doubleTapAtCoords.y,e.doubleTapAtCoords.gapMs);else if(e.assertTreeContains)await this.assertTreeContains(e.assertTreeContains);else if(typeof e.eraseText=="number")await this.eraseText(e.eraseText);else if(e.repeat&&Array.isArray(e.repeat.commands)){let t=e.repeat.times,r=t==null||t===""?Number.MAX_SAFE_INTEGER:Number(t);if(!Number.isFinite(r))throw new Error(`repeat.times is not a number: ${t}`);let n=e.repeat.when??e.repeat.condition,o=async()=>n?this.evaluateWhen(n):!0,a=n?r:Math.min(r,1e3),s=0;for(;s<a&&await o();){for(let l=0;l<e.repeat.commands.length;l++)await this.runStep(e.repeat.commands[l],l);s++}}else if(e.stopApp!==void 0)await this.stopApp();else if(e.clearState!==void 0)await this.clearState();else if(e.clearKeychain!==void 0)this.clearKeychain();else if(e.copyTextFrom!==void 0)await this.copyTextFrom(e.copyTextFrom);else if(typeof e.evalScript=="string")this.evalScript(e.evalScript);else if(e.runScript){let t=e.runScript,r=typeof t=="string"?void 0:t.when;if(r&&!await this.evaluateWhen(r)){console.log("[flow] runScript skipped (when predicate false)");return}this.runScript(t)}else if(e.openLink!==void 0)await this.openLink(e.openLink);else if(e.runFlow){let t=e.runFlow,r=typeof t=="string"?t:t.file,n=typeof t=="string"?void 0:t.commands,o=typeof t=="string"?void 0:t.env,a=typeof t=="string"?void 0:t.when;if(a&&!await this.evaluateWhen(a)){console.log(`[flow] runFlow skipped (when predicate false): ${r??"inline commands"}`);return}if(!r&&!n)throw new Error("runFlow requires either file or commands");this.js.enterEnvScope();try{if(o)for(let[s,l]of Object.entries(o))this.js.putEnv(s,l);if(r){let s=S.resolve(this.opts.flowDir,r),l=v.readFileSync(s,"utf8"),p=this.opts.flowDir;this.opts.flowDir=S.dirname(s);try{await this.runFlow(Gt(l))}finally{this.opts.flowDir=p}}else if(n)for(let s=0;s<n.length;s++)await this.runStep(n[s],s)}finally{this.js.leaveEnvScope()}}else throw new Error(`unsupported flow step: ${JSON.stringify(e)}`)}}liveStatus=null;async runFlow(e){let t=[],r=[],n=[];for(let a of e){let s=Object.keys(a);if(s.length===1&&s[0]==="onFlowStart"&&Array.isArray(a.onFlowStart)){t.push(...a.onFlowStart);continue}if(s.length===1&&s[0]==="onFlowComplete"&&Array.isArray(a.onFlowComplete)){r.push(...a.onFlowComplete);continue}n.push(a)}if(this.liveStatus&&await this.liveStatus.plan(n.map((a,s)=>{let l=typeof a=="string"?ht(a):a,p=Object.keys(l).find(u=>u!=="when")??Object.keys(l)[0];return{index:s,name:p,target:this.flowStepTargetLabel(l,p)}})),t.length>0){console.log(`[flow] onFlowStart (${t.length} steps)`);for(let a=0;a<t.length;a++)await this.runStep(t[a],a)}let o=null;try{await this.runFlowBody(n)}catch(a){o=a instanceof Error?a:new Error(String(a))}if(r.length>0){console.log(`[flow] onFlowComplete (${r.length} steps)`);for(let a=0;a<r.length;a++)try{await this.runStep(r[a],a)}catch(s){console.warn(`[flow] onFlowComplete step ${a+1} failed: ${s instanceof Error?s.message:s}`)}}if(o)throw o}async runFlowBody(e){for(let t=0;t<e.length;t++){let r=e[t],n=typeof r.wait=="number"?r.wait:0,o=typeof r.waitFor?.timeout=="number"?r.waitFor.timeout:0,a=typeof r.extendedWaitUntil?.timeout=="number"?r.extendedWaitUntil.timeout:0,s=Math.max(6e4,n+15e3,K(o)+15e3,K(a)+15e3);this.liveStatus&&(await this.liveStatus.waitWhilePaused(),await this.liveStatus.step(t,"running"));let l=Date.now(),p=async(u,g)=>{if(!this.liveStatus)return;let b=this.flowTraceSteps[this.flowTraceSteps.length-1],m=b&&b.stepIndex===t&&b.startedAtMs>=l;await this.liveStatus.step(t,u?"failure":m&&b.status==="skipped"?"skipped":"success",{durationMs:Date.now()-l,error:u?g instanceof Error?g.message.slice(0,300):String(g).slice(0,300):m&&b.error||void 0})};try{r.runFlow||r.launchApp?await this.runStep(r,t):await Promise.race([this.runStep(r,t),new Promise((u,g)=>setTimeout(()=>g(new Error(`step ${t+1} (${Object.keys(r)[0]}) exceeded ${s}ms deadline`)),s))])}catch(u){let g=this.flowTraceSteps[this.flowTraceSteps.length-1];if(!(g&&g.stepIndex===t&&g.startedAtMs>=l)){let b=Object.keys(r)[0];this.lastFailedStep={index:t,kind:b,target:r[b]},this.recordFlowTraceStep({stepIndex:t,stepName:b,targetLabel:this.flowStepTargetLabel(r,b),startedAtMs:l,status:"failure",error:u})}throw await p(!0,u),u}await p(!1)}}};function Kt(i){if(typeof i!="object"||i==null||!("control"in i))return!1;let e=i.control;return typeof e=="object"&&e!=null&&"paused"in e&&e.paused===!0}var ie=class{constructor(e,t,r){this.bridge=e;this.flowName=t;this.getSimId=r}disabled=!1;paused=!1;lastSimId;plannedSteps=null;completedSteps=new Map;runId=`flr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`;async send(e,t){let r=await this.bridge.send({type:"flowStatus",simId:t,status:{runId:this.runId,flowName:this.flowName,...e}});this.paused=Kt(r)}async push(e){if(!this.disabled)try{let t=this.getSimId?.();if(t!==this.lastSimId&&this.lastSimId!=null&&this.plannedSteps&&e.phase!=="plan"){await this.send({phase:"plan",state:"running",steps:this.plannedSteps},t);for(let r of this.completedSteps.values())await this.send({phase:"step",state:"running",step:r},t)}this.lastSimId=t,await this.send(e,t)}catch(t){this.disabled=!0,console.log(`[flow] live status unavailable (${t instanceof Error?t.message.slice(0,120):t}) \u2014 continuing without the devtools rail`)}}async plan(e){this.plannedSteps=e.map(t=>({...t})),this.completedSteps.clear(),await this.push({phase:"plan",state:"running",steps:e})}async step(e,t,r){let n={index:e,status:t,...r};await this.push({phase:"step",state:"running",step:n}),this.completedSteps.set(e,n)}async end(e){await this.push({phase:"end",state:e})}async waitWhilePaused(){if(!this.disabled)for(;this.paused;){for(console.log("[flow] paused from devtools \u2014 waiting\u2026");this.paused&&!this.disabled;)await new Promise(e=>setTimeout(e,400)),await this.push({phase:"heartbeat",state:"paused"});this.disabled||console.log("[flow] resumed")}}};var Ie=null;function Ur(){return Ie}var Fe=[];function Wr(){return Fe}async function Yt(i){if(!i)return"";let e=i.trim();if(!e)return"";if(/^\d+$/.test(e)||e.startsWith("http://")||e.startsWith("https://"))return e;let r=(await Ze()).find(n=>n.name.toLowerCase()===e.toLowerCase());return r?String(r.preferredPort):e}async function Zt(){let i=await Xe(),e=i.find(r=>r.patched);if(e)return`http://localhost:${e.port}/__soot/`;let t=i[0];return t?`http://localhost:${t.port}/__soot/`:null}async function mt(i){Ie=null,Fe=[],(i.length===0||i.includes("--help")||i.includes("-h"))&&(console.log(`
|
|
466
466
|
sootsim maestro \u2014 author and run Maestro YAML flows
|
|
467
467
|
|
|
468
468
|
usage:
|
|
@@ -542,10 +542,10 @@ flow extension:
|
|
|
542
542
|
takeScreenshot:
|
|
543
543
|
path: marketing/hero
|
|
544
544
|
withFrame: true
|
|
545
|
-
`),process.exit(0));let e=i[0];$.existsSync(e)||(console.error(` error: ${e} not found`),process.exit(1));let t=h=>i.find((d,y)=>i[y-1]===h),r=i.includes("--profile"),n=i.includes("--headed"),o=i.includes("--new")||n,a=t("--out")||"/tmp/sootsim-recordings",s=t("--screenshots")||(t("--out")?a:"/tmp/sootsim-flow"),l=t("--screenshot-paths")==="flow"?"flow":"dir",p=i.includes("--no-shell")?"tenant":i.includes("--shell-only")?"shell":void 0,u=t("--device")?.trim()||"",g=i.includes("--slow")?+(t("--slow")||"500"):0,b=i.includes("--electron"),m=i.includes("--preview"),k=m?await st(t("--preview-origin")):"",P=t("--preview-public-origin"),H=i.includes("--preview-open"),$e=t("--owner")?.trim()||"",ke=t("--repo")?.trim()||"",U=t("--billing-kind")?.trim()||"",gt=m?`maestro:${process.env.GITHUB_RUN_ID?`github:${process.env.GITHUB_RUN_ID}:attempt:${process.env.GITHUB_RUN_ATTEMPT||"1"}:job:${process.env.GITHUB_JOB||"preview"}`:`local:${zt()}`}:flow:${qt("sha256").update(w.relative(process.cwd(),w.resolve(e))).digest("hex").slice(0,16)}`:"";U&&U!=="test_run"&&(console.error(` error: invalid --billing-kind: ${U}`),process.exit(1));let wt=i.flatMap((h,d)=>i[d-1]==="--replace"?["--replace",h]:[]),yt=i.flatMap((h,d)=>i[d-1]==="--remap"?["--remap",h]:[]),M=i.includes("--record")||m,bt=i.includes("--tail-wait")?Math.max(0,+(t("--tail-wait")||"2000")):M?m?6e3:2e3:0,St=$.readFileSync(e,"utf8"),{frontmatter:T,steps:R}=ge(St);R.length===0&&(console.error(" error: flow file must contain a YAML array of steps"),process.exit(1));let W=u||T.device||"",Pe=T.theme||"",Y=b||T.electron===!0,vt=T.app===void 0||T.app===null?"":typeof T.app=="number"?String(T.app):T.app,oe=await Yt(vt),Ae={stripBooleanFlags:["--record","--profile","--electron","--new","--preview","--preview-open","--headless","--headed"],stripValueFlags:["--out","--device","--slow","--tail-wait","--url","--replace","--remap","--screenshots","--screenshot-paths","--preview-origin","--preview-public-origin","--driver","--billing-kind","--owner","--repo"]},x=
|
|
545
|
+
`),process.exit(0));let e=i[0];$.existsSync(e)||(console.error(` error: ${e} not found`),process.exit(1));let t=h=>i.find((d,y)=>i[y-1]===h),r=i.includes("--profile"),n=i.includes("--headed"),o=i.includes("--new")||n,a=t("--out")||"/tmp/sootsim-recordings",s=t("--screenshots")||(t("--out")?a:"/tmp/sootsim-flow"),l=t("--screenshot-paths")==="flow"?"flow":"dir",p=i.includes("--no-shell")?"tenant":i.includes("--shell-only")?"shell":void 0,u=t("--device")?.trim()||"",g=i.includes("--slow")?+(t("--slow")||"500"):0,b=i.includes("--electron"),m=i.includes("--preview"),k=m?await st(t("--preview-origin")):"",P=t("--preview-public-origin"),H=i.includes("--preview-open"),$e=t("--owner")?.trim()||"",ke=t("--repo")?.trim()||"",U=t("--billing-kind")?.trim()||"",gt=m?`maestro:${process.env.GITHUB_RUN_ID?`github:${process.env.GITHUB_RUN_ID}:attempt:${process.env.GITHUB_RUN_ATTEMPT||"1"}:job:${process.env.GITHUB_JOB||"preview"}`:`local:${zt()}`}:flow:${qt("sha256").update(w.relative(process.cwd(),w.resolve(e))).digest("hex").slice(0,16)}`:"";U&&U!=="test_run"&&(console.error(` error: invalid --billing-kind: ${U}`),process.exit(1));let wt=i.flatMap((h,d)=>i[d-1]==="--replace"?["--replace",h]:[]),yt=i.flatMap((h,d)=>i[d-1]==="--remap"?["--remap",h]:[]),M=i.includes("--record")||m,bt=i.includes("--tail-wait")?Math.max(0,+(t("--tail-wait")||"2000")):M?m?6e3:2e3:0,St=$.readFileSync(e,"utf8"),{frontmatter:T,steps:R}=ge(St);R.length===0&&(console.error(" error: flow file must contain a YAML array of steps"),process.exit(1));let W=u||T.device||"",Pe=T.theme||"",Y=b||T.electron===!0,vt=T.app===void 0||T.app===null?"":typeof T.app=="number"?String(T.app):T.app,oe=await Yt(vt),Ae={stripBooleanFlags:["--record","--profile","--electron","--new","--preview","--preview-open","--headless","--headed"],stripValueFlags:["--out","--device","--slow","--tail-wait","--url","--replace","--remap","--screenshots","--screenshot-paths","--preview-origin","--preview-public-origin","--driver","--billing-kind","--owner","--repo"]},x=fe(i,Ae),xt=t("--url")||"";Y&&!Qe()&&(console.error(" error: desktop companion not found. install or build it first with `bun run build:electron`"),process.exit(1));let Me=Y?"desktop companion":"bridge",Tt=oe?` | target: ${oe}`:"";console.log(`
|
|
546
546
|
sootsim maestro \u2014 ${w.basename(e)}
|
|
547
547
|
${R.length} steps | ${Me}${Tt}${M?" | recording":""}${r?" | profiling":""}${g?` | ${g}ms delay`:""}
|
|
548
|
-
`),m&&De({event:"preview_flow_started",properties:{flowName:w.basename(e),stepCount:R.length,mode:Me,electron:Y,record:M,profile:r,previewOrigin:k}});let A=xt||oe||"",se=o||Y&&x.simIdSource!=="flag",Re=t("--driver")||"",ae=!1,le=new Set,_e=!1;if(!A&&!se&&x.simIdSource==="none"){let h=
|
|
548
|
+
`),m&&De({event:"preview_flow_started",properties:{flowName:w.basename(e),stepCount:R.length,mode:Me,electron:Y,record:M,profile:r,previewOrigin:k}});let A=xt||oe||"",se=o||Y&&x.simIdSource!=="flag",Re=t("--driver")||"",ae=!1,le=new Set,_e=!1;if(!A&&!se&&x.simIdSource==="none"){let h=Je(x);try{let d=await h.listSims(),y=d.find(D=>D.isPrimary&&D.readyState==="open"),F=d.find(D=>D.readyState==="open"),J=y??F;J&&(_e=!0,console.log(` reusing active sim: ${J.id}`))}catch{}finally{h.close()}}if(!A&&!_e&&(se||x.simIdSource==="none")){let h=await Zt();h||(console.error(" error: no current sim and no sootsim target found"),await ce(),process.exit(1)),A=h}if(A&&W){let h=new URL(await et(A));h.searchParams.set("device",W),A=h.toString()}if(A){let h=[A];if(h.push(...wt),h.push(...yt),se&&h.push("--new"),h.push("--no-describe"),x.simIdSource==="flag"&&x.simId&&h.push("--sim",x.simId),Re&&(h.push("--driver",Re),ae=!0),i.includes("--headless")&&!n&&h.push("--headless"),await rt(h,{port:x.wsPort,timeoutMs:x.commandTimeoutMs}),ae){let d=ue();d&&le.add(d)}}let B=fe(i,Ae),Z=B.simIdSource==="flag"?B.simId:ue()||B.simId,Et=B.simIdSource==="flag"?"flag":Z?"saved":"none",E=me(B.wsPort,{commandTimeoutMs:B.commandTimeoutMs,simId:Z,simIdSource:Et}),c,Oe=async()=>{let h=T.env?.SOOTSIM_STATUS_BAR_TIME;if(h){if(!/^(?:[1-9]|1[0-2]):[0-5][0-9]$/.test(h))throw new Error("SOOTSIM_STATUS_BAR_TIME must be a 12-hour time such as 9:41");await E.send({type:"evaluate",simId:c.simId,code:`window.dispatchEvent(new CustomEvent('sootsim:statusBarOverride', { detail: { time: ${JSON.stringify(h)} } }))`})}if(Pe&&await E.send({type:"call",simId:c.simId,path:"SootSim.bridges.settings.set",args:["colorScheme",Pe]}),!W)return!1;let d=await E.send({type:"evaluate",simId:c.simId,code:"window.location.href"});if(typeof d=="string"&&d.length>0){let y=new URL(d);y.searchParams.set("device",W),c.setSimRouteHint(y.toString())}return!!await E.send({type:"call",simId:c.simId,path:"SootSim.bridges.settings.set",args:["deviceModel",W]})};if(c=new ne(E,{screenshotDir:s,flowDir:w.dirname(w.resolve(e)),screenshotPathMode:l,screenshotLayers:p,simId:Z,recordingOutputDir:M?a:void 0,recordingFormat:m?"mp4":"webm",billingOriginOverride:m?k:void 0,allowGitHubRecording:m,requireRecordingEntitlement:m,onAfterLaunch:async()=>{await Oe()&&await c.waitForTree(12e4),m&&await E.send({type:"evaluate",simId:c.simId,code:`(() => {
|
|
549
549
|
const r = window.SootSim?.bridges?.eventRecorder ?? window.__sootsimEventRecorder
|
|
550
550
|
return r?.start?.() ?? false
|
|
551
551
|
})()`})}}),g&&(c.stepDelay=g),c.liveStatus=new ie(E,w.basename(e),()=>c.simId),c.js.putEnv("MAESTRO_FILENAME",w.basename(e,w.extname(e))),T.env&&typeof T.env=="object")for(let[h,d]of Object.entries(T.env))c.js.putEnv(h,d);let _=null,I=null,L=null,O=null,j=null,de=null,V=0,X=!!R[0]?.launchApp;try{X||await c.waitForTree(12e4),await Oe()&&!X&&await c.waitForTree(12e4),m&&!X&&!process.env.SOOTSIM_PREVIEW_RESET_DONE&&await c.launchApp({clearState:!0}),M&&(X?c.prepareRecording():await c.startRecording()),r&&await c.startProfile(),m&&(await E.send({type:"evaluate",simId:c.simId,code:`(() => {
|
|
@@ -560,10 +560,10 @@ flow extension:
|
|
|
560
560
|
return r?.stop?.() ?? []
|
|
561
561
|
})()`}),console.log(` captured ${O.length} partial replay events`)}catch(d){console.warn(` event recorder stop failed: ${d?.message||String(d)}`)}console.error(`
|
|
562
562
|
x failed: ${h.message}
|
|
563
|
-
`),_&&(console.log(" partial profile:"),ft(_)),I&&console.log(` partial video: ${I}`);try{let d=c.lastFailedStep,y=d?`step-${String(d.index+1).padStart(2,"0")}-${d.kind}`:"unstaged",F=w.join(s,y);await c.captureFailureBundle(F,{error:h,stepIndex:d?.index,stepKind:d?.kind,stepTarget:d?.target}),de=F,console.log(` failure bundle: ${F}`),console.log(" (contents: screenshot.png, describe.json, a11y.txt, tree.txt, console.json, error.json)")}catch(d){try{let y=w.join(s,"error.png");await c.captureScreenshot(y),console.log(` error screenshot: ${y}`)}catch{}console.log(` (failure bundle capture failed: ${d instanceof Error?d.message:String(d)})`)}await
|
|
564
|
-
preparing preview upload\u2026`);let F=c.getFlowTraceSteps();F.length>0&&d.push("--timeline-events",await er(F));let J=await tr(F,y);J&&d.push("--snapshot-manifest",J),de&&d.push("--failure-bundle",de);let D=c.getLastRecordingFrameStats();D&&d.push("--trace-frame-stats",await rr(D));let{runUpload:It}=await import("./upload-
|
|
563
|
+
`),_&&(console.log(" partial profile:"),ft(_)),I&&console.log(` partial video: ${I}`);try{let d=c.lastFailedStep,y=d?`step-${String(d.index+1).padStart(2,"0")}-${d.kind}`:"unstaged",F=w.join(s,y);await c.captureFailureBundle(F,{error:h,stepIndex:d?.index,stepKind:d?.kind,stepTarget:d?.target}),de=F,console.log(` failure bundle: ${F}`),console.log(" (contents: screenshot.png, describe.json, a11y.txt, tree.txt, console.json, error.json)")}catch(d){try{let y=w.join(s,"error.png");await c.captureScreenshot(y),console.log(` error screenshot: ${y}`)}catch{}console.log(` (failure bundle capture failed: ${d instanceof Error?d.message:String(d)})`)}await Ke(E,{errorsCommand:`sootsim get errors 5${c.simId?` --sim ${c.simId}`:""}`,warningsCommand:`sootsim get warnings 5${c.simId?` --sim ${c.simId}`:""}`,requestsCommand:`sootsim get requests 5${c.simId?` --sim ${c.simId}`:""}`}),V=1}if(await c.liveStatus?.end(V===0?"passed":"failed"),m&&(V===0||I||O))try{let h=await Qt(O??[]),d=["--origin",k,"--events",h];P&&d.push("--public-origin",P),I&&d.push("--video",I),j&&d.push("--screenshot",j),I&&L&&Number.isFinite(L)&&(d.push("--video-duration-ms",String(Math.round(L))),d.push("--recorded-duration-ms",String(Math.round(L))));let y=c.getLastRecordingStartedAtMs();y&&Number.isFinite(y)&&d.push("--recording-started-at-ms",String(Math.round(y))),x.wsPort&&d.push("--port",String(x.wsPort)),c.simId&&d.push("--sim",c.simId),H&&d.push("--open"),$e&&d.push("--owner",$e),ke&&d.push("--repo",ke),d.push("--run-scope",gt),U&&d.push("--billing-kind",U),console.log(`
|
|
564
|
+
preparing preview upload\u2026`);let F=c.getFlowTraceSteps();F.length>0&&d.push("--timeline-events",await er(F));let J=await tr(F,y);J&&d.push("--snapshot-manifest",J),de&&d.push("--failure-bundle",de);let D=c.getLastRecordingFrameStats();D&&d.push("--trace-frame-stats",await rr(D));let{runUpload:It}=await import("./upload-WGPI5XX6.js");Ie=await It(d,{})}catch(h){console.error(` preview upload failed: ${h?.message||h}`),V=1}return Fe=c.getFlowTraceSteps(),E.close(),ae?(c.simId&&le.add(c.simId),await Xt(x.wsPort,x.commandTimeoutMs,[...le])):c.simId&&c.simId!==Z&&Ce(c.simId),await ce(),V}async function Xt(i,e,t){let r=[...new Set(t.filter(Boolean))];if(r.length===0)return;let n=me(i,{commandTimeoutMs:e});try{let o=await n.listSims(),a=r.filter(l=>o.some(p=>p.id===l&&p.readyState==="open"));if(a.length===0)return;let s=await nt(n,i,e,a);await tt(o,a),s.closed.length>0&&console.log(` closed flow sim(s): ${s.closed.join(", ")}`),s.remaining.length>0&&console.warn(` warn: flow sim(s) still connected after close: ${s.remaining.join(", ")}`)}catch(o){console.warn(` warn: failed to close flow sim(s): ${o instanceof Error?o.message:String(o)}`)}finally{n.close()}}async function Qt(i){let{gzipSync:e}=await import("zlib"),t=i.map(o=>JSON.stringify(o)).join(`
|
|
565
565
|
`)+(i.length?`
|
|
566
566
|
`:""),r=e(Buffer.from(t,"utf8")),n=w.join(z(),`sootsim-events-${Date.now()}.jsonl.gz`);return $.writeFileSync(n,r),console.log(` events: ${i.length} written to ${n} (${r.length} bytes gz)`),n}async function er(i){let{gzipSync:e}=await import("zlib"),t=i.map((a,s)=>({schemaVersion:1,t:a.endedAtMs,seq:1e6+s,context:"host",kind:"flow-step",id:`flow-step-${a.stepIndex}`,data:{stepIndex:a.stepIndex,stepNumber:a.stepIndex+1,stepName:a.stepName,...a.targetLabel?{targetLabel:a.targetLabel}:{},status:a.status,durationMs:a.durationMs,startedAtMs:a.startedAtMs,endedAtMs:a.endedAtMs,...a.error?{error:a.error}:{}}})),r=t.map(a=>JSON.stringify(a)).join(`
|
|
567
567
|
`)+`
|
|
568
|
-
`,n=e(Buffer.from(r,"utf8")),o=w.join(z(),`sootsim-flow-steps-${Date.now()}.jsonl.gz`);return $.writeFileSync(o,n),console.log(` flow trace: ${t.length} step events written to ${o} (${n.length} bytes gz)`),o}async function tr(i,e){if(!e)return null;let t=i.flatMap(n=>n.screenshotPath?[{id:`flow-step-${n.stepIndex}`,label:n.targetLabel??`Step ${n.stepIndex+1}`,kind:"interaction",t:Math.max(0,n.endedAtMs-e),path:n.screenshotPath}]:[]);if(t.length===0)return null;let r=w.join(z(),`sootsim-flow-snapshots-${Date.now()}.json`);return $.writeFileSync(r,JSON.stringify(t)),console.log(` flow snapshots: ${t.length} written to ${r}`),r}async function rr(i){let e=w.join(z(),`sootsim-frame-stats-${Date.now()}.json`);return $.writeFileSync(e,JSON.stringify(i)),console.log(` frame stats: written to ${e}`),e}async function nr(i){let e=i[0],t=r=>i.find((n,o)=>i[o-1]===r);switch(e){case"start":{let{path:r,state:n}=
|
|
568
|
+
`,n=e(Buffer.from(r,"utf8")),o=w.join(z(),`sootsim-flow-steps-${Date.now()}.jsonl.gz`);return $.writeFileSync(o,n),console.log(` flow trace: ${t.length} step events written to ${o} (${n.length} bytes gz)`),o}async function tr(i,e){if(!e)return null;let t=i.flatMap(n=>n.screenshotPath?[{id:`flow-step-${n.stepIndex}`,label:n.targetLabel??`Step ${n.stepIndex+1}`,kind:"interaction",t:Math.max(0,n.endedAtMs-e),path:n.screenshotPath}]:[]);if(t.length===0)return null;let r=w.join(z(),`sootsim-flow-snapshots-${Date.now()}.json`);return $.writeFileSync(r,JSON.stringify(t)),console.log(` flow snapshots: ${t.length} written to ${r}`),r}async function rr(i){let e=w.join(z(),`sootsim-frame-stats-${Date.now()}.json`);return $.writeFileSync(e,JSON.stringify(i)),console.log(` frame stats: written to ${e}`),e}async function nr(i){let e=i[0],t=r=>i.find((n,o)=>i[o-1]===r);switch(e){case"start":{let{path:r,state:n}=ze();console.log(" flow draft started"),console.log(` session: ${r}`),console.log(` steps: ${n.steps.length}`);return}case"keep":case"good":{let r=be();if(r.active||(console.error(" no active flow draft \u2014 run `sootsim maestro start` first"),process.exit(1)),!r.kept){console.log(" no pending action to keep");return}console.log(` kept: ${r.candidate.summary}`),console.log(` steps: ${r.stepCount}`);return}case"end":{let r=t("--output")||(i[1]&&!i[1].startsWith("-")?i[1]:void 0),n=i.includes("--validate")||i.includes("--video"),o=i.includes("--video"),a=be();a.active&&a.kept&&console.log(` auto-kept trailing action: ${a.candidate.summary}`);let s=Ye(r||(n?or():void 0));if(s.active||(console.error(" no active flow draft \u2014 run `sootsim maestro start` first"),process.exit(1)),!s.valid){console.error(" flow draft is not valid:");for(let l of s.issues)console.error(` - ${l}`);console.error(" draft preserved \u2014 keep at least one real interaction or run `sootsim maestro start` to reset"),process.exit(1)}if(n){let l=sr(i,s.outputPath),p=await mt(l);if(p!==0){console.error(`
|
|
569
569
|
validation failed \u2014 draft preserved so you can keep iterating`),process.exitCode=p;return}ye(),console.log(` flow draft validated (${s.stepCount} step${s.stepCount===1?"":"s"})`),s.outputPath&&console.log(` saved: ${s.outputPath}`),o&&console.log(" video: recorded during validation run");return}if(ye(),console.log(` flow draft ended (${s.stepCount} step${s.stepCount===1?"":"s"})`),s.outputPath){console.log(` saved: ${s.outputPath}`),console.log(` next: sootsim maestro test ${s.outputPath} --record`);return}console.log(""),process.stdout.write(s.yaml);return}case"validate":{let r=i[1];(!r||r.startsWith("-"))&&(console.error(" usage: sootsim maestro validate <path>"),process.exit(1));let n=we(r);if(n.length>0){console.error(` x ${r} failed validation:`);for(let o of n)console.error(` - ${o}`);process.exit(1)}console.log(` + ${r} looks valid`);return}}}function ir(i){return i[0]==="--sim"&&i.length>=2?[...i.slice(2),"--sim",i[1]]:i}async function jr(i){let e=ir(i),t=e[0];if(t==="start"||t==="keep"||t==="good"||t==="end"||t==="validate")return await nr(e),0;let r=await mt(e);return r!==0&&(process.exitCode=r),r}function ft(i){console.log(""),it(i)}function or(){return w.join(z(),`sootsim-flow-draft-${Date.now()}.yaml`)}function sr(i,e){if(!e)throw new Error("validated flow draft requires an output path");let t=[e];for(let r=1;r<i.length;r++){let n=i[r];if(!(n==="--validate"||n==="--video")){if(n==="--output"){r+=1;continue}r===1&&!n.startsWith("-")||t.push(n)}}return!t.includes("--record")&&i.includes("--video")&&t.push("--record"),t}export{ct as a,_t as b,Ur as c,Wr as d,Zt as e,mt as f,ir as g,jr as h};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*! sootsim v0.1.297 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import { createRequire as __sootsimCreateRequire } from 'node:module'
|
|
3
|
+
var require = __sootsimCreateRequire(import.meta.url)
|
|
4
|
+
import{b}from"./chunk-X5J5A63F.js";import{e as $}from"./chunk-IMXVXXWX.js";import{b as y,c as R,d as m,e as w,f as a}from"./chunk-VVSQCLBU.js";import{G as g,H as u,I as d,O as h,l as p}from"./chunk-BAFDYXCM.js";import S from"fs";import{WebSocket as E}from"ws";function C(t){if(!t||typeof t!="object")return!1;let e=Reflect.get(t,"sections");return typeof Reflect.get(t,"title")=="string"&&Array.isArray(e)&&e.every(o=>o&&typeof o=="object"&&typeof Reflect.get(o,"title")=="string"&&Array.isArray(Reflect.get(o,"items"))&&Reflect.get(o,"items").every(n=>n&&typeof n=="object"&&typeof Reflect.get(n,"summary")=="string"&&typeof Reflect.get(n,"hash")=="string"))}async function A(t,e=fetch){try{let o=new URL(w);o.searchParams.set("version",t);let n=await e(o,{headers:{accept:"application/json"},signal:AbortSignal.timeout(5e3)});if(!n.ok)return null;let s=await n.json();if(!s||typeof s!="object")return null;let r=Reflect.get(s,"entries");return!Array.isArray(r)||!C(r[0])?null:r[0]}catch{return null}}function O(t,e){let o=[`what's new in SootSim engine v${t}:`];if(!e||e.sections.length===0)o.push(" release notes are not available yet");else for(let n of e.sections){o.push(` ${n.title}:`);for(let s of n.items)o.push(` \u2022 ${s.summary}`)}return o.push(` full changelog: ${m}`),o.join(`
|
|
5
|
+
`)}async function Q(t,e={}){let[o,...n]=t;if(!o||o==="--help"||o==="-h"){k();return}switch(o){case"install":return L(n,e);case"list":case"ls":return j(n);case"use":return T(n);case"remove":case"rm":return D(n);case"which":case"active":return G();case"notes":case"changelog":return U(n);default:console.error(` unknown runtime subcommand: ${o}`),k(),process.exit(1)}}function k(){console.log(`
|
|
6
|
+
sootsim runtime \u2014 manage engine runtimes under ~/.sootsim/runtimes/
|
|
7
|
+
|
|
8
|
+
usage:
|
|
9
|
+
sootsim runtime install [version] install a version (default: channel latest)
|
|
10
|
+
sootsim runtime list show installed + available versions
|
|
11
|
+
sootsim runtime use <version> switch active runtime
|
|
12
|
+
sootsim runtime remove <version> delete an installed runtime
|
|
13
|
+
sootsim runtime which print active runtime version
|
|
14
|
+
sootsim runtime notes print repo or default engine release notes
|
|
15
|
+
|
|
16
|
+
flags:
|
|
17
|
+
--channel <name> channel to resolve 'latest' from (default: stable)
|
|
18
|
+
--force reinstall even if the version is already on disk
|
|
19
|
+
--set-active=false do not switch active runtime after install
|
|
20
|
+
|
|
21
|
+
environment:
|
|
22
|
+
SOOTSIM_CDN_ORIGIN override the CDN base URL (default: ${R})
|
|
23
|
+
|
|
24
|
+
examples:
|
|
25
|
+
sootsim runtime install
|
|
26
|
+
sootsim runtime install 1.2.3
|
|
27
|
+
sootsim runtime install --channel beta
|
|
28
|
+
sootsim runtime use 1.2.3
|
|
29
|
+
sootsim runtime notes
|
|
30
|
+
`)}async function L(t,e){let{version:o,flags:n}=F(t),s=n.channel??e.channel??"stable",r=n.force===!0,l=n.setActive!==!1;g(),console.log("sootsim runtime install"),console.log(` cdn: ${a.resolveCdnOrigin()}`);try{let i=await a.install({version:o,channel:s,force:r,setActive:l,protectVersions:h()});return console.log(` version: ${i.version} (channel: ${i.channel})`),i.installed?console.log(` installed ${i.version}`):console.log(` already installed at ${i.runtimeDir}`),l&&await I(i.version),i}catch(i){console.error(` ${N(i)}`),process.exit(1)}}async function I(t){d(t),console.log(` active: ${t}`),await _(t)||console.log(` (no daemon running \u2014 next sootsim/electron launch will pick up ${t})`)}async function _(t){let{isDaemonLockfileFresh:e,readDaemonLockfile:o}=await import("./home-paths-KOZFBUVS.js"),n=o();if(!e(n))return!1;let s=$();return new Promise(r=>{let l=!1,i=!1,f=x=>{l||(l=!0,r(x))},c=new E(`ws://127.0.0.1:${s}`,{handshakeTimeout:800}),v=setTimeout(()=>{try{c.close()}catch{}f(i)},1500);c.on("open",()=>{try{c.send(JSON.stringify({type:"runtime:use",version:t,id:0})),i=!0}catch{}setTimeout(()=>{try{c.close()}catch{}},100)}),c.on("close",()=>{clearTimeout(v),f(i)}),c.on("error",()=>{clearTimeout(v),f(!1)})})}async function j(t){g();let e=a.listInstalled(),o=u();if(console.log("installed:"),e.length===0)console.log(" (none)");else for(let n of e)console.log(` ${n===o?"*":" "} ${n}`);try{let n=await a.fetchManifest();console.log("available (latest per channel):");for(let[r,l]of Object.entries(n.channels))console.log(` ${r.padEnd(8)} ${l.latest}`);let s=Object.keys(n.versions).sort(y).reverse();if(s.length>1){console.log("hosted versions:");for(let r of s)console.log(` ${r}`)}}catch(n){console.log(`available: (could not fetch manifest: ${N(n)})`)}}async function T(t){let e=t[0];e||(console.error(" usage: sootsim runtime use <version>"),process.exit(1));let o=a.listInstalled();o.includes(e)||(console.error(` version ${e} is not installed`),console.error(` installed: ${o.join(", ")||"(none)"}`),console.error(` run \`sootsim runtime install ${e}\` first`),process.exit(1)),await I(e)}async function D(t){let e=t[0];e||(console.error(" usage: sootsim runtime remove <version>"),process.exit(1)),u()===e&&(console.error(` cannot remove active runtime ${e}`),console.error(" switch with `sootsim runtime use <other>` first, or install another version"),process.exit(1)),h().includes(e)&&(console.error(` cannot remove runtime ${e} while a project is using it`),process.exit(1));let n=p(e);if(!S.existsSync(n)){console.error(` ${e} is not installed`);return}S.rmSync(n,{recursive:!0,force:!0}),console.log(` removed ${e}`)}async function G(){let t=u();if(!t){console.log(" no active runtime");return}console.log(t)}async function U(t){t.length>0&&(console.error(" usage: sootsim runtime notes"),process.exit(1));let{config:e}=await b(),o=e?.runtimeVersion??u();if(!o){console.log(" no active runtime"),console.log(` release notes: ${m}`);return}console.log(O(o,await A(o)))}function F(t){let e={},o=[];for(let n=0;n<t.length;n++){let s=t[n];if(s==="--channel"&&n+1<t.length){e.channel=t[n+1],n++;continue}if(s.startsWith("--channel=")){e.channel=s.slice(10);continue}if(s==="--force"){e.force=!0;continue}if(s==="--set-active=false"||s==="--no-set-active"){e.setActive=!1;continue}o.push(s)}return{version:o[0]??null,flags:e}}function N(t){return t instanceof Error?t.message:String(t)}export{A as a,O as b,Q as c};
|