sootsim 0.0.1 → 0.0.2
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 +12 -0
- package/dist-cli/bin.js +16 -10
- package/dist-cli/chunks/agent-3T4BJEZM.js +61 -0
- package/dist-cli/chunks/agent-wrapper-WCYNLWHZ.js +15 -0
- package/dist-cli/chunks/assert-FPFJEFF3.js +47 -0
- package/dist-cli/chunks/auto-bootstrap-HDW6N77H.js +2 -0
- package/dist-cli/chunks/chunk-3HBBSRLE.js +2 -0
- package/dist-cli/chunks/chunk-4372UQHZ.js +308 -0
- package/dist-cli/chunks/chunk-4GWEO5CL.js +1 -0
- package/dist-cli/chunks/{chunk-G5MR66EB.js → chunk-5C5I5OFM.js} +2 -2
- package/dist-cli/chunks/chunk-6IPY24VM.js +11 -0
- package/dist-cli/chunks/chunk-AS4V7TZU.js +2 -0
- package/dist-cli/chunks/chunk-B5R4K2DG.js +5 -0
- package/dist-cli/chunks/chunk-CXTA5VGA.js +4 -0
- package/dist-cli/chunks/chunk-CZZB4DWG.js +3 -0
- package/dist-cli/chunks/chunk-DW54UPRZ.js +119 -0
- package/dist-cli/chunks/chunk-EIZCWDRE.js +1 -0
- package/dist-cli/chunks/{chunk-KSACMDXK.js → chunk-ET3NNZAR.js} +2 -2
- package/dist-cli/chunks/chunk-EWEKADK4.js +5 -0
- package/dist-cli/chunks/{chunk-JSF5LPNT.js → chunk-EWMYTXM2.js} +5 -5
- package/dist-cli/chunks/chunk-FUQ4XA6I.js +16 -0
- package/dist-cli/chunks/chunk-GQUOQNTP.js +27 -0
- package/dist-cli/chunks/chunk-HBNVKYSC.js +2 -0
- package/dist-cli/chunks/{chunk-64TOMNZX.js → chunk-HORCHQT7.js} +2 -2
- package/dist-cli/chunks/{chunk-YCETS3B3.js → chunk-ISAMAM3I.js} +2 -2
- package/dist-cli/chunks/{chunk-GPVPHE2B.js → chunk-K6YUSCAC.js} +2 -2
- package/dist-cli/chunks/{chunk-E522F5JW.js → chunk-K7LDP7JL.js} +1 -1
- package/dist-cli/chunks/chunk-KZ2LIDW6.js +2 -0
- package/dist-cli/chunks/{chunk-J2S3OCWA.js → chunk-LOV766MI.js} +1 -1
- package/dist-cli/chunks/{chunk-OROM7DZI.js → chunk-LXCFGKL2.js} +1 -1
- package/dist-cli/chunks/{chunk-PWXPA745.js → chunk-NE62JSI6.js} +1 -1
- package/dist-cli/chunks/chunk-NHA3G6A3.js +22 -0
- package/dist-cli/chunks/chunk-NXWCDGWS.js +2 -0
- package/dist-cli/chunks/{chunk-QOBRRY5X.js → chunk-RJUBGX5M.js} +1 -1
- package/dist-cli/chunks/chunk-SLCVEGTW.js +4 -0
- package/dist-cli/chunks/chunk-TGDP3D3V.js +34 -0
- package/dist-cli/chunks/chunk-TSZBQS6W.js +62 -0
- package/dist-cli/chunks/chunk-XKDQEYTE.js +1 -0
- package/dist-cli/chunks/chunk-XXUAOYYT.js +4 -0
- package/dist-cli/chunks/{chunk-7X6OPSRD.js → chunk-YVSZHVLU.js} +2 -2
- package/dist-cli/chunks/{compat-MRN2ORY5.js → compat-3HMKLGXL.js} +4 -4
- package/dist-cli/chunks/{config-CO5IYWUY.js → config-IJQ3KANN.js} +5 -5
- package/dist-cli/chunks/control-3RAFI4AW.js +2 -0
- package/dist-cli/chunks/{daemon-G4XVRFHM.js → daemon-BBEQJLRY.js} +2 -2
- package/dist-cli/chunks/{debug-ZNSZTWT6.js → debug-SGZ5ZFQI.js} +4 -4
- package/dist-cli/chunks/demo-app-registry-NCYP3WA6.js +2 -0
- package/dist-cli/chunks/{detox-JEGYNTYV.js → detox-PK74V2Y7.js} +2 -2
- package/dist-cli/chunks/{device-BS34FAFM.js → device-MWNFX54L.js} +2 -2
- package/dist-cli/chunks/drivers-EXUREU4B.js +2 -0
- package/dist-cli/chunks/electron-3NIHSU2K.js +15 -0
- package/dist-cli/chunks/flow-6Y3E6E5P.js +2 -0
- package/dist-cli/chunks/{hints-7Z656W4H.js → hints-XZJLBIXW.js} +2 -2
- package/dist-cli/chunks/home-paths-BNRMUBJA.js +2 -0
- package/dist-cli/chunks/{inspect-NAHXP2M5.js → inspect-FGTUAK4C.js} +153 -165
- package/dist-cli/chunks/install-LCXALH26.js +65 -0
- package/dist-cli/chunks/{install-desktop-PYIZIH67.js → install-desktop-U3RQ6XUX.js} +8 -4
- package/dist-cli/chunks/install-dev-desktop-BLKRFI42.js +100 -0
- package/dist-cli/chunks/keys-N5LBDSD5.js +19 -0
- package/dist-cli/chunks/launch-NIMSJH5I.js +16 -0
- package/dist-cli/chunks/{login-Z5Z54HUJ.js → login-CQV2XBRM.js} +5 -5
- package/dist-cli/chunks/{logout-T2QDYGCB.js → logout-R56NWAWQ.js} +2 -2
- package/dist-cli/chunks/{maestro-4AXTS7OE.js → maestro-ZYUVTM7H.js} +2 -2
- package/dist-cli/chunks/{preview-NMGWHWMX.js → preview-AOAWAYEQ.js} +2 -2
- package/dist-cli/chunks/{profile-6RGJA4FR.js → profile-DDADDPRW.js} +3 -3
- package/dist-cli/chunks/record-3OIOTHP6.js +37 -0
- package/dist-cli/chunks/runtime-JTLZYEXK.js +25 -0
- package/dist-cli/chunks/{screenshot-R3GCCSCI.js → screenshot-Q6N2V5LL.js} +3 -3
- package/dist-cli/chunks/screenshot-mode-WWLWJWQD.js +17 -0
- package/dist-cli/chunks/{screenshots-4UQJE4NC.js → screenshots-2JEPJGZO.js} +2 -2
- package/dist-cli/chunks/server-VH34RVAX.js +29 -0
- package/dist-cli/chunks/{skills-2PPKPL4B.js → skills-PU4627FY.js} +2 -2
- package/dist-cli/chunks/store-U2VDD2S4.js +2 -0
- package/dist-cli/chunks/{test-5LFKOQ4M.js → test-AECE56E7.js} +3 -3
- package/dist-cli/chunks/upload-KPP7KG6E.js +2 -0
- package/dist-cli/chunks/{whoami-H6FW34JS.js → whoami-NCGRRR7X.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +414 -0
- package/dist-lib/agent-events.cjs +48 -0
- package/dist-lib/agent-sessions.cjs +692 -0
- package/dist-lib/attached-projects.cjs +448 -0
- package/dist-lib/auth/shared-session.cjs +174 -0
- package/dist-lib/backend-origin.cjs +70 -0
- package/dist-lib/bridge-constants.cjs +32 -0
- package/dist-lib/cli-constants.cjs +32 -0
- package/dist-lib/config.cjs +88 -0
- package/dist-lib/dev-bundle-resolution.cjs +236 -0
- package/dist-lib/home-paths.cjs +234 -0
- package/dist-lib/host/bridge-host.cjs +3458 -0
- package/dist-lib/index.cjs +361 -0
- package/dist-lib/metro.cjs +215 -0
- package/dist-lib/render-mode.cjs +54 -0
- package/dist-lib/vite-base.cjs +4217 -0
- package/dist-lib/vite.cjs +178 -0
- package/package.json +80 -13
- package/scripts/postinstall.cjs +70 -0
- package/dist-cli/chunks/bridge-host-2EY7Z4AO.js +0 -2
- package/dist-cli/chunks/chunk-3C3ZH7PP.js +0 -4
- package/dist-cli/chunks/chunk-3R4ZZESY.js +0 -119
- package/dist-cli/chunks/chunk-74XPLOV4.js +0 -2
- package/dist-cli/chunks/chunk-7LMDCMSI.js +0 -8
- package/dist-cli/chunks/chunk-A2CZQIWO.js +0 -1
- package/dist-cli/chunks/chunk-CKZ376AY.js +0 -322
- package/dist-cli/chunks/chunk-E5UBZEYR.js +0 -2
- package/dist-cli/chunks/chunk-HOIHCO7S.js +0 -3
- package/dist-cli/chunks/chunk-KQWZZ56P.js +0 -2
- package/dist-cli/chunks/chunk-KSB6MSZ4.js +0 -34
- package/dist-cli/chunks/chunk-KXYKAYYB.js +0 -51
- package/dist-cli/chunks/chunk-MBFP2LVH.js +0 -3
- package/dist-cli/chunks/chunk-MPSZ5EWF.js +0 -16
- package/dist-cli/chunks/chunk-X2U72K7X.js +0 -1
- package/dist-cli/chunks/control-Y7TKKB6D.js +0 -2
- package/dist-cli/chunks/dev-ZUKCZQEX.js +0 -25
- package/dist-cli/chunks/dev-checkout-IEZVVTCN.js +0 -2
- package/dist-cli/chunks/drivers-46PFFIDF.js +0 -2
- package/dist-cli/chunks/electron-P2KOPX2S.js +0 -15
- package/dist-cli/chunks/flow-VVOF6UNC.js +0 -2
- package/dist-cli/chunks/install-EPUJX4AT.js +0 -67
- package/dist-cli/chunks/record-IE27Z2GA.js +0 -37
- package/dist-cli/chunks/screenshot-mode-SZQDNGYE.js +0 -17
- package/dist-cli/chunks/server-AN2G5KO4.js +0 -21
- package/dist-cli/chunks/store-PU5ES4YQ.js +0 -2
- package/dist-cli/chunks/upload-BYNPC54C.js +0 -2
- package/dist-cli/chunks/vite-plugin-5AEUUBKP.js +0 -9
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/*! sootsim v0.0.
|
|
2
|
-
import{a as
|
|
3
|
-
`)}function
|
|
1
|
+
/*! sootsim v0.0.2 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a as U}from"./chunk-K6YUSCAC.js";import{a as Ne,b as _e}from"./chunk-LOV766MI.js";import{a as Y,b as E,c as C,d as z,e as ie,f as V,g as te,h as Ie,i as Fe,j as fe}from"./chunk-HORCHQT7.js";import{a as Te,e as ae}from"./chunk-EWMYTXM2.js";import{a as me,c as pe,d as xe}from"./chunk-DW54UPRZ.js";import{g as Ae}from"./chunk-6IPY24VM.js";import"./chunk-AS4V7TZU.js";import{a as Me}from"./chunk-TGDP3D3V.js";import"./chunk-LXCFGKL2.js";import{a as we}from"./chunk-3HBBSRLE.js";import{c as $e,e as Se,f as ke,h as ve}from"./chunk-FUQ4XA6I.js";import"./chunk-XXUAOYYT.js";import"./chunk-EIZCWDRE.js";import"./chunk-CXTA5VGA.js";import"./chunk-YVSZHVLU.js";import"./chunk-B5R4K2DG.js";import"./chunk-K7LDP7JL.js";import{existsSync as ut,mkdirSync as mt,readFileSync as pt,rmSync as Pe,writeFileSync as ft}from"fs";import{tmpdir as gt}from"os";import{dirname as yt,join as bt,resolve as ht}from"path";var oe=1,wt="SOOTSIM_INSPECT_NOTICE_PATH",xt=300*1e3,$t=15e3;function Oe(){return ht(process.env[wt]||bt(gt(),"sootsim-inspect-notice-state.json"))}function St(o,c){return Object.fromEntries(Object.entries(o).filter(([,i])=>typeof i?.signature=="string"&&Number.isFinite(i?.updatedAt)&&c-i.updatedAt<=xt))}function kt(o){let c=Oe();if(!ut(c))return{version:oe,entries:{}};try{let i=JSON.parse(pt(c,"utf8"));return i.version!==oe||!i.entries||typeof i.entries!="object"?(Pe(c,{force:!0}),{version:oe,entries:{}}):{version:oe,entries:St(i.entries,o)}}catch{return Pe(c,{force:!0}),{version:oe,entries:{}}}}function vt(o){let c=Oe();mt(yt(c),{recursive:!0}),ft(c,JSON.stringify(o,null,2)+`
|
|
3
|
+
`)}function Tt(o,c){let i=c.trim()||"default";return`${o}:${i}`}function ge(o,c,i,d={}){let u=d.nowMs??Date.now(),a=d.cooldownMs??$t,b=kt(u),k=Tt(o,c),$=b.entries[k];return $&&$.signature===i&&u-$.updatedAt<a?!1:(b.entries[k]={signature:i,updatedAt:u},vt(b),!0)}async function Ee(o,c={args:[]}){let i=await o.send({type:"evaluate",code:"(async () => await window.__sootsimTest.getNodeCount())()"}),d=typeof i=="number"?i:0;if(E(c.args)){C({nodes:d});return}console.log(` nodes: ${d}`)}function ye(o,c){let i=o.indexOf(c);return i>=0&&i+1<o.length?o[i+1]:null}async function Re(o){let{bridge:c,args:i,positional:d}=o,u=i.includes("--verbose")||i.includes("-v"),a=E(i),b=u&&!a,k=i.includes("--watch")||i.includes("-w"),$=1e3,I=i.includes("--compact"),y=i.includes("--no-xy"),S=ye(i,"--testid-like"),A=ye(i,"--only"),v=ye(i,"--subtree"),j=d[1],l=j?/[*?]/.test(j):!1,R=!l&&!A?j:void 0,D=A??(l?j:void 0),q=async()=>{await ie(c,{verbose:b});let Z=`(async () => {
|
|
4
4
|
const t = window.__sootsimTest
|
|
5
5
|
const mainShell = window.SootSim?.bridges?.mainShell
|
|
6
6
|
const kb = window.__sootsimKeyboard
|
|
@@ -11,33 +11,48 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
11
11
|
shell = typeof mainShell?.getState === 'function' ? await mainShell.getState() : null
|
|
12
12
|
} catch {}
|
|
13
13
|
|
|
14
|
-
const tree = await t.dumpTree(12, ${JSON.stringify({describe:!0,verbose:
|
|
14
|
+
const tree = await t.dumpTree(12, ${JSON.stringify({describe:!0,verbose:u,filter:R||"",testIdLike:S||void 0,onlyGlob:D||void 0,subtreeRoot:v||void 0,compact:I,hideXy:y})})
|
|
15
15
|
const nodeCount = (await t.getNodeCount?.()) || 0
|
|
16
16
|
const keyboard = kb && typeof kb.getLayout === 'function' ? kb.getLayout() : null
|
|
17
17
|
return { tree, shell, nodeCount, keyboard }
|
|
18
|
-
})()
|
|
19
|
-
`).length>=80&&
|
|
20
|
-
keyboard: ${t.join(" ")||"visible"}`)}};if(
|
|
21
|
-
`);;)console.clear(),await
|
|
18
|
+
})()`,x=await c.send({type:"evaluate",code:Z}),J=x?.tree,H=x?.shell,K=x?.keyboard;if(a){C({shell:H,tree:J??"",keyboard:K});return}if(H&&typeof H=="object"){let e=[H.state?`state=${H.state}`:null,H.activeApp?`app=${H.activeApp}`:null,H.showSwitcher?"switcher":null,H.switcherPhase&&H.switcherPhase!=="idle"?`phase=${H.switcherPhase}`:null].filter(Boolean);e.length>0&&console.log(` shell: ${e.join(" ")}`)}if(typeof J=="string"&&J.startsWith("__SUBTREE_NOT_FOUND__:")){let e=J.slice(22);console.log(` subtree root not found: ${e}`),U("subtree-root-not-found",e);return}if(!J){let e=x?.nodeCount??0;console.log(" no matching nodes found"),!(R||S||D||v)&&e<10&&U("app-still-loading",e);return}if(console.log(J),!(R||S||D||v)&&!k&&J.split(`
|
|
19
|
+
`).length>=80&&U("describe-use-filters"),K&&K.visible){let e=K.spec,t=[e?.keyboardType?`type=${e.keyboardType}`:null,e?.returnKeyType&&e.returnKeyType!=="default"?`return=${e.returnKeyType}`:null,K.mode!=="letters"?`mode=${K.mode}`:null,K.shifted?"shift":null,K.capsLock?"caps":null,e?.autoCapitalize&&e.autoCapitalize!=="sentences"?`autoCap=${e.autoCapitalize}`:null,K.accessoryBarId?`accessory=${K.accessoryBarId}`:null].filter(Boolean);console.log(`
|
|
20
|
+
keyboard: ${t.join(" ")||"visible"}`)}};if(k)for(console.log(` watching... (Ctrl+C to stop)
|
|
21
|
+
`);;)console.clear(),await q(),await Y($);else await q()}var Mt=["SOOTSIM_AGENT","CLAUDECODE","CLAUDE_CODE_ENTRYPOINT","CLAUDE_CODE_SESSION_ID","CODEX_THREAD_ID","CURSOR_TRACE_ID","AIDER_MODEL"];function Ce(){if(process.env.SOOTSIM_AGENT==="0")return!1;for(let o of Mt){let c=process.env[o];if(c&&c.trim()&&c!=="0")return!0}return!1}async function Be(o){let{bridge:c,args:i,effectiveArgs:d,positional:u,inspectUsage:a}=o,b=x=>{let J=d.indexOf(x);return J>=0&&J+1<d.length?d[J+1]:null},k=x=>d.includes(x),$=b("--testid")||b("--test-id"),I=b("--role"),y=b("--type"),S=b("--text"),A=k("--pressable"),v=k("--visible"),j=!$&&!I&&!y&&!S&&!A&&!v?u[1]:null,l=S??j,R,D;$?(D="testid",R=`(async () => {
|
|
22
22
|
const t = window.__sootsimTest
|
|
23
|
-
return (await t.findByTestId(${JSON.stringify(
|
|
24
|
-
})()`):
|
|
23
|
+
return (await t.findByTestId(${JSON.stringify($)})) || (await t.findById(${JSON.stringify($)}))
|
|
24
|
+
})()`):I?(D="role",R=`(async () => await window.__sootsimTest.queryAll({ hasRole: ${JSON.stringify(I)}, pruneHidden: true }))()`):y?(D="type",R=`(async () => await window.__sootsimTest.queryAll({ type: ${JSON.stringify(y)}, pruneHidden: true }))()`):A?(D="pressable",R=`(async () => {
|
|
25
25
|
const t = window.__sootsimTest
|
|
26
26
|
const all = await t.queryAll({ pruneHidden: true })
|
|
27
27
|
return all.filter(n => n.pressable)
|
|
28
|
-
})()`):
|
|
28
|
+
})()`):v?(D="visible",R=`(async () => {
|
|
29
29
|
const all = await window.__sootsimTest.queryAll({ pruneHidden: true })
|
|
30
30
|
return all.filter(n => n.layout && n.layout.width > 0 && n.layout.height > 0)
|
|
31
|
-
})()`):l?(
|
|
31
|
+
})()`):l?(D="text",R=`(async () => await window.__sootsimTest.findByText(${JSON.stringify(l)}))()`):(console.error(a("find","<text> | --text <t> | --testid <id> | --role <r> | --type <t> | --pressable | --visible")),process.exit(1));let q=await c.send({type:"evaluate",code:R}),ne=E(i),Z=i.includes("--verbose")||i.includes("--dump");if(ne)C(q??null);else if(Array.isArray(q))if(q.length===0){console.log(` no ${D} nodes found`);let x=await c.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()"});typeof x=="number"&&x<10&&U("app-still-loading",x)}else{console.log(` found ${q.length} node${q.length===1?"":"s"} (${D}):`);for(let x of q.slice(0,20)){let J=x.absolutePosition?`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`:"",H=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",K=x.text?` "${x.text.slice(0,30)}"`:"",Q=x.testID?` #${x.testID}`:"",e=x.pressable?" (tap)":"",t=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${t}${K}${Q} ${H} ${J}${e}`),Z&&console.log(De(JSON.stringify(x,null,2)," "))}q.length>20&&console.log(` ... and ${q.length-20} more`)}else if(q==null)console.log(` not found: ${l||$||I||y||""||D}`),$&&U("wait-selector-for-missing-testid",$);else{let x=q;if(x.type&&x.absolutePosition){let J=`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`,H=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",K=x.text?` "${x.text.slice(0,40)}"`:"",Q=x.testID?` #${x.testID}`:"",e=x.pressable?" (tap)":"",t=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${t}${K}${Q} ${H} ${J}${e}`),Z&&console.log(De(JSON.stringify(x,null,2)," "))}else console.log(JSON.stringify(q,null,2))}}function De(o,c){return o.split(`
|
|
32
32
|
`).map(i=>c+i).join(`
|
|
33
|
-
`)}async function
|
|
33
|
+
`)}async function Le(o,c={}){let i=await o.send({type:"evaluate",code:`(() => {
|
|
34
34
|
const kb = window.__sootsimKeyboard
|
|
35
35
|
if (!kb || typeof kb.getLayout !== 'function') {
|
|
36
36
|
return { error: 'keyboard bridge getLayout() not available' }
|
|
37
37
|
}
|
|
38
38
|
return kb.getLayout()
|
|
39
|
-
})()`});if("error"in i&&(console.error(i.error),process.exit(1)),c.json){console.log(JSON.stringify(i,null,2));return}let{visible:d,spec:
|
|
40
|
-
`))}async function
|
|
39
|
+
})()`});if("error"in i&&(console.error(i.error),process.exit(1)),c.json){console.log(JSON.stringify(i,null,2));return}let{visible:d,spec:u,mode:a,shifted:b,capsLock:k,accessoryBarId:$}=i,I=[];I.push(`keyboard: ${d?"visible":"hidden"}`),u?(I.push(` type: ${u.keyboardType}`),I.push(` returnKey: ${u.returnKeyType}`),I.push(` autoCap: ${u.autoCapitalize}`),I.push(` autoCorrect: ${u.autoCorrect?"on":"off"}`),I.push(` appearance: ${u.keyboardAppearance}`),u.secureTextEntry&&I.push(" secureTextEntry: true"),u.enablesReturnKeyAutomatically&&I.push(` return: ${u.currentTextIsEmpty?"disabled (empty)":"enabled"}`)):I.push(" spec: <none> (shown via dev-tools with no TextInput)"),I.push(` mode: ${a}${b?" (shifted)":""}${k?" (caps)":""}`),$&&I.push(` accessoryBar: ${$}`),console.log(I.join(`
|
|
40
|
+
`))}async function je(o){let c=await o.bridge.listBrowsers();if(E(o.args)){C(c.map(i=>({...i,active:i.id===o.browserId})));return}Ae(c,o.browserId)}function X(o){return o<1024?`${o}B`:o<1024*1024?`${(o/1024).toFixed(1)}KB`:`${(o/1024/1024).toFixed(1)}MB`}function le(o,c){return c<=0?"?":`${(o/c*100).toFixed(0)}%`}async function Je(o,c={args:[]}){let d=await o.send({type:"evaluate",code:`(async () => {
|
|
41
|
+
const host = window.__sootsimRenderHost
|
|
42
|
+
const stats = host?.queryStats ? await host.queryStats() : null
|
|
43
|
+
const hostMem = performance.memory
|
|
44
|
+
? {
|
|
45
|
+
usedJSHeapSize: performance.memory.usedJSHeapSize,
|
|
46
|
+
totalJSHeapSize: performance.memory.totalJSHeapSize,
|
|
47
|
+
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
|
|
48
|
+
}
|
|
49
|
+
: null
|
|
50
|
+
return {
|
|
51
|
+
imageLoader: stats?.memory?.imageLoader ?? null,
|
|
52
|
+
workerHeap: stats?.memory?.workerHeap ?? null,
|
|
53
|
+
hostHeap: hostMem,
|
|
54
|
+
}
|
|
55
|
+
})()`})??{};if(E(c.args)){C(d);return}if(console.log(" memory:"),d.imageLoader){let u=d.imageLoader;console.log(" image-loader cache"),console.log(` entries: ${u.cacheEntries} / ${u.cacheMaxEntries} (${le(u.cacheEntries,u.cacheMaxEntries)})`),console.log(` pixel bytes: ${X(u.cachePixelBytes)} / ${X(u.cachePixelBudget)} (${le(u.cachePixelBytes,u.cachePixelBudget)})`),console.log(` pending: ${u.pendingFetches} fetches, ${u.pendingBytes} bytes`),console.log(` failed uris: ${u.failedUris}`),console.log(` snapshots: ${u.snapshots}`),console.log(` camera frames: ${u.cameraFrames}`)}else console.log(" image-loader cache: not available (engine pre-rebuild?)");if(d.workerHeap){let u=d.workerHeap;console.log(" worker heap (chrome only)"),console.log(` used: ${X(u.usedJSHeapSize)} / ${X(u.jsHeapSizeLimit)} (${le(u.usedJSHeapSize,u.jsHeapSizeLimit)})`),console.log(` total: ${X(u.totalJSHeapSize)}`)}if(d.hostHeap){let u=d.hostHeap;console.log(" host heap (chrome only)"),console.log(` used: ${X(u.usedJSHeapSize)} / ${X(u.jsHeapSizeLimit)} (${le(u.usedJSHeapSize,u.jsHeapSizeLimit)})`),console.log(` total: ${X(u.totalJSHeapSize)}`)}}function se(o){let c=o.indexOf("--testid");if(c>=0&&o[c+1])return{mode:"testid",value:o[c+1]};let i=o.indexOf("--test-id");if(i>=0&&o[i+1])return{mode:"testid",value:o[i+1]};let d=o.indexOf("--text");return d>=0&&o[d+1]?{mode:"text",value:o[d+1]}:null}async function ce(o,c){let i=JSON.stringify(c.value),d=c.mode==="testid"?`(await t.findByTestId(${i})) || (await t.findById(${i}))`:`await t.findByText(${i})`;return await o.send({type:"evaluate",code:`(async () => {
|
|
41
56
|
const t = window.__sootsimTest
|
|
42
57
|
if (!t) return null
|
|
43
58
|
const n = ${d}
|
|
@@ -55,7 +70,7 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
55
70
|
? resolved.cy
|
|
56
71
|
: n.absolutePosition.y + (n.layout.height || 0) / 2
|
|
57
72
|
return { x: cx, y: cy, testID: n.testID, text: n.text }
|
|
58
|
-
})()`})??null}async function
|
|
73
|
+
})()`})??null}async function He(o,c={}){let i=await o.send({type:"evaluate",code:`(async () => {
|
|
59
74
|
const test = window.__sootsimTest
|
|
60
75
|
const kb = window.__sootsimKeyboard
|
|
61
76
|
const navSnap =
|
|
@@ -79,8 +94,15 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
79
94
|
})()
|
|
80
95
|
: null
|
|
81
96
|
return { nav: navSnap, keyboard }
|
|
82
|
-
})()`}),d=i?.nav??null,
|
|
83
|
-
`))}async function
|
|
97
|
+
})()`}),d=i?.nav??null,u=i?.keyboard??null,a=await V(o,500).catch(()=>null);if(c.json){console.log(JSON.stringify({shell:a??null,nav:d,keyboard:u},null,2));return}let b=[];if(a){let k=a.activeApp??a.state??"<none>",$=a.showSwitcher?" (app switcher open)":"",I=typeof a.launchProgress=="number"&&a.launchProgress<.98?` launching (${Math.round(a.launchProgress*100)}%)`:"";b.push(`shell: ${k}${$}${I}`)}else b.push("shell: <unavailable>");if(d){let k=d.transitionPhase!=="idle"?` (${d.transitionPhase}, ${d.activeTransitionCount} active)`:"";if(b.push(`nav: phase=${d.transitionPhase}${k}`),d.screens.length===0)b.push(" <no registered screens \u2014 app may not use react-native-screens>");else for(let $ of d.screens){let I=$.isActive?"\u25B6":" ",y=$.routeName?` ${$.routeName}`:"",S=$.headerHeight>0?` header=${$.headerHeight}`:"",A=$.largeTitleState&&$.largeTitleState!=="expanded"?` large-title=${$.largeTitleState}`:"";b.push(` ${I} #${$.id}${y}${S}${A}`)}}else b.push("nav: <runtime not available>");if(u&&u.visible){let k=u.spec?.keyboardType??"default",$=u.spec?.returnKeyType??"default";b.push(`keyboard: visible (${k}, return=${$}, mode=${u.mode??"?"})`)}else b.push("keyboard: hidden");console.log(b.join(`
|
|
98
|
+
`))}async function ee({bridge:o,maxMs:c,pollMs:i=50,stablePolls:d=3,strict:u=!1}){let a=await o.send({type:"evaluate",code:`(async () => {
|
|
99
|
+
const start = Date.now()
|
|
100
|
+
const deadline = start + ${Math.max(0,Math.round(c))}
|
|
101
|
+
const pollMs = ${Math.max(1,Math.round(i))}
|
|
102
|
+
const requiredStablePolls = ${Math.max(1,Math.round(d))}
|
|
103
|
+
const strict = ${u?"true":"false"}
|
|
104
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
105
|
+
const readSnapshot = async () => {
|
|
84
106
|
let animating = false
|
|
85
107
|
try {
|
|
86
108
|
const stats = await window.__sootsimRenderHost?.queryStats?.()
|
|
@@ -103,30 +125,26 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
103
125
|
walk(root)
|
|
104
126
|
}
|
|
105
127
|
return { layout: nodes.join(';'), animating }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const root = window.__sootsimRoot
|
|
118
|
-
const nodes = []
|
|
119
|
-
if (root) {
|
|
120
|
-
const walk = (n) => {
|
|
121
|
-
if (n.layout && n.layout.width > 0) {
|
|
122
|
-
nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
|
|
123
|
-
}
|
|
124
|
-
for (const c of n.children || []) walk(c)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let lastLayout = ''
|
|
131
|
+
let stable = 0
|
|
132
|
+
while (Date.now() < deadline) {
|
|
133
|
+
const snapshot = await readSnapshot()
|
|
134
|
+
const strictOk = !strict || !snapshot.animating
|
|
135
|
+
if (strictOk && snapshot.layout === lastLayout) {
|
|
136
|
+
stable++
|
|
137
|
+
if (stable >= requiredStablePolls) {
|
|
138
|
+
return { settled: true, elapsed: Date.now() - start }
|
|
125
139
|
}
|
|
126
|
-
|
|
140
|
+
} else {
|
|
141
|
+
stable = 0
|
|
127
142
|
}
|
|
128
|
-
|
|
129
|
-
|
|
143
|
+
lastLayout = snapshot.layout
|
|
144
|
+
await sleep(pollMs)
|
|
145
|
+
}
|
|
146
|
+
return { settled: false, elapsed: Date.now() - start }
|
|
147
|
+
})()`}),{elapsed:b,settled:k}=a??{};return{elapsed:typeof b=="number"?b:c,settled:k===!0}}async function qe(o){let{bridge:c,args:i,positional:d}=o,u=d[1]?Number(d[1])*1e3:3e3,a=i.includes("--strict"),{elapsed:b,settled:k}=await ee({bridge:c,maxMs:u,strict:a});console.log(k?` settled in ${b}ms`:` timed out after ${b}ms (may still be animating)`)}async function We(o){let c=o.positional[1]?Number(o.positional[1]):.5;(!Number.isFinite(c)||c<0)&&(console.error(o.inspectUsage("sleep","[seconds]")),process.exit(1)),await Y(c*1e3),console.log(` slept ${c}s`)}async function ze(o){let{bridge:c,args:i,positional:d}=o,u=d[1]?Number(d[1]):5,a=await c.send({type:"evaluate",code:`(async () => await window.__sootsimTest.dumpTree(${u}))()`});if(E(i)){C({depth:u,tree:a??null});return}console.log(typeof a=="string"?a:JSON.stringify(a,null,2))}async function Ke(o,c={args:[]}){let i=await o.send({type:"evaluate",code:"window.location.href"}),d=typeof i=="string"?i:"";if(E(c.args)){C({url:d});return}console.log(d)}async function Ue(o){let{wsPort:c,commandTimeoutMs:i,browserId:d,positional:u}=o,a=u[1]?Number(u[1]):30,b=Math.max(1e3,(Number.isFinite(a)?a:30)*1e3),k=Math.max(1,Math.ceil(b/500));console.log(" waiting for browser reconnect...");let $=await Ie(c,i,d,{attempts:k});$||(console.error(" timed out waiting for browser reconnect"),process.exit(1)),$.bridge.close(),ae({source:"inspect wait",step:{wait:b},summary:`wait ${Math.round(b/1e3)}s`}),console.log(` ready: ${$.count} nodes`)}async function Ye(o){let{bridge:c,args:i}=o,d=i.includes("--strict"),u=i.indexOf("--max-ms"),a=u>=0&&i[u+1]?Math.max(100,Number(i[u+1])):3e3,{elapsed:b,settled:k}=await ee({bridge:c,maxMs:a,strict:d});k?console.log(` idle in ${b}ms`):(console.error(` \u26A0 wait idle timed out after ${b}ms (may still be animating)`),process.exit(1))}async function Ge(o){let{bridge:c,args:i}=o,d=2e4,u=i.indexOf("--max-ms");u>=0&&i[u+1]&&(d=Math.max(100,Number(i[u+1])));let a=Date.now(),b=a+d,k=`(async () => {
|
|
130
148
|
const t = window.__sootsimTest
|
|
131
149
|
let nodes = 0
|
|
132
150
|
try { nodes = (await t?.getNodeCount?.()) || 0 } catch {}
|
|
@@ -135,9 +153,9 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
135
153
|
at: (window).__sootsimExternalAppReadyAt || 0,
|
|
136
154
|
nodes,
|
|
137
155
|
}
|
|
138
|
-
})()
|
|
156
|
+
})()`,$={flag:void 0,at:0,nodes:0};for(;Date.now()<b;){try{$=await c.send({type:"evaluate",code:k})??$}catch{}if($.flag===!0){console.log(` ready in ${Date.now()-a}ms: ${$.nodes} nodes (flag)`);return}await new Promise(I=>setTimeout(I,150))}console.error(` \u26A0 wait ready timed out after ${Date.now()-a}ms \u2014 guest app did not emit sootsim:externalAppReady (nodes: ${$.nodes})`),process.exit(1)}async function Xe(o){let{bridge:c,args:i,positional:d,inspectUsage:u}=o,a=d[1];a||(console.error(u("wait selector","<testid> [--max-ms 5000]")),process.exit(1));let b=i.indexOf("--max-ms"),k=b>=0&&i[b+1]?Math.max(100,Number(i[b+1])):5e3,$=await c.send({type:"evaluate",code:`(async () => {
|
|
139
157
|
const start = Date.now()
|
|
140
|
-
const deadline = start + ${
|
|
158
|
+
const deadline = start + ${k}
|
|
141
159
|
const t = window.__sootsimTest
|
|
142
160
|
const find = async () => {
|
|
143
161
|
try {
|
|
@@ -154,8 +172,8 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
154
172
|
await new Promise((r) => setTimeout(r, 80))
|
|
155
173
|
}
|
|
156
174
|
return { found: false, elapsed: Date.now() - start }
|
|
157
|
-
})()`}),{found:
|
|
158
|
-
`).slice(0,5);for(let
|
|
175
|
+
})()`}),{found:I,node:y,elapsed:S}=$??{};if(I&&y){let A=y.absolutePosition?`@(${Math.round(y.absolutePosition.x)},${Math.round(y.absolutePosition.y)})`:"",v=y.layout?`${Math.round(y.layout.width)}x${Math.round(y.layout.height)}`:"?x?";console.log(` found #${a} in ${S}ms ${v} ${A}`)}else console.error(` \u26A0 wait selector #${a} timed out after ${S??k}ms`),process.exit(1)}function st(o){return o==null?"\u2014":o<1024?`${o}B`:o<1024*1024?`${(o/1024).toFixed(1)}K`:`${(o/1024/1024).toFixed(1)}M`}function nt(o){return o==null?" \u2026":o<1e3?`${o}ms`.padStart(5):`${(o/1e3).toFixed(2)}s`.padStart(5)}function _t(o){return o.error?"err":o.status==null?" \u2026 ":String(o.status)}function Ve(o){let c=new Date(o.startTs).toLocaleTimeString(),i=_t(o).padEnd(3),d=o.method.padEnd(5),u=st(o.size).padStart(6),a=nt(o.durationMs);console.log(` [${c}] ${i} ${d} ${u} ${a} ${o.displayUrl}`),o.error&&console.log(` error: ${o.error}`)}function It(o){let c=[["id",o.id],["source",o.source],["kind",o.kind],["method",o.method],["status",o.error?`error: ${o.error}`:`${o.status??"\u2014"} ${o.statusText??""}`.trim()],["url",o.url],["started",new Date(o.startTs).toLocaleTimeString()],["duration",nt(o.durationMs).trim()],["size",st(o.size)],["content-type",o.type??"\u2014"]];for(let[i,d]of c)console.log(` ${i.padEnd(13)} ${d}`)}var Ft={error:"\x1B[31m",warn:"\x1B[33m",info:"\x1B[36m",debug:"\x1B[35m",log:"\x1B[37m"},Ze="\x1B[0m",At="\x1B[2m";function Qe(o,c){let i=new Date(o.ts).toLocaleTimeString(),d=o.level.toUpperCase().padEnd(5),u=o.args.join(" ");if(c){let a=Ft[o.level];console.log(` ${At}[${i}]${Ze} ${a}${d}${Ze} ${u}`)}else console.log(` [${i}] ${d} ${u}`);if(o.stack&&o.level==="error"){let a=o.stack.split(`
|
|
176
|
+
`).slice(0,5);for(let b of a)console.log(` ${b.trim()}`)}}var G="__sootsimCliPerf",Pt=120;async function et(o,c){let i=o.find((A,v)=>o[v-1]==="--id"),d=o.find((A,v)=>o[v-1]==="--text");if(i||d){let A=await c.send({type:"evaluate",code:Ne({id:i,text:d})});if(!A)throw new Error(i?`no node with id "${i}"`:`no node matching text "${d}"`);let{x:v,y:j,w:l,h:R}=A;return{x:v,y:j,w:l,h:R}}let u=o.find((A,v)=>o[v-1]==="--area");if(u){let A=u.split(",").map(D=>Number(D.trim()));if(A.length!==4||A.some(D=>!Number.isFinite(D)))throw new Error(`--area expects x,y,w,h (got "${u}")`);let[v,j,l,R]=A;return{x:v,y:j,w:l,h:R}}let a=A=>{let v=o.find((l,R)=>o[R-1]===A);if(v==null)return null;let j=Number(v);return Number.isFinite(j)?j:null},b=a("--x"),k=a("--y"),$=a("--w"),I=a("--h");if(b!=null||k!=null||$!=null||I!=null)return{x:b??0,y:k??0,w:$??1,h:I??1};let S=o.filter((A,v)=>v>0&&!A.startsWith("-")&&o[v-1]!=="--output"&&o[v-1]!=="--area"&&o[v-1]!=="--id"&&o[v-1]!=="--text"&&o[v-1]!=="--x"&&o[v-1]!=="--y"&&o[v-1]!=="--w"&&o[v-1]!=="--h").map(Number).filter(A=>Number.isFinite(A));if(S.length>=2){let[A,v,j=1,l=1]=S;return{x:A,y:v,w:j,h:l}}return null}function be(o){let c={"<8":0,"8-12":0,"12-16":0,"16-20":0,"20-33":0,">33":0};for(let i of o)i<8?c["<8"]++:i<12?c["8-12"]++:i<16?c["12-16"]++:i<20?c["16-20"]++:i<33?c["20-33"]++:c[">33"]++;console.log(" histogram:");for(let[i,d]of Object.entries(c)){let u="\u2588".repeat(Math.ceil(d/o.length*40));console.log(` ${i.padEnd(6)} ${u} ${d}`)}}async function de(o,c,i){let d=Date.now()+c,u=await V(o,c);for(;;){if(i(u))return{settled:!0,state:u};if(Date.now()>=d)return{settled:!1,state:u};await Y(16),u=await V(o)}}async function he(o){return o.send({type:"evaluate",code:`(async () => {
|
|
159
177
|
const kb = window.__sootsimKeyboard
|
|
160
178
|
const test = window.__sootsimTest
|
|
161
179
|
if (!kb) return { error: 'keyboard bridge not available' }
|
|
@@ -187,7 +205,7 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
187
205
|
frame: runtimeSnapshot?.keyboard?.frame ?? null,
|
|
188
206
|
focusedRect: runtimeSnapshot?.focused?.rect ?? null,
|
|
189
207
|
}
|
|
190
|
-
})()`})}async function
|
|
208
|
+
})()`})}async function Ot(o,c=600){let i=Date.now()+c;for(;Date.now()<=i;){let d=await he(o);if(d.visible)return d;await Y(30)}return he(o)}async function ue(o,c){let i=await he(o);if(i.visible)return i;console.error(` ${c} requires the iOS keyboard to be visible. focus an input first with sootsim do tap-id/tap-text or sootsim do type-into.`),process.exit(1)}async function tt(o,c,i){return c==="appearance"?o.send({type:"evaluate",code:`(async () => {
|
|
191
209
|
const requested = ${JSON.stringify(i??"toggle")}
|
|
192
210
|
const rootBg = (document.documentElement?.style?.background || '').toLowerCase()
|
|
193
211
|
const inferredCurrent = rootBg.includes('33') ? 'dark' : 'light'
|
|
@@ -199,58 +217,28 @@ import{a as Y}from"./chunk-GPVPHE2B.js";import{a as xe,b as $e}from"./chunk-J2S3
|
|
|
199
217
|
}
|
|
200
218
|
window.postMessage({ type: 'soot-action', action: 'set-appearance', value: applied }, '*')
|
|
201
219
|
return { ok: true, requested, applied }
|
|
202
|
-
})()`}):
|
|
220
|
+
})()`}):o.send({type:"evaluate",code:`(async () => {
|
|
203
221
|
window.dispatchEvent(new CustomEvent(${JSON.stringify(c==="lock"?"sootsim:toggleLock":"sootsim:shake")}))
|
|
204
222
|
return { ok: true, action: ${JSON.stringify(c)} }
|
|
205
|
-
})()`})}function
|
|
206
|
-
`),process.exit(0))}if(
|
|
207
|
-
`),process.exit(0))}let t=
|
|
223
|
+
})()`})}function Et(o){let c={Enter:"return",NumpadEnter:"return",Backspace:"delete",Delete:"delete",Space:"space",ShiftLeft:"shift",ShiftRight:"shift"};if(c[o])return c[o];let i=o.match(/^Digit([0-9])$/);if(i)return i[1];let d=o.match(/^Key([A-Z])$/);return d?d[1].toLowerCase():null}function Rt(o){if(typeof o!="string")return null;let c=o.replace(/\s+/g," ").trim();return c?c.slice(0,80):null}function rt(...o){for(let c of o){if(typeof c!="string")continue;let i=c.trim();if(i)return i}return null}async function L(o,c,i){ae({source:o,step:c,summary:i})}function Ct(o,c,i){if(!i||i.hit===!1)return null;let d=rt(i.responderTestID,i.testID);if(d)return{step:{tapOn:{id:d}},summary:`tap #${d}`};let u=Rt(i.text);return u?{step:{tapOn:u},summary:`tap "${u}"`}:{step:{tapAtCoords:{x:o,y:c}},summary:`tap @${Math.round(o)},${Math.round(c)}`}}function ot(o,c,i){let d=rt(c?.testID,c?.id);return d?{step:{tapOn:{id:d}},summary:`tap #${d}`}:i==="id"?{step:{tapOn:{id:o}},summary:`tap #${o}`}:{step:{tapOn:o},summary:`tap "${o}"`}}async function ss(o,c){let i=o[0]==="get"||o[0]==="do"||o[0]==="debug"||o[0]==="wait"?o[0]:null,d=i?o.slice(1):o,u=$e(d,{port:c.port,commandTimeoutMs:c.timeoutMs,stripBooleanFlags:["--verbose","-v","--help","-h","--clear-state","--json","--all","--watch","-w","--strict","--no-wait","--dump","--failed","--tail","-f","--internal"],stripValueFlags:["--output","--nth","--index","--testid","--test-id","--text","--max-ms","--filter","--limit","--level"]}),a=u.positional,b=a[0],k=i==="get"||i==="do"||i==="debug"||i==="wait"?i:"inspect",$=typeof d[0]=="string"&&xe.has(d[0]),I=$?d[0]:null,y=e=>$&&e===d[0]?`sootsim ${e}`:`sootsim ${k} ${e}`,S=(e,t)=>` usage: ${y(e)}${t?` ${t}`:""}`;if(!b||o.includes("--help")||o.includes("-h")){let e={bridgePort:7668,defaultShellUrl:we};if(k==="do"||k==="get"||k==="debug"||k==="wait"){let r=me(k,e);r&&(console.log(`${r}
|
|
224
|
+
`),process.exit(0))}if(I==="shell"){let r=pe("shell",e);r&&(console.log(`${r}
|
|
225
|
+
`),process.exit(0))}let t=pe("inspect",e),s=["do","get","debug","wait"].map(r=>me(r,e)).filter(r=>r!=null).join(`
|
|
208
226
|
|
|
209
227
|
`);console.log(`${t??""}
|
|
210
228
|
|
|
211
|
-
${
|
|
212
|
-
`),process.exit(0)}let
|
|
213
|
-
`);let
|
|
214
|
-
|
|
215
|
-
const deadline = start + ${t}
|
|
216
|
-
const hash = () => {
|
|
217
|
-
const root = window.__sootsimRoot
|
|
218
|
-
if (!root) return ''
|
|
219
|
-
const nodes = []
|
|
220
|
-
const walk = (n) => {
|
|
221
|
-
if (n.layout && n.layout.width > 0) {
|
|
222
|
-
nodes.push(Math.round(n.layout.x) + ',' + Math.round(n.layout.y) + ',' + Math.round(n.layout.width))
|
|
223
|
-
}
|
|
224
|
-
for (const c of n.children || []) walk(c)
|
|
225
|
-
}
|
|
226
|
-
walk(root)
|
|
227
|
-
return nodes.join(';')
|
|
228
|
-
}
|
|
229
|
-
let last = ''
|
|
230
|
-
let stable = 0
|
|
231
|
-
while (Date.now() < deadline) {
|
|
232
|
-
const h = hash()
|
|
233
|
-
if (h === last) {
|
|
234
|
-
stable++
|
|
235
|
-
if (stable >= 2) return { settled: true, elapsed: Date.now() - start }
|
|
236
|
-
} else {
|
|
237
|
-
stable = 0
|
|
238
|
-
}
|
|
239
|
-
last = h
|
|
240
|
-
await new Promise((r) => setTimeout(r, 32))
|
|
241
|
-
}
|
|
242
|
-
return { settled: false, elapsed: Date.now() - start }
|
|
243
|
-
})()`}),{settled:r,elapsed:n}=o??{};r===!1&&process.stderr.write(` \u26A0 auto-wait timed out after ${n??t}ms \u2014 next command may see mid-animation state. use \`sootsim do settle\` for a longer wait.
|
|
244
|
-
`)}catch{}}async function V(){try{return await l.send({type:"evaluate",code:`(() => ({
|
|
229
|
+
${s}
|
|
230
|
+
`),process.exit(0)}let A=u.wsPort,v=u.browserId,j=u.commandTimeoutMs;if(b==="list"&&d.some(e=>e==="--drivers"||e==="-D")){let{buildDriverListRows:e}=await import("./drivers-EXUREU4B.js"),t=e();console.log(` available drivers (${t.length}):
|
|
231
|
+
`);let s=Math.max(...t.map(n=>n.id.length),6),r=Math.max(...t.map(n=>n.kind.length),4);for(let n of t){let m=n.available?"\u2713":"\u2717",p=n.id.padEnd(s),h=n.kind.padEnd(r);console.log(` ${m} ${p} ${h} ${n.description}`),n.available&&n.detail?console.log(` ${n.detail}`):!n.available&&n.reason&&console.log(` unavailable: ${n.reason}`)}return}let l=Se(u),R=v||"default",D=new Set(["errors","warnings","requests","js","eval","reload","globals","perf","list","wait","sleep"]);function q(e){let t=e.displayUrl||e.url;return e.status!=null?`${e.method} ${t} -> ${e.status}${e.statusText?` ${e.statusText}`:""}`:e.error?`${e.method} ${t} -> ${e.error}`:`${e.method} ${t}`}async function ne(e){let t=Ce()?1200:350;try{let{settled:s,elapsed:r}=await ee({bridge:e,maxMs:t,pollMs:32,stablePolls:2});s||process.stderr.write(` \u26A0 auto-wait timed out after ${r??t}ms \u2014 next command may see mid-animation state. use \`sootsim do settle\` for a longer wait.
|
|
232
|
+
`)}catch{}}async function Z(){try{return await l.send({type:"evaluate",code:`(() => ({
|
|
245
233
|
console: window.__sootsimConsole?.count?.() || null,
|
|
246
234
|
requests: window.__sootsimTest?.getRequestCounts?.() || null,
|
|
247
|
-
}))()`})||{console:null,requests:null}}catch{return{console:null,requests:null}}}async function
|
|
248
|
-
network: ${
|
|
235
|
+
}))()`})||{console:null,requests:null}}catch{return{console:null,requests:null}}}async function x(e={}){let t=e.counts!==void 0?e.counts:await z(l,"getRequestCounts");if(!t||typeof t!="object")return;let s=Math.max(0,Number(t.failed)||0);if(s===0||!e.includeTail&&!ge("requests",R,String(s))||(console.log(`
|
|
236
|
+
network: ${s} failed request${s===1?"":"s"}`),console.log(` inspect: ${y("requests")} 5`),!e.includeTail))return;let r=await z(l,"getFailedRequests",5);if(!(!Array.isArray(r)||r.length===0)){console.log(`
|
|
249
237
|
recent failed requests:
|
|
250
|
-
`);for(let n of r){let
|
|
251
|
-
console: ${
|
|
238
|
+
`);for(let n of r){let m=new Date(n.timestamp).toLocaleTimeString();console.log(` [${m}] ${q(n)}`),n.responseBody?console.log(` ${n.responseBody}`):n.error&&console.log(` ${n.error}`)}}}async function J(e={}){let t=e.counts!==void 0?e.counts:await l.send({type:"evaluate",code:"window.__sootsimConsole?.count?.() || { errors: 0, warnings: 0, total: 0 }"});if(!t||typeof t!="object")return;let s=t,r=Math.max(0,Number(s.errors)||0),n=Math.max(0,Number(s.warnings)||0);if(r===0&&n===0||!e.includeTail&&!ge("console",R,`${r}:${n}`))return;let m=[];if(r>0&&m.push(`${r} console error${r===1?"":"s"}`),n>0&&m.push(`${n} console warning${n===1?"":"s"}`),console.log(`
|
|
239
|
+
console: ${m.join(", ")}`),console.log(` inspect: ${y("errors")} 5`),n>0&&console.log(` inspect: ${y("warnings")} 5`),!e.includeTail||r===0)return;let p=await l.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors?.(5) || []"});if(!(!Array.isArray(p)||p.length===0)){console.log(`
|
|
252
240
|
recent console errors:
|
|
253
|
-
`);for(let
|
|
241
|
+
`);for(let h of p){let f=new Date(h.timestamp).toLocaleTimeString(),w=Array.isArray(h.args)?h.args.map(O=>typeof O=="object"?JSON.stringify(O):String(O)).join(" "):String(h);console.log(` [${f}] ${w}`)}}}let H=new Set(["tap","double-tap","tap-text","tap-id","type","type-into","key","key-sequence","keycode","drag","swipe","long-press","touch","gesture","pinch","scroll","shell"]),K=new Set(["a11y","capture","count","double-tap","drag","find","gesture","layout","long-press","node","pinch","sample-color","scroll","screenshot","swipe","tap","tap-id","tap-text","touch","tree","type-into"]),Q=(o.includes("--verbose")||o.includes("-v"))&&!o.includes("--json");k==="do"&&b==="shell"&&(console.error(" `sootsim do shell` was removed. use `sootsim shell ...` instead."),process.exit(1)),H.has(b)&&await ke(l),K.has(b)&&await ie(l,{verbose:Q});try{switch(b){case"list":{await je({bridge:l,browserId:v,args:d});break}case"tree":{await ze({bridge:l,args:d,positional:a});break}case"a11y":{let e=a[1]?Number(a[1]):5,t=await l.send({type:"evaluate",code:`(async () => {
|
|
254
242
|
const t = window.__sootsimTest
|
|
255
243
|
if (!t) return []
|
|
256
244
|
const all = await t.queryAll({ pruneHidden: true })
|
|
@@ -278,8 +266,8 @@ ${o}
|
|
|
278
266
|
position: n.absolutePosition ? { x: Math.round(n.absolutePosition.x), y: Math.round(n.absolutePosition.y) } : null,
|
|
279
267
|
size: n.layout ? { w: Math.round(n.layout.width), h: Math.round(n.layout.height) } : null,
|
|
280
268
|
}))
|
|
281
|
-
})()`});if(!Array.isArray(t)||t.length===0){console.log(" no accessible nodes found");break}if(
|
|
282
|
-
`);for(let
|
|
269
|
+
})()`});if(!Array.isArray(t)||t.length===0){console.log(" no accessible nodes found");break}if(o.includes("--json"))console.log(JSON.stringify(t,null,2));else{console.log(` accessibility tree (${t.length} nodes):
|
|
270
|
+
`);for(let s of t){let r=[];if(r.push(`[${s.role}]`),s.label){let n=s.label.length>50?s.label.slice(0,47)+"...":s.label;r.push(`"${n}"`)}if(s.hint&&r.push(`(hint: "${s.hint}")`),s.testID&&r.push(`#${s.testID}`),s.state){let n=[];s.state.disabled&&n.push("disabled"),s.state.selected&&n.push("selected"),s.state.checked===!0&&n.push("checked"),s.state.checked==="mixed"&&n.push("mixed"),s.state.busy&&n.push("busy"),s.state.expanded===!0&&n.push("expanded"),s.state.expanded===!1&&n.push("collapsed"),n.length&&r.push(`{${n.join(", ")}}`)}s.position&&r.push(`@(${s.position.x},${s.position.y})`),s.size&&r.push(`${s.size.w}x${s.size.h}`),console.log(" "+r.join(" "))}}break}case"find":{await Be({bridge:l,args:o,effectiveArgs:d,positional:a,inspectUsage:S});break}case"count":{await Ee(l,{args:d});break}case"keyboard":{await Le(l,{json:o.includes("--json")});break}case"screens":{await He(l,{json:o.includes("--json")});break}case"memory":{await Je(l,{args:d});break}case"wait":{await Ue({wsPort:A,commandTimeoutMs:j,browserId:v,positional:a});break}case"sleep":{await We({positional:a,inspectUsage:S});break}case"settle":{await qe({bridge:l,args:o,positional:a});break}case"ready":{await Ge({bridge:l,args:o});break}case"idle":{await Ye({bridge:l,args:o,positional:a});break}case"selector":{await Xe({bridge:l,args:o,positional:a,inspectUsage:S});break}case"layout":{let e=a[1];e||(console.error(S("layout","<id>")),process.exit(1));let t=await l.send({type:"evaluate",code:`(async () => await window.__sootsimTest.getLayout(${JSON.stringify(e)}))()`});console.log(JSON.stringify(t,null,2));break}case"capture":case"screenshot":{let t=o.find((h,f)=>o[f-1]==="--output")||"/tmp/sootsim-inspect.png",s=await et(o,l),r={type:"screenshot"};s&&(r.crop=s);let m=(await l.send(r)).replace(/^data:image\/png;base64,/,"");s&&console.log(` area: x=${s.x} y=${s.y} w=${s.w} h=${s.h}`),(await import("fs")).writeFileSync(t,Buffer.from(m,"base64")),console.log(` saved: ${t}`);break}case"sample-color":{let e=await et(o,l);e||(console.error(S("sample-color","<x> <y> [w] [h] | --id <testID> | --text <text>")),console.error(" samples an averaged color from the canvas. coords are logical sootsim units."),process.exit(1));let t=await l.send({type:"evaluate",code:_e(e)});if(o.includes("--json"))console.log(JSON.stringify(t,null,2));else{let{r:s,g:r,b:n,a:m,hex:p,samples:h}=t,f=e.w===1&&e.h===1?`@(${e.x},${e.y})`:`@(${e.x},${e.y}) ${e.w}x${e.h}`;console.log(` ${p} rgba(${s}, ${r}, ${n}, ${m}) ${f} ${h} samples`)}break}case"node":{let e=a[1];e||(console.error(S("node","<matcher>")),console.error(" resolves testID, id, then text \u2014 dumps full node info as JSON"),process.exit(1));let t=await l.send({type:"evaluate",code:`(async () => {
|
|
283
271
|
const t = window.__sootsimTest
|
|
284
272
|
const q = ${JSON.stringify(e)}
|
|
285
273
|
let node = null
|
|
@@ -335,17 +323,17 @@ ${o}
|
|
|
335
323
|
transform,
|
|
336
324
|
parentChain,
|
|
337
325
|
}
|
|
338
|
-
})()`});console.log(JSON.stringify(t,null,2));break}case"tap":{let e=Number(a[1]),t=Number(a[2]),
|
|
326
|
+
})()`});console.log(JSON.stringify(t,null,2));break}case"tap":{let e=Number(a[1]),t=Number(a[2]),s=se(o);if(s){let m=await ce(l,s);m||(console.error(` not found: ${s.value}`),s.mode==="testid"&&U("wait-selector-for-missing-testid",s.value),process.exit(1)),e=m.x,t=m.y}(!Number.isFinite(e)||!Number.isFinite(t))&&(console.error(S("tap","<x> <y> | --testid <id> | --text <t>")),process.exit(1));let r=await l.send({type:"tap",x:e,y:t}),n=Ct(e,t,r);n&&await L("inspect tap",n.step,n.summary),console.log(JSON.stringify(r,null,2));break}case"drag":case"swipe":{let e=Number(a[1]),t=Number(a[2]),s=Number(a[3]),r=Number(a[4]),n=b==="swipe"?10:12,m=b==="swipe"?8:16,p=a[5]?Number(a[5]):n,h=a[6]?Number(a[6]):m;(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(p)||!Number.isFinite(h))&&(console.error(S(b,"<x1> <y1> <x2> <y2> [steps] [stepMs]")),process.exit(1));let f=await l.send({type:"evaluate",code:`(async () => {
|
|
339
327
|
const interact = window.__sootsimInteract
|
|
340
328
|
if (!interact?.drag) return { ok: false, reason: 'no interact.drag' }
|
|
341
|
-
const value = await interact.drag(${e}, ${t}, ${
|
|
329
|
+
const value = await interact.drag(${e}, ${t}, ${s}, ${r}, ${Math.max(1,Math.round(p))}, ${Math.max(0,Math.round(h))})
|
|
342
330
|
return { ok: !!value, value }
|
|
343
|
-
})()`});if(
|
|
331
|
+
})()`});if(f?.ok){let w=Math.max(1,Math.round(Math.max(1,p)*Math.max(0,h)));await L(`inspect ${b}`,{swipe:{start:`${e}, ${t}`,end:`${s}, ${r}`,duration:w}},`${b} ${e},${t} -> ${s},${r}`)}console.log(JSON.stringify(f,null,2));break}case"pinch":{let e=Number(a[1]),t=Number(a[2]),s=Number(a[3]),r=Number(a[4]),n=Number(a[5]),m=Number(a[6]),p=Number(a[7]),h=Number(a[8]),f=a[9]?Number(a[9]):12,w=a[10]?Number(a[10]):16;(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(s)||!Number.isFinite(r)||!Number.isFinite(n)||!Number.isFinite(m)||!Number.isFinite(p)||!Number.isFinite(h)||!Number.isFinite(f)||!Number.isFinite(w))&&(console.error(S("pinch","<x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]")),process.exit(1));let O=await l.send({type:"evaluate",code:`(async () => {
|
|
344
332
|
const interact = window.__sootsimInteract
|
|
345
333
|
if (!interact?.pinch) return { ok: false, reason: 'no interact.pinch' }
|
|
346
|
-
const value = await interact.pinch(${e}, ${t}, ${
|
|
334
|
+
const value = await interact.pinch(${e}, ${t}, ${s}, ${r}, ${n}, ${m}, ${p}, ${h}, ${Math.max(1,Math.round(f))}, ${Math.max(0,Math.round(w))})
|
|
347
335
|
return { ok: !!value, value }
|
|
348
|
-
})()`});O?.ok&&await L("inspect pinch",{pinch:{from:[e,t,
|
|
336
|
+
})()`});O?.ok&&await L("inspect pinch",{pinch:{from:[e,t,s,r],to:[n,m,p,h],steps:Math.max(1,Math.round(f)),stepMs:Math.max(0,Math.round(w))}},`pinch (${e},${t}) (${s},${r}) -> (${n},${m}) (${p},${h})`),console.log(JSON.stringify(O,null,2));break}case"tap-text":{let e=a[1];e||(console.error(S("tap-text","<text>")),process.exit(1));let t=_=>{let P=o.indexOf(_);return P>=0&&P+1<o.length?o[P+1]:null},s=_=>o.includes(_),r=t("--nth")??t("--index"),n=r!==null?Number(r):null;n!==null&&!Number.isFinite(n)&&(console.error(` --nth/--index requires an integer, got: ${r}`),process.exit(1));let m=t("--within"),p=t("--role"),h=s("--exact"),f=s("--first"),w=t("--min-y"),O=t("--max-y"),B=t("--min-x"),N=t("--max-x");for(let[_,P]of[["--min-y",w],["--max-y",O],["--min-x",B],["--max-x",N]])P!==null&&!Number.isFinite(Number(P))&&(console.error(` ${_} requires a number, got: ${P}`),process.exit(1));let M=o.indexOf("--near"),F=null;if(M>=0){let _=Number(o[M+1]),P=Number(o[M+2]);(!Number.isFinite(_)||!Number.isFinite(P))&&(console.error(" --near requires two numbers: --near <x> <y>"),process.exit(1)),F={x:_,y:P}}let W=JSON.stringify({query:e,exact:h,role:p,within:m,minX:B!==null?Number(B):null,maxX:N!==null?Number(N):null,minY:w!==null?Number(w):null,maxY:O!==null?Number(O):null,near:F,nth:n,first:f}),g=await l.send({type:"evaluate",code:`(async () => {
|
|
349
337
|
const t = window.__sootsimTest
|
|
350
338
|
if (!t) return { error: 'bridge-not-ready' }
|
|
351
339
|
const F = ${W}
|
|
@@ -459,7 +447,7 @@ ${o}
|
|
|
459
447
|
total,
|
|
460
448
|
idx,
|
|
461
449
|
}
|
|
462
|
-
})()`});if(g?.error==="bridge-not-ready"&&(console.error(" sootsim test bridge not ready"),process.exit(1)),g?.ambiguous){let
|
|
450
|
+
})()`});if(g?.error==="bridge-not-ready"&&(console.error(" sootsim test bridge not ready"),process.exit(1)),g?.ambiguous){let _=g.candidates;console.error(` ambiguous: ${g.total} matches for "${e}"`);for(let P of _){let re=P.abs?`@(${Math.round(P.abs.x)},${Math.round(P.abs.y)})`:"",at=P.layout?` ${P.layout.width}x${P.layout.height}`:"",it=P.testID?` #${P.testID}`:"",lt=P.text?` "${P.text}"`:"",ct=P.ancestorTestIDs.length>0?` within ${P.ancestorTestIDs.slice(0,3).map(dt=>`#${dt}`).join(" > ")}`:"";console.error(` [${P.idx}] <${P.type}>${lt}${it} ${re}${at}${ct}`)}g.total>_.length&&console.error(` ... and ${g.total-_.length} more`),console.error(" pick one:"),console.error(" --nth <index> pick the nth match (top-to-bottom, left-to-right; negatives from end)"),console.error(" --within <testID> narrow to descendants of a node"),console.error(" --min-y / --max-y geometric filter (pixels, absolute)"),console.error(" --min-x / --max-x geometric filter (pixels, absolute)"),console.error(" --near <x> <y> pick the closest match to a point"),console.error(" --exact exact text match (default is substring)"),console.error(" --role <role> narrow to accessibilityRole"),console.error(" --first keep the old pick-first-silently behavior"),process.exit(2)}g?.nthOutOfRange&&(console.error(` not found: nth ${g.nth} of ${g.total} match${g.total===1?"":"es"} for "${e}"`),process.exit(1)),(!g||typeof g.cx!="number")&&(console.error(` not found: ${e}`),process.exit(1));let T=await l.send({type:"tap",x:g.cx,y:g.cy});if(T?.hit!==!1&&T?.ok!==!1){let _=ot(e,{id:g.target?.id??null,testID:g.target?.testID??null,type:g.target?.type??null,cx:g.cx,cy:g.cy},"text");await L("inspect tap-text",_.step,_.summary)}console.log(JSON.stringify({matched:g.match,tapped:{nodeId:g.target?.nodeId??null,id:g.target?.id??null,testID:g.target?.testID??null,type:g.target?.type??null,cx:g.cx,cy:g.cy},...g.strategy&&g.strategy!=="matched-node"?{strategy:g.strategy}:{},...g.total>1||n!==null?{nth:{index:g.idx,total:g.total}}:{},result:T},null,2));break}case"tap-id":{let e=a[1];e||(console.error(S("tap-id","<id>")),process.exit(1));let t=JSON.stringify(e),s=await l.send({type:"evaluate",code:`(async () => {
|
|
463
451
|
const t = window.__sootsimTest
|
|
464
452
|
if (!t) return null
|
|
465
453
|
const n = (await t.findByTestId(${t})) || (await t.findById(${t}))
|
|
@@ -494,10 +482,10 @@ ${o}
|
|
|
494
482
|
},
|
|
495
483
|
strategy: (resolved && resolved.strategy) || 'matched-node',
|
|
496
484
|
}
|
|
497
|
-
})()`});(!
|
|
485
|
+
})()`});(!s||typeof s.cx!="number")&&(console.error(` not found: ${e}`),process.exit(1));let r=await l.send({type:"tap",x:s.cx,y:s.cy});if(r?.hit!==!1&&r?.ok!==!1){let n=ot(e,{id:s.target?.id??null,testID:s.target?.testID??null,type:s.target?.type??null,cx:s.cx,cy:s.cy},"id");await L("inspect tap-id",n.step,n.summary)}console.log(JSON.stringify({matched:s.match,tapped:{nodeId:s.target?.nodeId??null,id:s.target?.id??null,testID:s.target?.testID??null,type:s.target?.type??null,cx:s.cx,cy:s.cy},...s.strategy&&s.strategy!=="matched-node"?{strategy:s.strategy}:{},result:r},null,2));break}case"type-into":{let e=a[1],t=a.slice(2).join(" ");(!e||!t)&&(console.error(S("type-into","<id> <text>")),process.exit(1));let s=JSON.stringify(e),r=await l.send({type:"evaluate",code:`(async () => {
|
|
498
486
|
const t = window.__sootsimTest
|
|
499
487
|
if (!t) return null
|
|
500
|
-
const n = await (t.findByTestId(${
|
|
488
|
+
const n = await (t.findByTestId(${s}) || t.findById(${s}))
|
|
501
489
|
if (!n || !n.absolutePosition || !n.layout) return null
|
|
502
490
|
return {
|
|
503
491
|
cx: n.absolutePosition.x + (n.layout.width || 0) / 2,
|
|
@@ -506,7 +494,7 @@ ${o}
|
|
|
506
494
|
isTextInput: !!n.isTextInput,
|
|
507
495
|
placeholder: n.placeholder || null,
|
|
508
496
|
}
|
|
509
|
-
})()`});(!r||typeof r.cx!="number")&&(console.error(` not found: ${e}`),process.exit(1)),r.isTextInput||console.error(` warning: ${e} is not a text input (isTextInput: false)`);let n=await l.send({type:"tap",x:r.cx,y:r.cy}),
|
|
497
|
+
})()`});(!r||typeof r.cx!="number")&&(console.error(` not found: ${e}`),process.exit(1)),r.isTextInput||console.error(` warning: ${e} is not a text input (isTextInput: false)`);let n=await l.send({type:"tap",x:r.cx,y:r.cy}),m=await Ot(l);m.visible||(console.error(` keyboard did not open after tapping ${e}`),process.exit(1));let p=m.focusedInput;p&&(p.testID===e||p.id===e||(console.error(` focus routing mismatch after tap: requested ${JSON.stringify(e)} but focus is on ${JSON.stringify(p.testID??p.id??null)}. did the tap land on an outer Pressable wrapper?`),process.exit(1))),await l.send({type:"keyboard",action:"type",text:t}),await L("inspect type-into",{tapOn:{id:e},inputText:t},`type-into #${e} ${JSON.stringify(t)}`),console.log(JSON.stringify({target:e,isTextInput:r.isTextInput,keyboardOpened:m.visible??n?.keyboardOpened??!1,focusedInput:m.focusedInput??null,typed:t},null,2));break}case"type":{let e=a.slice(1).join(" ");e||(console.error(S("type","<text>")),process.exit(1)),await ue(l,"type"),await l.send({type:"keyboard",action:"type",text:e}),await L("inspect type",{inputText:e},`type ${JSON.stringify(e)}`),console.log(` typed: ${JSON.stringify(e)}`);break}case"key":{let e=a[1];e||(console.error(S("key","<name>")),process.exit(1)),await ue(l,"key"),await l.send({type:"keyboard",action:"press",text:e}),await L("inspect key",{pressKey:e},`key ${e}`),console.log(` pressed: ${e}`);break}case"key-sequence":{let e=a.slice(1);e.length===0&&(console.error(S("key-sequence","<key> [<key> ...]")),process.exit(1)),await ue(l,"key-sequence");for(let t of e)await l.send({type:"keyboard",action:"press",text:t});await L("inspect key-sequence",{pressKey:e.join(" ")},`key-sequence ${e.join(" ")}`),console.log(` pressed: ${e.join(", ")}`);break}case"keycode":{let e=a.slice(1);e.length===0&&(console.error(S("keycode","<code> [<code> ...]")),process.exit(1));let t=e.map(r=>({code:r,key:Et(r)})),s=t.filter(r=>!r.key);s.length>0&&(console.error(` unsupported keycode(s): ${s.map(r=>r.code).join(", ")}`),process.exit(1)),await ue(l,"keycode");for(let r of t)await l.send({type:"keyboard",action:"press",text:r.key});await L("inspect keycode",{pressKey:t.map(r=>r.key).join(" ")},`keycode ${e.join(" ")}`),console.log(` pressed: ${e.join(", ")}`);break}case"dispatch":{let e=a[1];e||(console.error(S("dispatch","<char>")),process.exit(1)),await l.send({type:"keyboard",action:"dispatchKey",text:e}),await L("inspect dispatch",{dispatchKey:e},`dispatch ${JSON.stringify(e)}`),console.log(` dispatched: ${e}`);break}case"dismiss":{await l.send({type:"keyboard",action:"dismiss"}),await L("inspect dismiss",{hideKeyboard:!0},"dismiss keyboard"),console.log(" keyboard dismissed");break}case"double-tap":{let e=Number(a[1]),t=Number(a[2]),s=se(o);if(s){let p=await ce(l,s);p||(console.error(` not found: ${s.value}`),s.mode==="testid"&&U("wait-selector-for-missing-testid",s.value),process.exit(1)),e=p.x,t=p.y}let r=a[3]?Number(a[3]):80;(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(r))&&(console.error(S("double-tap","<x> <y> [gapMs] | --testid <id>")),process.exit(1));let n=Math.max(0,Math.round(r)),m=await l.send({type:"evaluate",code:`(async () => {
|
|
510
498
|
const interact = window.__sootsimInteract
|
|
511
499
|
if (interact?.doubleTap) {
|
|
512
500
|
return {
|
|
@@ -529,18 +517,18 @@ ${o}
|
|
|
529
517
|
first,
|
|
530
518
|
second,
|
|
531
519
|
}
|
|
532
|
-
})()`});
|
|
520
|
+
})()`});m?.ok&&await L("inspect double-tap",{doubleTapAtCoords:{x:e,y:t,gapMs:n}},`double-tap @${e},${t}`),console.log(JSON.stringify(m,null,2));break}case"long-press":{let e=Number(a[1]),t=Number(a[2]),s=se(o);if(s){let m=await ce(l,s);m||(console.error(` not found: ${s.value}`),s.mode==="testid"&&U("wait-selector-for-missing-testid",s.value),process.exit(1)),e=m.x,t=m.y}let r=a[3]?Number(a[3]):600;(!Number.isFinite(e)||!Number.isFinite(t)||!Number.isFinite(r))&&(console.error(S("long-press","<x> <y> [durationMs] | --testid <id>")),process.exit(1));let n=await l.send({type:"evaluate",code:`(async () => {
|
|
533
521
|
const interact = window.__sootsimInteract
|
|
534
522
|
if (!interact?.longPress) return { ok: false, reason: 'no interact.longPress' }
|
|
535
523
|
const value = await interact.longPress(${e}, ${t}, ${Math.max(0,Math.round(r))})
|
|
536
524
|
return { ok: !!value, value }
|
|
537
|
-
})()`});n?.ok&&await L("inspect long-press",{tapAtCoords:{x:e,y:t}},`long-press @${e},${t}`),console.log(JSON.stringify(n,null,2));break}case"touch":{let e=a[1],t=Number(a[2]),
|
|
538
|
-
${
|
|
525
|
+
})()`});n?.ok&&await L("inspect long-press",{tapAtCoords:{x:e,y:t}},`long-press @${e},${t}`),console.log(JSON.stringify(n,null,2));break}case"touch":{let e=a[1],t=Number(a[2]),s=Number(a[3]),r=a[4]?Number(a[4]):999,n=e==="down"?"touchDown":e==="move"?"touchMove":e==="up"?"touchUp":e==="cancel"?"touchCancel":null;n||(console.error(S("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1)),e!=="cancel"&&(!Number.isFinite(t)||!Number.isFinite(s))&&(console.error(S("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1));let m=e==="down"?"tap":e==="move"?"move":null,p=m&&Number.isFinite(t)&&Number.isFinite(s)?`window.dispatchEvent(new CustomEvent('sootsim:agentAction', { detail: { type: '${m}', x: ${t}, y: ${s} } }));`:"",h=await l.send({type:"evaluate",code:`(async () => {
|
|
526
|
+
${p}
|
|
539
527
|
const interact = window.__sootsimInteract
|
|
540
528
|
if (!interact?.${n}) return { ok: false, reason: 'no interact.${n}' }
|
|
541
|
-
const value = ${e==="cancel"?`await interact.${n}(${Math.max(1,Math.round(r))})`:`await interact.${n}(${t}, ${
|
|
529
|
+
const value = ${e==="cancel"?`await interact.${n}(${Math.max(1,Math.round(r))})`:`await interact.${n}(${t}, ${s}, ${Math.max(1,Math.round(r))})`}
|
|
542
530
|
return { ok: !!value, value }
|
|
543
|
-
})()`});
|
|
531
|
+
})()`});h?.ok&&e!=="cancel"&&await L("inspect touch",{tapAtCoords:{x:t,y:s}},`touch ${e} @${t},${s}`),console.log(JSON.stringify(h,null,2));break}case"gesture":{let e=a[1],t=a[2]?Number(a[2]):220;(!e||!Number.isFinite(t))&&(console.error(S("gesture","<preset> [durationMs]")),process.exit(1));let s=await l.send({type:"evaluate",code:`(async () => {
|
|
544
532
|
const spec = globalThis.__sootsimDeviceSpec || {}
|
|
545
533
|
return {
|
|
546
534
|
width: spec.width || window.innerWidth || 393,
|
|
@@ -548,12 +536,12 @@ ${o}
|
|
|
548
536
|
statusBarHeight: spec.statusBarHeight || 0,
|
|
549
537
|
homeIndicatorHeight: spec.homeIndicatorHeight || 0,
|
|
550
538
|
}
|
|
551
|
-
})()`}),r=Number(
|
|
539
|
+
})()`}),r=Number(s?.width)||393,n=Number(s?.height)||852,m=Number(s?.statusBarHeight)||0,p=Number(s?.homeIndicatorHeight)||0,h=Math.round(r/2),f=Math.round(n/2),w=Math.max(24,m+18),O=Math.max(24,p+18),B=18,N=Math.min(220,Math.round(n*.24)),M=Math.min(180,Math.round(r*.32)),F=h,W=f,g=h,T=f;switch(e){case"scroll-up":W=f+Math.round(N/2),T=f-Math.round(N/2);break;case"scroll-down":W=f-Math.round(N/2),T=f+Math.round(N/2);break;case"scroll-left":F=h+Math.round(M/2),g=h-Math.round(M/2);break;case"scroll-right":F=h-Math.round(M/2),g=h+Math.round(M/2);break;case"swipe-from-left-edge":F=B,W=f,g=Math.min(r-B,B+M);break;case"swipe-from-right-edge":F=r-B,W=f,g=Math.max(B,r-B-M);break;case"swipe-from-top-edge":F=h,W=w,T=Math.min(n-O,w+N);break;case"swipe-from-bottom-edge":F=h,W=n-O,T=Math.max(w,n-O-N);break;default:console.error(` unknown gesture preset: ${e}`),process.exit(1)}let _=Math.max(8,Math.round(t/16)),P=Math.max(1,Math.round(t/_)),re=await l.send({type:"evaluate",code:`(async () => {
|
|
552
540
|
const interact = window.__sootsimInteract
|
|
553
541
|
if (!interact?.drag) return { ok: false, reason: 'no interact.drag' }
|
|
554
|
-
const value = await interact.drag(${
|
|
542
|
+
const value = await interact.drag(${F}, ${W}, ${g}, ${T}, ${_}, ${P})
|
|
555
543
|
return { ok: !!value, value }
|
|
556
|
-
})()`});
|
|
544
|
+
})()`});re?.ok&&await L("inspect gesture",{swipe:{start:`${F}, ${W}`,end:`${g}, ${T}`,duration:Math.max(1,Math.round(t))}},`gesture ${e}`),console.log(JSON.stringify({preset:e,from:{x:F,y:W},to:{x:g,y:T},result:re},null,2));break}case"scroll":{let e=se(o),t=e?.mode==="testid"?e.value:a[1],s=Number(a[e?1:2]),r=Number(a[e?2:3]);(!t||!Number.isFinite(s)||!Number.isFinite(r))&&(console.error(S("scroll","<id> <dx> <dy> | --testid <id> <dx> <dy>")),process.exit(1));let n=await l.send({type:"evaluate",code:`(async () => {
|
|
557
545
|
const t = window.__sootsimTest
|
|
558
546
|
if (!t) return null
|
|
559
547
|
const n = await t.findByTestId(${JSON.stringify(t)})
|
|
@@ -563,11 +551,11 @@ ${o}
|
|
|
563
551
|
cx: n.absolutePosition.x + (n.layout.width || 0) / 2,
|
|
564
552
|
cy: n.absolutePosition.y + (n.layout.height || 0) / 2,
|
|
565
553
|
}
|
|
566
|
-
})()`}),
|
|
554
|
+
})()`}),m=await z(l,"scrollTo",t,s,r,!1);m?.ok&&await L("inspect scroll",{scrollTo:{id:t,x:s,y:r}},`scroll ${t} -> ${s},${r}`),console.log(JSON.stringify({...m,...n?{at:{x:n.cx,y:n.cy}}:{}},null,2));break}case"state":{let e=a[1];if(i==="get"&&!e){let s=await z(l,"getSessionState"),r=await l.send({type:"evaluate",code:`({
|
|
567
555
|
errors: window.__sootsimConsole?.getErrors?.()?.length ?? 0,
|
|
568
556
|
warnings: window.__sootsimConsole?.getWarnings?.()?.length ?? 0,
|
|
569
|
-
})`});
|
|
570
|
-
${
|
|
557
|
+
})`});s&&typeof s=="object"&&s.diagnostics&&(s.diagnostics.errors=r?.errors??0,s.diagnostics.warnings=r?.warnings??0),console.log(JSON.stringify(s,null,2));break}if(!e||e==="--help"||e==="-h"){console.log(`
|
|
558
|
+
${y("state")} \u2014 dump raw runtime state
|
|
571
559
|
|
|
572
560
|
subcommands:
|
|
573
561
|
shell dump shell transition/layout state
|
|
@@ -581,15 +569,15 @@ ${o}
|
|
|
581
569
|
gesture <x> <y> dump gesture routing/debug info at coordinates
|
|
582
570
|
|
|
583
571
|
examples:
|
|
584
|
-
${
|
|
585
|
-
${
|
|
586
|
-
${
|
|
587
|
-
${
|
|
588
|
-
${
|
|
589
|
-
${
|
|
590
|
-
${
|
|
591
|
-
${
|
|
592
|
-
`);break}let t;switch(e){case"shell":t=await
|
|
572
|
+
${y("state")} shell
|
|
573
|
+
${y("state")} worker
|
|
574
|
+
${y("state")} keyboard
|
|
575
|
+
${y("state")} ownership
|
|
576
|
+
${y("state")} node photos
|
|
577
|
+
${y("state")} scroll feed
|
|
578
|
+
${y("state")} scroll-hit 360 420
|
|
579
|
+
${y("state")} hit 200 720
|
|
580
|
+
`);break}let t;switch(e){case"shell":t=await V(l,500);break;case"worker":t=await ve(l,"__sootsimRenderHost.queryStats");break;case"ownership":t=await l.send({type:"evaluate",code:`(() => {
|
|
593
581
|
const h = window.__sootsimRenderHost
|
|
594
582
|
if (!h || typeof h.getOwnershipSnapshot !== 'function') {
|
|
595
583
|
return { error: 'getOwnershipSnapshot not available' }
|
|
@@ -620,8 +608,8 @@ ${o}
|
|
|
620
608
|
text: focused.text || null,
|
|
621
609
|
} : null,
|
|
622
610
|
}
|
|
623
|
-
})()`});break;case"node":{let
|
|
624
|
-
${
|
|
611
|
+
})()`});break;case"node":{let s=a[2];s||(console.error(` usage: ${y("state")} node <id>`),process.exit(1)),t=await z(l,"findByTestId",s)||await z(l,"findById",s);break}case"scroll":{let s=a[2];s||(console.error(` usage: ${y("state")} scroll <id>`),process.exit(1)),t=await z(l,"getScrollState",s);break}case"scroll-hit":{let s=Number(a[2]),r=Number(a[3]);(!Number.isFinite(s)||!Number.isFinite(r))&&(console.error(` usage: ${y("state")} scroll-hit <x> <y>`),process.exit(1)),t=await z(l,"getScrollStateAt",s,r);break}case"hit":{let s=Number(a[2]),r=Number(a[3]);(!Number.isFinite(s)||!Number.isFinite(r))&&(console.error(` usage: ${y("state")} hit <x> <y>`),process.exit(1)),t=await z(l,"debugHitAt",s,r);break}case"gesture":{let s=Number(a[2]),r=Number(a[3]);(!Number.isFinite(s)||!Number.isFinite(r))&&(console.error(` usage: ${y("state")} gesture <x> <y>`),process.exit(1)),t=await z(l,"debugGestureAt",s,r);break}default:console.error(` unknown state subcommand: ${e}`),process.exit(1)}console.log(JSON.stringify(t,null,2));break}case"shell":{let e=a[1];if(!e||e==="--help"||e==="-h"){console.log(`
|
|
612
|
+
${y("shell")} \u2014 run built-in shell commands
|
|
625
613
|
|
|
626
614
|
subcommands:
|
|
627
615
|
launch <appId> [waitMs] [--clear-state]
|
|
@@ -636,15 +624,15 @@ ${o}
|
|
|
636
624
|
shake trigger the simulator shake gesture
|
|
637
625
|
|
|
638
626
|
examples:
|
|
639
|
-
${
|
|
640
|
-
${
|
|
641
|
-
${
|
|
642
|
-
${
|
|
643
|
-
${
|
|
644
|
-
${
|
|
645
|
-
${
|
|
646
|
-
${
|
|
647
|
-
`);break}let t=e==="launch"||e==="open-card"||e==="home"||e==="switcher",
|
|
627
|
+
${y("shell")} launch photos
|
|
628
|
+
${y("shell")} launch rn --clear-state
|
|
629
|
+
${y("shell")} launch photos 1500
|
|
630
|
+
${y("shell")} home 500
|
|
631
|
+
${y("shell")} switcher 800
|
|
632
|
+
${y("shell")} open-card clock 800
|
|
633
|
+
${y("shell")} appearance dark
|
|
634
|
+
${y("shell")} lock
|
|
635
|
+
`);break}let t=e==="launch"||e==="open-card"||e==="home"||e==="switcher",s=e==="launch"||e==="open-card"?a[3]:a[2],r=s?Number(s):350;t&&(!Number.isFinite(r)||r<0)&&(console.error(S("shell",e==="launch"||e==="open-card"?"<launch|open-card> <appId> [settleMs]":"<home|switcher> [settleMs]")),process.exit(1));let n=!1,m=!1,p=null,h=o.includes("--clear-state");if(e==="launch"){let f=a[2];f||(console.error(S("shell","launch <appId> [settleMs] [--clear-state]")),process.exit(1)),h&&await l.send({type:"evaluate",code:Te}),n=!!await te(l,"launchApp",r,f),{settled:m,state:p}=await de(l,Math.round(r),w=>!!w&&w.state==="app"&&w.activeApp===f&&w.showSwitcher===!1&&w.switcherPhase==="idle"&&typeof w.launchProgress=="number"&&w.launchProgress>=.98),n&&await L("inspect shell launch",h?{launchApp:{clearState:!0}}:{launchApp:{}},h?"launch app (clear state)":"launch app")}else if(e==="home")n=!!await te(l,"goHome",r),{settled:m,state:p}=await de(l,Math.round(r),f=>!!f&&f.state==="home"&&f.activeApp==null&&f.showSwitcher===!1&&f.switcherPhase==="idle"&&typeof f.launchProgress=="number"&&f.launchProgress>=.98);else if(e==="switcher")n=!!await te(l,"openSwitcher",r),{settled:m,state:p}=await de(l,Math.round(r),f=>!!f&&f.state==="app"&&f.showSwitcher===!0&&f.switcherPhase==="idle"&&typeof f.zoomLevel=="number"&&Math.abs(f.zoomLevel)<=.02&&typeof f.horizontalZoom=="number"&&Math.abs(f.horizontalZoom)<=.02),m&&(await Y(Pt),p=await V(l));else if(e==="open-card"){let f=a[2];f||(console.error(S("shell","open-card <appId> [settleMs]")),process.exit(1)),n=!!await te(l,"openSwitcherCard",r,f),{settled:m,state:p}=await de(l,Math.round(r),w=>!!w&&w.state==="app"&&w.activeApp===f&&w.showSwitcher===!1&&w.switcherPhase==="idle"&&typeof w.zoomLevel=="number"&&w.zoomLevel>=.98&&typeof w.horizontalZoom=="number"&&w.horizontalZoom>=.98),n&&await L("inspect shell open-card",{openSwitcherCard:{appId:f}},`open switcher card ${f}`)}else if(e==="appearance"){let f=a[2];(!f||!["light","dark","auto","toggle"].includes(f))&&(console.error(S("shell","appearance <light|dark|auto|toggle>")),process.exit(1));let w=await tt(l,"appearance",f);n=!!w?.ok,p={appearance:w}}else if(e==="lock"||e==="shake"){let f=await tt(l,e);n=!!f?.ok,p={[e]:f}}else console.error(` unknown shell subcommand: ${e}`),process.exit(1);console.log(JSON.stringify({ok:n,settled:m,state:p},null,2));break}case"url":{await Ke(l,{args:d});break}case"reload":{let s=!1,r=!1;try{await l.send({type:"evaluate",code:"window.__sootsimConsole?.clear()"});let p=await l.send({type:"evaluate",code:`;(() => {
|
|
648
636
|
const reloadExternalApp = window.SootSim?.bridges?.hotRemount?.reloadExternalApp
|
|
649
637
|
if (typeof reloadExternalApp === 'function') {
|
|
650
638
|
reloadExternalApp()
|
|
@@ -652,10 +640,10 @@ ${o}
|
|
|
652
640
|
}
|
|
653
641
|
window.location.reload()
|
|
654
642
|
return { kind: 'page' }
|
|
655
|
-
})()`});r=!!
|
|
656
|
-
\u26A0 ${
|
|
657
|
-
`);for(let
|
|
658
|
-
`).slice(0,2);for(let O of w)console.log(` ${O.trim()}`)}}}}catch{}
|
|
643
|
+
})()`});r=!!p&&p.kind==="external-app",s=!0}catch{}console.log(" reloading...");let n=l,m=null;if(r)m=await fe(l,{timeoutMs:1e4,errorGraceMs:3e3});else{s&&await Y(300);let p=await Fe(A,j,v,{timeoutMs:1e4});p?(n=p,m=await fe(p,{timeoutMs:1e4,errorGraceMs:3e3})):(console.log(" \u26A0 reload: bridge never reconnected within 10000ms"),n=null)}if(m)if(m.ready){let p=m.source==="nodes-fallback"?" (no ready signal, node-count fallback)":"";console.log(` ready in ${m.elapsedMs}ms: ${m.nodes} nodes${p}`)}else m.source==="error-bail"?console.log(` \u26A0 reload bailed after ${m.elapsedMs}ms: ${m.errors} console error(s), ready signal never fired`):console.log(` \u26A0 reload timed out after ${m.elapsedMs}ms (${m.nodes} nodes, ${m.errors} errors)`);if(n)try{let p=await n.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors(10) || []"});if(n!==l&&n.close(),Array.isArray(p)&&p.length>0){console.log(`
|
|
644
|
+
\u26A0 ${p.length} error(s) during mount:
|
|
645
|
+
`);for(let h of p){let f=h.args.map(w=>typeof w=="object"?JSON.stringify(w):w).join(" ");if(console.log(` ${f}`),h.stack){let w=h.stack.split(`
|
|
646
|
+
`).slice(0,2);for(let O of w)console.log(` ${O.trim()}`)}}}}catch{}m&&!m.ready&&(process.exitCode=1);break}case"eval":case"js":{let e=a.slice(1).join(" ");e||(console.error(S("js","<javascript>")),console.error(""),console.error(" runs the snippet in the engine realm. SootSim is the"),console.error(" canonical state surface \u2014 reach into it directly."),console.error(""),console.error(" examples:"),console.error(` ${y("js")} SootSim.bridges.test.findByText("Sign in")`),console.error(` ${y("js")} SootSim.bridges.debug.snapshot("before")`),console.error(` ${y("js")} SootSim.bridges.keyboard.type("hello")`),console.error(` ${y("js")} SootSim.state.root.children.length`),process.exit(1));let t=e;t.startsWith("(async")||(t=`(async () => ${t})()`);let s=await l.send({type:"evaluate",code:t});console.log(JSON.stringify(s,null,2));let r=e.toLowerCase(),n=[];(r.includes("sootsim:gohome")||r.includes("gohome"))&&n.push("sootsim shell home"),(r.includes("sootsim:appswitcher")||r.includes("appswitcher"))&&n.push("sootsim shell switcher"),(r.includes("keyboard.isvisible")||r.includes("keyboard.getmode"))&&n.push("sootsim debug state keyboard"),r.includes("interact.tap")&&n.push("sootsim do tap <x> <y>"),r.includes("keyboard.type")&&n.push("sootsim do type <text>"),(r.includes("keyboard.press")||r.includes("keyboard.dispatchkey"))&&n.push("sootsim do key <name>"),r.includes("keyboard.dismiss")&&n.push("sootsim do dismiss"),r.includes("dumptree")&&n.push("sootsim get tree"),r.includes("dumpaccessibilitytree")&&n.push("sootsim get a11y"),r.includes("getnodecount")&&n.push("sootsim get count"),r.includes("findbytext")&&n.push("sootsim find <text>"),(r.includes("findbytestid")||r.includes("findbyid"))&&n.push("sootsim find --testid <id>"),r.includes("document.hidden")&&n.push("sootsim debug state keyboard (includes tab health)"),n.length>0&&U("prefer-cli-over-eval",n);break}case"globals":{let e=await l.send({type:"evaluate",code:`(async () => {
|
|
659
647
|
const globals = {}
|
|
660
648
|
|
|
661
649
|
// test bridge (proxy in worker mode)
|
|
@@ -693,8 +681,8 @@ ${o}
|
|
|
693
681
|
|
|
694
682
|
return globals
|
|
695
683
|
})()`});console.log(` sootsim JS API:
|
|
696
|
-
`);for(let[t,
|
|
697
|
-
${
|
|
684
|
+
`);for(let[t,s]of Object.entries(e)){console.log(` ${t}:`);for(let r of s)console.log(` .${r}`);console.log("")}console.log(` use: ${y("js")} <expression>`),console.log(` example: ${y("js")} test.findByText("Sign in")`);break}case"describe":{await Re({bridge:l,args:o,positional:a});break}case"perf":{let e=a[1];if(!e||e==="--help"||e==="-h"){console.log(`
|
|
685
|
+
${y("perf")} \u2014 performance profiling
|
|
698
686
|
|
|
699
687
|
subcommands:
|
|
700
688
|
stats one-shot stats (zero overhead query)
|
|
@@ -704,11 +692,11 @@ ${o}
|
|
|
704
692
|
transition <e> profile a shell transition (goHome, appSwitcher, lockScreen)
|
|
705
693
|
|
|
706
694
|
examples:
|
|
707
|
-
${
|
|
708
|
-
${
|
|
695
|
+
${y("perf")} stats
|
|
696
|
+
${y("perf")} start
|
|
709
697
|
# ... interact with the app ...
|
|
710
|
-
${
|
|
711
|
-
${
|
|
698
|
+
${y("perf")} stop
|
|
699
|
+
${y("perf")} transition goHome
|
|
712
700
|
`);break}switch(e){case"stats":{let t=await l.send({type:"evaluate",code:`(async () => {
|
|
713
701
|
// worker mode (host exposes these)
|
|
714
702
|
if (window.__sootsimPerfStats) {
|
|
@@ -734,7 +722,7 @@ ${o}
|
|
|
734
722
|
jankFrames: frameStats.recentFrames?.filter(f => f > 16.67).length || 0,
|
|
735
723
|
recentCount: frameStats.recentFrames?.length || 0,
|
|
736
724
|
}
|
|
737
|
-
})()`});t.error&&(console.error(` error: ${t.error}`),process.exit(1));let
|
|
725
|
+
})()`});t.error&&(console.error(` error: ${t.error}`),process.exit(1));let s=t.avgMs!=="?"?(1e3/parseFloat(t.avgMs)).toFixed(1):"?";console.log(" perf stats:"),console.log(` frames: ${t.frames}`),console.log(` avg: ${t.avgMs}ms (${s} fps)`),console.log(` max: ${t.maxMs}ms`),console.log(` layout: ${t.layoutMs}ms total`),console.log(` nodes: ${t.nodeCount}`),t.recentCount>0&&console.log(` jank: ${t.jankFrames}/${t.recentCount} frames >16.67ms`);break}case"start":{await l.send({type:"evaluate",code:`(async () => {
|
|
738
726
|
// worker mode
|
|
739
727
|
if (window.__sootsimPerfStart && window.__sootsimRenderHost) {
|
|
740
728
|
const result = window.__sootsimPerfStart()
|
|
@@ -756,7 +744,7 @@ ${o}
|
|
|
756
744
|
startedAt: performance.now(),
|
|
757
745
|
}
|
|
758
746
|
return { started: true }
|
|
759
|
-
})()`}),console.log(` profiling started \u2014 interact with the app, then run '${
|
|
747
|
+
})()`}),console.log(` profiling started \u2014 interact with the app, then run '${y("perf")} stop'`);break}case"stop":{let t=await l.send({type:"evaluate",code:`(async () => {
|
|
760
748
|
// worker mode
|
|
761
749
|
if (window.__sootsimRenderHost) {
|
|
762
750
|
const session = window.${G} || {}
|
|
@@ -850,8 +838,8 @@ ${o}
|
|
|
850
838
|
jankFrames: recent.filter(f => f > 16.67).length,
|
|
851
839
|
sampleCount: recent.length,
|
|
852
840
|
}
|
|
853
|
-
})()`});t.error&&(console.error(` error: ${t.error}`),process.exit(1));let
|
|
854
|
-
`),console.log(` frames: ${t.frames}`),console.log(` total: ${t.totalMs.toFixed(1)}ms`),console.log(` avg: ${t.avgMs.toFixed(2)}ms (${
|
|
841
|
+
})()`});t.error&&(console.error(` error: ${t.error}`),process.exit(1));let s=t.avgMs>0?(1e3/t.avgMs).toFixed(1):"?",r=t.sampleCount>0?(t.jankFrames/t.sampleCount*100).toFixed(1):"0";console.log(` profiling stopped:
|
|
842
|
+
`),console.log(` frames: ${t.frames}`),console.log(` total: ${t.totalMs.toFixed(1)}ms`),console.log(` avg: ${t.avgMs.toFixed(2)}ms (${s} fps)`),console.log(` max: ${t.maxMs.toFixed(2)}ms`),console.log(""),t.layoutAvgMs!==void 0&&(console.log(" breakdown (avg per frame):"),console.log(` layout: ${t.layoutAvgMs.toFixed(2)}ms`),console.log(` render: ${t.renderAvgMs.toFixed(2)}ms`),console.log(` copy: ${t.copyAvgMs.toFixed(2)}ms`),t.auxAvgMs!==void 0&&console.log(` aux: ${t.auxAvgMs.toFixed(2)}ms`),t.otherAvgMs!==void 0&&console.log(` other: ${t.otherAvgMs.toFixed(2)}ms`),console.log("")),console.log(` distribution (${t.sampleCount} samples):`),console.log(` p50: ${t.p50.toFixed(2)}ms`),console.log(` p95: ${t.p95.toFixed(2)}ms`),console.log(` p99: ${t.p99.toFixed(2)}ms`),console.log(` jank: ${t.jankFrames} frames (${r}%) >16.67ms`);break}case"frames":{let t=a[2]?Number(a[2]):50;(!Number.isFinite(t)||t<=0)&&(console.error(` error: expected a positive frame count, got "${a[2]}"`),process.exit(1));let s=await l.send({type:"evaluate",code:`(async () => {
|
|
855
843
|
if (window.__sootsimRenderHost) {
|
|
856
844
|
const session = window.${G} || {}
|
|
857
845
|
if (session.active) {
|
|
@@ -886,7 +874,7 @@ ${o}
|
|
|
886
874
|
mode: 'main-thread',
|
|
887
875
|
frames: (stats.recentFrames || []).slice(-${t}),
|
|
888
876
|
}
|
|
889
|
-
})()`});if(
|
|
877
|
+
})()`});if(s.error&&(console.error(` error: ${s.error}`),process.exit(1)),s.mode==="render-worker"){let n=Array.isArray(s.samples)?s.samples:[];if(n.length===0){console.log(` no frame data \u2014 run '${y("perf")} start' first`);break}console.log(` last ${n.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[m,p,h,f,w,O,B]of n)console.log(` ${p.toFixed(2).padStart(7)} ${h.toFixed(2).padStart(7)} ${f.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${O.toFixed(2).padStart(6)} ${B.toFixed(2).padStart(7)} ${String(m).padStart(5)}`);console.log(""),be(n.map(m=>m[1])),s.live&&console.log(" sampling continues");break}let r=Array.isArray(s.frames)?s.frames:Array.isArray(s)?s:[];if(r.length===0){console.log(` no frame data \u2014 run '${y("perf")} start' first`);break}console.log(` last ${r.length} frame times (ms):`),console.log(` ${r.map(n=>n.toFixed(2)).join(", ")}`),be(r);break}case"worst":{let t=a[2]?Number(a[2]):20;(!Number.isFinite(t)||t<=0)&&(console.error(` error: expected a positive frame count, got "${a[2]}"`),process.exit(1));let s=await l.send({type:"evaluate",code:`(async () => {
|
|
890
878
|
if (window.__sootsimRenderHost) {
|
|
891
879
|
const session = window.${G} || {}
|
|
892
880
|
if (session.active) {
|
|
@@ -928,8 +916,8 @@ ${o}
|
|
|
928
916
|
mode: 'main-thread',
|
|
929
917
|
frames: recent.slice().sort((a, b) => b - a).slice(0, ${t}),
|
|
930
918
|
}
|
|
931
|
-
})()`});if(
|
|
932
|
-
${
|
|
919
|
+
})()`});if(s.error&&(console.error(` error: ${s.error}`),process.exit(1)),s.mode==="render-worker"){let n=Array.isArray(s.samples)?s.samples:[];if(n.length===0){console.log(` no frame data \u2014 run '${y("perf")} start' first`);break}console.log(` worst ${n.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[m,p,h,f,w,O,B]of n)console.log(` ${p.toFixed(2).padStart(7)} ${h.toFixed(2).padStart(7)} ${f.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${O.toFixed(2).padStart(6)} ${B.toFixed(2).padStart(7)} ${String(m).padStart(5)}`);s.live&&(console.log(""),console.log(" sampling continues"));break}let r=Array.isArray(s.frames)?s.frames:Array.isArray(s)?s:[];if(r.length===0){console.log(` no frame data \u2014 run '${y("perf")} start' first`);break}console.log(` worst ${r.length} frame times (ms):`),console.log(` ${r.map(n=>n.toFixed(2)).join(", ")}`);break}case"transition":{let t=a[2];if(!t||!["goHome","appSwitcher","lockScreen"].includes(t)){console.log(`
|
|
920
|
+
${y("perf")} transition <event> \u2014 profile a shell transition
|
|
933
921
|
|
|
934
922
|
events:
|
|
935
923
|
goHome swipe-to-home animation
|
|
@@ -939,8 +927,8 @@ ${o}
|
|
|
939
927
|
note: uses 600ms capture window \u2014 may need --timeout 10000 flag
|
|
940
928
|
|
|
941
929
|
examples:
|
|
942
|
-
${
|
|
943
|
-
${
|
|
930
|
+
${y("perf")} transition goHome --timeout 10000
|
|
931
|
+
${y("perf")} transition appSwitcher
|
|
944
932
|
`);break}let r=`sootsim:${t}`;console.log(` profiling ${t} transition...`),console.log(" (use --timeout 10000 if this times out)");let n=await l.send({type:"evaluate",code:`(async () => {
|
|
945
933
|
// only supported in render-worker mode
|
|
946
934
|
if (!window.__sootsimRenderHost) {
|
|
@@ -1000,11 +988,11 @@ ${o}
|
|
|
1000
988
|
jankFrames: frameTimes.filter(f => f > 16.67).length,
|
|
1001
989
|
samples,
|
|
1002
990
|
}
|
|
1003
|
-
})()`});if(n.error&&(console.error(` error: ${n.error}`),process.exit(1)),n.warning&&console.log(` warning: ${n.warning}`),n.frames===0){console.log(" no frames captured");break}let
|
|
991
|
+
})()`});if(n.error&&(console.error(` error: ${n.error}`),process.exit(1)),n.warning&&console.log(` warning: ${n.warning}`),n.frames===0){console.log(" no frames captured");break}let m=n.avgMs>0?(1e3/n.avgMs).toFixed(1):"?",p=n.frames>0?(n.jankFrames/n.frames*100).toFixed(1):"0";console.log(` ${t} transition profiled:
|
|
1004
992
|
|
|
1005
993
|
frames: ${n.frames}
|
|
1006
994
|
total: ${n.totalMs.toFixed(1)}ms
|
|
1007
|
-
avg: ${n.avgMs.toFixed(2)}ms (${
|
|
995
|
+
avg: ${n.avgMs.toFixed(2)}ms (${m} fps)
|
|
1008
996
|
max: ${n.maxMs.toFixed(2)}ms
|
|
1009
997
|
|
|
1010
998
|
breakdown (avg per frame):
|
|
@@ -1018,25 +1006,25 @@ ${o}
|
|
|
1018
1006
|
p50: ${n.p50.toFixed(2)}ms
|
|
1019
1007
|
p95: ${n.p95.toFixed(2)}ms
|
|
1020
1008
|
p99: ${n.p99.toFixed(2)}ms
|
|
1021
|
-
jank: ${n.jankFrames} frames (${
|
|
1022
|
-
`);for(let n of r){let
|
|
1023
|
-
`).slice(0,3);for(let
|
|
1024
|
-
`);for(let r of
|
|
1025
|
-
`);for(let t of e){let
|
|
1026
|
-
`);for(let
|
|
1009
|
+
jank: ${n.jankFrames} frames (${p}%) >16.67ms`),Array.isArray(n.samples)&&n.samples.length>0&&(console.log(""),be(n.samples.map(h=>h[1])));break}default:console.error(` unknown perf subcommand: ${e}`),process.exit(1)}break}case"errors":{let e=a[1];if(e==="clear"){await l.send({type:"evaluate",code:'window.__sootsimConsole?.clear(); "cleared"'}),E(d)?C({cleared:!0}):console.log(" error buffer cleared");break}let t=e?Number(e):20,s=await l.send({type:"evaluate",code:`window.__sootsimConsole?.getErrors(${t}) || []`}),r=Array.isArray(s)?s:[];if(E(d)){C(r);break}if(r.length===0){console.log(" no errors captured");break}console.log(` ${r.length} error(s):
|
|
1010
|
+
`);for(let n of r){let m=new Date(n.timestamp).toLocaleTimeString(),p=n.args.map(h=>typeof h=="object"?JSON.stringify(h):h).join(" ");if(console.log(` [${m}] ${p}`),n.stack){let h=n.stack.split(`
|
|
1011
|
+
`).slice(0,3);for(let f of h)console.log(` ${f.trim()}`)}}break}case"warnings":{let e=a[1]?Number(a[1]):20,t=await l.send({type:"evaluate",code:`window.__sootsimConsole?.getWarnings(${e}) || []`}),s=Array.isArray(t)?t:[];if(E(d)){C(s);break}if(s.length===0){console.log(" no warnings captured");break}console.log(` ${s.length} warning(s):
|
|
1012
|
+
`);for(let r of s){let n=new Date(r.timestamp).toLocaleTimeString(),m=r.args.map(p=>typeof p=="object"?JSON.stringify(p):p).join(" ");console.log(` [${n}] ${m}`)}break}case"animations":{let e=await z(l,"listAnimations")??[];if(o.includes("--json")){console.log(JSON.stringify(e,null,2));break}if(e.length===0){console.log(" no active animations");break}console.log(` ${e.length} active animation(s):
|
|
1013
|
+
`);for(let t of e){let s=String(t.kind).padEnd(6),r=`${Number(t.from).toFixed(2)}\u2192${Number(t.to).toFixed(2)}`,n=Number(t.current??0).toFixed(2),m=`${Math.round((t.progress??0)*100)}%`,p=`${Math.round(t.elapsedMs??0)}ms`,h=t.loop?" loop":"",f=t.layoutBound?" layout":"";console.log(` #${t.id} ${s} ${r.padEnd(14)} cur=${n.padEnd(7)} ${m.padStart(4)} ${p}${h}${f}`)}break}case"animation":{let e=a[1];(!e||e==="--help"||e==="-h")&&(console.error(` usage: ${y("animation")} <id>`),process.exit(1));let t=Number(e);Number.isFinite(t)||(console.error(` invalid id: ${e}`),process.exit(1));let s=await z(l,"getAnimation",t);console.log(JSON.stringify(s,null,2));break}case"stop-animation":{let e=a[1];(!e||e==="--help"||e==="-h")&&(console.error(` usage: ${y("stop-animation")} <id|all>`),process.exit(1));let t=e==="all"?"all":Number(e);t!=="all"&&!Number.isFinite(t)&&(console.error(` invalid id: ${e}`),process.exit(1));let s=await z(l,"stopAnimation",t);console.log(` stopped ${s??0} animation(s)`);break}case"requests":{let e=a[1];if(e==="clear"){await z(l,"clearRequests"),E(d)?C({cleared:!0}):console.log(" request buffer cleared");break}let t=e==="all",s=t?a[2]:e,r=s?Number(s):20,n=t?await z(l,"getRequests",r):await z(l,"getFailedRequests",r),m=Array.isArray(n)?n:[];if(E(d)){C(m);break}if(m.length===0){console.log(t?" no requests captured":" no failed requests captured");break}console.log(` ${m.length} ${t?"request(s)":"failed request(s)"}:
|
|
1014
|
+
`);for(let p of m){let h=new Date(p.timestamp).toLocaleTimeString();console.log(` [${h}] ${q(p)}`),p.responseBody?console.log(` ${p.responseBody}`):p.error&&console.log(` ${p.error}`)}break}case"network":{let e=a[1],t=null,s=null,r=!1,n=!1,m=!1;for(let N=0;N<d.length;N++){let M=d[N];if(M==="--filter")t=d[N+1]??null,N++;else if(M==="--limit"){let F=Number(d[N+1]);Number.isFinite(F)&&(s=F),N++}else M==="--failed"?r=!0:M==="--tail"||M==="-f"?n=!0:M==="--json"&&(m=!0)}if(e==="clear"){await l.send({type:"evaluate",code:'window.__sootsimObservability?.network.clear(); "cleared"'}),console.log(" network buffer cleared");break}if(e==="get"){let N=a[2];N||(console.error(" usage: sootsim network get <id>"),process.exit(1));let M=await l.send({type:"evaluate",code:`(() => {
|
|
1027
1015
|
const obs = window.__sootsimObservability;
|
|
1028
1016
|
if (!obs) return null;
|
|
1029
|
-
return obs.network.getSnapshot().find(e => e.id === ${JSON.stringify(
|
|
1030
|
-
})()`});
|
|
1017
|
+
return obs.network.getSnapshot().find(e => e.id === ${JSON.stringify(N)}) || null;
|
|
1018
|
+
})()`});M||(console.error(` no entry with id ${N}`),process.exit(1)),m?console.log(JSON.stringify(M,null,2)):It(M);break}let p=s??(n?200:e?Number(e):20);Number.isFinite(p)||(console.error(` invalid limit: ${e}`),process.exit(1));let h=async()=>{let N=await l.send({type:"evaluate",code:`(() => {
|
|
1031
1019
|
const obs = window.__sootsimObservability;
|
|
1032
1020
|
if (!obs) return { ok: false };
|
|
1033
1021
|
return { ok: true, entries: obs.network.getSnapshot() };
|
|
1034
|
-
})()`});if(!
|
|
1035
|
-
`);for(let
|
|
1036
|
-
`);let w=new Set,O=!0,
|
|
1022
|
+
})()`});if(!N||!N.ok)throw new Error("observability bridge not installed \u2014 is the engine running?");return N.entries??[]},f=N=>{let M=N;if(r&&(M=M.filter(F=>!!F.error||F.status!=null&&F.status>=400)),t){let F=t.toLowerCase();M=M.filter(W=>(W.displayUrl||W.url).toLowerCase().includes(F))}return M};if(!n){let N=await h(),M=f(N).slice(-p);if(m){console.log(JSON.stringify(M,null,2));break}if(M.length===0){console.log(N.length===0?" no network requests captured":" no matching requests");break}console.log(` ${M.length} request(s):
|
|
1023
|
+
`);for(let F of M)Ve(F);break}console.log(` tailing network (ctrl-c to stop)...
|
|
1024
|
+
`);let w=new Set,O=!0,B=()=>{O=!1};process.on("SIGINT",B);try{for(;O;){let N=await h(),M=f(N);for(let F of M)F.durationMs!=null&&(w.has(F.id)||(w.add(F.id),m?console.log(JSON.stringify(F)):Ve(F)));await Y(250)}}finally{process.off("SIGINT",B)}break}case"logs":{let e=a[1],t=null,s=null,r=null,n=!1,m=!1,p=!1;for(let g=0;g<d.length;g++){let T=d[g];if(T==="--filter")t=d[g+1]??null,g++;else if(T==="--limit"){let _=Number(d[g+1]);Number.isFinite(_)&&(s=_),g++}else T==="--level"?(r=d[g+1]??null,g++):T==="--tail"||T==="-f"?n=!0:T==="--json"?m=!0:(T==="--internal"||T==="--all")&&(p=!0)}let h=r?new Set(r.split(",").map(g=>g.trim()).filter(g=>g==="log"||g==="info"||g==="warn"||g==="error"||g==="debug")):null;if(e==="clear"){await l.send({type:"evaluate",code:'window.__sootsimObservability?.logs.clear(); "cleared"'}),console.log(" log buffer cleared");break}let f=!m&&process.stdout.isTTY===!0,w=s??(n?500:e?Number(e):50);Number.isFinite(w)||(console.error(` invalid limit: ${e}`),process.exit(1));let O=async()=>{let g=await l.send({type:"evaluate",code:`(() => {
|
|
1037
1025
|
const obs = window.__sootsimObservability;
|
|
1038
1026
|
if (!obs) return { ok: false };
|
|
1039
1027
|
return { ok: true, entries: obs.logs.getSnapshot() };
|
|
1040
|
-
})()`});if(!g||!g.ok)throw new Error("observability bridge not installed \u2014 is the engine running?");return g.entries??[]},
|
|
1041
|
-
`);for(let
|
|
1042
|
-
`);let
|
|
1028
|
+
})()`});if(!g||!g.ok)throw new Error("observability bridge not installed \u2014 is the engine running?");return g.entries??[]},B=g=>{let T=g.args[0];return typeof T!="string"?!1:T.startsWith("[sootsim]")},N=g=>{let T=g;if(p||(T=T.filter(_=>!B(_))),h&&(T=T.filter(_=>h.has(_.level))),t){let _=t.toLowerCase();T=T.filter(P=>P.args.join(" ").toLowerCase().includes(_))}return T};if(!n){let g=await O(),T=N(g).slice(-w);if(m){console.log(JSON.stringify(T,null,2));break}if(T.length===0){console.log(g.length===0?" no logs captured":" no matching logs");break}console.log(` ${T.length} log(s):
|
|
1029
|
+
`);for(let _ of T)Qe(_,f);break}console.log(` tailing logs (ctrl-c to stop)...
|
|
1030
|
+
`);let M=new Set,F=!0,W=()=>{F=!1};process.on("SIGINT",W);try{for(;F;){let g=await O(),T=N(g);for(let _ of T)M.has(_.id)||(M.add(_.id),m?console.log(JSON.stringify(_)):Qe(_,f));await Y(250)}}finally{process.off("SIGINT",W)}break}default:console.error(` unknown subcommand: ${b}`),process.exit(1)}if(H.has(b)&&!o.includes("--no-wait")&&process.env.SOOTSIM_NO_AUTO_WAIT!=="1"&&await ne(l),!D.has(b)&&!E(d)){let e=await Z();try{await J({counts:e.console})}catch{}try{await x({counts:e.requests})}catch{}}}catch(e){console.error(` ${b??"inspect"} failed: ${e.message}`);try{await Me(l)}catch{}try{await J({includeTail:!0})}catch{}try{await x({includeTail:!0})}catch{}process.exit(1)}finally{l.close()}}export{ss as runInspect};
|