sootsim 0.1.62 → 0.1.64

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.
Files changed (137) hide show
  1. package/dist-cli/bin.js +3 -3
  2. package/dist-cli/chunks/{agent-VKARDTF5.js → agent-SHMN3LWB.js} +2 -2
  3. package/dist-cli/chunks/{agent-wrapper-6QDQ77TJ.js → agent-wrapper-ESDQSMYX.js} +2 -2
  4. package/dist-cli/chunks/{assert-PYSEWHJK.js → assert-X3GQJUDI.js} +2 -2
  5. package/dist-cli/chunks/auto-bootstrap-PH4II3F2.js +2 -0
  6. package/dist-cli/chunks/beta-YKR6YRXH.js +2 -0
  7. package/dist-cli/chunks/{chunk-35UHLN73.js → chunk-2GAZ3JW7.js} +2 -2
  8. package/dist-cli/chunks/{chunk-4JXE3ZUG.js → chunk-346HJVD6.js} +1 -1
  9. package/dist-cli/chunks/{chunk-3VE2XCQM.js → chunk-34PKFCEI.js} +3 -3
  10. package/dist-cli/chunks/{chunk-5POON745.js → chunk-3R3BQDKC.js} +2 -2
  11. package/dist-cli/chunks/{chunk-H2QWYBE2.js → chunk-6X3I2LF4.js} +2 -2
  12. package/dist-cli/chunks/{chunk-WN2ATVFO.js → chunk-ALDKVFW3.js} +2 -2
  13. package/dist-cli/chunks/{chunk-TALVQX2P.js → chunk-BT6IVKHN.js} +1 -1
  14. package/dist-cli/chunks/chunk-CETSCOUK.js +1 -0
  15. package/dist-cli/chunks/{chunk-6TJONB3X.js → chunk-DJIQVKM6.js} +10 -10
  16. package/dist-cli/chunks/{chunk-3N6CKIJG.js → chunk-DSLBZC6J.js} +2 -2
  17. package/dist-cli/chunks/{chunk-DV4MSLJL.js → chunk-E5EWHEA5.js} +2 -2
  18. package/dist-cli/chunks/{chunk-63NGN7QH.js → chunk-FFVJK2R7.js} +2 -2
  19. package/dist-cli/chunks/{chunk-RIYRSTXD.js → chunk-G4GM43A7.js} +2 -2
  20. package/dist-cli/chunks/{chunk-ND2UZFA4.js → chunk-GKUKCZBA.js} +44 -44
  21. package/dist-cli/chunks/{chunk-CEOCVI4R.js → chunk-HERZHQFG.js} +2 -2
  22. package/dist-cli/chunks/{chunk-6XLG7CQG.js → chunk-J6TCNU6W.js} +1 -1
  23. package/dist-cli/chunks/chunk-KY2VMN66.js +1 -0
  24. package/dist-cli/chunks/{chunk-DN47N6UL.js → chunk-L3MRXOBW.js} +3 -3
  25. package/dist-cli/chunks/{chunk-EIXXQDAI.js → chunk-LKJI7RRW.js} +2 -2
  26. package/dist-cli/chunks/{chunk-DNAVJIEL.js → chunk-M4CADRP5.js} +2 -2
  27. package/dist-cli/chunks/{chunk-3BWDOYAV.js → chunk-N63QYSHT.js} +3 -3
  28. package/dist-cli/chunks/{chunk-V3TU7DR4.js → chunk-OBL6OIK5.js} +1 -1
  29. package/dist-cli/chunks/chunk-OBSMT5TS.js +2 -0
  30. package/dist-cli/chunks/{chunk-VBA6DIBD.js → chunk-PXRELDJJ.js} +2 -2
  31. package/dist-cli/chunks/{chunk-Q5EKBSA2.js → chunk-R6ZTREB6.js} +2 -2
  32. package/dist-cli/chunks/{chunk-NXFXTJSP.js → chunk-RKUDWRIN.js} +2 -2
  33. package/dist-cli/chunks/{chunk-UEF3ZIEI.js → chunk-RQHWF2OD.js} +2 -2
  34. package/dist-cli/chunks/{chunk-OMSSLTQC.js → chunk-RRGCQNVD.js} +1 -1
  35. package/dist-cli/chunks/{chunk-3WZ7ZTIA.js → chunk-SMYSG4VE.js} +1 -1
  36. package/dist-cli/chunks/{chunk-C6LE22VK.js → chunk-SVT7H2QF.js} +2 -2
  37. package/dist-cli/chunks/{chunk-6RJRJRAW.js → chunk-T5TDH2UO.js} +1 -1
  38. package/dist-cli/chunks/{chunk-J5RNZMJJ.js → chunk-UVDVALC7.js} +2 -2
  39. package/dist-cli/chunks/{chunk-66KS2T62.js → chunk-VE4QTDAY.js} +2 -2
  40. package/dist-cli/chunks/{chunk-2JSZSUTN.js → chunk-VGD57MTN.js} +2 -2
  41. package/dist-cli/chunks/{chunk-6EUVCG33.js → chunk-WKVIKFMU.js} +1 -1
  42. package/dist-cli/chunks/chunk-WN4XOOK5.js +2 -0
  43. package/dist-cli/chunks/{chunk-4MZLNYBR.js → chunk-X3QWOTLT.js} +1 -1
  44. package/dist-cli/chunks/chunk-XHD3XCT5.js +1 -0
  45. package/dist-cli/chunks/{chunk-JIEJ2O4W.js → chunk-XHDHG6YH.js} +1 -1
  46. package/dist-cli/chunks/{chunk-BIZ4APXE.js → chunk-YGMHOMAJ.js} +2 -2
  47. package/dist-cli/chunks/{chunk-YRKWTQ66.js → chunk-YJIQYIHM.js} +1 -1
  48. package/dist-cli/chunks/{chunk-TIUEUINU.js → chunk-YXZFG3ZY.js} +1 -1
  49. package/dist-cli/chunks/{chunk-YAKDXQA7.js → chunk-ZV2TI6OH.js} +2 -2
  50. package/dist-cli/chunks/cli-version-32VNOX3F.js +2 -0
  51. package/dist-cli/chunks/{compat-GO5ZKWUL.js → compat-SOHG4UE5.js} +3 -3
  52. package/dist-cli/chunks/{config-GWDGFFIB.js → config-JQF6TGCG.js} +2 -2
  53. package/dist-cli/chunks/control-GIAGLNPG.js +2 -0
  54. package/dist-cli/chunks/{cpu-profile-TQRN7NFF.js → cpu-profile-3C7LHLJE.js} +2 -2
  55. package/dist-cli/chunks/{daemon-XLTCNIET.js → daemon-SD773LNY.js} +2 -2
  56. package/dist-cli/chunks/{debug-324KIABR.js → debug-MNWVCAAF.js} +3 -3
  57. package/dist-cli/chunks/demo-app-registry-JUKLYD4R.js +2 -0
  58. package/dist-cli/chunks/{detox-QGITZG47.js → detox-VOWHHVNU.js} +2 -2
  59. package/dist-cli/chunks/{device-6WFYBS5R.js → device-TFKPS72A.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-HBDMYEKJ.js → diagnose-J2BTJTGW.js} +2 -2
  61. package/dist-cli/chunks/drivers-HVKRY4MB.js +2 -0
  62. package/dist-cli/chunks/{electron-5DX3DITH.js → electron-NHJHQAOJ.js} +3 -3
  63. package/dist-cli/chunks/flow-D6MKC5NH.js +2 -0
  64. package/dist-cli/chunks/{hints-CJ3ETNUR.js → hints-XONGBPNI.js} +2 -2
  65. package/dist-cli/chunks/{home-paths-OCOWHSRV.js → home-paths-KK7NZVIK.js} +2 -2
  66. package/dist-cli/chunks/{inspect-QPZXN3IK.js → inspect-7AINMWI2.js} +135 -102
  67. package/dist-cli/chunks/install-YPSDICK4.js +2 -0
  68. package/dist-cli/chunks/{install-desktop-RB3JNYHC.js → install-desktop-CRFW4MDL.js} +3 -3
  69. package/dist-cli/chunks/{keys-HFOS3J5A.js → keys-PLJITE2X.js} +2 -2
  70. package/dist-cli/chunks/{launch-XQGAPI6Q.js → launch-FHMTFUI3.js} +3 -3
  71. package/dist-cli/chunks/{login-U6ZPN4IL.js → login-DCFVFSY3.js} +4 -4
  72. package/dist-cli/chunks/{logout-VY2F5T4J.js → logout-55UH67FS.js} +2 -2
  73. package/dist-cli/chunks/{maestro-32UN2FHS.js → maestro-HNNW73KG.js} +2 -2
  74. package/dist-cli/chunks/{preview-AJWIS25K.js → preview-EYIZWAEJ.js} +2 -2
  75. package/dist-cli/chunks/{profile-4XPDQIQY.js → profile-UOG2ET7W.js} +2 -2
  76. package/dist-cli/chunks/{react-VSZ2RQEC.js → react-MRICF5YD.js} +2 -2
  77. package/dist-cli/chunks/record-33ZECMTQ.js +50 -0
  78. package/dist-cli/chunks/runtime-OG4HGCYH.js +2 -0
  79. package/dist-cli/chunks/{runtime-delivery-O7G4Y6GE.js → runtime-delivery-KYEJ3C24.js} +2 -2
  80. package/dist-cli/chunks/{screenshot-ALDT4B77.js → screenshot-B6B3CE2W.js} +2 -2
  81. package/dist-cli/chunks/{screenshot-mode-5VYUB7G6.js → screenshot-mode-QVII6GH6.js} +2 -2
  82. package/dist-cli/chunks/{screenshots-TYQ4EVJR.js → screenshots-GYQ3JHAW.js} +2 -2
  83. package/dist-cli/chunks/{server-X2GDTWC6.js → server-G4WPXKFR.js} +2 -2
  84. package/dist-cli/chunks/setup-repo-2TQURG52.js +2 -0
  85. package/dist-cli/chunks/{skills-C6RSSO4R.js → skills-RF27H27Y.js} +2 -2
  86. package/dist-cli/chunks/{start-Y2S3LSL5.js → start-EBOUYGAP.js} +4 -4
  87. package/dist-cli/chunks/store-FRMH2SYG.js +2 -0
  88. package/dist-cli/chunks/telemetry-EZIRTFFL.js +2 -0
  89. package/dist-cli/chunks/{test-IAHTJWBS.js → test-SATSKLC6.js} +3 -3
  90. package/dist-cli/chunks/{three-mode-ZCZXY47S.js → three-mode-XLTSGRVJ.js} +2 -2
  91. package/dist-cli/chunks/{timeline-KZHGTPDV.js → timeline-ELOCAU3S.js} +2 -2
  92. package/dist-cli/chunks/{upgrade-47JCBCFB.js → upgrade-2OZLYETX.js} +2 -2
  93. package/dist-cli/chunks/upload-SJCUW6BT.js +2 -0
  94. package/dist-cli/chunks/web-YOKL7JUD.js +2 -0
  95. package/dist-cli/chunks/{what-happened-FULTHMRQ.js → what-happened-YGFJR2TI.js} +2 -2
  96. package/dist-cli/chunks/{whoami-3KUBLDUA.js → whoami-GKH3GF3H.js} +2 -2
  97. package/dist-lib/agent-daemon-client.cjs +1 -1
  98. package/dist-lib/agent-events.cjs +1 -1
  99. package/dist-lib/agent-sessions.cjs +1 -1
  100. package/dist-lib/attached-projects.cjs +1 -1
  101. package/dist-lib/auth/shared-session.cjs +1 -1
  102. package/dist-lib/backend-origin.cjs +1 -1
  103. package/dist-lib/bridge-constants.cjs +1 -1
  104. package/dist-lib/cli-constants.cjs +1 -1
  105. package/dist-lib/config.cjs +1 -1
  106. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  107. package/dist-lib/home-paths.cjs +1 -1
  108. package/dist-lib/host/bridge-host.cjs +1 -1
  109. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  110. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  111. package/dist-lib/index.cjs +1 -1
  112. package/dist-lib/metro.cjs +1 -1
  113. package/dist-lib/profiles.cjs +1 -1
  114. package/dist-lib/render-mode.cjs +1 -1
  115. package/dist-lib/vite-base.cjs +1 -1
  116. package/dist-lib/vite.cjs +1 -1
  117. package/package.json +1 -1
  118. package/dist-cli/chunks/auto-bootstrap-SUDPJ45T.js +0 -2
  119. package/dist-cli/chunks/beta-3HRWHUIR.js +0 -2
  120. package/dist-cli/chunks/chunk-DYYNEGJV.js +0 -2
  121. package/dist-cli/chunks/chunk-S2RNIQCY.js +0 -1
  122. package/dist-cli/chunks/chunk-T6IRZEOS.js +0 -1
  123. package/dist-cli/chunks/chunk-TSGJJFFO.js +0 -1
  124. package/dist-cli/chunks/chunk-XTR4CILB.js +0 -2
  125. package/dist-cli/chunks/cli-version-INI6PYTD.js +0 -2
  126. package/dist-cli/chunks/control-GMAG2HKS.js +0 -2
  127. package/dist-cli/chunks/demo-app-registry-OEAV2G5S.js +0 -2
  128. package/dist-cli/chunks/drivers-TJSMGOQQ.js +0 -2
  129. package/dist-cli/chunks/flow-HNHYMZO6.js +0 -2
  130. package/dist-cli/chunks/install-OVCWRSPD.js +0 -2
  131. package/dist-cli/chunks/record-W6ZTLQTB.js +0 -45
  132. package/dist-cli/chunks/runtime-6UMHX7N7.js +0 -2
  133. package/dist-cli/chunks/setup-repo-Q7SMPBCH.js +0 -2
  134. package/dist-cli/chunks/store-ABVWLB26.js +0 -2
  135. package/dist-cli/chunks/telemetry-2LWDURQ5.js +0 -2
  136. package/dist-cli/chunks/upload-PNZ3UEOL.js +0 -2
  137. package/dist-cli/chunks/web-N6G3E6EE.js +0 -2
@@ -1,12 +1,12 @@
1
- /*! sootsim v0.1.62 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7ZTIA.js";import{a as X,b as C,c as B,d as z,e as de,f as re,g as at,h as lt,i as ke}from"./chunk-DV4MSLJL.js";import{a as Be,h as ce}from"./chunk-BIZ4APXE.js";import{b as ct,c as dt,i as ut}from"./chunk-EIXXQDAI.js";import"./chunk-NXFXTJSP.js";import{a as je}from"./chunk-6RJRJRAW.js";import{B as se,C as rt,I as it,a as We,b as qe,c as He,d as Ue,e as Ke,f as ze,g as Se,h as ve,m as Ye,n as Ge,o as Xe,p as Ve,q as Qe,r as Ze,s as et,t as tt,u as ot,v as st,z as nt}from"./chunk-6TJONB3X.js";import"./chunk-3N6CKIJG.js";import"./chunk-CEOCVI4R.js";import"./chunk-4MZLNYBR.js";import"./chunk-TSGJJFFO.js";import"./chunk-35UHLN73.js";import"./chunk-YRKWTQ66.js";import{a as we,c as xe,d as Oe}from"./chunk-ND2UZFA4.js";import{a as Ae}from"./chunk-XTR4CILB.js";import{c as Re,e as Ee,f as De,g as Ce,h as $e}from"./chunk-C6LE22VK.js";import{b as Pe}from"./chunk-4JXE3ZUG.js";import"./chunk-DYYNEGJV.js";import"./chunk-6EUVCG33.js";import"./chunk-6XLG7CQG.js";import{existsSync as Ht,mkdirSync as Ut,readFileSync as Kt,rmSync as mt,writeFileSync as zt}from"fs";import{tmpdir as Yt}from"os";import{dirname as Gt,join as Xt,resolve as Vt}from"path";var ie=1,Qt="SOOTSIM_INSPECT_NOTICE_PATH",Zt=300*1e3,eo=15e3;function pt(){return Vt(process.env[Qt]||Xt(Yt(),"sootsim-inspect-notice-state.json"))}function to(s,d){return Object.fromEntries(Object.entries(s).filter(([,i])=>typeof i?.signature=="string"&&Number.isFinite(i?.updatedAt)&&d-i.updatedAt<=Zt))}function oo(s){let d=pt();if(!Ht(d))return{version:ie,entries:{}};try{let i=JSON.parse(Kt(d,"utf8"));return i.version!==ie||!i.entries||typeof i.entries!="object"?(mt(d,{force:!0}),{version:ie,entries:{}}):{version:ie,entries:to(i.entries,s)}}catch{return mt(d,{force:!0}),{version:ie,entries:{}}}}function so(s){let d=pt();Ut(Gt(d),{recursive:!0}),zt(d,JSON.stringify(s,null,2)+`
3
- `)}function no(s,d){let i=d.trim()||"default";return`${s}:${i}`}function Te(s,d,i,l={}){let f=l.nowMs??Date.now(),a=l.cooldownMs??eo,y=oo(f),S=no(s,d),T=y.entries[S];return T&&T.signature===i&&f-T.updatedAt<a?!1:(y.entries[S]={signature:i,updatedAt:f},so(y),!0)}async function ft(s,d={args:[]}){let i=await We(s);if(C(d.args)){B(i);return}console.log(` nodes: ${i.nodes}`)}function Me(s,d){let i=s.indexOf(d);return i>=0&&i+1<s.length?s[i+1]:null}async function gt(s){let{bridge:d,args:i,positional:l}=s,f=i.includes("--verbose")||i.includes("-v"),a=C(i),y=f&&!a,S=i.includes("--watch")||i.includes("-w"),T=1e3,k=i.includes("--compact"),h=i.includes("--no-xy"),v=Me(i,"--testid-like"),N=Me(i,"--only"),M=Me(i,"--subtree"),E=l[1],J=E?/[*?]/.test(E):!1,c=!J&&!N?E:void 0,K=N??(J?E:void 0),j=async()=>{await de(d,{verbose:y});let Y=await Ue(d,{describe:!0,verbose:f,filter:c||"",testIdLike:v||void 0,onlyGlob:K||void 0,subtreeRoot:M||void 0,compact:k,hideXy:h}),W=Y?.tree,x=Y?.shell,_=Y?.keyboard;if(a){B({shell:x,tree:W??"",keyboard:_});return}if(x&&typeof x=="object"){let O=[x.state?`state=${x.state}`:null,x.activeApp?`app=${x.activeApp}`:null,x.showSwitcher?"switcher":null,x.switcherPhase&&x.switcherPhase!=="idle"?`phase=${x.switcherPhase}`:null].filter(Boolean);O.length>0&&console.log(` shell: ${O.join(" ")}`)}if(typeof W=="string"&&W.startsWith("__SUBTREE_NOT_FOUND__:")){let O=W.slice(22);console.log(` subtree root not found: ${O}`),G("subtree-root-not-found",O);return}if(!W){let O=Y?.nodeCount??0;console.log(" no matching nodes found"),!(c||v||K||M)&&O<10&&G("app-still-loading",O);return}if(console.log(W),!(c||v||K||M)&&!S&&W.split(`
4
- `).length>=80&&G("describe-use-filters"),_&&_.visible){let O=_.spec,V=[O?.keyboardType?`type=${O.keyboardType}`:null,O?.returnKeyType&&O.returnKeyType!=="default"?`return=${O.returnKeyType}`:null,_.mode!=="letters"?`mode=${_.mode}`:null,_.shifted?"shift":null,_.capsLock?"caps":null,O?.autoCapitalize&&O.autoCapitalize!=="sentences"?`autoCap=${O.autoCapitalize}`:null,_.accessoryBarId?`accessory=${_.accessoryBarId}`:null].filter(Boolean);console.log(`
1
+ /*! sootsim v0.1.64 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as G}from"./chunk-RQHWF2OD.js";import{a as Je,b as We}from"./chunk-SMYSG4VE.js";import{a as X,b as C,c as B,d as z,e as ue,f as re,g as lt,h as ct,i as Te}from"./chunk-E5EWHEA5.js";import{a as je,h as ce}from"./chunk-YGMHOMAJ.js";import{b as dt,c as ut,i as mt}from"./chunk-LKJI7RRW.js";import"./chunk-RKUDWRIN.js";import{a as Le}from"./chunk-T5TDH2UO.js";import{A as rt,C as se,D as it,J as at,a as de,b as qe,c as He,d as Ue,e as Ke,f as ze,g as Ye,h as ve,i as ke,n as Ge,o as Xe,p as Ve,q as Qe,r as Ze,s as et,t as tt,u as ot,v as st,w as nt}from"./chunk-DJIQVKM6.js";import"./chunk-DSLBZC6J.js";import"./chunk-HERZHQFG.js";import"./chunk-X3QWOTLT.js";import"./chunk-XHD3XCT5.js";import"./chunk-2GAZ3JW7.js";import"./chunk-YJIQYIHM.js";import{a as xe,c as $e,d as Pe}from"./chunk-GKUKCZBA.js";import{a as Oe}from"./chunk-WN4XOOK5.js";import{c as Ee,e as De,f as Ce,g as Be,h as Se}from"./chunk-SVT7H2QF.js";import{b as Re}from"./chunk-346HJVD6.js";import"./chunk-OBSMT5TS.js";import"./chunk-WKVIKFMU.js";import"./chunk-J6TCNU6W.js";import{existsSync as Ut,mkdirSync as Kt,readFileSync as zt,rmSync as pt,writeFileSync as Yt}from"fs";import{tmpdir as Gt}from"os";import{dirname as Xt,join as Vt,resolve as Qt}from"path";var ie=1,Zt="SOOTSIM_INSPECT_NOTICE_PATH",eo=300*1e3,to=15e3;function ft(){return Qt(process.env[Zt]||Vt(Gt(),"sootsim-inspect-notice-state.json"))}function oo(s,d){return Object.fromEntries(Object.entries(s).filter(([,a])=>typeof a?.signature=="string"&&Number.isFinite(a?.updatedAt)&&d-a.updatedAt<=eo))}function so(s){let d=ft();if(!Ut(d))return{version:ie,entries:{}};try{let a=JSON.parse(zt(d,"utf8"));return a.version!==ie||!a.entries||typeof a.entries!="object"?(pt(d,{force:!0}),{version:ie,entries:{}}):{version:ie,entries:oo(a.entries,s)}}catch{return pt(d,{force:!0}),{version:ie,entries:{}}}}function no(s){let d=ft();Kt(Xt(d),{recursive:!0}),Yt(d,JSON.stringify(s,null,2)+`
3
+ `)}function ro(s,d){let a=d.trim()||"default";return`${s}:${a}`}function Me(s,d,a,l={}){let g=l.nowMs??Date.now(),i=l.cooldownMs??to,h=so(g),S=ro(s,d),I=h.entries[S];return I&&I.signature===a&&g-I.updatedAt<i?!1:(h.entries[S]={signature:a,updatedAt:g},no(h),!0)}async function gt(s,d={args:[]}){let a=await qe(s);if(C(d.args)){B(a);return}console.log(` nodes: ${a.nodes}`)}function Ie(s,d){let a=s.indexOf(d);return a>=0&&a+1<s.length?s[a+1]:null}async function yt(s){let{bridge:d,args:a,positional:l}=s,g=a.includes("--verbose")||a.includes("-v"),i=C(a),h=g&&!i,S=a.includes("--watch")||a.includes("-w"),I=1e3,k=a.includes("--compact"),b=a.includes("--no-xy"),v=Ie(a,"--testid-like"),F=Ie(a,"--only"),T=Ie(a,"--subtree"),E=l[1],J=E?/[*?]/.test(E):!1,c=!J&&!F?E:void 0,K=F??(J?E:void 0),j=async()=>{await ue(d,{verbose:h});let Y=await Ke(d,{describe:!0,verbose:g,filter:c||"",testIdLike:v||void 0,onlyGlob:K||void 0,subtreeRoot:T||void 0,compact:k,hideXy:b}),W=Y?.tree,x=Y?.shell,N=Y?.keyboard;if(i){B({shell:x,tree:W??"",keyboard:N});return}if(x&&typeof x=="object"){let O=[x.state?`state=${x.state}`:null,x.activeApp?`app=${x.activeApp}`:null,x.showSwitcher?"switcher":null,x.switcherPhase&&x.switcherPhase!=="idle"?`phase=${x.switcherPhase}`:null].filter(Boolean);O.length>0&&console.log(` shell: ${O.join(" ")}`)}if(typeof W=="string"&&W.startsWith("__SUBTREE_NOT_FOUND__:")){let O=W.slice(22);console.log(` subtree root not found: ${O}`),G("subtree-root-not-found",O);return}if(!W){let O=Y?.nodeCount??0;console.log(" no matching nodes found"),!(c||v||K||T)&&O<10&&G("app-still-loading",O);return}if(console.log(W),!(c||v||K||T)&&!S&&W.split(`
4
+ `).length>=80&&G("describe-use-filters"),N&&N.visible){let O=N.spec,V=[O?.keyboardType?`type=${O.keyboardType}`:null,O?.returnKeyType&&O.returnKeyType!=="default"?`return=${O.returnKeyType}`:null,N.mode!=="letters"?`mode=${N.mode}`:null,N.shifted?"shift":null,N.capsLock?"caps":null,O?.autoCapitalize&&O.autoCapitalize!=="sentences"?`autoCap=${O.autoCapitalize}`:null,N.accessoryBarId?`accessory=${N.accessoryBarId}`:null].filter(Boolean);console.log(`
5
5
  keyboard: ${V.join(" ")||"visible"}`)}};if(S)for(console.log(` watching... (Ctrl+C to stop)
6
- `);;)console.clear(),await j(),await X(T);else await j()}var ro=["SOOTSIM_AGENT","CLAUDECODE","CLAUDE_CODE_ENTRYPOINT","CLAUDE_CODE_SESSION_ID","CODEX_THREAD_ID","CURSOR_TRACE_ID","AIDER_MODEL"];function yt(){if(process.env.SOOTSIM_AGENT==="0")return!1;for(let s of ro){let d=process.env[s];if(d&&d.trim()&&d!=="0")return!0}return!1}async function ht(s){let{bridge:d,args:i,effectiveArgs:l,positional:f,inspectUsage:a}=s,y=x=>{let _=l.indexOf(x);return _>=0&&_+1<l.length?l[_+1]:null},S=x=>l.includes(x),T=y("--testid")||y("--test-id"),k=y("--role"),h=y("--type"),v=y("--text"),N=S("--pressable"),M=S("--visible"),E=S("--interactive-targets")||S("--actions"),J=!T&&!k&&!h&&!v&&!N&&!M&&!E?f[1]:null,c=v??J,K=await ze(d,{testId:T,role:k,type:h,text:c,pressable:N,visible:M,interactive:E});K||(console.error(a("find","<text> | --text <t> | --testid <id> | --role <r> | --type <t> | --pressable | --visible | --interactive-targets")),process.exit(1));let{mode:j,result:D}=K,Y=C(i),W=i.includes("--verbose")||i.includes("--dump");if(Y)j==="interactive-targets"&&Array.isArray(D)?B(Se(D).map(x=>({...x,tap:ve(x)}))):B(D??null);else if(Array.isArray(D))if(D.length===0){console.log(` no ${j} nodes found`);let x=await d.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()"});typeof x=="number"&&x<10&&G("app-still-loading",x)}else if(j==="interactive-targets"){let x=Se(D);console.log(` found ${x.length} interactive target${x.length===1?"":"s"} (sorted by score):`);for(let _ of x.slice(0,20)){let Z=_.absolutePosition?`@(${Math.round(_.absolutePosition.x)},${Math.round(_.absolutePosition.y)})`:"",O=_.layout?`${Math.round(_.layout.width)}x${Math.round(_.layout.height)}`:"?x?",V=_.text?` "${_.text.slice(0,30)}"`:"",oe=_.testID?` #${_.testID}`:"",ee=_.accessibilityLabel?` \u24D8"${String(_.accessibilityLabel).slice(0,24)}"`:"",ye=_.accessibilityRole?`[${_.accessibilityRole}]`:_.type,he=ve(_);console.log(` ${ye}${V}${ee}${oe} ${O} ${Z}`),console.log(` \u2192 ${he}`),W&&console.log(Ie(JSON.stringify(_,null,2)," "))}x.length>20&&console.log(` ... and ${x.length-20} more`)}else{console.log(` found ${D.length} node${D.length===1?"":"s"} (${j}):`);for(let x of D.slice(0,20)){let _=x.absolutePosition?`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`:"",Z=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",O=x.text?` "${x.text.slice(0,30)}"`:"",V=x.testID?` #${x.testID}`:"",oe=x.pressable?" (tap)":"",ee=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${ee}${O}${V} ${Z} ${_}${oe}`),W&&console.log(Ie(JSON.stringify(x,null,2)," "))}D.length>20&&console.log(` ... and ${D.length-20} more`)}else if(D==null)console.log(` not found: ${c||T||k||h||""||j}`),T&&G("wait-selector-for-missing-testid",T);else{let x=D;if(x.type&&x.absolutePosition){let _=`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`,Z=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",O=x.text?` "${x.text.slice(0,40)}"`:"",V=x.testID?` #${x.testID}`:"",oe=x.pressable?" (tap)":"",ee=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${ee}${O}${V} ${Z} ${_}${oe}`),W&&console.log(Ie(JSON.stringify(x,null,2)," "))}else console.log(JSON.stringify(D,null,2))}}function Ie(s,d){return s.split(`
7
- `).map(i=>d+i).join(`
8
- `)}async function bt(s,d={}){let i=await nt(s);if("error"in i&&(console.error(i.error),process.exit(1)),d.json){console.log(JSON.stringify(i,null,2));return}let{visible:l,spec:f,mode:a,shifted:y,capsLock:S,accessoryBarId:T}=i,k=[];k.push(`keyboard: ${l?"visible":"hidden"}`),f?(k.push(` type: ${f.keyboardType}`),k.push(` returnKey: ${f.returnKeyType}`),k.push(` autoCap: ${f.autoCapitalize}`),k.push(` autoCorrect: ${f.autoCorrect?"on":"off"}`),k.push(` appearance: ${f.keyboardAppearance}`),f.secureTextEntry&&k.push(" secureTextEntry: true"),f.enablesReturnKeyAutomatically&&k.push(` return: ${f.currentTextIsEmpty?"disabled (empty)":"enabled"}`)):k.push(" spec: <none> (shown via dev-tools with no TextInput)"),k.push(` mode: ${a}${y?" (shifted)":""}${S?" (caps)":""}`),T&&k.push(` accessoryBar: ${T}`),console.log(k.join(`
9
- `))}async function wt(s){let d=await s.bridge.listSims();if(C(s.args)){B(d.map(i=>({...i,active:i.id===s.simId})));return}ut(d,s.simId)}function te(s){return s<1024?`${s}B`:s<1024*1024?`${(s/1024).toFixed(1)}KB`:`${(s/1024/1024).toFixed(1)}MB`}function ue(s,d){return d<=0?"?":`${(s/d*100).toFixed(0)}%`}async function xt(s,d={args:[]}){let i=await it(s);if(C(d.args)){B(i);return}if(console.log(" memory:"),i.imageLoader){let l=i.imageLoader;console.log(" image-loader cache"),console.log(` entries: ${l.cacheEntries} / ${l.cacheMaxEntries} (${ue(l.cacheEntries,l.cacheMaxEntries)})`),console.log(` pixel bytes: ${te(l.cachePixelBytes)} / ${te(l.cachePixelBudget)} (${ue(l.cachePixelBytes,l.cachePixelBudget)})`),console.log(` pending: ${l.pendingFetches} fetches, ${l.pendingBytes} bytes`),console.log(` failed uris: ${l.failedUris}`),console.log(` snapshots: ${l.snapshots}`),console.log(` camera frames: ${l.cameraFrames}`)}else console.log(" image-loader cache: not available (engine pre-rebuild?)");if(i.workerHeap){let l=i.workerHeap;console.log(" worker heap (chrome only)"),console.log(` used: ${te(l.usedJSHeapSize)} / ${te(l.jsHeapSizeLimit)} (${ue(l.usedJSHeapSize,l.jsHeapSizeLimit)})`),console.log(` total: ${te(l.totalJSHeapSize)}`)}if(i.hostHeap){let l=i.hostHeap;console.log(" host heap (chrome only)"),console.log(` used: ${te(l.usedJSHeapSize)} / ${te(l.jsHeapSizeLimit)} (${ue(l.usedJSHeapSize,l.jsHeapSizeLimit)})`),console.log(` total: ${te(l.totalJSHeapSize)}`)}}function ae(s){let d=s.indexOf("--testid");if(d>=0&&s[d+1])return{mode:"testid",value:s[d+1]};let i=s.indexOf("--test-id");if(i>=0&&s[i+1])return{mode:"testid",value:s[i+1]};let l=s.indexOf("--text");return l>=0&&s[l+1]?{mode:"text",value:s[l+1]}:null}async function me(s,d){let i=JSON.stringify(d.value),l=d.mode==="testid"?`(await t.findByTestId(${i})) || (await t.findById(${i}))`:`await t.findByText(${i})`;return await s.send({type:"evaluate",code:`(async () => {
6
+ `);;)console.clear(),await j(),await X(I);else await j()}var io=["SOOTSIM_AGENT","CLAUDECODE","CLAUDE_CODE_ENTRYPOINT","CLAUDE_CODE_SESSION_ID","CODEX_THREAD_ID","CURSOR_TRACE_ID","AIDER_MODEL"];function ht(){if(process.env.SOOTSIM_AGENT==="0")return!1;for(let s of io){let d=process.env[s];if(d&&d.trim()&&d!=="0")return!0}return!1}async function bt(s){let{bridge:d,args:a,effectiveArgs:l,positional:g,inspectUsage:i}=s,h=x=>{let N=l.indexOf(x);return N>=0&&N+1<l.length?l[N+1]:null},S=x=>l.includes(x),I=h("--testid")||h("--test-id"),k=h("--role"),b=h("--type"),v=h("--text"),F=S("--pressable"),T=S("--visible"),E=S("--interactive-targets")||S("--actions"),J=!I&&!k&&!b&&!v&&!F&&!T&&!E?g[1]:null,c=v??J,K=await Ye(d,{testId:I,role:k,type:b,text:c,pressable:F,visible:T,interactive:E});K||(console.error(i("find","<text> | --text <t> | --testid <id> | --role <r> | --type <t> | --pressable | --visible | --interactive-targets")),process.exit(1));let{mode:j,result:D}=K,Y=C(a),W=a.includes("--verbose")||a.includes("--dump");if(Y)j==="interactive-targets"&&Array.isArray(D)?B(ve(D).map(x=>({...x,tap:ke(x)}))):B(D??null);else if(Array.isArray(D))if(D.length===0){console.log(` no ${j} nodes found`);let x=await d.send({type:"evaluate",code:"(async () => (await window.__sootsimTest?.getNodeCount?.()) || 0)()"});typeof x=="number"&&x<10&&G("app-still-loading",x)}else if(j==="interactive-targets"){let x=ve(D);console.log(` found ${x.length} interactive target${x.length===1?"":"s"} (sorted by score):`);for(let N of x.slice(0,20)){let Z=N.absolutePosition?`@(${Math.round(N.absolutePosition.x)},${Math.round(N.absolutePosition.y)})`:"",O=N.layout?`${Math.round(N.layout.width)}x${Math.round(N.layout.height)}`:"?x?",V=N.text?` "${N.text.slice(0,30)}"`:"",oe=N.testID?` #${N.testID}`:"",ee=N.accessibilityLabel?` \u24D8"${String(N.accessibilityLabel).slice(0,24)}"`:"",he=N.accessibilityRole?`[${N.accessibilityRole}]`:N.type,be=ke(N);console.log(` ${he}${V}${ee}${oe} ${O} ${Z}`),console.log(` \u2192 ${be}`),W&&console.log(Ne(JSON.stringify(N,null,2)," "))}x.length>20&&console.log(` ... and ${x.length-20} more`)}else{console.log(` found ${D.length} node${D.length===1?"":"s"} (${j}):`);for(let x of D.slice(0,20)){let N=x.absolutePosition?`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`:"",Z=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",O=x.text?` "${x.text.slice(0,30)}"`:"",V=x.testID?` #${x.testID}`:"",oe=x.pressable?" (tap)":"",ee=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${ee}${O}${V} ${Z} ${N}${oe}`),W&&console.log(Ne(JSON.stringify(x,null,2)," "))}D.length>20&&console.log(` ... and ${D.length-20} more`)}else if(D==null)console.log(` not found: ${c||I||k||b||""||j}`),I&&G("wait-selector-for-missing-testid",I);else{let x=D;if(x.type&&x.absolutePosition){let N=`@(${Math.round(x.absolutePosition.x)},${Math.round(x.absolutePosition.y)})`,Z=x.layout?`${Math.round(x.layout.width)}x${Math.round(x.layout.height)}`:"?x?",O=x.text?` "${x.text.slice(0,40)}"`:"",V=x.testID?` #${x.testID}`:"",oe=x.pressable?" (tap)":"",ee=x.accessibilityRole?`[${x.accessibilityRole}]`:x.type;console.log(` ${ee}${O}${V} ${Z} ${N}${oe}`),W&&console.log(Ne(JSON.stringify(x,null,2)," "))}else console.log(JSON.stringify(D,null,2))}}function Ne(s,d){return s.split(`
7
+ `).map(a=>d+a).join(`
8
+ `)}async function wt(s,d={}){let a=await rt(s);if("error"in a&&(console.error(a.error),process.exit(1)),d.json){console.log(JSON.stringify(a,null,2));return}let{visible:l,spec:g,mode:i,shifted:h,capsLock:S,accessoryBarId:I}=a,k=[];k.push(`keyboard: ${l?"visible":"hidden"}`),g?(k.push(` type: ${g.keyboardType}`),k.push(` returnKey: ${g.returnKeyType}`),k.push(` autoCap: ${g.autoCapitalize}`),k.push(` autoCorrect: ${g.autoCorrect?"on":"off"}`),k.push(` appearance: ${g.keyboardAppearance}`),g.secureTextEntry&&k.push(" secureTextEntry: true"),g.enablesReturnKeyAutomatically&&k.push(` return: ${g.currentTextIsEmpty?"disabled (empty)":"enabled"}`)):k.push(" spec: <none> (shown via dev-tools with no TextInput)"),k.push(` mode: ${i}${h?" (shifted)":""}${S?" (caps)":""}`),I&&k.push(` accessoryBar: ${I}`),console.log(k.join(`
9
+ `))}async function xt(s){let d=await s.bridge.listSims();if(C(s.args)){B(d.map(a=>({...a,active:a.id===s.simId})));return}mt(d,s.simId)}function te(s){return s<1024?`${s}B`:s<1024*1024?`${(s/1024).toFixed(1)}KB`:`${(s/1024/1024).toFixed(1)}MB`}function me(s,d){return d<=0?"?":`${(s/d*100).toFixed(0)}%`}async function $t(s,d={args:[]}){let a=await at(s);if(C(d.args)){B(a);return}if(console.log(" memory:"),a.imageLoader){let l=a.imageLoader;console.log(" image-loader cache"),console.log(` entries: ${l.cacheEntries} / ${l.cacheMaxEntries} (${me(l.cacheEntries,l.cacheMaxEntries)})`),console.log(` pixel bytes: ${te(l.cachePixelBytes)} / ${te(l.cachePixelBudget)} (${me(l.cachePixelBytes,l.cachePixelBudget)})`),console.log(` pending: ${l.pendingFetches} fetches, ${l.pendingBytes} bytes`),console.log(` failed uris: ${l.failedUris}`),console.log(` snapshots: ${l.snapshots}`),console.log(` camera frames: ${l.cameraFrames}`)}else console.log(" image-loader cache: not available (engine pre-rebuild?)");if(a.workerHeap){let l=a.workerHeap;console.log(" worker heap (chrome only)"),console.log(` used: ${te(l.usedJSHeapSize)} / ${te(l.jsHeapSizeLimit)} (${me(l.usedJSHeapSize,l.jsHeapSizeLimit)})`),console.log(` total: ${te(l.totalJSHeapSize)}`)}if(a.hostHeap){let l=a.hostHeap;console.log(" host heap (chrome only)"),console.log(` used: ${te(l.usedJSHeapSize)} / ${te(l.jsHeapSizeLimit)} (${me(l.usedJSHeapSize,l.jsHeapSizeLimit)})`),console.log(` total: ${te(l.totalJSHeapSize)}`)}}function ae(s){let d=s.indexOf("--testid");if(d>=0&&s[d+1])return{mode:"testid",value:s[d+1]};let a=s.indexOf("--test-id");if(a>=0&&s[a+1])return{mode:"testid",value:s[a+1]};let l=s.indexOf("--text");return l>=0&&s[l+1]?{mode:"text",value:s[l+1]}:null}async function pe(s,d){let a=JSON.stringify(d.value),l=d.mode==="testid"?`(await t.findByTestId(${a})) || (await t.findById(${a}))`:`await t.findByText(${a})`;return await s.send({type:"evaluate",code:`(async () => {
10
10
  const t = window.__sootsimTest
11
11
  if (!t) return null
12
12
  const n = ${l}
@@ -28,19 +28,43 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
28
28
  y: cy,
29
29
  id: n.id ?? null,
30
30
  testID: n.testID ?? null,
31
- text: ${JSON.stringify(d.mode==="text")} ? ${i} : (n.text ?? n.accessibilityLabel ?? null),
31
+ text: ${JSON.stringify(d.mode==="text")} ? ${a} : (n.text ?? n.accessibilityLabel ?? null),
32
32
  type: n.type ?? null,
33
33
  }
34
- })()`})??null}async function $t(s,d={}){let{nav:i,keyboard:l,shell:f}=await rt(s);if(d.json){console.log(JSON.stringify({shell:f??null,nav:i,keyboard:l},null,2));return}let a=[];if(f){let y=f.activeApp??f.state??"<none>",S=f.showSwitcher?" (app switcher open)":"",T=typeof f.launchProgress=="number"&&f.launchProgress<.98?` launching (${Math.round(f.launchProgress*100)}%)`:"";a.push(`shell: ${y}${S}${T}`)}else a.push("shell: <unavailable>");if(i){let y=i.transitionPhase!=="idle"?` (${i.transitionPhase}, ${i.activeTransitionCount} active)`:"";if(a.push(`nav: phase=${i.transitionPhase}${y}`),i.screens.length===0)a.push(" <no registered screens \u2014 app may not use react-native-screens>");else for(let S of i.screens){let T=S.isActive?"\u25B6":" ",k=S.routeName?` ${S.routeName}`:"",h=S.headerHeight>0?` header=${S.headerHeight}`:"",v=S.largeTitleState&&S.largeTitleState!=="expanded"?` large-title=${S.largeTitleState}`:"";a.push(` ${T} #${S.id}${k}${h}${v}`)}}else a.push("nav: <runtime not available>");if(l&&l.visible){let y=l.spec?.keyboardType??"default",S=l.spec?.returnKeyType??"default";a.push(`keyboard: visible (${y}, return=${S}, mode=${l.mode??"?"})`)}else a.push("keyboard: hidden");console.log(a.join(`
35
- `))}async function ne({bridge:s,maxMs:d,pollMs:i=50,stablePolls:l=3,strict:f=!1}){let a=await s.send({type:"evaluate",code:`(async () => {
34
+ })()`})??null}async function St(s,d={}){let{nav:a,keyboard:l,shell:g}=await it(s);if(d.json){console.log(JSON.stringify({shell:g??null,nav:a,keyboard:l},null,2));return}let i=[];if(g){let h=g.activeApp??g.state??"<none>",S=g.showSwitcher?" (app switcher open)":"",I=typeof g.launchProgress=="number"&&g.launchProgress<.98?` launching (${Math.round(g.launchProgress*100)}%)`:"";i.push(`shell: ${h}${S}${I}`)}else i.push("shell: <unavailable>");if(a){let h=a.transitionPhase!=="idle"?` (${a.transitionPhase}, ${a.activeTransitionCount} active)`:"";if(i.push(`nav: phase=${a.transitionPhase}${h}`),a.screens.length===0)i.push(" <no registered screens \u2014 app may not use react-native-screens>");else for(let S of a.screens){let I=S.isActive?"\u25B6":" ",k=S.routeName?` ${S.routeName}`:"",b=S.headerHeight>0?` header=${S.headerHeight}`:"",v=S.largeTitleState&&S.largeTitleState!=="expanded"?` large-title=${S.largeTitleState}`:"";i.push(` ${I} #${S.id}${k}${b}${v}`)}}else i.push("nav: <runtime not available>");if(l&&l.visible){let h=l.spec?.keyboardType??"default",S=l.spec?.returnKeyType??"default";i.push(`keyboard: visible (${h}, return=${S}, mode=${l.mode??"?"})`)}else i.push("keyboard: hidden");console.log(i.join(`
35
+ `))}async function ne({bridge:s,maxMs:d,pollMs:a=50,stablePolls:l=3,strict:g=!1}){let i=await s.send({type:"evaluate",code:`(async () => {
36
36
  const start = Date.now()
37
37
  const deadline = start + ${Math.max(0,Math.round(d))}
38
- const pollMs = ${Math.max(1,Math.round(i))}
38
+ const pollMs = ${Math.max(1,Math.round(a))}
39
39
  const requiredStablePolls = ${Math.max(1,Math.round(l))}
40
- const strict = ${f?"true":"false"}
40
+ const strict = ${g?"true":"false"}
41
41
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
42
+
43
+ // route-aware settle: a tap that pushes/pops a screen is async \u2014 the
44
+ // old screen still renders for a moment, then the new one mounts and
45
+ // its content loads. a pure layout-hash check reports "idle" on the
46
+ // outgoing screen or on the incoming skeleton, so a driver re-taps
47
+ // and stacks duplicate navigations. drain any in-flight screen
48
+ // transition FIRST, bounded by the overall budget. when no
49
+ // transition is happening this returns in ~80ms (startWindowMs), so
50
+ // a plain button tap barely pays for it.
51
+ try {
52
+ const wfst = window.__sootsimTest?.waitForScreenTransitions
53
+ if (typeof wfst === 'function') {
54
+ const remaining = deadline - Date.now()
55
+ if (remaining > 120) {
56
+ await wfst({
57
+ timeoutMs: Math.min(remaining - 80, 4000),
58
+ settleMs: 64,
59
+ startWindowMs: 80,
60
+ })
61
+ }
62
+ }
63
+ } catch {}
64
+
42
65
  const readSnapshot = async () => {
43
66
  let animating = false
67
+ let pendingFetches = 0
44
68
  try {
45
69
  const stats = await window.__sootsimRenderHost?.queryStats?.()
46
70
  if (stats) {
@@ -48,6 +72,14 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
48
72
  stats.hasActiveAnims === true ||
49
73
  stats.hasActiveNativeAnimations === true ||
50
74
  stats.hasPendingAnimationFrames === true
75
+ // a freshly-pushed screen showing a skeleton is layout-stable
76
+ // but not actually settled \u2014 its data/images are still in
77
+ // flight. treat bounded image-loader fetches as not-idle so
78
+ // settle waits for real content, capped by the budget.
79
+ const pf = stats.memory && stats.memory.imageLoader
80
+ ? stats.memory.imageLoader.pendingFetches
81
+ : 0
82
+ pendingFetches = typeof pf === 'number' ? pf : 0
51
83
  }
52
84
  } catch {}
53
85
  const root = window.__sootsimRoot
@@ -61,7 +93,7 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
61
93
  }
62
94
  walk(root)
63
95
  }
64
- return { layout: nodes.join(';'), animating }
96
+ return { layout: nodes.join(';'), animating, pendingFetches }
65
97
  }
66
98
 
67
99
  let lastLayout = ''
@@ -69,7 +101,8 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
69
101
  while (Date.now() < deadline) {
70
102
  const snapshot = await readSnapshot()
71
103
  const strictOk = !strict || !snapshot.animating
72
- if (strictOk && snapshot.layout === lastLayout) {
104
+ const contentReady = snapshot.pendingFetches === 0
105
+ if (strictOk && contentReady && snapshot.layout === lastLayout) {
73
106
  stable++
74
107
  if (stable >= requiredStablePolls) {
75
108
  return { settled: true, elapsed: Date.now() - start }
@@ -81,12 +114,12 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
81
114
  await sleep(pollMs)
82
115
  }
83
116
  return { settled: false, elapsed: Date.now() - start }
84
- })()`}),{elapsed:y,settled:S}=a??{};return{elapsed:typeof y=="number"?y:d,settled:S===!0}}async function St(s){let{bridge:d,args:i,positional:l}=s,f=l[1]?Number(l[1])*1e3:3e3,a=i.includes("--strict"),{elapsed:y,settled:S}=await ne({bridge:d,maxMs:f,strict:a});console.log(S?` settled in ${y}ms`:` timed out after ${y}ms (may still be animating)`)}async function vt(s){let d=s.positional[1]?Number(s.positional[1]):.5;(!Number.isFinite(d)||d<0)&&(console.error(s.inspectUsage("sleep","[seconds]")),process.exit(1)),await X(d*1e3),console.log(` slept ${d}s`)}async function kt(s){let{bridge:d,args:i,positional:l}=s,f=l[1]?Number(l[1]):5,{tree:a}=await qe(d,f);if(C(i)){B({depth:f,tree:a??null});return}console.log(typeof a=="string"?a:JSON.stringify(a,null,2))}async function Tt(s,d={args:[]}){let i=await He(s);if(C(d.args)){B(i);return}console.log(i.url)}async function Mt(s){let{wsPort:d,commandTimeoutMs:i,simId:l,simIdSource:f,positional:a}=s,y=a[1]?Number(a[1]):30,S=Math.max(1e3,(Number.isFinite(y)?y:30)*1e3),T=Math.max(1,Math.ceil(S/500));console.log(" waiting for sim reconnect...");let k=await at(d,i,l,{attempts:T,simIdSource:f});k||(console.error(" timed out waiting for sim reconnect"),process.exit(1)),k.bridge.close(),ce({source:"inspect wait",step:{wait:S},summary:`wait ${Math.round(S/1e3)}s`}),console.log(` ready: ${k.count} nodes`)}var It=new Set(["app-launch","toast","keyboard","screen","route","alert","actionsheet","picker","notification","fetch","console","shell","scroll","gesture","text-input","react-commit","animation","reanimated"]);function pe(s,d){let i=s.indexOf(d);if(i>=0&&i+1<s.length)return s[i+1]}function io(s,d){if(!d.filter&&!d.equals)return!0;let i=s.data,l=[];if(i&&typeof i=="object")for(let a of["url","displayUrl","message","name","activeName","path","pathname","title","phase","event","type","kind"]){let y=i[a];typeof y=="string"&&y.length>0&&l.push(y)}let f=l.join(" ");return d.equals?l.some(a=>a===d.equals):d.filter?f.toLowerCase().includes(d.filter.toLowerCase()):!0}async function Nt(s){let{bridge:d,args:i,positional:l,inspectUsage:f}=s,a=l[1];a||(console.error(f("wait event","<kind> [--max-ms 5000] [--filter <substring>] [--equals <exact>] [--since now|cursor]")),process.exit(1)),It.has(a)||console.error(` warning: '${a}' is not a known timeline kind \u2014 waiting anyway. known: ${[...It].sort().join(", ")}`);let y=pe(i,"--max-ms"),S=y&&Number.isFinite(Number(y))?Math.max(100,Number(y)):5e3,T=pe(i,"--filter"),k=pe(i,"--equals"),h=pe(i,"--since")??"now",v=i.includes("--json"),N=Date.now(),M=N+S,E=200,J=N;for(;Date.now()<M;){let K={kinds:[a],since:h==="cursor"?void 0:J,limit:50},j=await d.send({type:"evaluate",code:`(async () => {
117
+ })()`}),{elapsed:h,settled:S}=i??{};return{elapsed:typeof h=="number"?h:d,settled:S===!0}}async function vt(s){let{bridge:d,args:a,positional:l}=s,g=l[1]?Number(l[1])*1e3:3e3,i=a.includes("--strict"),{elapsed:h,settled:S}=await ne({bridge:d,maxMs:g,strict:i});console.log(S?` settled in ${h}ms`:` timed out after ${h}ms (may still be animating)`)}async function kt(s){let d=s.positional[1]?Number(s.positional[1]):.5;(!Number.isFinite(d)||d<0)&&(console.error(s.inspectUsage("sleep","[seconds]")),process.exit(1)),await X(d*1e3),console.log(` slept ${d}s`)}async function Tt(s){let{bridge:d,args:a,positional:l}=s,g=l[1]?Number(l[1]):5,{tree:i}=await He(d,g);if(C(a)){B({depth:g,tree:i??null});return}console.log(typeof i=="string"?i:JSON.stringify(i,null,2))}async function Mt(s,d={args:[]}){let a=await Ue(s);if(C(d.args)){B(a);return}console.log(a.url)}async function It(s){let{wsPort:d,commandTimeoutMs:a,simId:l,simIdSource:g,positional:i}=s,h=i[1]?Number(i[1]):30,S=Math.max(1e3,(Number.isFinite(h)?h:30)*1e3),I=Math.max(1,Math.ceil(S/500));console.log(" waiting for sim reconnect...");let k=await lt(d,a,l,{attempts:I,simIdSource:g});k||(console.error(" timed out waiting for sim reconnect"),process.exit(1)),k.bridge.close(),ce({source:"inspect wait",step:{wait:S},summary:`wait ${Math.round(S/1e3)}s`}),console.log(` ready: ${k.count} nodes`)}var Nt=new Set(["app-launch","toast","keyboard","screen","route","alert","actionsheet","picker","notification","fetch","console","shell","scroll","gesture","text-input","react-commit","animation","reanimated"]);function fe(s,d){let a=s.indexOf(d);if(a>=0&&a+1<s.length)return s[a+1]}function ao(s,d){if(!d.filter&&!d.equals)return!0;let a=s.data,l=[];if(a&&typeof a=="object")for(let i of["url","displayUrl","message","name","activeName","path","pathname","title","phase","event","type","kind"]){let h=a[i];typeof h=="string"&&h.length>0&&l.push(h)}let g=l.join(" ");return d.equals?l.some(i=>i===d.equals):d.filter?g.toLowerCase().includes(d.filter.toLowerCase()):!0}async function Ft(s){let{bridge:d,args:a,positional:l,inspectUsage:g}=s,i=l[1];i||(console.error(g("wait event","<kind> [--max-ms 5000] [--filter <substring>] [--equals <exact>] [--since now|cursor]")),process.exit(1)),Nt.has(i)||console.error(` warning: '${i}' is not a known timeline kind \u2014 waiting anyway. known: ${[...Nt].sort().join(", ")}`);let h=fe(a,"--max-ms"),S=h&&Number.isFinite(Number(h))?Math.max(100,Number(h)):5e3,I=fe(a,"--filter"),k=fe(a,"--equals"),b=fe(a,"--since")??"now",v=a.includes("--json"),F=Date.now(),T=F+S,E=200,J=F;for(;Date.now()<T;){let K={kinds:[i],since:b==="cursor"?void 0:J,limit:50},j=await d.send({type:"evaluate",code:`(async () => {
85
118
  const t = window.SootSim?.bridges?.timeline
86
119
  if (!t) return { ok: false, error: 'timeline bridge missing' }
87
120
  return { ok: true, result: await t.recent(${JSON.stringify(K)}) }
88
- })()`});(!j||!j.ok)&&(console.error(` could not query timeline: ${j&&"error"in j?j.error:"unknown"}`),process.exit(1));let D=j.result.events??[];for(let Y of D)if(io(Y,{filter:T,equals:k})){let W=Date.now()-N;console.log(v?JSON.stringify({found:!0,elapsedMs:W,event:Y}):` ${a} event after ${W}ms${T?` (filter: ${T})`:""}${k?` (equals: ${k})`:""}`);return}j.result.watermark&&j.result.watermark>J&&(J=j.result.watermark),await new Promise(Y=>setTimeout(Y,E))}let c=Date.now()-N;v?console.log(JSON.stringify({found:!1,elapsedMs:c,kind:a,filter:T,equals:k})):console.error(` \u26A0 wait event ${a} timed out after ${c}ms${T?` (filter: ${T})`:""}${k?` (equals: ${k})`:""}`),process.exit(1)}async function _t(s){let{bridge:d,args:i}=s,l=i.includes("--strict"),f=i.indexOf("--max-ms"),a=f>=0&&i[f+1]?Math.max(100,Number(i[f+1])):3e3,{elapsed:y,settled:S}=await ne({bridge:d,maxMs:a,strict:l});S?console.log(` idle in ${y}ms`):(console.error(` \u26A0 wait idle timed out after ${y}ms (may still be animating)`),process.exit(1))}async function Ft(s){let{bridge:d,args:i}=s,l=2e4,f=i.indexOf("--max-ms");f>=0&&i[f+1]&&(l=Math.max(100,Number(i[f+1])));let{ready:a,elapsedMs:y,nodes:S,targets:T,flag:k,loadingText:h,errors:v}=await Ye(d,l);if(a){console.log(` ready in ${y}ms: ${S} nodes, ${T} targets`);return}let N=h?`still showing "${h}"`:k!==!0?"guest app has not emitted sootsim:externalAppReady":T<=0?"ready flag emitted but no visible app content is inspectable yet":"node tree is still changing";console.error(` \u26A0 wait ready timed out after ${y}ms \u2014 ${N} (nodes: ${S}, targets: ${T}, errors: ${v})`),process.exit(1)}async function At(s){let{bridge:d,args:i,positional:l,inspectUsage:f}=s,a=l[1];a||(console.error(f("wait selector","<testid> [--max-ms 5000]")),process.exit(1));let y=i.indexOf("--max-ms"),S=y>=0&&i[y+1]?Math.max(100,Number(i[y+1])):5e3,{found:T,node:k,elapsed:h}=await Ge(d,a,S);if(T&&k){let v=k.absolutePosition?`@(${Math.round(k.absolutePosition.x)},${Math.round(k.absolutePosition.y)})`:"",N=k.layout?`${Math.round(k.layout.width)}x${Math.round(k.layout.height)}`:"?x?";console.log(` found #${a} in ${h}ms ${N} ${v}`)}else console.error(` \u26A0 wait selector #${a} timed out after ${h??S}ms`),process.exit(1)}function Ct(s){return s==null?"\u2014":s<1024?`${s}B`:s<1024*1024?`${(s/1024).toFixed(1)}K`:`${(s/1024/1024).toFixed(1)}M`}function Bt(s){return s==null?" \u2026":s<1e3?`${s}ms`.padStart(5):`${(s/1e3).toFixed(2)}s`.padStart(5)}function lo(s){return s.error?"err":s.status==null?" \u2026 ":String(s.status)}function Ot(s){let d=new Date(s.startTs).toLocaleTimeString(),i=lo(s).padEnd(3),l=s.method.padEnd(5),f=Ct(s.size).padStart(6),a=Bt(s.durationMs);console.log(` [${d}] ${i} ${l} ${f} ${a} ${s.displayUrl}`),s.error&&console.log(` error: ${s.error}`)}function co(s){let d=[["id",s.id],["source",s.source],["kind",s.kind],["method",s.method],["status",s.error?`error: ${s.error}`:`${s.status??"\u2014"} ${s.statusText??""}`.trim()],["url",s.url],["started",new Date(s.startTs).toLocaleTimeString()],["duration",Bt(s.durationMs).trim()],["size",Ct(s.size)],["content-type",s.type??"\u2014"]];for(let[i,l]of d)console.log(` ${i.padEnd(13)} ${l}`)}var uo={error:"\x1B[31m",warn:"\x1B[33m",info:"\x1B[36m",debug:"\x1B[35m",log:"\x1B[37m"},Pt="\x1B[0m",mo="\x1B[2m";function Rt(s,d){let i=new Date(s.ts).toLocaleTimeString(),l=s.level.toUpperCase().padEnd(5),f=s.args.join(" ");if(d){let a=uo[s.level];console.log(` ${mo}[${i}]${Pt} ${a}${l}${Pt} ${f}`)}else console.log(` [${i}] ${l} ${f}`);if(s.stack&&s.level==="error"){let a=s.stack.split(`
89
- `).slice(0,5);for(let y of a)console.log(` ${y.trim()}`)}}var Q="__sootsimCliPerf",po=120;async function Et(s,d){let i=s.find((N,M)=>s[M-1]==="--id"),l=s.find((N,M)=>s[M-1]==="--text");if(i||l){let N=await d.send({type:"evaluate",code:Le({id:i,text:l})});if(!N)throw new Error(i?`no node with id "${i}"`:`no node matching text "${l}"`);let{x:M,y:E,w:J,h:c}=N;return{x:M,y:E,w:J,h:c}}let f=s.find((N,M)=>s[M-1]==="--area");if(f){let N=f.split(",").map(K=>Number(K.trim()));if(N.length!==4||N.some(K=>!Number.isFinite(K)))throw new Error(`--area expects x,y,w,h (got "${f}")`);let[M,E,J,c]=N;return{x:M,y:E,w:J,h:c}}let a=N=>{let M=s.find((J,c)=>s[c-1]===N);if(M==null)return null;let E=Number(M);return Number.isFinite(E)?E:null},y=a("--x"),S=a("--y"),T=a("--w"),k=a("--h");if(y!=null||S!=null||T!=null||k!=null)return{x:y??0,y:S??0,w:T??1,h:k??1};let v=s.filter((N,M)=>M>0&&!N.startsWith("-")&&s[M-1]!=="--output"&&s[M-1]!=="--area"&&s[M-1]!=="--id"&&s[M-1]!=="--text"&&s[M-1]!=="--x"&&s[M-1]!=="--y"&&s[M-1]!=="--w"&&s[M-1]!=="--h").map(Number).filter(N=>Number.isFinite(N));if(v.length>=2){let[N,M,E=1,J=1]=v;return{x:N,y:M,w:E,h:J}}return null}function Ne(s){let d={"<8":0,"8-12":0,"12-16":0,"16-20":0,"20-33":0,">33":0};for(let i of s)i<8?d["<8"]++:i<12?d["8-12"]++:i<16?d["12-16"]++:i<20?d["16-20"]++:i<33?d["20-33"]++:d[">33"]++;console.log(" histogram:");for(let[i,l]of Object.entries(d)){let f="\u2588".repeat(Math.ceil(l/s.length*40));console.log(` ${i.padEnd(6)} ${f} ${l}`)}}async function fe(s,d,i){let l=Date.now()+d,f=await se(s,d);for(;;){if(i(f))return{settled:!0,state:f};if(Date.now()>=l)return{settled:!1,state:f};await X(16),f=await se(s)}}async function Fe(s){return s.send({type:"evaluate",code:`(async () => {
121
+ })()`});(!j||!j.ok)&&(console.error(` could not query timeline: ${j&&"error"in j?j.error:"unknown"}`),process.exit(1));let D=j.result.events??[];for(let Y of D)if(ao(Y,{filter:I,equals:k})){let W=Date.now()-F;console.log(v?JSON.stringify({found:!0,elapsedMs:W,event:Y}):` ${i} event after ${W}ms${I?` (filter: ${I})`:""}${k?` (equals: ${k})`:""}`);return}j.result.watermark&&j.result.watermark>J&&(J=j.result.watermark),await new Promise(Y=>setTimeout(Y,E))}let c=Date.now()-F;v?console.log(JSON.stringify({found:!1,elapsedMs:c,kind:i,filter:I,equals:k})):console.error(` \u26A0 wait event ${i} timed out after ${c}ms${I?` (filter: ${I})`:""}${k?` (equals: ${k})`:""}`),process.exit(1)}async function _t(s){let{bridge:d,args:a}=s,l=a.includes("--strict"),g=de(a,3e3),{elapsed:i,settled:h}=await ne({bridge:d,maxMs:g,strict:l});h?console.log(` idle in ${i}ms`):(console.error(` \u26A0 wait idle timed out after ${i}ms (may still be animating)`),process.exit(1))}async function At(s){let{bridge:d,args:a}=s,l=de(a,2e4),{ready:g,elapsedMs:i,nodes:h,targets:S,flag:I,loadingText:k,errors:b}=await Ge(d,l);if(g){console.log(` ready in ${i}ms: ${h} nodes, ${S} targets`);return}let v=k?`still showing "${k}"`:I!==!0?"guest app has not emitted sootsim:externalAppReady":S<=0?"ready flag emitted but no visible app content is inspectable yet":"node tree is still changing";console.error(` \u26A0 wait ready timed out after ${i}ms \u2014 ${v} (nodes: ${h}, targets: ${S}, errors: ${b})`),process.exit(1)}async function Ot(s){let{bridge:d,args:a,positional:l,inspectUsage:g}=s,i=l[1];i||(console.error(g("wait selector","<testid> [--max-ms 5000]")),process.exit(1));let h=a.indexOf("--max-ms"),S=h>=0&&a[h+1]?Math.max(100,Number(a[h+1])):5e3,{found:I,node:k,elapsed:b}=await Xe(d,i,S);if(I&&k){let v=k.absolutePosition?`@(${Math.round(k.absolutePosition.x)},${Math.round(k.absolutePosition.y)})`:"",F=k.layout?`${Math.round(k.layout.width)}x${Math.round(k.layout.height)}`:"?x?";console.log(` found #${i} in ${b}ms ${F} ${v}`)}else console.error(` \u26A0 wait selector #${i} timed out after ${b??S}ms`),process.exit(1)}function Bt(s){return s==null?"\u2014":s<1024?`${s}B`:s<1024*1024?`${(s/1024).toFixed(1)}K`:`${(s/1024/1024).toFixed(1)}M`}function jt(s){return s==null?" \u2026":s<1e3?`${s}ms`.padStart(5):`${(s/1e3).toFixed(2)}s`.padStart(5)}function co(s){return s.error?"err":s.status==null?" \u2026 ":String(s.status)}function Pt(s){let d=new Date(s.startTs).toLocaleTimeString(),a=co(s).padEnd(3),l=s.method.padEnd(5),g=Bt(s.size).padStart(6),i=jt(s.durationMs);console.log(` [${d}] ${a} ${l} ${g} ${i} ${s.displayUrl}`),s.error&&console.log(` error: ${s.error}`)}function uo(s){let d=[["id",s.id],["source",s.source],["kind",s.kind],["method",s.method],["status",s.error?`error: ${s.error}`:`${s.status??"\u2014"} ${s.statusText??""}`.trim()],["url",s.url],["started",new Date(s.startTs).toLocaleTimeString()],["duration",jt(s.durationMs).trim()],["size",Bt(s.size)],["content-type",s.type??"\u2014"]];for(let[a,l]of d)console.log(` ${a.padEnd(13)} ${l}`)}var mo={error:"\x1B[31m",warn:"\x1B[33m",info:"\x1B[36m",debug:"\x1B[35m",log:"\x1B[37m"},Rt="\x1B[0m",po="\x1B[2m";function Et(s,d){let a=new Date(s.ts).toLocaleTimeString(),l=s.level.toUpperCase().padEnd(5),g=s.args.join(" ");if(d){let i=mo[s.level];console.log(` ${po}[${a}]${Rt} ${i}${l}${Rt} ${g}`)}else console.log(` [${a}] ${l} ${g}`);if(s.stack&&s.level==="error"){let i=s.stack.split(`
122
+ `).slice(0,5);for(let h of i)console.log(` ${h.trim()}`)}}var Q="__sootsimCliPerf",fo=120;async function Dt(s,d){let a=s.find((F,T)=>s[T-1]==="--id"),l=s.find((F,T)=>s[T-1]==="--text");if(a||l){let F=await d.send({type:"evaluate",code:Je({id:a,text:l})});if(!F)throw new Error(a?`no node with id "${a}"`:`no node matching text "${l}"`);let{x:T,y:E,w:J,h:c}=F;return{x:T,y:E,w:J,h:c}}let g=s.find((F,T)=>s[T-1]==="--area");if(g){let F=g.split(",").map(K=>Number(K.trim()));if(F.length!==4||F.some(K=>!Number.isFinite(K)))throw new Error(`--area expects x,y,w,h (got "${g}")`);let[T,E,J,c]=F;return{x:T,y:E,w:J,h:c}}let i=F=>{let T=s.find((J,c)=>s[c-1]===F);if(T==null)return null;let E=Number(T);return Number.isFinite(E)?E:null},h=i("--x"),S=i("--y"),I=i("--w"),k=i("--h");if(h!=null||S!=null||I!=null||k!=null)return{x:h??0,y:S??0,w:I??1,h:k??1};let v=s.filter((F,T)=>T>0&&!F.startsWith("-")&&s[T-1]!=="--output"&&s[T-1]!=="--area"&&s[T-1]!=="--id"&&s[T-1]!=="--text"&&s[T-1]!=="--x"&&s[T-1]!=="--y"&&s[T-1]!=="--w"&&s[T-1]!=="--h").map(Number).filter(F=>Number.isFinite(F));if(v.length>=2){let[F,T,E=1,J=1]=v;return{x:F,y:T,w:E,h:J}}return null}function Fe(s){let d={"<8":0,"8-12":0,"12-16":0,"16-20":0,"20-33":0,">33":0};for(let a of s)a<8?d["<8"]++:a<12?d["8-12"]++:a<16?d["12-16"]++:a<20?d["16-20"]++:a<33?d["20-33"]++:d[">33"]++;console.log(" histogram:");for(let[a,l]of Object.entries(d)){let g="\u2588".repeat(Math.ceil(l/s.length*40));console.log(` ${a.padEnd(6)} ${g} ${l}`)}}async function ge(s,d,a){let l=Date.now()+d,g=await se(s,d);for(;;){if(a(g))return{settled:!0,state:g};if(Date.now()>=l)return{settled:!1,state:g};await X(16),g=await se(s)}}async function Ae(s){return s.send({type:"evaluate",code:`(async () => {
90
123
  const kb = window.__sootsimKeyboard
91
124
  const test = window.__sootsimTest
92
125
  if (!kb) return { error: 'keyboard bridge not available' }
@@ -118,8 +151,8 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
118
151
  frame: runtimeSnapshot?.keyboard?.frame ?? null,
119
152
  focusedRect: runtimeSnapshot?.focused?.rect ?? null,
120
153
  }
121
- })()`})}async function fo(s,d=600){let i=Date.now()+d;for(;Date.now()<=i;){let l=await Fe(s);if(l.visible)return l;await X(30)}return Fe(s)}async function ge(s,d){let i=await Fe(s);if(i.visible)return i;console.error(` ${d} 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 Dt(s,d,i){return d==="appearance"?s.send({type:"evaluate",code:`(async () => {
122
- const requested = ${JSON.stringify(i??"toggle")}
154
+ })()`})}async function go(s,d=600){let a=Date.now()+d;for(;Date.now()<=a;){let l=await Ae(s);if(l.visible)return l;await X(30)}return Ae(s)}async function ye(s,d){let a=await Ae(s);if(a.visible)return a;console.error(` ${d} 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 Ct(s,d,a){return d==="appearance"?s.send({type:"evaluate",code:`(async () => {
155
+ const requested = ${JSON.stringify(a??"toggle")}
123
156
  const rootBg = (document.documentElement?.style?.background || '').toLowerCase()
124
157
  const inferredCurrent = rootBg.includes('33') ? 'dark' : 'light'
125
158
  let next = requested
@@ -135,25 +168,25 @@ import{a as G}from"./chunk-UEF3ZIEI.js";import{a as Le,b as Je}from"./chunk-3WZ7
135
168
  })()`}):s.send({type:"evaluate",code:`(async () => {
136
169
  window.dispatchEvent(new CustomEvent(${JSON.stringify(d==="lock"?"sootsim:toggleLock":"sootsim:shake")}))
137
170
  return { ok: true, action: ${JSON.stringify(d)} }
138
- })()`})}function go(s){let d={Enter:"return",NumpadEnter:"return",Backspace:"delete",Delete:"delete",Space:"space",ShiftLeft:"shift",ShiftRight:"shift"};if(d[s])return d[s];let i=s.match(/^Digit([0-9])$/);if(i)return i[1];let l=s.match(/^Key([A-Z])$/);return l?l[1].toLowerCase():null}function yo(s){if(typeof s!="string")return null;let d=s.replace(/\s+/g," ").trim();return d?d.slice(0,80):null}function jt(...s){for(let d of s){if(typeof d!="string")continue;let i=d.trim();if(i)return i}return null}function ho(s){let d=s.indexOf("--node-id");if(d<0)return null;let i=s[d+1];if(!i)return null;let l=Number(i);return Number.isInteger(l)&&l>0?l:null}async function L(s,d,i){let l=ce({source:s,step:d,summary:i});l.active&&(l.replaced?console.error(` draft: replaced unkept action "${l.replaced.summary}" \u2014 \`flow keep\` commits one action at a time`):console.error(" draft: action pending \u2014 `sootsim flow keep` to commit"))}function bo(s,d,i){if(!i||i.hit===!1)return null;let l=jt(i.responderTestID,i.testID);if(l)return{step:{tapOn:{id:l}},summary:`tap #${l}`};let f=yo(i.text);return f?{step:{tapOn:f},summary:`tap "${f}"`}:{step:{tapAtCoords:{x:s,y:d}},summary:`tap @${Math.round(s)},${Math.round(d)}`}}function _e(s,d,i){let l=jt(d?.testID,d?.id);return l?{step:{tapOn:{id:l}},summary:`tap #${l}`}:i==="id"?{step:{tapOn:{id:s}},summary:`tap #${s}`}:{step:{tapOn:s},summary:`tap "${s}"`}}async function Qs(s,d){let i=s[0]==="get"||s[0]==="do"||s[0]==="debug"||s[0]==="wait"?s[0]:null,l=i?s.slice(1):s,f=Re(l,{port:d.port,commandTimeoutMs:d.timeoutMs,stripBooleanFlags:["--verbose","-v","--help","-h","--clear-state","--json","--all","--watch","-w","--strict","--no-wait","--dump","--failed","--slow","--tail","-f","--interactive-targets","--actions","--internal"],stripValueFlags:["--output","--nth","--index","--testid","--test-id","--text","--node-id","--max-ms","--filter","--limit","--level","--threshold","--equals","--since"]}),a=f.positional,y=a[0],S=i==="get"||i==="do"||i==="debug"||i==="wait"?i:"inspect",T=typeof l[0]=="string"&&Oe.has(l[0]),k=T?l[0]:null,h=t=>T&&t===l[0]?`sootsim ${t}`:`sootsim ${S} ${t}`,v=(t,e)=>` usage: ${h(t)}${e?` ${e}`:""}`;if(!y||s.includes("--help")||s.includes("-h")){let t={bridgePort:7668,defaultShellUrl:Ae};if(S==="do"||S==="get"||S==="debug"||S==="wait"){let n=we(S,t);n&&(console.log(`${n}
139
- `),process.exit(0))}if(k==="shell"){let n=xe("shell",t);n&&(console.log(`${n}
140
- `),process.exit(0))}let e=xe("inspect",t),o=["do","get","debug","wait"].map(n=>we(n,t)).filter(n=>n!=null).join(`
171
+ })()`})}function yo(s){let d={Enter:"return",NumpadEnter:"return",Backspace:"delete",Delete:"delete",Space:"space",ShiftLeft:"shift",ShiftRight:"shift"};if(d[s])return d[s];let a=s.match(/^Digit([0-9])$/);if(a)return a[1];let l=s.match(/^Key([A-Z])$/);return l?l[1].toLowerCase():null}function ho(s){if(typeof s!="string")return null;let d=s.replace(/\s+/g," ").trim();return d?d.slice(0,80):null}function Lt(...s){for(let d of s){if(typeof d!="string")continue;let a=d.trim();if(a)return a}return null}function bo(s){let d=s.indexOf("--node-id");if(d<0)return null;let a=s[d+1];if(!a)return null;let l=Number(a);return Number.isInteger(l)&&l>0?l:null}async function L(s,d,a){let l=ce({source:s,step:d,summary:a});l.active&&(l.replaced?console.error(` draft: replaced unkept action "${l.replaced.summary}" \u2014 \`flow keep\` commits one action at a time`):console.error(" draft: action pending \u2014 `sootsim flow keep` to commit"))}function wo(s,d,a){if(!a||a.hit===!1)return null;let l=Lt(a.responderTestID,a.testID);if(l)return{step:{tapOn:{id:l}},summary:`tap #${l}`};let g=ho(a.text);return g?{step:{tapOn:g},summary:`tap "${g}"`}:{step:{tapAtCoords:{x:s,y:d}},summary:`tap @${Math.round(s)},${Math.round(d)}`}}function _e(s,d,a){let l=Lt(d?.testID,d?.id);return l?{step:{tapOn:{id:l}},summary:`tap #${l}`}:a==="id"?{step:{tapOn:{id:s}},summary:`tap #${s}`}:{step:{tapOn:s},summary:`tap "${s}"`}}async function en(s,d){let a=s[0]==="get"||s[0]==="do"||s[0]==="debug"||s[0]==="wait"?s[0]:null,l=a?s.slice(1):s,g=Ee(l,{port:d.port,commandTimeoutMs:d.timeoutMs,stripBooleanFlags:["--verbose","-v","--help","-h","--clear-state","--json","--all","--watch","-w","--strict","--no-wait","--dump","--failed","--slow","--tail","-f","--interactive-targets","--actions","--internal"],stripValueFlags:["--output","--nth","--index","--testid","--test-id","--text","--node-id","--max-ms","--filter","--limit","--level","--threshold","--equals","--since"]}),i=g.positional,h=i[0],S=a==="get"||a==="do"||a==="debug"||a==="wait"?a:"inspect",I=typeof l[0]=="string"&&Pe.has(l[0]),k=I?l[0]:null,b=t=>I&&t===l[0]?`sootsim ${t}`:`sootsim ${S} ${t}`,v=(t,e)=>` usage: ${b(t)}${e?` ${e}`:""}`;if(!h||s.includes("--help")||s.includes("-h")){let t={bridgePort:7668,defaultShellUrl:Oe};if(S==="do"||S==="get"||S==="debug"||S==="wait"){let n=xe(S,t);n&&(console.log(`${n}
172
+ `),process.exit(0))}if(k==="shell"){let n=$e("shell",t);n&&(console.log(`${n}
173
+ `),process.exit(0))}let e=$e("inspect",t),o=["do","get","debug","wait"].map(n=>xe(n,t)).filter(n=>n!=null).join(`
141
174
 
142
175
  `);console.log(`${e??""}
143
176
 
144
177
  ${o}
145
- `),process.exit(0)}let N=f.wsPort,M=f.simId,E=f.simIdSource,J=f.commandTimeoutMs;if(y==="list"&&l.some(t=>t==="--drivers"||t==="-D")){let{buildDriverListRows:t}=await import("./drivers-TJSMGOQQ.js"),e=t();console.log(` available drivers (${e.length}):
146
- `);let o=Math.max(...e.map(r=>r.id.length),6),n=Math.max(...e.map(r=>r.kind.length),4);for(let r of e){let u=r.available?"\u2713":"\u2717",m=r.id.padEnd(o),w=r.kind.padEnd(n);console.log(` ${u} ${m} ${w} ${r.description}`),r.available&&r.detail?console.log(` ${r.detail}`):!r.available&&r.reason&&console.log(` unavailable: ${r.reason}`)}return}let c=Ee(f),K=M||"default",j=new Set(["errors","warnings","requests","js","eval","reload","globals","perf","list","wait","sleep"]),D=200;function Y(t){let e=t.replace(/\s+/g," ").trim();if(!e)return"";if(/^<(!doctype html|html|\?xml)|<body[\s>]/i.test(e)){let n=/<title[^>]*>([^<]+)<\/title>/i.exec(t)?.[1]?.trim(),r=/<body[^>]*>([\s\S]*?)<\//i.exec(t)?.[1]?.replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim().slice(0,80),u=n||r||"html error page";return`<html ${t.length}B> "${u}" (body elided \u2014 add --json for the full payload)`}return e.length<=D?e:`${e.slice(0,D)}\u2026 (+${e.length-D} more bytes)`}function W(t){let e=t.displayUrl||t.url;return t.status!=null?`${t.method} ${e} -> ${t.status}${t.statusText?` ${t.statusText}`:""}`:t.error?`${t.method} ${e} -> ${t.error}`:`${t.method} ${e}`}async function x(t){let e=yt()?1200:350;try{let{settled:o,elapsed:n}=await ne({bridge:t,maxMs:e,pollMs:32,stablePolls:2});o||process.stderr.write(` \u26A0 auto-wait timed out after ${n??e}ms \u2014 next command may see mid-animation state. use \`sootsim do settle\` for a longer wait.
147
- `)}catch{}}async function _(){try{return await c.send({type:"evaluate",code:`(() => ({
178
+ `),process.exit(0)}let F=g.wsPort,T=g.simId,E=g.simIdSource,J=g.commandTimeoutMs;if(h==="list"&&l.some(t=>t==="--drivers"||t==="-D")){let{buildDriverListRows:t}=await import("./drivers-HVKRY4MB.js"),e=t();console.log(` available drivers (${e.length}):
179
+ `);let o=Math.max(...e.map(r=>r.id.length),6),n=Math.max(...e.map(r=>r.kind.length),4);for(let r of e){let u=r.available?"\u2713":"\u2717",m=r.id.padEnd(o),w=r.kind.padEnd(n);console.log(` ${u} ${m} ${w} ${r.description}`),r.available&&r.detail?console.log(` ${r.detail}`):!r.available&&r.reason&&console.log(` unavailable: ${r.reason}`)}return}let c=De(g),K=T||"default",j=new Set(["errors","warnings","requests","js","eval","reload","globals","perf","list","wait","sleep"]),D=200;function Y(t){let e=t.replace(/\s+/g," ").trim();if(!e)return"";if(/^<(!doctype html|html|\?xml)|<body[\s>]/i.test(e)){let n=/<title[^>]*>([^<]+)<\/title>/i.exec(t)?.[1]?.trim(),r=/<body[^>]*>([\s\S]*?)<\//i.exec(t)?.[1]?.replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim().slice(0,80),u=n||r||"html error page";return`<html ${t.length}B> "${u}" (body elided \u2014 add --json for the full payload)`}return e.length<=D?e:`${e.slice(0,D)}\u2026 (+${e.length-D} more bytes)`}function W(t){let e=t.displayUrl||t.url;return t.status!=null?`${t.method} ${e} -> ${t.status}${t.statusText?` ${t.statusText}`:""}`:t.error?`${t.method} ${e} -> ${t.error}`:`${t.method} ${e}`}async function x(t){let e=ht()?5e3:1500;try{let{settled:o,elapsed:n}=await ne({bridge:t,maxMs:e,pollMs:32,stablePolls:2});o||process.stderr.write(` \u26A0 auto-wait timed out after ${n??e}ms \u2014 next command may see mid-animation state. use \`sootsim do settle\` for a longer wait.
180
+ `)}catch{}}async function N(){try{return await c.send({type:"evaluate",code:`(() => ({
148
181
  console: window.__sootsimConsole?.count?.() || null,
149
182
  requests: window.__sootsimTest?.getRequestCounts?.() || null,
150
- }))()`})||{console:null,requests:null}}catch{return{console:null,requests:null}}}async function Z(t={}){let e=t.counts!==void 0?t.counts:await z(c,"getRequestCounts");if(!e||typeof e!="object")return;let o=Math.max(0,Number(e.failed)||0);if(o===0||!t.includeTail&&!Te("requests",K,String(o))||(console.log(`
151
- network: ${o} failed request${o===1?"":"s"}`),console.log(` inspect: ${h("requests")} 5`),!t.includeTail))return;let n=await z(c,"getFailedRequests",5);if(!(!Array.isArray(n)||n.length===0)){console.log(`
183
+ }))()`})||{console:null,requests:null}}catch{return{console:null,requests:null}}}async function Z(t={}){let e=t.counts!==void 0?t.counts:await z(c,"getRequestCounts");if(!e||typeof e!="object")return;let o=Math.max(0,Number(e.failed)||0);if(o===0||!t.includeTail&&!Me("requests",K,String(o))||(console.log(`
184
+ network: ${o} failed request${o===1?"":"s"}`),console.log(` inspect: ${b("requests")} 5`),!t.includeTail))return;let n=await z(c,"getFailedRequests",5);if(!(!Array.isArray(n)||n.length===0)){console.log(`
152
185
  recent failed requests:
153
- `);for(let r of n){let u=new Date(r.timestamp).toLocaleTimeString();console.log(` [${u}] ${W(r)}`),r.responseBody?console.log(` ${Y(r.responseBody)}`):r.error&&console.log(` ${r.error}`)}}}async function O(t={}){let e=t.counts!==void 0?t.counts:await c.send({type:"evaluate",code:"window.__sootsimConsole?.count?.() || { errors: 0, warnings: 0, total: 0 }"});if(!e||typeof e!="object")return;let o=e,n=Math.max(0,Number(o.errors)||0),r=Math.max(0,Number(o.warnings)||0);if(n===0&&r===0||!t.includeTail&&!Te("console",K,`${n}:${r}`))return;let u=[];if(n>0&&u.push(`${n} console error${n===1?"":"s"}`),r>0&&u.push(`${r} console warning${r===1?"":"s"}`),console.log(`
154
- console: ${u.join(", ")}`),console.log(` inspect: ${h("errors")} 5`),r>0&&console.log(` inspect: ${h("warnings")} 5`),!t.includeTail||n===0)return;let m=await c.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors?.(5) || []"});if(!(!Array.isArray(m)||m.length===0)){console.log(`
186
+ `);for(let r of n){let u=new Date(r.timestamp).toLocaleTimeString();console.log(` [${u}] ${W(r)}`),r.responseBody?console.log(` ${Y(r.responseBody)}`):r.error&&console.log(` ${r.error}`)}}}async function O(t={}){let e=t.counts!==void 0?t.counts:await c.send({type:"evaluate",code:"window.__sootsimConsole?.count?.() || { errors: 0, warnings: 0, total: 0 }"});if(!e||typeof e!="object")return;let o=e,n=Math.max(0,Number(o.errors)||0),r=Math.max(0,Number(o.warnings)||0);if(n===0&&r===0||!t.includeTail&&!Me("console",K,`${n}:${r}`))return;let u=[];if(n>0&&u.push(`${n} console error${n===1?"":"s"}`),r>0&&u.push(`${r} console warning${r===1?"":"s"}`),console.log(`
187
+ console: ${u.join(", ")}`),console.log(` inspect: ${b("errors")} 5`),r>0&&console.log(` inspect: ${b("warnings")} 5`),!t.includeTail||n===0)return;let m=await c.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors?.(5) || []"});if(!(!Array.isArray(m)||m.length===0)){console.log(`
155
188
  recent console errors:
156
- `);for(let w of m){let g=new Date(w.timestamp).toLocaleTimeString(),$=Array.isArray(w.args)?w.args.map(F=>typeof F=="object"?JSON.stringify(F):String(F)).join(" "):String(w);console.log(` [${g}] ${$}`)}}}let V=["console","fetch","toast","alert","notification","screen","app-launch","keyboard","route","actionsheet","picker","shell","scroll","gesture","text-input","animation","reanimated"];async function oe(t){let e=Pe(),o=null;try{o=await Ce(t,`(() => {
189
+ `);for(let w of m){let f=new Date(w.timestamp).toLocaleTimeString(),$=Array.isArray(w.args)?w.args.map(_=>typeof _=="object"?JSON.stringify(_):String(_)).join(" "):String(w);console.log(` [${f}] ${$}`)}}}let V=["console","fetch","toast","alert","notification","screen","app-launch","keyboard","route","actionsheet","picker","shell","scroll","gesture","text-input","animation","reanimated"];async function oe(t){let e=Re(),o=null;try{o=await Be(t,`(() => {
157
190
  const tl = window.SootSim && window.SootSim.bridges && window.SootSim.bridges.timeline
158
191
  if (!tl || typeof tl.summary !== 'function') return null
159
192
  const cursorKey = ${JSON.stringify(e)}
@@ -169,9 +202,9 @@ ${o}
169
202
  }
170
203
  }
171
204
  return summary ? { summary, consoleSplit } : null
172
- })()`)}catch{return}if(!o||!o.summary||!o.summary.total)return;let n=o.summary.byKind??{},r=[],u=new Set;for(let m of V){let w=n[m];if(w)if(u.add(m),m==="console"&&o.consoleSplit){let{error:g,warn:$}=o.consoleSplit;g>0&&r.push(`${g} error${g===1?"":"s"}`),$>0&&r.push(`${$} warning${$===1?"":"s"}`)}else r.push(`${w} ${m}${w===1?"":"s"}`)}for(let[m,w]of Object.entries(n))!u.has(m)&&w&&r.push(`${w} ${m}${w===1?"":"s"}`);if(r.length!==0&&(console.log(`
173
- since last: ${r.join(" \xB7 ")} \u2014 sootsim what-happened`),o.summary.lastAt))try{await $e(t,"SootSim.bridges.timeline.cursorAdvance",e,o.summary.lastAt)}catch{}}let ee=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"]),ye=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"]),he=(s.includes("--verbose")||s.includes("-v"))&&!s.includes("--json");S==="do"&&y==="shell"&&(console.error(" `sootsim do shell` was removed. use `sootsim shell ...` instead."),process.exit(1)),ee.has(y)&&await De(c),ye.has(y)&&await de(c,{verbose:he});try{switch(y){case"list":{await wt({bridge:c,simId:M,args:l});break}case"tree":{await kt({bridge:c,args:l,positional:a});break}case"a11y":{let t=await Ke(c);if(!Array.isArray(t)||t.length===0){console.log(" no accessible nodes found");break}if(s.includes("--json"))console.log(JSON.stringify(t,null,2));else{console.log(` accessibility tree (${t.length} nodes):
174
- `);for(let e of t){let o=[];if(o.push(`[${e.role}]`),e.label){let n=e.label.length>50?e.label.slice(0,47)+"...":e.label;o.push(`"${n}"`)}if(e.hint&&o.push(`(hint: "${e.hint}")`),e.testID&&o.push(`#${e.testID}`),e.state){let n=[];e.state.disabled&&n.push("disabled"),e.state.selected&&n.push("selected"),e.state.checked===!0&&n.push("checked"),e.state.checked==="mixed"&&n.push("mixed"),e.state.busy&&n.push("busy"),e.state.expanded===!0&&n.push("expanded"),e.state.expanded===!1&&n.push("collapsed"),n.length&&o.push(`{${n.join(", ")}}`)}e.position&&o.push(`@(${e.position.x},${e.position.y})`),e.size&&o.push(`${e.size.w}x${e.size.h}`),console.log(" "+o.join(" "))}}break}case"find":{await ht({bridge:c,args:s,effectiveArgs:l,positional:a,inspectUsage:v});break}case"count":{await ft(c,{args:l});break}case"keyboard":{await bt(c,{json:s.includes("--json")});break}case"screens":{await $t(c,{json:s.includes("--json")});break}case"memory":{await xt(c,{args:l});break}case"wait":{await Mt({wsPort:N,commandTimeoutMs:J,simId:M,simIdSource:E,positional:a});break}case"sleep":{await vt({positional:a,inspectUsage:v});break}case"settle":{await St({bridge:c,args:s,positional:a});break}case"ready":{await Ft({bridge:c,args:s});break}case"idle":{await _t({bridge:c,args:s,positional:a});break}case"selector":{await At({bridge:c,args:s,positional:a,inspectUsage:v});break}case"event":{await Nt({bridge:c,args:s,positional:a,inspectUsage:v});break}case"layout":{let t=a[1];t||(console.error(v("layout","<id>")),process.exit(1));let e=await c.send({type:"evaluate",code:`(async () => await window.__sootsimTest.getLayout(${JSON.stringify(t)}))()`});console.log(JSON.stringify(e,null,2));break}case"capture":case"screenshot":{let e=s.find((w,g)=>s[g-1]==="--output")||"/tmp/sootsim-inspect.png",o=await Et(s,c),n={type:"screenshot"};o&&(n.crop=o);let u=(await c.send(n)).replace(/^data:image\/png;base64,/,"");o&&console.log(` area: x=${o.x} y=${o.y} w=${o.w} h=${o.h}`),(await import("fs")).writeFileSync(e,Buffer.from(u,"base64")),console.log(` saved: ${e}`);break}case"sample-color":{let t=await Et(s,c);t||(console.error(v("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 e=await c.send({type:"evaluate",code:Je(t)});if(s.includes("--json"))console.log(JSON.stringify(e,null,2));else{let{r:o,g:n,b:r,a:u,hex:m,samples:w}=e,g=t.w===1&&t.h===1?`@(${t.x},${t.y})`:`@(${t.x},${t.y}) ${t.w}x${t.h}`;console.log(` ${m} rgba(${o}, ${n}, ${r}, ${u}) ${g} ${w} samples`)}break}case"node":{let t=a[1];t||(console.error(v("node","<matcher>")),console.error(" resolves testID, id, then text \u2014 dumps full node info as JSON"),process.exit(1));let e=await c.send({type:"evaluate",code:`(async () => {
205
+ })()`)}catch{return}if(!o||!o.summary||!o.summary.total)return;let n=o.summary.byKind??{},r=[],u=new Set;for(let m of V){let w=n[m];if(w)if(u.add(m),m==="console"&&o.consoleSplit){let{error:f,warn:$}=o.consoleSplit;f>0&&r.push(`${f} error${f===1?"":"s"}`),$>0&&r.push(`${$} warning${$===1?"":"s"}`)}else r.push(`${w} ${m}${w===1?"":"s"}`)}for(let[m,w]of Object.entries(n))!u.has(m)&&w&&r.push(`${w} ${m}${w===1?"":"s"}`);if(r.length!==0&&(console.log(`
206
+ since last: ${r.join(" \xB7 ")} \u2014 sootsim what-happened`),o.summary.lastAt))try{await Se(t,"SootSim.bridges.timeline.cursorAdvance",e,o.summary.lastAt)}catch{}}let ee=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"]),he=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"]),be=(s.includes("--verbose")||s.includes("-v"))&&!s.includes("--json");S==="do"&&h==="shell"&&(console.error(" `sootsim do shell` was removed. use `sootsim shell ...` instead."),process.exit(1)),ee.has(h)&&await Ce(c),he.has(h)&&await ue(c,{verbose:be});try{switch(h){case"list":{await xt({bridge:c,simId:T,args:l});break}case"tree":{await Tt({bridge:c,args:l,positional:i});break}case"a11y":{let t=await ze(c);if(!Array.isArray(t)||t.length===0){console.log(" no accessible nodes found");break}if(s.includes("--json"))console.log(JSON.stringify(t,null,2));else{console.log(` accessibility tree (${t.length} nodes):
207
+ `);for(let e of t){let o=[];if(o.push(`[${e.role}]`),e.label){let n=e.label.length>50?e.label.slice(0,47)+"...":e.label;o.push(`"${n}"`)}if(e.hint&&o.push(`(hint: "${e.hint}")`),e.testID&&o.push(`#${e.testID}`),e.state){let n=[];e.state.disabled&&n.push("disabled"),e.state.selected&&n.push("selected"),e.state.checked===!0&&n.push("checked"),e.state.checked==="mixed"&&n.push("mixed"),e.state.busy&&n.push("busy"),e.state.expanded===!0&&n.push("expanded"),e.state.expanded===!1&&n.push("collapsed"),n.length&&o.push(`{${n.join(", ")}}`)}e.position&&o.push(`@(${e.position.x},${e.position.y})`),e.size&&o.push(`${e.size.w}x${e.size.h}`),console.log(" "+o.join(" "))}}break}case"find":{await bt({bridge:c,args:s,effectiveArgs:l,positional:i,inspectUsage:v});break}case"count":{await gt(c,{args:l});break}case"keyboard":{await wt(c,{json:s.includes("--json")});break}case"screens":{await St(c,{json:s.includes("--json")});break}case"memory":{await $t(c,{args:l});break}case"wait":{await It({wsPort:F,commandTimeoutMs:J,simId:T,simIdSource:E,positional:i});break}case"sleep":{await kt({positional:i,inspectUsage:v});break}case"settle":{await vt({bridge:c,args:s,positional:i});break}case"ready":{await At({bridge:c,args:s});break}case"idle":{await _t({bridge:c,args:s,positional:i});break}case"selector":{await Ot({bridge:c,args:s,positional:i,inspectUsage:v});break}case"event":{await Ft({bridge:c,args:s,positional:i,inspectUsage:v});break}case"layout":{let t=i[1];t||(console.error(v("layout","<id>")),process.exit(1));let e=await c.send({type:"evaluate",code:`(async () => await window.__sootsimTest.getLayout(${JSON.stringify(t)}))()`});console.log(JSON.stringify(e,null,2));break}case"capture":case"screenshot":{let e=s.find((w,f)=>s[f-1]==="--output")||"/tmp/sootsim-inspect.png",o=await Dt(s,c),n={type:"screenshot"};o&&(n.crop=o);let u=(await c.send(n)).replace(/^data:image\/png;base64,/,"");o&&console.log(` area: x=${o.x} y=${o.y} w=${o.w} h=${o.h}`),(await import("fs")).writeFileSync(e,Buffer.from(u,"base64")),console.log(` saved: ${e}`);break}case"sample-color":{let t=await Dt(s,c);t||(console.error(v("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 e=await c.send({type:"evaluate",code:We(t)});if(s.includes("--json"))console.log(JSON.stringify(e,null,2));else{let{r:o,g:n,b:r,a:u,hex:m,samples:w}=e,f=t.w===1&&t.h===1?`@(${t.x},${t.y})`:`@(${t.x},${t.y}) ${t.w}x${t.h}`;console.log(` ${m} rgba(${o}, ${n}, ${r}, ${u}) ${f} ${w} samples`)}break}case"node":{let t=i[1];t||(console.error(v("node","<matcher>")),console.error(" resolves testID, id, then text \u2014 dumps full node info as JSON"),process.exit(1));let e=await c.send({type:"evaluate",code:`(async () => {
175
208
  const t = window.__sootsimTest
176
209
  const q = ${JSON.stringify(t)}
177
210
  let node = null
@@ -227,20 +260,20 @@ ${o}
227
260
  transform,
228
261
  parentChain,
229
262
  }
230
- })()`});console.log(JSON.stringify(e,null,2));break}case"tap":{let t=Number(a[1]),e=Number(a[2]),o=ae(s),n=null;if(o){let m=await me(c,o);m||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=m.x,e=m.y,n=m}(!Number.isFinite(t)||!Number.isFinite(e))&&(console.error(v("tap","<x> <y> | --testid <id> | --text <t>")),process.exit(1));let r=await c.send({type:"tap",x:t,y:e,...o?{target:{id:n?.id??(o.mode==="testid"?o.value:null),testID:n?.testID??(o.mode==="testid"?o.value:null),text:n?.text??(o.mode==="text"?o.value:null),type:n?.type??null}}:{}}),u=bo(t,e,r);u&&await L("inspect tap",u.step,u.summary),console.log(JSON.stringify(r,null,2));break}case"drag":case"swipe":{let t=Number(a[1]),e=Number(a[2]),o=Number(a[3]),n=Number(a[4]),r=y==="swipe"?10:12,u=y==="swipe"?8:16,m=a[5]?Number(a[5]):r,w=a[6]?Number(a[6]):u;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(o)||!Number.isFinite(n)||!Number.isFinite(m)||!Number.isFinite(w))&&(console.error(v(y,"<x1> <y1> <x2> <y2> [steps] [stepMs]")),process.exit(1));let g=await c.send({type:"evaluate",code:`(async () => {
263
+ })()`});console.log(JSON.stringify(e,null,2));break}case"tap":{let t=Number(i[1]),e=Number(i[2]),o=ae(s),n=null;if(o){let m=await pe(c,o);m||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=m.x,e=m.y,n=m}(!Number.isFinite(t)||!Number.isFinite(e))&&(console.error(v("tap","<x> <y> | --testid <id> | --text <t>")),process.exit(1));let r=await c.send({type:"tap",x:t,y:e,...o?{target:{id:n?.id??(o.mode==="testid"?o.value:null),testID:n?.testID??(o.mode==="testid"?o.value:null),text:n?.text??(o.mode==="text"?o.value:null),type:n?.type??null}}:{}}),u=wo(t,e,r);u&&await L("inspect tap",u.step,u.summary),console.log(JSON.stringify(r,null,2));break}case"drag":case"swipe":{let t=Number(i[1]),e=Number(i[2]),o=Number(i[3]),n=Number(i[4]),r=h==="swipe"?10:12,u=h==="swipe"?8:16,m=i[5]?Number(i[5]):r,w=i[6]?Number(i[6]):u;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(o)||!Number.isFinite(n)||!Number.isFinite(m)||!Number.isFinite(w))&&(console.error(v(h,"<x1> <y1> <x2> <y2> [steps] [stepMs]")),process.exit(1));let f=await c.send({type:"evaluate",code:`(async () => {
231
264
  const interact = window.__sootsimInteract
232
265
  if (!interact?.drag) return { ok: false, reason: 'no interact.drag' }
233
266
  const value = await interact.drag(${t}, ${e}, ${o}, ${n}, ${Math.max(1,Math.round(m))}, ${Math.max(0,Math.round(w))})
234
267
  return { ok: !!value, value }
235
- })()`});if(g?.ok){let $=Math.max(1,Math.round(Math.max(1,m)*Math.max(0,w)));await L(`inspect ${y}`,{swipe:{start:`${t}, ${e}`,end:`${o}, ${n}`,duration:$}},`${y} ${t},${e} -> ${o},${n}`)}console.log(JSON.stringify(g,null,2));break}case"pinch":{let t=Number(a[1]),e=Number(a[2]),o=Number(a[3]),n=Number(a[4]),r=Number(a[5]),u=Number(a[6]),m=Number(a[7]),w=Number(a[8]),g=a[9]?Number(a[9]):12,$=a[10]?Number(a[10]):16;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(o)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(u)||!Number.isFinite(m)||!Number.isFinite(w)||!Number.isFinite(g)||!Number.isFinite($))&&(console.error(v("pinch","<x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]")),process.exit(1));let F=await c.send({type:"evaluate",code:`(async () => {
268
+ })()`});if(f?.ok){let $=Math.max(1,Math.round(Math.max(1,m)*Math.max(0,w)));await L(`inspect ${h}`,{swipe:{start:`${t}, ${e}`,end:`${o}, ${n}`,duration:$}},`${h} ${t},${e} -> ${o},${n}`)}console.log(JSON.stringify(f,null,2));break}case"pinch":{let t=Number(i[1]),e=Number(i[2]),o=Number(i[3]),n=Number(i[4]),r=Number(i[5]),u=Number(i[6]),m=Number(i[7]),w=Number(i[8]),f=i[9]?Number(i[9]):12,$=i[10]?Number(i[10]):16;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(o)||!Number.isFinite(n)||!Number.isFinite(r)||!Number.isFinite(u)||!Number.isFinite(m)||!Number.isFinite(w)||!Number.isFinite(f)||!Number.isFinite($))&&(console.error(v("pinch","<x1> <y1> <x2> <y2> <x1'> <y1'> <x2'> <y2'> [steps] [stepMs]")),process.exit(1));let _=await c.send({type:"evaluate",code:`(async () => {
236
269
  const interact = window.__sootsimInteract
237
270
  if (!interact?.pinch) return { ok: false, reason: 'no interact.pinch' }
238
- const value = await interact.pinch(${t}, ${e}, ${o}, ${n}, ${r}, ${u}, ${m}, ${w}, ${Math.max(1,Math.round(g))}, ${Math.max(0,Math.round($))})
271
+ const value = await interact.pinch(${t}, ${e}, ${o}, ${n}, ${r}, ${u}, ${m}, ${w}, ${Math.max(1,Math.round(f))}, ${Math.max(0,Math.round($))})
239
272
  return { ok: !!value, value }
240
- })()`});F?.ok&&await L("inspect pinch",{pinch:{from:[t,e,o,n],to:[r,u,m,w],steps:Math.max(1,Math.round(g)),stepMs:Math.max(0,Math.round($))}},`pinch (${t},${e}) (${o},${n}) -> (${r},${u}) (${m},${w})`),console.log(JSON.stringify(F,null,2));break}case"tap-text":{let t=a[1];t||(console.error(v("tap-text","<text>")),process.exit(1));let e=R=>{let A=s.indexOf(R);return A>=0&&A+1<s.length?s[A+1]:null},o=R=>s.includes(R),n=e("--nth")??e("--index"),r=n!==null?Number(n):null;r!==null&&!Number.isFinite(r)&&(console.error(` --nth/--index requires an integer, got: ${n}`),process.exit(1));let u=e("--within"),m=e("--role"),w=o("--exact"),g=o("--first"),$=e("--min-y"),F=e("--max-y"),q=e("--min-x"),H=e("--max-x");for(let[R,A]of[["--min-y",$],["--max-y",F],["--min-x",q],["--max-x",H]])A!==null&&!Number.isFinite(Number(A))&&(console.error(` ${R} requires a number, got: ${A}`),process.exit(1));let U=s.indexOf("--near"),I=null;if(U>=0){let R=Number(s[U+1]),A=Number(s[U+2]);(!Number.isFinite(R)||!Number.isFinite(A))&&(console.error(" --near requires two numbers: --near <x> <y>"),process.exit(1)),I={x:R,y:A}}let b=JSON.stringify({query:t,exact:w,role:m,within:u,minX:q!==null?Number(q):null,maxX:H!==null?Number(H):null,minY:$!==null?Number($):null,maxY:F!==null?Number(F):null,near:I,nth:r,first:g}),p=await c.send({type:"evaluate",code:`(async () => {
273
+ })()`});_?.ok&&await L("inspect pinch",{pinch:{from:[t,e,o,n],to:[r,u,m,w],steps:Math.max(1,Math.round(f)),stepMs:Math.max(0,Math.round($))}},`pinch (${t},${e}) (${o},${n}) -> (${r},${u}) (${m},${w})`),console.log(JSON.stringify(_,null,2));break}case"tap-text":{let t=i[1];t||(console.error(v("tap-text","<text>")),process.exit(1));let e=R=>{let A=s.indexOf(R);return A>=0&&A+1<s.length?s[A+1]:null},o=R=>s.includes(R),n=e("--nth")??e("--index"),r=n!==null?Number(n):null;r!==null&&!Number.isFinite(r)&&(console.error(` --nth/--index requires an integer, got: ${n}`),process.exit(1));let u=e("--within"),m=e("--role"),w=o("--exact"),f=o("--first"),$=e("--min-y"),_=e("--max-y"),q=e("--min-x"),H=e("--max-x");for(let[R,A]of[["--min-y",$],["--max-y",_],["--min-x",q],["--max-x",H]])A!==null&&!Number.isFinite(Number(A))&&(console.error(` ${R} requires a number, got: ${A}`),process.exit(1));let U=s.indexOf("--near"),M=null;if(U>=0){let R=Number(s[U+1]),A=Number(s[U+2]);(!Number.isFinite(R)||!Number.isFinite(A))&&(console.error(" --near requires two numbers: --near <x> <y>"),process.exit(1)),M={x:R,y:A}}let y=JSON.stringify({query:t,exact:w,role:m,within:u,minX:q!==null?Number(q):null,maxX:H!==null?Number(H):null,minY:$!==null?Number($):null,maxY:_!==null?Number(_):null,near:M,nth:r,first:f}),p=await c.send({type:"evaluate",code:`(async () => {
241
274
  const t = window.__sootsimTest
242
275
  if (!t) return { error: 'bridge-not-ready' }
243
- const F = ${b}
276
+ const F = ${y}
244
277
 
245
278
  const res = await t.queryTextCandidates({
246
279
  query: F.query,
@@ -357,7 +390,7 @@ ${o}
357
390
  total,
358
391
  idx,
359
392
  }
360
- })()`});if(p?.error==="bridge-not-ready"&&(console.error(" sootsim test bridge not ready"),process.exit(1)),p?.ambiguous){let R=p.candidates;console.error(` ambiguous: ${p.total} matches for "${t}"`);for(let A of R){let be=A.abs?`@(${Math.round(A.abs.x)},${Math.round(A.abs.y)})`:"",le=A.layout?` ${A.layout.width}x${A.layout.height}`:"",Lt=A.testID?` #${A.testID}`:"",Jt=A.text?` "${A.text}"`:"",Wt=A.ancestorTestIDs.length>0?` within ${A.ancestorTestIDs.slice(0,3).map(qt=>`#${qt}`).join(" > ")}`:"";console.error(` [${A.idx}] <${A.type}>${Jt}${Lt} ${be}${le}${Wt}`)}p.total>R.length&&console.error(` ... and ${p.total-R.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)}p?.nthOutOfRange&&(console.error(` not found: nth ${p.nth} of ${p.total} match${p.total===1?"":"es"} for "${t}"`),process.exit(1)),(!p||typeof p.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1));let P=await c.send({type:"tap",x:p.cx,y:p.cy,target:{id:p.target?.id??null,testID:p.target?.testID??null,text:t,type:p.target?.type??null}});if(P?.hit!==!1&&P?.ok!==!1){let R=_e(t,{id:p.target?.id??null,testID:p.target?.testID??null,type:p.target?.type??null,cx:p.cx,cy:p.cy},"text");await L("inspect tap-text",R.step,R.summary)}console.log(JSON.stringify({matched:p.match,tapped:{nodeId:p.target?.nodeId??null,id:p.target?.id??null,testID:p.target?.testID??null,type:p.target?.type??null,cx:p.cx,cy:p.cy},...p.strategy&&p.strategy!=="matched-node"?{strategy:p.strategy}:{},...p.total>1||r!==null?{nth:{index:p.idx,total:p.total}}:{},result:P},null,2));break}case"tap-best":{let t=a[1];t||(console.error(v("tap-best","<query>")),process.exit(1));let e=JSON.stringify(t),o=await c.send({type:"evaluate",code:`(async () => {
393
+ })()`});if(p?.error==="bridge-not-ready"&&(console.error(" sootsim test bridge not ready"),process.exit(1)),p?.ambiguous){let R=p.candidates;console.error(` ambiguous: ${p.total} matches for "${t}"`);for(let A of R){let we=A.abs?`@(${Math.round(A.abs.x)},${Math.round(A.abs.y)})`:"",le=A.layout?` ${A.layout.width}x${A.layout.height}`:"",Jt=A.testID?` #${A.testID}`:"",Wt=A.text?` "${A.text}"`:"",qt=A.ancestorTestIDs.length>0?` within ${A.ancestorTestIDs.slice(0,3).map(Ht=>`#${Ht}`).join(" > ")}`:"";console.error(` [${A.idx}] <${A.type}>${Wt}${Jt} ${we}${le}${qt}`)}p.total>R.length&&console.error(` ... and ${p.total-R.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)}p?.nthOutOfRange&&(console.error(` not found: nth ${p.nth} of ${p.total} match${p.total===1?"":"es"} for "${t}"`),process.exit(1)),(!p||typeof p.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1));let P=await c.send({type:"tap",x:p.cx,y:p.cy,target:{id:p.target?.id??null,testID:p.target?.testID??null,text:t,type:p.target?.type??null}});if(P?.hit!==!1&&P?.ok!==!1){let R=_e(t,{id:p.target?.id??null,testID:p.target?.testID??null,type:p.target?.type??null,cx:p.cx,cy:p.cy},"text");await L("inspect tap-text",R.step,R.summary)}console.log(JSON.stringify({matched:p.match,tapped:{nodeId:p.target?.nodeId??null,id:p.target?.id??null,testID:p.target?.testID??null,type:p.target?.type??null,cx:p.cx,cy:p.cy},...p.strategy&&p.strategy!=="matched-node"?{strategy:p.strategy}:{},...p.total>1||r!==null?{nth:{index:p.idx,total:p.total}}:{},result:P},null,2));break}case"tap-best":{let t=i[1];t||(console.error(v("tap-best","<query>")),process.exit(1));let e=JSON.stringify(t),o=await c.send({type:"evaluate",code:`(async () => {
361
394
  const t = window.__sootsimTest
362
395
  if (!t) return { error: 'bridge-not-ready' }
363
396
  // try testID first \u2014 strongest signal of "this is the
@@ -398,7 +431,7 @@ ${o}
398
431
  }
399
432
  }
400
433
  return { strategy: 'none' }
401
- })()`});"error"in o&&(console.error(` ${o.error}`),process.exit(1)),o.strategy==="none"&&(console.error(` tap-best: no testID or visible text matched "${t}". try \`sootsim find --interactive-targets\` to list candidates.`),process.exit(1));let n=o.node,r=n.absolutePosition.x+n.layout.width/2,u=n.absolutePosition.y+n.layout.height/2,m=await c.send({type:"tap",x:r,y:u,target:{id:n.id,testID:n.testID,text:o.strategy==="text"?t:null,type:n.type}});if(m?.hit!==!1&&m?.ok!==!1){let w=_e(t,{id:n.id,testID:n.testID,type:n.type,cx:r,cy:u},o.strategy==="testid"?"id":"text");await L("inspect tap-best",w.step,w.summary)}console.log(JSON.stringify({matched:{strategy:o.strategy,nodeId:n.nodeId,id:n.id,testID:n.testID,type:n.type,text:n.text},tapped:{cx:r,cy:u},result:m},null,2));break}case"tap-id":{let t=a[1];t||(console.error(v("tap-id","<id>")),process.exit(1));let e=JSON.stringify(t),o=await c.send({type:"evaluate",code:`(async () => {
434
+ })()`});"error"in o&&(console.error(` ${o.error}`),process.exit(1)),o.strategy==="none"&&(console.error(` tap-best: no testID or visible text matched "${t}". try \`sootsim find --interactive-targets\` to list candidates.`),process.exit(1));let n=o.node,r=n.absolutePosition.x+n.layout.width/2,u=n.absolutePosition.y+n.layout.height/2,m=await c.send({type:"tap",x:r,y:u,target:{id:n.id,testID:n.testID,text:o.strategy==="text"?t:null,type:n.type}});if(m?.hit!==!1&&m?.ok!==!1){let w=_e(t,{id:n.id,testID:n.testID,type:n.type,cx:r,cy:u},o.strategy==="testid"?"id":"text");await L("inspect tap-best",w.step,w.summary)}console.log(JSON.stringify({matched:{strategy:o.strategy,nodeId:n.nodeId,id:n.id,testID:n.testID,type:n.type,text:n.text},tapped:{cx:r,cy:u},result:m},null,2));break}case"tap-id":{let t=i[1];t||(console.error(v("tap-id","<id>")),process.exit(1));let e=JSON.stringify(t),o=await c.send({type:"evaluate",code:`(async () => {
402
435
  const t = window.__sootsimTest
403
436
  if (!t) return null
404
437
  const n = (await t.findByTestId(${e})) || (await t.findById(${e}))
@@ -440,7 +473,7 @@ ${o}
440
473
  },
441
474
  strategy: (resolved && resolved.strategy) || 'matched-node',
442
475
  }
443
- })()`});(!o||typeof o.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1));let n=await c.send({type:"tap",x:o.cx,y:o.cy,target:{id:o.target?.id??o.match?.id??null,testID:o.target?.testID??o.match?.testID??null,text:o.target?.text??o.target?.accessibilityLabel??o.match?.text??o.match?.accessibilityLabel??null,type:o.target?.type??o.match?.type??null}});if(n?.hit!==!1&&n?.ok!==!1){let r=_e(t,{id:o.target?.id??null,testID:o.target?.testID??null,type:o.target?.type??null,cx:o.cx,cy:o.cy},"id");await L("inspect tap-id",r.step,r.summary)}console.log(JSON.stringify({matched:o.match,tapped:{nodeId:o.target?.nodeId??null,id:o.target?.id??null,testID:o.target?.testID??null,type:o.target?.type??null,cx:o.cx,cy:o.cy},...o.strategy&&o.strategy!=="matched-node"?{strategy:o.strategy}:{},result:n},null,2));break}case"type-into":{let t=a[1],e=a.slice(2).join(" ");(!t||!e)&&(console.error(v("type-into","<id> <text>")),process.exit(1));let o=JSON.stringify(t),n=await c.send({type:"evaluate",code:`(async () => {
476
+ })()`});(!o||typeof o.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1));let n=await c.send({type:"tap",x:o.cx,y:o.cy,target:{id:o.target?.id??o.match?.id??null,testID:o.target?.testID??o.match?.testID??null,text:o.target?.text??o.target?.accessibilityLabel??o.match?.text??o.match?.accessibilityLabel??null,type:o.target?.type??o.match?.type??null}});if(n?.hit!==!1&&n?.ok!==!1){let r=_e(t,{id:o.target?.id??null,testID:o.target?.testID??null,type:o.target?.type??null,cx:o.cx,cy:o.cy},"id");await L("inspect tap-id",r.step,r.summary)}console.log(JSON.stringify({matched:o.match,tapped:{nodeId:o.target?.nodeId??null,id:o.target?.id??null,testID:o.target?.testID??null,type:o.target?.type??null,cx:o.cx,cy:o.cy},...o.strategy&&o.strategy!=="matched-node"?{strategy:o.strategy}:{},result:n},null,2));break}case"type-into":{let t=i[1],e=i.slice(2).join(" ");(!t||!e)&&(console.error(v("type-into","<id> <text>")),process.exit(1));let o=JSON.stringify(t),n=await c.send({type:"evaluate",code:`(async () => {
444
477
  const t = window.__sootsimTest
445
478
  if (!t) return null
446
479
  const n = await (t.findByTestId(${o}) || t.findById(${o}))
@@ -454,7 +487,7 @@ ${o}
454
487
  isTextInput: !!n.isTextInput,
455
488
  placeholder: n.placeholder || null,
456
489
  }
457
- })()`});(!n||typeof n.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1)),n.isTextInput||console.error(` warning: ${t} is not a text input (isTextInput: false)`);let r=await c.send({type:"tap",x:n.cx,y:n.cy,target:{id:n.id??t,testID:n.testID??t,text:null,type:n.type??null}}),u=await fo(c);u.visible||(console.error(` keyboard did not open after tapping ${t}`),process.exit(1));let m=u.focusedInput;m&&(m.testID===t||m.id===t||(console.error(` focus routing mismatch after tap: requested ${JSON.stringify(t)} but focus is on ${JSON.stringify(m.testID??m.id??null)}. did the tap land on an outer Pressable wrapper?`),process.exit(1))),await c.send({type:"keyboard",action:"type",text:e}),await L("inspect type-into",{tapOn:{id:t},inputText:e},`type-into #${t} ${JSON.stringify(e)}`),console.log(JSON.stringify({target:t,isTextInput:n.isTextInput,keyboardOpened:u.visible??r?.keyboardOpened??!1,focusedInput:u.focusedInput??null,typed:e},null,2));break}case"type":{let t=a.slice(1).join(" ");t||(console.error(v("type","<text>")),process.exit(1)),await ge(c,"type"),await c.send({type:"keyboard",action:"type",text:t}),await L("inspect type",{inputText:t},`type ${JSON.stringify(t)}`),console.log(` typed: ${JSON.stringify(t)}`);break}case"key":{let t=a[1];t||(console.error(v("key","<name>")),process.exit(1)),await ge(c,"key"),await c.send({type:"keyboard",action:"press",text:t}),await L("inspect key",{pressKey:t},`key ${t}`),console.log(` pressed: ${t}`);break}case"key-sequence":{let t=a.slice(1);t.length===0&&(console.error(v("key-sequence","<key> [<key> ...]")),process.exit(1)),await ge(c,"key-sequence");for(let e of t)await c.send({type:"keyboard",action:"press",text:e});await L("inspect key-sequence",{pressKey:t.join(" ")},`key-sequence ${t.join(" ")}`),console.log(` pressed: ${t.join(", ")}`);break}case"keycode":{let t=a.slice(1);t.length===0&&(console.error(v("keycode","<code> [<code> ...]")),process.exit(1));let e=t.map(n=>({code:n,key:go(n)})),o=e.filter(n=>!n.key);o.length>0&&(console.error(` unsupported keycode(s): ${o.map(n=>n.code).join(", ")}`),process.exit(1)),await ge(c,"keycode");for(let n of e)await c.send({type:"keyboard",action:"press",text:n.key});await L("inspect keycode",{pressKey:e.map(n=>n.key).join(" ")},`keycode ${t.join(" ")}`),console.log(` pressed: ${t.join(", ")}`);break}case"dispatch":{let t=a[1];t||(console.error(v("dispatch","<char>")),process.exit(1)),await c.send({type:"keyboard",action:"dispatchKey",text:t}),await L("inspect dispatch",{dispatchKey:t},`dispatch ${JSON.stringify(t)}`),console.log(` dispatched: ${t}`);break}case"dismiss":{await c.send({type:"keyboard",action:"dismiss"}),await L("inspect dismiss",{hideKeyboard:!0},"dismiss keyboard"),console.log(" keyboard dismissed");break}case"double-tap":{let t=Number(a[1]),e=Number(a[2]),o=ae(s);if(o){let m=await me(c,o);m||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=m.x,e=m.y}let n=a[3]?Number(a[3]):80;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n))&&(console.error(v("double-tap","<x> <y> [gapMs] | --testid <id>")),process.exit(1));let r=Math.max(0,Math.round(n)),u=await c.send({type:"evaluate",code:`(async () => {
490
+ })()`});(!n||typeof n.cx!="number")&&(console.error(` not found: ${t}`),process.exit(1)),n.isTextInput||console.error(` warning: ${t} is not a text input (isTextInput: false)`);let r=await c.send({type:"tap",x:n.cx,y:n.cy,target:{id:n.id??t,testID:n.testID??t,text:null,type:n.type??null}}),u=await go(c);u.visible||(console.error(` keyboard did not open after tapping ${t}`),process.exit(1));let m=u.focusedInput;m&&(m.testID===t||m.id===t||(console.error(` focus routing mismatch after tap: requested ${JSON.stringify(t)} but focus is on ${JSON.stringify(m.testID??m.id??null)}. did the tap land on an outer Pressable wrapper?`),process.exit(1))),await c.send({type:"keyboard",action:"type",text:e}),await L("inspect type-into",{tapOn:{id:t},inputText:e},`type-into #${t} ${JSON.stringify(e)}`),console.log(JSON.stringify({target:t,isTextInput:n.isTextInput,keyboardOpened:u.visible??r?.keyboardOpened??!1,focusedInput:u.focusedInput??null,typed:e},null,2));break}case"type":{let t=i.slice(1).join(" ");t||(console.error(v("type","<text>")),process.exit(1)),await ye(c,"type"),await c.send({type:"keyboard",action:"type",text:t}),await L("inspect type",{inputText:t},`type ${JSON.stringify(t)}`),console.log(` typed: ${JSON.stringify(t)}`);break}case"key":{let t=i[1];t||(console.error(v("key","<name>")),process.exit(1)),await ye(c,"key"),await c.send({type:"keyboard",action:"press",text:t}),await L("inspect key",{pressKey:t},`key ${t}`),console.log(` pressed: ${t}`);break}case"key-sequence":{let t=i.slice(1);t.length===0&&(console.error(v("key-sequence","<key> [<key> ...]")),process.exit(1)),await ye(c,"key-sequence");for(let e of t)await c.send({type:"keyboard",action:"press",text:e});await L("inspect key-sequence",{pressKey:t.join(" ")},`key-sequence ${t.join(" ")}`),console.log(` pressed: ${t.join(", ")}`);break}case"keycode":{let t=i.slice(1);t.length===0&&(console.error(v("keycode","<code> [<code> ...]")),process.exit(1));let e=t.map(n=>({code:n,key:yo(n)})),o=e.filter(n=>!n.key);o.length>0&&(console.error(` unsupported keycode(s): ${o.map(n=>n.code).join(", ")}`),process.exit(1)),await ye(c,"keycode");for(let n of e)await c.send({type:"keyboard",action:"press",text:n.key});await L("inspect keycode",{pressKey:e.map(n=>n.key).join(" ")},`keycode ${t.join(" ")}`),console.log(` pressed: ${t.join(", ")}`);break}case"dispatch":{let t=i[1];t||(console.error(v("dispatch","<char>")),process.exit(1)),await c.send({type:"keyboard",action:"dispatchKey",text:t}),await L("inspect dispatch",{dispatchKey:t},`dispatch ${JSON.stringify(t)}`),console.log(` dispatched: ${t}`);break}case"dismiss":{await c.send({type:"keyboard",action:"dismiss"}),await L("inspect dismiss",{hideKeyboard:!0},"dismiss keyboard"),console.log(" keyboard dismissed");break}case"double-tap":{let t=Number(i[1]),e=Number(i[2]),o=ae(s);if(o){let m=await pe(c,o);m||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=m.x,e=m.y}let n=i[3]?Number(i[3]):80;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n))&&(console.error(v("double-tap","<x> <y> [gapMs] | --testid <id>")),process.exit(1));let r=Math.max(0,Math.round(n)),u=await c.send({type:"evaluate",code:`(async () => {
458
491
  const interact = window.__sootsimInteract
459
492
  if (interact?.doubleTap) {
460
493
  return {
@@ -477,18 +510,18 @@ ${o}
477
510
  first,
478
511
  second,
479
512
  }
480
- })()`});u?.ok&&await L("inspect double-tap",{doubleTapAtCoords:{x:t,y:e,gapMs:r}},`double-tap @${t},${e}`),console.log(JSON.stringify(u,null,2));break}case"long-press":{let t=Number(a[1]),e=Number(a[2]),o=ae(s);if(o){let u=await me(c,o);u||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=u.x,e=u.y}let n=a[3]?Number(a[3]):600;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n))&&(console.error(v("long-press","<x> <y> [durationMs] | --testid <id>")),process.exit(1));let r=await c.send({type:"evaluate",code:`(async () => {
513
+ })()`});u?.ok&&await L("inspect double-tap",{doubleTapAtCoords:{x:t,y:e,gapMs:r}},`double-tap @${t},${e}`),console.log(JSON.stringify(u,null,2));break}case"long-press":{let t=Number(i[1]),e=Number(i[2]),o=ae(s);if(o){let u=await pe(c,o);u||(console.error(` not found: ${o.value}`),o.mode==="testid"&&G("wait-selector-for-missing-testid",o.value),process.exit(1)),t=u.x,e=u.y}let n=i[3]?Number(i[3]):600;(!Number.isFinite(t)||!Number.isFinite(e)||!Number.isFinite(n))&&(console.error(v("long-press","<x> <y> [durationMs] | --testid <id>")),process.exit(1));let r=await c.send({type:"evaluate",code:`(async () => {
481
514
  const interact = window.__sootsimInteract
482
515
  if (!interact?.longPress) return { ok: false, reason: 'no interact.longPress' }
483
516
  const value = await interact.longPress(${t}, ${e}, ${Math.max(0,Math.round(n))})
484
517
  return { ok: !!value, value }
485
- })()`});r?.ok&&await L("inspect long-press",{tapAtCoords:{x:t,y:e}},`long-press @${t},${e}`),console.log(JSON.stringify(r,null,2));break}case"touch":{let t=a[1],e=Number(a[2]),o=Number(a[3]),n=a[4]?Number(a[4]):999,r=t==="down"?"touchDown":t==="move"?"touchMove":t==="up"?"touchUp":t==="cancel"?"touchCancel":null;r||(console.error(v("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1)),t!=="cancel"&&(!Number.isFinite(e)||!Number.isFinite(o))&&(console.error(v("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1));let u=t==="down"?"tap":t==="move"?"move":null,m=u&&Number.isFinite(e)&&Number.isFinite(o)?`window.dispatchEvent(new CustomEvent('sootsim:agentAction', { detail: { type: '${u}', x: ${e}, y: ${o} } }));`:"",w=await c.send({type:"evaluate",code:`(async () => {
518
+ })()`});r?.ok&&await L("inspect long-press",{tapAtCoords:{x:t,y:e}},`long-press @${t},${e}`),console.log(JSON.stringify(r,null,2));break}case"touch":{let t=i[1],e=Number(i[2]),o=Number(i[3]),n=i[4]?Number(i[4]):999,r=t==="down"?"touchDown":t==="move"?"touchMove":t==="up"?"touchUp":t==="cancel"?"touchCancel":null;r||(console.error(v("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1)),t!=="cancel"&&(!Number.isFinite(e)||!Number.isFinite(o))&&(console.error(v("touch","<down|move|up|cancel> <x> <y> [pointerId]")),process.exit(1));let u=t==="down"?"tap":t==="move"?"move":null,m=u&&Number.isFinite(e)&&Number.isFinite(o)?`window.dispatchEvent(new CustomEvent('sootsim:agentAction', { detail: { type: '${u}', x: ${e}, y: ${o} } }));`:"",w=await c.send({type:"evaluate",code:`(async () => {
486
519
  ${m}
487
520
  const interact = window.__sootsimInteract
488
521
  if (!interact?.${r}) return { ok: false, reason: 'no interact.${r}' }
489
522
  const value = ${t==="cancel"?`await interact.${r}(${Math.max(1,Math.round(n))})`:`await interact.${r}(${e}, ${o}, ${Math.max(1,Math.round(n))})`}
490
523
  return { ok: !!value, value }
491
- })()`});w?.ok&&t!=="cancel"&&await L("inspect touch",{tapAtCoords:{x:e,y:o}},`touch ${t} @${e},${o}`),console.log(JSON.stringify(w,null,2));break}case"gesture":{let t=["scroll-up","scroll-down","scroll-left","scroll-right","swipe-from-left-edge","swipe-from-right-edge","swipe-from-top-edge","swipe-from-bottom-edge"],e=a[1],o=a[2]?Number(a[2]):220;(!e||!Number.isFinite(o))&&(console.error(v("gesture","<preset> [durationMs]")),console.error(` presets: ${t.join(", ")}`),process.exit(1)),t.includes(e)||(console.error(` unknown gesture preset: ${e}`),console.error(` presets: ${t.join(", ")}`),process.exit(1));let n=await c.send({type:"evaluate",code:`(async () => {
524
+ })()`});w?.ok&&t!=="cancel"&&await L("inspect touch",{tapAtCoords:{x:e,y:o}},`touch ${t} @${e},${o}`),console.log(JSON.stringify(w,null,2));break}case"gesture":{let t=["scroll-up","scroll-down","scroll-left","scroll-right","swipe-from-left-edge","swipe-from-right-edge","swipe-from-top-edge","swipe-from-bottom-edge"],e=i[1],o=i[2]?Number(i[2]):220;(!e||!Number.isFinite(o))&&(console.error(v("gesture","<preset> [durationMs]")),console.error(` presets: ${t.join(", ")}`),process.exit(1)),t.includes(e)||(console.error(` unknown gesture preset: ${e}`),console.error(` presets: ${t.join(", ")}`),process.exit(1));let n=await c.send({type:"evaluate",code:`(async () => {
492
525
  const spec = globalThis.__sootsimDeviceSpec || {}
493
526
  return {
494
527
  width: spec.width || window.innerWidth || 393,
@@ -496,12 +529,12 @@ ${o}
496
529
  statusBarHeight: spec.statusBarHeight || 0,
497
530
  homeIndicatorHeight: spec.homeIndicatorHeight || 0,
498
531
  }
499
- })()`}),r=Number(n?.width)||393,u=Number(n?.height)||852,m=Number(n?.statusBarHeight)||0,w=Number(n?.homeIndicatorHeight)||0,g=Math.round(r/2),$=Math.round(u/2),F=Math.max(24,m+18),q=Math.max(24,w+18),H=18,U=Math.min(220,Math.round(u*.24)),I=Math.min(180,Math.round(r*.32)),b=g,p=$,P=g,R=$;switch(e){case"scroll-up":p=$+Math.round(U/2),R=$-Math.round(U/2);break;case"scroll-down":p=$-Math.round(U/2),R=$+Math.round(U/2);break;case"scroll-left":b=g+Math.round(I/2),P=g-Math.round(I/2);break;case"scroll-right":b=g-Math.round(I/2),P=g+Math.round(I/2);break;case"swipe-from-left-edge":b=H,p=$,P=Math.min(r-H,H+I);break;case"swipe-from-right-edge":b=r-H,p=$,P=Math.max(H,r-H-I);break;case"swipe-from-top-edge":b=g,p=F,R=Math.min(u-q,F+U);break;case"swipe-from-bottom-edge":b=g,p=u-q,R=Math.max(F,u-q-U);break}let A=Math.max(8,Math.round(o/16)),be=Math.max(1,Math.round(o/A)),le=await c.send({type:"evaluate",code:`(async () => {
532
+ })()`}),r=Number(n?.width)||393,u=Number(n?.height)||852,m=Number(n?.statusBarHeight)||0,w=Number(n?.homeIndicatorHeight)||0,f=Math.round(r/2),$=Math.round(u/2),_=Math.max(24,m+18),q=Math.max(24,w+18),H=18,U=Math.min(220,Math.round(u*.24)),M=Math.min(180,Math.round(r*.32)),y=f,p=$,P=f,R=$;switch(e){case"scroll-up":p=$+Math.round(U/2),R=$-Math.round(U/2);break;case"scroll-down":p=$-Math.round(U/2),R=$+Math.round(U/2);break;case"scroll-left":y=f+Math.round(M/2),P=f-Math.round(M/2);break;case"scroll-right":y=f-Math.round(M/2),P=f+Math.round(M/2);break;case"swipe-from-left-edge":y=H,p=$,P=Math.min(r-H,H+M);break;case"swipe-from-right-edge":y=r-H,p=$,P=Math.max(H,r-H-M);break;case"swipe-from-top-edge":y=f,p=_,R=Math.min(u-q,_+U);break;case"swipe-from-bottom-edge":y=f,p=u-q,R=Math.max(_,u-q-U);break}let A=Math.max(8,Math.round(o/16)),we=Math.max(1,Math.round(o/A)),le=await c.send({type:"evaluate",code:`(async () => {
500
533
  const interact = window.__sootsimInteract
501
534
  if (!interact?.drag) return { ok: false, reason: 'no interact.drag' }
502
- const value = await interact.drag(${b}, ${p}, ${P}, ${R}, ${A}, ${be})
535
+ const value = await interact.drag(${y}, ${p}, ${P}, ${R}, ${A}, ${we})
503
536
  return { ok: !!value, value }
504
- })()`});le?.ok&&await L("inspect gesture",{swipe:{start:`${b}, ${p}`,end:`${P}, ${R}`,duration:Math.max(1,Math.round(o))}},`gesture ${e}`),console.log(JSON.stringify({preset:e,from:{x:b,y:p},to:{x:P,y:R},result:le},null,2));break}case"scroll":{let t=ae(s),e=ho(s),o=t?.mode==="testid"?t.value:e==null?a[1]:null,n=t||e!=null?1:2,r=Number(a[n]),u=Number(a[n+1]);(!o&&e==null||!Number.isFinite(r)||!Number.isFinite(u))&&(console.error(v("scroll","<id> <x> <y> | --testid <id> <x> <y> | --node-id <nodeId> <x> <y>")),process.exit(1));let m=await c.send({type:"evaluate",code:`(async () => {
537
+ })()`});le?.ok&&await L("inspect gesture",{swipe:{start:`${y}, ${p}`,end:`${P}, ${R}`,duration:Math.max(1,Math.round(o))}},`gesture ${e}`),console.log(JSON.stringify({preset:e,from:{x:y,y:p},to:{x:P,y:R},result:le},null,2));break}case"scroll":{let t=ae(s),e=bo(s),o=t?.mode==="testid"?t.value:e==null?i[1]:null,n=t||e!=null?1:2,r=Number(i[n]),u=Number(i[n+1]);(!o&&e==null||!Number.isFinite(r)||!Number.isFinite(u))&&(console.error(v("scroll","<id> <x> <y> | --testid <id> <x> <y> | --node-id <nodeId> <x> <y>")),process.exit(1));let m=await c.send({type:"evaluate",code:`(async () => {
505
538
  const t = window.__sootsimTest
506
539
  if (!t) return null
507
540
  const n = ${e!=null?`await t.inspectByNodeId(${JSON.stringify(e)})`:`await t.findByTestId(${JSON.stringify(o)})
@@ -511,11 +544,11 @@ ${o}
511
544
  cx: n.absolutePosition.x + (n.layout.width || 0) / 2,
512
545
  cy: n.absolutePosition.y + (n.layout.height || 0) / 2,
513
546
  }
514
- })()`}),w=await z(c,"scrollTo",e!=null?{nodeId:e}:o,r,u,!1);if(w?.ok){let g=e!=null?`node ${e}`:`#${o}`;await L("inspect scroll",{scrollTo:{...e!=null?{nodeId:e}:{id:o},x:r,y:u}},`scroll ${g} -> ${r},${u}`)}console.log(JSON.stringify({...w,...m?{at:{x:m.cx,y:m.cy}}:{}},null,2));break}case"state":{let t=a[1];if(i==="get"&&!t){let o=await z(c,"getRuntimeState"),n=await c.send({type:"evaluate",code:`({
547
+ })()`}),w=await z(c,"scrollTo",e!=null?{nodeId:e}:o,r,u,!1);if(w?.ok){let f=e!=null?`node ${e}`:`#${o}`;await L("inspect scroll",{scrollTo:{...e!=null?{nodeId:e}:{id:o},x:r,y:u}},`scroll ${f} -> ${r},${u}`)}console.log(JSON.stringify({...w,...m?{at:{x:m.cx,y:m.cy}}:{}},null,2));break}case"state":{let t=i[1];if(a==="get"&&!t){let o=await z(c,"getRuntimeState"),n=await c.send({type:"evaluate",code:`({
515
548
  errors: window.__sootsimConsole?.getErrors?.()?.length ?? 0,
516
549
  warnings: window.__sootsimConsole?.getWarnings?.()?.length ?? 0,
517
550
  })`});if(o&&typeof o=="object"&&o.diagnostics&&(o.diagnostics.errors=n?.errors??0,o.diagnostics.warnings=n?.warnings??0),o&&typeof o=="object"&&o.shell==null)try{let r=await se(c);r&&(o.shell=r)}catch{}console.log(JSON.stringify(o,null,2));break}if(!t||t==="--help"||t==="-h"){console.log(`
518
- ${h("state")} \u2014 dump raw runtime state
551
+ ${b("state")} \u2014 dump raw runtime state
519
552
 
520
553
  subcommands:
521
554
  shell dump shell transition/layout state
@@ -529,15 +562,15 @@ ${o}
529
562
  gesture <x> <y> dump gesture routing/debug info at coordinates
530
563
 
531
564
  examples:
532
- ${h("state")} shell
533
- ${h("state")} worker
534
- ${h("state")} keyboard
535
- ${h("state")} ownership
536
- ${h("state")} node photos
537
- ${h("state")} scroll feed
538
- ${h("state")} scroll-hit 360 420
539
- ${h("state")} hit 200 720
540
- `);break}let e;switch(t){case"shell":e=await se(c,500);break;case"worker":e=await $e(c,"__sootsimRenderHost.queryStats");break;case"ownership":e=await c.send({type:"evaluate",code:`(() => {
565
+ ${b("state")} shell
566
+ ${b("state")} worker
567
+ ${b("state")} keyboard
568
+ ${b("state")} ownership
569
+ ${b("state")} node photos
570
+ ${b("state")} scroll feed
571
+ ${b("state")} scroll-hit 360 420
572
+ ${b("state")} hit 200 720
573
+ `);break}let e;switch(t){case"shell":e=await se(c,500);break;case"worker":e=await Se(c,"__sootsimRenderHost.queryStats");break;case"ownership":e=await c.send({type:"evaluate",code:`(() => {
541
574
  const h = window.__sootsimRenderHost
542
575
  if (!h || typeof h.getOwnershipSnapshot !== 'function') {
543
576
  return { error: 'getOwnershipSnapshot not available' }
@@ -568,8 +601,8 @@ ${o}
568
601
  text: focused.text || null,
569
602
  } : null,
570
603
  }
571
- })()`});break;case"node":{let o=a[2];o||(console.error(` usage: ${h("state")} node <id>`),process.exit(1)),e=await z(c,"findByTestId",o)||await z(c,"findById",o);break}case"scroll":{let o=a[2];o||(console.error(` usage: ${h("state")} scroll <id>`),process.exit(1)),e=await z(c,"getScrollState",o);break}case"scroll-hit":{let o=Number(a[2]),n=Number(a[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${h("state")} scroll-hit <x> <y>`),process.exit(1)),e=await z(c,"getScrollStateAt",o,n);break}case"hit":{let o=Number(a[2]),n=Number(a[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${h("state")} hit <x> <y>`),process.exit(1)),e=await z(c,"debugHitAt",o,n);break}case"gesture":{let o=Number(a[2]),n=Number(a[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${h("state")} gesture <x> <y>`),process.exit(1)),e=await z(c,"debugGestureAt",o,n);break}default:console.error(` unknown state subcommand: ${t}`),process.exit(1)}console.log(JSON.stringify(e,null,2));break}case"shell":{let t=a[1];if(!t||t==="--help"||t==="-h"){console.log(`
572
- ${h("shell")} \u2014 run built-in shell commands
604
+ })()`});break;case"node":{let o=i[2];o||(console.error(` usage: ${b("state")} node <id>`),process.exit(1)),e=await z(c,"findByTestId",o)||await z(c,"findById",o);break}case"scroll":{let o=i[2];o||(console.error(` usage: ${b("state")} scroll <id>`),process.exit(1)),e=await z(c,"getScrollState",o);break}case"scroll-hit":{let o=Number(i[2]),n=Number(i[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${b("state")} scroll-hit <x> <y>`),process.exit(1)),e=await z(c,"getScrollStateAt",o,n);break}case"hit":{let o=Number(i[2]),n=Number(i[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${b("state")} hit <x> <y>`),process.exit(1)),e=await z(c,"debugHitAt",o,n);break}case"gesture":{let o=Number(i[2]),n=Number(i[3]);(!Number.isFinite(o)||!Number.isFinite(n))&&(console.error(` usage: ${b("state")} gesture <x> <y>`),process.exit(1)),e=await z(c,"debugGestureAt",o,n);break}default:console.error(` unknown state subcommand: ${t}`),process.exit(1)}console.log(JSON.stringify(e,null,2));break}case"shell":{let t=i[1];if(!t||t==="--help"||t==="-h"){console.log(`
605
+ ${b("shell")} \u2014 run built-in shell commands
573
606
 
574
607
  subcommands:
575
608
  launch <appId> [waitMs] [--clear-state]
@@ -584,15 +617,15 @@ ${o}
584
617
  shake trigger the simulator shake gesture
585
618
 
586
619
  examples:
587
- ${h("shell")} launch photos
588
- ${h("shell")} launch rn --clear-state
589
- ${h("shell")} launch photos 1500
590
- ${h("shell")} home 500
591
- ${h("shell")} switcher 800
592
- ${h("shell")} open-card clock 800
593
- ${h("shell")} appearance dark
594
- ${h("shell")} lock
595
- `);break}let e=t==="launch"||t==="open-card"||t==="home"||t==="switcher",o=t==="launch"||t==="open-card"?a[3]:a[2],n=o?Number(o):350;e&&(!Number.isFinite(n)||n<0)&&(console.error(v("shell",t==="launch"||t==="open-card"?"<launch|open-card> <appId> [settleMs]":"<home|switcher> [settleMs]")),process.exit(1));let r=!1,u=!1,m=null,w=s.includes("--clear-state");if(t==="launch"){let g=a[2];g||(console.error(v("shell","launch <appId> [settleMs] [--clear-state]")),process.exit(1)),w&&await c.send({type:"evaluate",code:Be}),r=!!await re(c,"launchApp",n,g),{settled:u,state:m}=await fe(c,Math.round(n),$=>!!$&&$.state==="app"&&$.activeApp===g&&$.showSwitcher===!1&&$.switcherPhase==="idle"&&typeof $.launchProgress=="number"&&$.launchProgress>=.98),r&&await L("inspect shell launch",w?{launchApp:{clearState:!0}}:{launchApp:{}},w?"launch app (clear state)":"launch app")}else if(t==="home")r=!!await re(c,"goHome",n),{settled:u,state:m}=await fe(c,Math.round(n),g=>!!g&&g.state==="home"&&g.activeApp==null&&g.showSwitcher===!1&&g.switcherPhase==="idle"&&typeof g.launchProgress=="number"&&g.launchProgress>=.98);else if(t==="switcher")r=!!await re(c,"openSwitcher",n),{settled:u,state:m}=await fe(c,Math.round(n),g=>!!g&&g.state==="app"&&g.showSwitcher===!0&&g.switcherPhase==="idle"&&typeof g.zoomLevel=="number"&&Math.abs(g.zoomLevel)<=.02&&typeof g.horizontalZoom=="number"&&Math.abs(g.horizontalZoom)<=.02),u&&(await X(po),m=await se(c));else if(t==="open-card"){let g=a[2];g||(console.error(v("shell","open-card <appId> [settleMs]")),process.exit(1)),r=!!await re(c,"openSwitcherCard",n,g),{settled:u,state:m}=await fe(c,Math.round(n),$=>!!$&&$.state==="app"&&$.activeApp===g&&$.showSwitcher===!1&&$.switcherPhase==="idle"&&typeof $.zoomLevel=="number"&&$.zoomLevel>=.98&&typeof $.horizontalZoom=="number"&&$.horizontalZoom>=.98),r&&await L("inspect shell open-card",{openSwitcherCard:{appId:g}},`open switcher card ${g}`)}else if(t==="appearance"){let g=a[2];(!g||!["light","dark","auto","toggle"].includes(g))&&(console.error(v("shell","appearance <light|dark|auto|toggle>")),process.exit(1));let $=await Dt(c,"appearance",g);if(r=!!$?.ok,m={appearance:$},r){let F=$?.applied??g;console.log(` appearance: ${F}`)}}else if(t==="lock"||t==="shake"){let g=await Dt(c,t);r=!!g?.ok,m={[t]:g}}else console.error(` unknown shell subcommand: ${t}`),process.exit(1);console.log(JSON.stringify({ok:r,settled:u,state:m},null,2));break}case"url":{await Tt(c,{args:l});break}case"reload":{let o=!1,n=!1;try{await c.send({type:"evaluate",code:"window.__sootsimConsole?.clear()"});let m=await c.send({type:"evaluate",code:`;(() => {
620
+ ${b("shell")} launch photos
621
+ ${b("shell")} launch rn --clear-state
622
+ ${b("shell")} launch photos 1500
623
+ ${b("shell")} home 500
624
+ ${b("shell")} switcher 800
625
+ ${b("shell")} open-card clock 800
626
+ ${b("shell")} appearance dark
627
+ ${b("shell")} lock
628
+ `);break}let e=t==="launch"||t==="open-card"||t==="home"||t==="switcher",o=t==="launch"||t==="open-card"?i[3]:i[2],n=o?Number(o):350;e&&(!Number.isFinite(n)||n<0)&&(console.error(v("shell",t==="launch"||t==="open-card"?"<launch|open-card> <appId> [settleMs]":"<home|switcher> [settleMs]")),process.exit(1));let r=!1,u=!1,m=null,w=s.includes("--clear-state");if(t==="launch"){let f=i[2];f||(console.error(v("shell","launch <appId> [settleMs] [--clear-state]")),process.exit(1)),w&&await c.send({type:"evaluate",code:je}),r=!!await re(c,"launchApp",n,f),{settled:u,state:m}=await ge(c,Math.round(n),$=>!!$&&$.state==="app"&&$.activeApp===f&&$.showSwitcher===!1&&$.switcherPhase==="idle"&&typeof $.launchProgress=="number"&&$.launchProgress>=.98),r&&await L("inspect shell launch",w?{launchApp:{clearState:!0}}:{launchApp:{}},w?"launch app (clear state)":"launch app")}else if(t==="home")r=!!await re(c,"goHome",n),{settled:u,state:m}=await ge(c,Math.round(n),f=>!!f&&f.state==="home"&&f.activeApp==null&&f.showSwitcher===!1&&f.switcherPhase==="idle"&&typeof f.launchProgress=="number"&&f.launchProgress>=.98);else if(t==="switcher")r=!!await re(c,"openSwitcher",n),{settled:u,state:m}=await ge(c,Math.round(n),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),u&&(await X(fo),m=await se(c));else if(t==="open-card"){let f=i[2];f||(console.error(v("shell","open-card <appId> [settleMs]")),process.exit(1)),r=!!await re(c,"openSwitcherCard",n,f),{settled:u,state:m}=await ge(c,Math.round(n),$=>!!$&&$.state==="app"&&$.activeApp===f&&$.showSwitcher===!1&&$.switcherPhase==="idle"&&typeof $.zoomLevel=="number"&&$.zoomLevel>=.98&&typeof $.horizontalZoom=="number"&&$.horizontalZoom>=.98),r&&await L("inspect shell open-card",{openSwitcherCard:{appId:f}},`open switcher card ${f}`)}else if(t==="appearance"){let f=i[2];(!f||!["light","dark","auto","toggle"].includes(f))&&(console.error(v("shell","appearance <light|dark|auto|toggle>")),process.exit(1));let $=await Ct(c,"appearance",f);if(r=!!$?.ok,m={appearance:$},r){let _=$?.applied??f;console.log(` appearance: ${_}`)}}else if(t==="lock"||t==="shake"){let f=await Ct(c,t);r=!!f?.ok,m={[t]:f}}else console.error(` unknown shell subcommand: ${t}`),process.exit(1);console.log(JSON.stringify({ok:r,settled:u,state:m},null,2));break}case"url":{await Mt(c,{args:l});break}case"reload":{let o=!1,n=!1;try{await c.send({type:"evaluate",code:"window.__sootsimConsole?.clear()"});let m=await c.send({type:"evaluate",code:`;(() => {
596
629
  const reloadExternalApp = window.SootSim?.bridges?.hotRemount?.reloadExternalApp
597
630
  if (typeof reloadExternalApp === 'function') {
598
631
  reloadExternalApp()
@@ -600,10 +633,10 @@ ${o}
600
633
  }
601
634
  window.location.reload()
602
635
  return { kind: 'page' }
603
- })()`});n=!!m&&m.kind==="external-app",o=!0}catch{}console.log(" reloading...");let r=c,u=null;if(n)u=await ke(c,{timeoutMs:1e4,errorGraceMs:3e3});else{o&&await X(300);let m=await lt(N,J,M,{timeoutMs:1e4,simIdSource:E});m?(r=m,u=await ke(m,{timeoutMs:1e4,errorGraceMs:3e3})):(console.log(" \u26A0 reload: bridge never reconnected within 10000ms"),r=null)}if(u)if(u.ready){let m=u.source==="nodes-fallback"?" (no ready signal, node-count fallback)":"";console.log(` ready in ${u.elapsedMs}ms: ${u.nodes} nodes${m}`)}else u.source==="error-bail"?console.log(` \u26A0 reload bailed after ${u.elapsedMs}ms: ${u.errors} console error(s), ready signal never fired`):console.log(` \u26A0 reload timed out after ${u.elapsedMs}ms (${u.nodes} nodes, ${u.errors} errors)`);if(r)try{let m=await r.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors(10) || []"});if(r!==c&&r.close(),Array.isArray(m)&&m.length>0){console.log(`
636
+ })()`});n=!!m&&m.kind==="external-app",o=!0}catch{}console.log(" reloading...");let r=c,u=null;if(n)u=await Te(c,{timeoutMs:1e4,errorGraceMs:3e3});else{o&&await X(300);let m=await ct(F,J,T,{timeoutMs:1e4,simIdSource:E});m?(r=m,u=await Te(m,{timeoutMs:1e4,errorGraceMs:3e3})):(console.log(" \u26A0 reload: bridge never reconnected within 10000ms"),r=null)}if(u)if(u.ready){let m=u.source==="nodes-fallback"?" (no ready signal, node-count fallback)":"";console.log(` ready in ${u.elapsedMs}ms: ${u.nodes} nodes${m}`)}else u.source==="error-bail"?console.log(` \u26A0 reload bailed after ${u.elapsedMs}ms: ${u.errors} console error(s), ready signal never fired`):console.log(` \u26A0 reload timed out after ${u.elapsedMs}ms (${u.nodes} nodes, ${u.errors} errors)`);if(r)try{let m=await r.send({type:"evaluate",code:"window.__sootsimConsole?.getErrors(10) || []"});if(r!==c&&r.close(),Array.isArray(m)&&m.length>0){console.log(`
604
637
  \u26A0 ${m.length} error(s) during mount:
605
- `);for(let w of m){let g=w.args.map($=>typeof $=="object"?JSON.stringify($):$).join(" ");if(console.log(` ${g}`),w.stack){let $=w.stack.split(`
606
- `).slice(0,2);for(let F of $)console.log(` ${F.trim()}`)}}}}catch{}u&&!u.ready&&(process.exitCode=1);break}case"eval":case"js":{let t=a.slice(1).join(" ");t||(console.error(v("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(` ${h("js")} SootSim.bridges.test.findByText("Sign in")`),console.error(` ${h("js")} SootSim.bridges.debug.snapshot("before")`),console.error(` ${h("js")} SootSim.bridges.keyboard.type("hello")`),console.error(` ${h("js")} SootSim.state.root.children.length`),process.exit(1));let e=t;e.startsWith("(async")||(e=`(async () => ${e})()`);let o=await c.send({type:"evaluate",code:e});console.log(JSON.stringify(o,null,2));let n=t.toLowerCase(),r=[];(n.includes("sootsim:gohome")||n.includes("gohome"))&&r.push("sootsim shell home"),(n.includes("sootsim:appswitcher")||n.includes("appswitcher"))&&r.push("sootsim shell switcher"),(n.includes("keyboard.isvisible")||n.includes("keyboard.getmode"))&&r.push("sootsim debug state keyboard"),n.includes("interact.tap")&&r.push("sootsim do tap <x> <y>"),n.includes("keyboard.type")&&r.push("sootsim do type <text>"),(n.includes("keyboard.press")||n.includes("keyboard.dispatchkey"))&&r.push("sootsim do key <name>"),n.includes("keyboard.dismiss")&&r.push("sootsim do dismiss"),n.includes("dumptree")&&r.push("sootsim get tree"),n.includes("dumpaccessibilitytree")&&r.push("sootsim get a11y"),n.includes("getnodecount")&&r.push("sootsim get count"),n.includes("findbytext")&&r.push("sootsim find <text>"),(n.includes("findbytestid")||n.includes("findbyid"))&&r.push("sootsim find --testid <id>"),n.includes("document.hidden")&&r.push("sootsim debug state keyboard (includes tab health)"),r.length>0&&G("prefer-cli-over-eval",r);break}case"globals":{let t=await c.send({type:"evaluate",code:`(async () => {
638
+ `);for(let w of m){let f=w.args.map($=>typeof $=="object"?JSON.stringify($):$).join(" ");if(console.log(` ${f}`),w.stack){let $=w.stack.split(`
639
+ `).slice(0,2);for(let _ of $)console.log(` ${_.trim()}`)}}}}catch{}u&&!u.ready&&(process.exitCode=1);break}case"eval":case"js":{let t=i.slice(1).join(" ");t||(console.error(v("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(` ${b("js")} SootSim.bridges.test.findByText("Sign in")`),console.error(` ${b("js")} SootSim.bridges.debug.snapshot("before")`),console.error(` ${b("js")} SootSim.bridges.keyboard.type("hello")`),console.error(` ${b("js")} SootSim.state.root.children.length`),process.exit(1));let e=t;e.startsWith("(async")||(e=`(async () => ${e})()`);let o=await c.send({type:"evaluate",code:e});console.log(JSON.stringify(o,null,2));let n=t.toLowerCase(),r=[];(n.includes("sootsim:gohome")||n.includes("gohome"))&&r.push("sootsim shell home"),(n.includes("sootsim:appswitcher")||n.includes("appswitcher"))&&r.push("sootsim shell switcher"),(n.includes("keyboard.isvisible")||n.includes("keyboard.getmode"))&&r.push("sootsim debug state keyboard"),n.includes("interact.tap")&&r.push("sootsim do tap <x> <y>"),n.includes("keyboard.type")&&r.push("sootsim do type <text>"),(n.includes("keyboard.press")||n.includes("keyboard.dispatchkey"))&&r.push("sootsim do key <name>"),n.includes("keyboard.dismiss")&&r.push("sootsim do dismiss"),n.includes("dumptree")&&r.push("sootsim get tree"),n.includes("dumpaccessibilitytree")&&r.push("sootsim get a11y"),n.includes("getnodecount")&&r.push("sootsim get count"),n.includes("findbytext")&&r.push("sootsim find <text>"),(n.includes("findbytestid")||n.includes("findbyid"))&&r.push("sootsim find --testid <id>"),n.includes("document.hidden")&&r.push("sootsim debug state keyboard (includes tab health)"),r.length>0&&G("prefer-cli-over-eval",r);break}case"globals":{let t=await c.send({type:"evaluate",code:`(async () => {
607
640
  const globals = {}
608
641
 
609
642
  // test bridge (proxy in worker mode)
@@ -641,8 +674,8 @@ ${o}
641
674
 
642
675
  return globals
643
676
  })()`});console.log(` sootsim JS API:
644
- `);for(let[e,o]of Object.entries(t)){console.log(` ${e}:`);for(let n of o)console.log(` .${n}`);console.log("")}console.log(` use: ${h("js")} <expression>`),console.log(` example: ${h("js")} test.findByText("Sign in")`);break}case"describe":{await gt({bridge:c,args:s,positional:a});break}case"perf":{let t=a[1];if(!t||t==="--help"||t==="-h"){console.log(`
645
- ${h("perf")} \u2014 performance profiling
677
+ `);for(let[e,o]of Object.entries(t)){console.log(` ${e}:`);for(let n of o)console.log(` .${n}`);console.log("")}console.log(` use: ${b("js")} <expression>`),console.log(` example: ${b("js")} test.findByText("Sign in")`);break}case"describe":{await yt({bridge:c,args:s,positional:i});break}case"perf":{let t=i[1];if(!t||t==="--help"||t==="-h"){console.log(`
678
+ ${b("perf")} \u2014 performance profiling
646
679
 
647
680
  subcommands:
648
681
  stats one-shot stats (zero overhead query)
@@ -652,11 +685,11 @@ ${o}
652
685
  transition <e> profile a shell transition (goHome, appSwitcher, lockScreen)
653
686
 
654
687
  examples:
655
- ${h("perf")} stats
656
- ${h("perf")} start
688
+ ${b("perf")} stats
689
+ ${b("perf")} start
657
690
  # ... interact with the app ...
658
- ${h("perf")} stop
659
- ${h("perf")} transition goHome
691
+ ${b("perf")} stop
692
+ ${b("perf")} transition goHome
660
693
  `);break}switch(t){case"stats":{let e=await c.send({type:"evaluate",code:`(async () => {
661
694
  // worker mode (host exposes these)
662
695
  if (window.__sootsimPerfStats) {
@@ -704,7 +737,7 @@ ${o}
704
737
  startedAt: performance.now(),
705
738
  }
706
739
  return { started: true }
707
- })()`}),console.log(` profiling started \u2014 interact with the app, then run '${h("perf")} stop'`);break}case"stop":{let e=await c.send({type:"evaluate",code:`(async () => {
740
+ })()`}),console.log(` profiling started \u2014 interact with the app, then run '${b("perf")} stop'`);break}case"stop":{let e=await c.send({type:"evaluate",code:`(async () => {
708
741
  // worker mode
709
742
  if (window.__sootsimRenderHost) {
710
743
  const session = window.${Q} || {}
@@ -799,7 +832,7 @@ ${o}
799
832
  sampleCount: recent.length,
800
833
  }
801
834
  })()`});e.error&&(console.error(` error: ${e.error}`),process.exit(1));let o=e.avgMs>0?(1e3/e.avgMs).toFixed(1):"?",n=e.sampleCount>0?(e.jankFrames/e.sampleCount*100).toFixed(1):"0";console.log(` profiling stopped:
802
- `),console.log(` frames: ${e.frames}`),console.log(` total: ${e.totalMs.toFixed(1)}ms`),console.log(` avg: ${e.avgMs.toFixed(2)}ms (${o} fps)`),console.log(` max: ${e.maxMs.toFixed(2)}ms`),console.log(""),e.layoutAvgMs!==void 0&&(console.log(" breakdown (avg per frame):"),console.log(` layout: ${e.layoutAvgMs.toFixed(2)}ms`),console.log(` render: ${e.renderAvgMs.toFixed(2)}ms`),console.log(` copy: ${e.copyAvgMs.toFixed(2)}ms`),e.auxAvgMs!==void 0&&console.log(` aux: ${e.auxAvgMs.toFixed(2)}ms`),e.otherAvgMs!==void 0&&console.log(` other: ${e.otherAvgMs.toFixed(2)}ms`),console.log("")),console.log(` distribution (${e.sampleCount} samples):`),console.log(` p50: ${e.p50.toFixed(2)}ms`),console.log(` p95: ${e.p95.toFixed(2)}ms`),console.log(` p99: ${e.p99.toFixed(2)}ms`),console.log(` jank: ${e.jankFrames} frames (${n}%) >16.67ms`);break}case"frames":{let e=a[2]?Number(a[2]):50;(!Number.isFinite(e)||e<=0)&&(console.error(` error: expected a positive frame count, got "${a[2]}"`),process.exit(1));let o=await c.send({type:"evaluate",code:`(async () => {
835
+ `),console.log(` frames: ${e.frames}`),console.log(` total: ${e.totalMs.toFixed(1)}ms`),console.log(` avg: ${e.avgMs.toFixed(2)}ms (${o} fps)`),console.log(` max: ${e.maxMs.toFixed(2)}ms`),console.log(""),e.layoutAvgMs!==void 0&&(console.log(" breakdown (avg per frame):"),console.log(` layout: ${e.layoutAvgMs.toFixed(2)}ms`),console.log(` render: ${e.renderAvgMs.toFixed(2)}ms`),console.log(` copy: ${e.copyAvgMs.toFixed(2)}ms`),e.auxAvgMs!==void 0&&console.log(` aux: ${e.auxAvgMs.toFixed(2)}ms`),e.otherAvgMs!==void 0&&console.log(` other: ${e.otherAvgMs.toFixed(2)}ms`),console.log("")),console.log(` distribution (${e.sampleCount} samples):`),console.log(` p50: ${e.p50.toFixed(2)}ms`),console.log(` p95: ${e.p95.toFixed(2)}ms`),console.log(` p99: ${e.p99.toFixed(2)}ms`),console.log(` jank: ${e.jankFrames} frames (${n}%) >16.67ms`);break}case"frames":{let e=i[2]?Number(i[2]):50;(!Number.isFinite(e)||e<=0)&&(console.error(` error: expected a positive frame count, got "${i[2]}"`),process.exit(1));let o=await c.send({type:"evaluate",code:`(async () => {
803
836
  if (window.__sootsimRenderHost) {
804
837
  const session = window.${Q} || {}
805
838
  if (session.active) {
@@ -834,7 +867,7 @@ ${o}
834
867
  mode: 'main-thread',
835
868
  frames: (stats.recentFrames || []).slice(-${e}),
836
869
  }
837
- })()`});if(o.error&&(console.error(` error: ${o.error}`),process.exit(1)),o.mode==="render-worker"){let r=Array.isArray(o.samples)?o.samples:[];if(r.length===0){console.log(` no frame data \u2014 run '${h("perf")} start' first`);break}console.log(` last ${r.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[u,m,w,g,$,F,q]of r)console.log(` ${m.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${g.toFixed(2).padStart(7)} ${$.toFixed(2).padStart(7)} ${F.toFixed(2).padStart(6)} ${q.toFixed(2).padStart(7)} ${String(u).padStart(5)}`);console.log(""),Ne(r.map(u=>u[1])),o.live&&console.log(" sampling continues");break}let n=Array.isArray(o.frames)?o.frames:Array.isArray(o)?o:[];if(n.length===0){console.log(` no frame data \u2014 run '${h("perf")} start' first`);break}console.log(` last ${n.length} frame times (ms):`),console.log(` ${n.map(r=>r.toFixed(2)).join(", ")}`),Ne(n);break}case"worst":{let e=a[2]?Number(a[2]):20;(!Number.isFinite(e)||e<=0)&&(console.error(` error: expected a positive frame count, got "${a[2]}"`),process.exit(1));let o=await c.send({type:"evaluate",code:`(async () => {
870
+ })()`});if(o.error&&(console.error(` error: ${o.error}`),process.exit(1)),o.mode==="render-worker"){let r=Array.isArray(o.samples)?o.samples:[];if(r.length===0){console.log(` no frame data \u2014 run '${b("perf")} start' first`);break}console.log(` last ${r.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[u,m,w,f,$,_,q]of r)console.log(` ${m.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${f.toFixed(2).padStart(7)} ${$.toFixed(2).padStart(7)} ${_.toFixed(2).padStart(6)} ${q.toFixed(2).padStart(7)} ${String(u).padStart(5)}`);console.log(""),Fe(r.map(u=>u[1])),o.live&&console.log(" sampling continues");break}let n=Array.isArray(o.frames)?o.frames:Array.isArray(o)?o:[];if(n.length===0){console.log(` no frame data \u2014 run '${b("perf")} start' first`);break}console.log(` last ${n.length} frame times (ms):`),console.log(` ${n.map(r=>r.toFixed(2)).join(", ")}`),Fe(n);break}case"worst":{let e=i[2]?Number(i[2]):20;(!Number.isFinite(e)||e<=0)&&(console.error(` error: expected a positive frame count, got "${i[2]}"`),process.exit(1));let o=await c.send({type:"evaluate",code:`(async () => {
838
871
  if (window.__sootsimRenderHost) {
839
872
  const session = window.${Q} || {}
840
873
  if (session.active) {
@@ -876,8 +909,8 @@ ${o}
876
909
  mode: 'main-thread',
877
910
  frames: recent.slice().sort((a, b) => b - a).slice(0, ${e}),
878
911
  }
879
- })()`});if(o.error&&(console.error(` error: ${o.error}`),process.exit(1)),o.mode==="render-worker"){let r=Array.isArray(o.samples)?o.samples:[];if(r.length===0){console.log(` no frame data \u2014 run '${h("perf")} start' first`);break}console.log(` worst ${r.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[u,m,w,g,$,F,q]of r)console.log(` ${m.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${g.toFixed(2).padStart(7)} ${$.toFixed(2).padStart(7)} ${F.toFixed(2).padStart(6)} ${q.toFixed(2).padStart(7)} ${String(u).padStart(5)}`);o.live&&(console.log(""),console.log(" sampling continues"));break}let n=Array.isArray(o.frames)?o.frames:Array.isArray(o)?o:[];if(n.length===0){console.log(` no frame data \u2014 run '${h("perf")} start' first`);break}console.log(` worst ${n.length} frame times (ms):`),console.log(` ${n.map(r=>r.toFixed(2)).join(", ")}`);break}case"transition":{let e=a[2];if(!e||!["goHome","appSwitcher","lockScreen"].includes(e)){console.log(`
880
- ${h("perf")} transition <event> \u2014 profile a shell transition
912
+ })()`});if(o.error&&(console.error(` error: ${o.error}`),process.exit(1)),o.mode==="render-worker"){let r=Array.isArray(o.samples)?o.samples:[];if(r.length===0){console.log(` no frame data \u2014 run '${b("perf")} start' first`);break}console.log(` worst ${r.length} sampled frames (ms):`),console.log(" total layout render copy aux other t+");for(let[u,m,w,f,$,_,q]of r)console.log(` ${m.toFixed(2).padStart(7)} ${w.toFixed(2).padStart(7)} ${f.toFixed(2).padStart(7)} ${$.toFixed(2).padStart(7)} ${_.toFixed(2).padStart(6)} ${q.toFixed(2).padStart(7)} ${String(u).padStart(5)}`);o.live&&(console.log(""),console.log(" sampling continues"));break}let n=Array.isArray(o.frames)?o.frames:Array.isArray(o)?o:[];if(n.length===0){console.log(` no frame data \u2014 run '${b("perf")} start' first`);break}console.log(` worst ${n.length} frame times (ms):`),console.log(` ${n.map(r=>r.toFixed(2)).join(", ")}`);break}case"transition":{let e=i[2];if(!e||!["goHome","appSwitcher","lockScreen"].includes(e)){console.log(`
913
+ ${b("perf")} transition <event> \u2014 profile a shell transition
881
914
 
882
915
  events:
883
916
  goHome swipe-to-home animation
@@ -887,8 +920,8 @@ ${o}
887
920
  note: uses 600ms capture window \u2014 may need --timeout 10000 flag
888
921
 
889
922
  examples:
890
- ${h("perf")} transition goHome --timeout 10000
891
- ${h("perf")} transition appSwitcher
923
+ ${b("perf")} transition goHome --timeout 10000
924
+ ${b("perf")} transition appSwitcher
892
925
  `);break}let n=`sootsim:${e}`;console.log(` profiling ${e} transition...`),console.log(" (use --timeout 10000 if this times out)");let r=await c.send({type:"evaluate",code:`(async () => {
893
926
  // only supported in render-worker mode
894
927
  if (!window.__sootsimRenderHost) {
@@ -966,27 +999,27 @@ ${o}
966
999
  p50: ${r.p50.toFixed(2)}ms
967
1000
  p95: ${r.p95.toFixed(2)}ms
968
1001
  p99: ${r.p99.toFixed(2)}ms
969
- jank: ${r.jankFrames} frames (${m}%) >16.67ms`),Array.isArray(r.samples)&&r.samples.length>0&&(console.log(""),Ne(r.samples.map(w=>w[1])));break}default:console.error(` unknown perf subcommand: ${t}`),process.exit(1)}break}case"errors":{let t=a[1];if(t==="clear"){await Qe(c),C(l)?B({cleared:!0}):console.log(" error buffer cleared");break}let e=t?Number(t):20,o=await Xe(c,e);if(C(l)){B(o);break}if(o.length===0){console.log(" no errors captured");break}console.log(` ${o.length} error(s):
1002
+ jank: ${r.jankFrames} frames (${m}%) >16.67ms`),Array.isArray(r.samples)&&r.samples.length>0&&(console.log(""),Fe(r.samples.map(w=>w[1])));break}default:console.error(` unknown perf subcommand: ${t}`),process.exit(1)}break}case"errors":{let t=i[1];if(t==="clear"){await Ze(c),C(l)?B({cleared:!0}):console.log(" error buffer cleared");break}let e=t?Number(t):20,o=await Ve(c,e);if(C(l)){B(o);break}if(o.length===0){console.log(" no errors captured");break}console.log(` ${o.length} error(s):
970
1003
  `);for(let n of o){let r=new Date(n.timestamp).toLocaleTimeString(),u=n.args.map(m=>typeof m=="object"?JSON.stringify(m):m).join(" ");if(console.log(` [${r}] ${u}`),n.stack){let m=n.stack.split(`
971
- `).slice(0,3);for(let w of m)console.log(` ${w.trim()}`)}}break}case"warnings":{let t=a[1]?Number(a[1]):20,e=await Ve(c,t);if(C(l)){B(e);break}if(e.length===0){console.log(" no warnings captured");break}console.log(` ${e.length} warning(s):
1004
+ `).slice(0,3);for(let w of m)console.log(` ${w.trim()}`)}}break}case"warnings":{let t=i[1]?Number(i[1]):20,e=await Qe(c,t);if(C(l)){B(e);break}if(e.length===0){console.log(" no warnings captured");break}console.log(` ${e.length} warning(s):
972
1005
  `);for(let o of e){let n=new Date(o.timestamp).toLocaleTimeString(),r=o.args.map(u=>typeof u=="object"?JSON.stringify(u):u).join(" ");console.log(` [${n}] ${r}`)}break}case"animations":{let t=await z(c,"listAnimations")??[];if(s.includes("--json")){console.log(JSON.stringify(t,null,2));break}if(t.length===0){console.log(" no active animations");break}console.log(` ${t.length} active animation(s):
973
- `);for(let e of t){let o=String(e.kind).padEnd(6),n=`${Number(e.from).toFixed(2)}\u2192${Number(e.to).toFixed(2)}`,r=Number(e.current??0).toFixed(2),u=`${Math.round((e.progress??0)*100)}%`,m=`${Math.round(e.elapsedMs??0)}ms`,w=e.loop?" loop":"",g=e.layoutBound?" layout":"";console.log(` #${e.id} ${o} ${n.padEnd(14)} cur=${r.padEnd(7)} ${u.padStart(4)} ${m}${w}${g}`)}break}case"animation":{let t=a[1];(!t||t==="--help"||t==="-h")&&(console.error(` usage: ${h("animation")} <id>`),process.exit(1));let e=Number(t);Number.isFinite(e)||(console.error(` invalid id: ${t}`),process.exit(1));let o=await z(c,"getAnimation",e);console.log(JSON.stringify(o,null,2));break}case"stop-animation":{let t=a[1];(!t||t==="--help"||t==="-h")&&(console.error(` usage: ${h("stop-animation")} <id|all>`),process.exit(1));let e=t==="all"?"all":Number(t);e!=="all"&&!Number.isFinite(e)&&(console.error(` invalid id: ${t}`),process.exit(1));let o=await z(c,"stopAnimation",e);console.log(` stopped ${o??0} animation(s)`);break}case"requests":{let t=a[1];if(t==="clear"){await et(c),C(l)?B({cleared:!0}):console.log(" request buffer cleared");break}let e=t==="all",o=e?a[2]:t,n=o?Number(o):20,r=await Ze(c,{failed:!e,limit:n});if(C(l)){B(r);break}if(r.length===0){console.log(e?" no requests captured":" no failed requests captured");break}console.log(` ${r.length} ${e?"request(s)":"failed request(s)"}:
974
- `);for(let u of r){let m=new Date(u.timestamp).toLocaleTimeString();console.log(` [${m}] ${W(u)}`),u.responseBody?console.log(` ${u.responseBody}`):u.error&&console.log(` ${u.error}`)}break}case"network":{let t=a[1],e=null,o=null,n=!1,r=!1,u=1e3,m=!1,w=!1;for(let I=0;I<l.length;I++){let b=l[I];if(b==="--filter")e=l[I+1]??null,I++;else if(b==="--limit"){let p=Number(l[I+1]);Number.isFinite(p)&&(o=p),I++}else if(b==="--threshold"){let p=Number(l[I+1]);Number.isFinite(p)&&p>0&&(u=p),I++}else b==="--failed"?n=!0:b==="--slow"?r=!0:b==="--tail"||b==="-f"?m=!0:b==="--json"&&(w=!0)}if(t==="clear"){await c.send({type:"evaluate",code:'window.__sootsimObservability?.network.clear(); "cleared"'}),console.log(" network buffer cleared");break}if(t==="get"){let I=a[2];I||(console.error(" usage: sootsim network get <id>"),process.exit(1));let b=await c.send({type:"evaluate",code:`(() => {
1006
+ `);for(let e of t){let o=String(e.kind).padEnd(6),n=`${Number(e.from).toFixed(2)}\u2192${Number(e.to).toFixed(2)}`,r=Number(e.current??0).toFixed(2),u=`${Math.round((e.progress??0)*100)}%`,m=`${Math.round(e.elapsedMs??0)}ms`,w=e.loop?" loop":"",f=e.layoutBound?" layout":"";console.log(` #${e.id} ${o} ${n.padEnd(14)} cur=${r.padEnd(7)} ${u.padStart(4)} ${m}${w}${f}`)}break}case"animation":{let t=i[1];(!t||t==="--help"||t==="-h")&&(console.error(` usage: ${b("animation")} <id>`),process.exit(1));let e=Number(t);Number.isFinite(e)||(console.error(` invalid id: ${t}`),process.exit(1));let o=await z(c,"getAnimation",e);console.log(JSON.stringify(o,null,2));break}case"stop-animation":{let t=i[1];(!t||t==="--help"||t==="-h")&&(console.error(` usage: ${b("stop-animation")} <id|all>`),process.exit(1));let e=t==="all"?"all":Number(t);e!=="all"&&!Number.isFinite(e)&&(console.error(` invalid id: ${t}`),process.exit(1));let o=await z(c,"stopAnimation",e);console.log(` stopped ${o??0} animation(s)`);break}case"requests":{let t=i[1];if(t==="clear"){await tt(c),C(l)?B({cleared:!0}):console.log(" request buffer cleared");break}let e=t==="all",o=e?i[2]:t,n=o?Number(o):20,r=await et(c,{failed:!e,limit:n});if(C(l)){B(r);break}if(r.length===0){console.log(e?" no requests captured":" no failed requests captured");break}console.log(` ${r.length} ${e?"request(s)":"failed request(s)"}:
1007
+ `);for(let u of r){let m=new Date(u.timestamp).toLocaleTimeString();console.log(` [${m}] ${W(u)}`),u.responseBody?console.log(` ${u.responseBody}`):u.error&&console.log(` ${u.error}`)}break}case"network":{let t=i[1],e=null,o=null,n=!1,r=!1,u=1e3,m=!1,w=!1;for(let M=0;M<l.length;M++){let y=l[M];if(y==="--filter")e=l[M+1]??null,M++;else if(y==="--limit"){let p=Number(l[M+1]);Number.isFinite(p)&&(o=p),M++}else if(y==="--threshold"){let p=Number(l[M+1]);Number.isFinite(p)&&p>0&&(u=p),M++}else y==="--failed"?n=!0:y==="--slow"?r=!0:y==="--tail"||y==="-f"?m=!0:y==="--json"&&(w=!0)}if(t==="clear"){await c.send({type:"evaluate",code:'window.__sootsimObservability?.network.clear(); "cleared"'}),console.log(" network buffer cleared");break}if(t==="get"){let M=i[2];M||(console.error(" usage: sootsim network get <id>"),process.exit(1));let y=await c.send({type:"evaluate",code:`(() => {
975
1008
  const obs = window.__sootsimObservability;
976
1009
  if (!obs) return null;
977
- return obs.network.getSnapshot().find(e => e.id === ${JSON.stringify(I)}) || null;
978
- })()`});b||(console.error(` no entry with id ${I}`),process.exit(1)),w?console.log(JSON.stringify(b,null,2)):co(b);break}let g=o??(m?200:t?Number(t):20);Number.isFinite(g)||(console.error(` invalid limit: ${t} \u2014 \`network\` takes a numeric count (e.g. ${h("network")} 100).
979
- to target a specific sim, use \`--sim ${t}\` instead.`),process.exit(1));let $=async()=>{let I=await c.send({type:"evaluate",code:`(() => {
1010
+ return obs.network.getSnapshot().find(e => e.id === ${JSON.stringify(M)}) || null;
1011
+ })()`});y||(console.error(` no entry with id ${M}`),process.exit(1)),w?console.log(JSON.stringify(y,null,2)):uo(y);break}let f=o??(m?200:t?Number(t):20);Number.isFinite(f)||(console.error(` invalid limit: ${t} \u2014 \`network\` takes a numeric count (e.g. ${b("network")} 100).
1012
+ to target a specific sim, use \`--sim ${t}\` instead.`),process.exit(1));let $=async()=>{let M=await c.send({type:"evaluate",code:`(() => {
980
1013
  const obs = window.__sootsimObservability;
981
1014
  if (!obs) return { ok: false };
982
1015
  return { ok: true, entries: obs.network.getSnapshot() };
983
- })()`});if(!I||!I.ok)throw new Error("observability bridge not installed \u2014 is the engine running?");return I.entries??[]},F=I=>{let b=I;if(n&&(b=b.filter(p=>!!p.error||p.status!=null&&p.status>=400)),r&&(b=b.filter(p=>p.durationMs!=null&&p.durationMs>=u)),e){let p=e.toLowerCase();b=b.filter(P=>(P.displayUrl||P.url).toLowerCase().includes(p))}return r&&!m&&(b=[...b].sort((p,P)=>(P.durationMs??0)-(p.durationMs??0))),b};if(!m){let I=await $(),b=F(I).slice(-g);if(w){console.log(JSON.stringify(b,null,2));break}if(b.length===0){I.length===0?console.log(" no network requests captured"):console.log(r?` no requests slower than ${u}ms (${I.length} total \u2014 try --threshold <ms>)`:" no matching requests");break}console.log(r?` ${b.length} request(s) slower than ${u}ms (sorted by duration desc):
984
- `:` ${b.length} request(s):
985
- `);for(let p of b)Ot(p);break}console.log(` tailing network (ctrl-c to stop)...
986
- `);let q=new Set,H=!0,U=()=>{H=!1};process.on("SIGINT",U);try{for(;H;){let I=await $(),b=F(I);for(let p of b)p.durationMs!=null&&(q.has(p.id)||(q.add(p.id),w?console.log(JSON.stringify(p)):Ot(p)));await X(250)}}finally{process.off("SIGINT",U)}break}case"logs":{let t=a[1],e=null,o=null,n=null,r=!1,u=!1,m=!1;for(let b=0;b<l.length;b++){let p=l[b];if(p==="--filter")e=l[b+1]??null,b++;else if(p==="--limit"){let P=Number(l[b+1]);Number.isFinite(P)&&(o=P),b++}else p==="--level"?(n=l[b+1]??null,b++):p==="--tail"||p==="-f"?r=!0:p==="--json"?u=!0:(p==="--internal"||p==="--all")&&(m=!0)}let w=n?new Set(n.split(",").map(b=>b.trim()).filter(b=>b==="log"||b==="info"||b==="warn"||b==="error"||b==="debug")):null;if(t==="clear"){await ot(c),console.log(" log buffer cleared");break}let g=!u&&process.stdout.isTTY===!0,$=o??(r?500:t?Number(t):50);Number.isFinite($)||(console.error(` invalid limit: ${t} \u2014 \`logs\` takes a numeric count (e.g. ${h("logs")} 100).
987
- to target a specific sim, use \`--sim ${t}\` instead.`),process.exit(1));let F=()=>tt(c),q=b=>st(b,{level:w,filter:e,showInternal:m});if(!r){let b=await F(),p=q(b).slice(-$);if(u){console.log(JSON.stringify(p,null,2));break}if(p.length===0){console.log(b.length===0?" no logs captured":" no matching logs");break}console.log(` ${p.length} log(s):
988
- `);for(let P of p)Rt(P,g);break}console.log(` tailing logs (ctrl-c to stop)...
989
- `);let H=new Set,U=!0,I=()=>{U=!1};process.on("SIGINT",I);try{for(;U;){let b=await F(),p=q(b);for(let P of p)H.has(P.id)||(H.add(P.id),u?console.log(JSON.stringify(P)):Rt(P,g));await X(250)}}finally{process.off("SIGINT",I)}break}default:console.error(` unknown subcommand: ${y}`),process.exit(1)}if(ee.has(y)&&!s.includes("--no-wait")&&process.env.SOOTSIM_NO_AUTO_WAIT!=="1"&&await x(c),!j.has(y)&&!C(l))try{await oe(c)}catch{}}catch(t){let e=t instanceof Error?t.message:String(t);console.error(` ${y??"inspect"} failed: ${e}`);let o=/^no sim connected with id (.+)$/.exec(e),n=/^command timed out after \d+s$/.test(e)||e.startsWith("sim disconnected:")||e.startsWith("bridge never reconnected")||e.startsWith("could not connect to ws://");if(o)await dt(c,N,o[1]);else if(/^no sim connected$/.test(e))ct(N);else if(n)process.stderr.write(` the sim is not responding. recover it with:
1016
+ })()`});if(!M||!M.ok)throw new Error("observability bridge not installed \u2014 is the engine running?");return M.entries??[]},_=M=>{let y=M;if(n&&(y=y.filter(p=>!!p.error||p.status!=null&&p.status>=400)),r&&(y=y.filter(p=>p.durationMs!=null&&p.durationMs>=u)),e){let p=e.toLowerCase();y=y.filter(P=>(P.displayUrl||P.url).toLowerCase().includes(p))}return r&&!m&&(y=[...y].sort((p,P)=>(P.durationMs??0)-(p.durationMs??0))),y};if(!m){let M=await $(),y=_(M).slice(-f);if(w){console.log(JSON.stringify(y,null,2));break}if(y.length===0){M.length===0?console.log(" no network requests captured"):console.log(r?` no requests slower than ${u}ms (${M.length} total \u2014 try --threshold <ms>)`:" no matching requests");break}console.log(r?` ${y.length} request(s) slower than ${u}ms (sorted by duration desc):
1017
+ `:` ${y.length} request(s):
1018
+ `);for(let p of y)Pt(p);break}console.log(` tailing network (ctrl-c to stop)...
1019
+ `);let q=new Set,H=!0,U=()=>{H=!1};process.on("SIGINT",U);try{for(;H;){let M=await $(),y=_(M);for(let p of y)p.durationMs!=null&&(q.has(p.id)||(q.add(p.id),w?console.log(JSON.stringify(p)):Pt(p)));await X(250)}}finally{process.off("SIGINT",U)}break}case"logs":{let t=i[1],e=null,o=null,n=null,r=!1,u=!1,m=!1;for(let y=0;y<l.length;y++){let p=l[y];if(p==="--filter")e=l[y+1]??null,y++;else if(p==="--limit"){let P=Number(l[y+1]);Number.isFinite(P)&&(o=P),y++}else p==="--level"?(n=l[y+1]??null,y++):p==="--tail"||p==="-f"?r=!0:p==="--json"?u=!0:(p==="--internal"||p==="--all")&&(m=!0)}let w=n?new Set(n.split(",").map(y=>y.trim()).filter(y=>y==="log"||y==="info"||y==="warn"||y==="error"||y==="debug")):null;if(t==="clear"){await st(c),console.log(" log buffer cleared");break}let f=!u&&process.stdout.isTTY===!0,$=o??(r?500:t?Number(t):50);Number.isFinite($)||(console.error(` invalid limit: ${t} \u2014 \`logs\` takes a numeric count (e.g. ${b("logs")} 100).
1020
+ to target a specific sim, use \`--sim ${t}\` instead.`),process.exit(1));let _=()=>ot(c),q=y=>nt(y,{level:w,filter:e,showInternal:m});if(!r){let y=await _(),p=q(y).slice(-$);if(u){console.log(JSON.stringify(p,null,2));break}if(p.length===0){console.log(y.length===0?" no logs captured":" no matching logs");break}console.log(` ${p.length} log(s):
1021
+ `);for(let P of p)Et(P,f);break}console.log(` tailing logs (ctrl-c to stop)...
1022
+ `);let H=new Set,U=!0,M=()=>{U=!1};process.on("SIGINT",M);try{for(;U;){let y=await _(),p=q(y);for(let P of p)H.has(P.id)||(H.add(P.id),u?console.log(JSON.stringify(P)):Et(P,f));await X(250)}}finally{process.off("SIGINT",M)}break}default:console.error(` unknown subcommand: ${h}`),process.exit(1)}if(ee.has(h)&&!s.includes("--no-wait")&&process.env.SOOTSIM_NO_AUTO_WAIT!=="1"&&await x(c),!j.has(h)&&!C(l))try{await oe(c)}catch{}}catch(t){let e=t instanceof Error?t.message:String(t);console.error(` ${h??"inspect"} failed: ${e}`);let o=/^no sim connected with id (.+)$/.exec(e),n=/^command timed out after \d+s$/.test(e)||e.startsWith("sim disconnected:")||e.startsWith("bridge never reconnected")||e.startsWith("could not connect to ws://");if(o)await ut(c,F,o[1]);else if(/^no sim connected$/.test(e))dt(F);else if(n)process.stderr.write(` the sim is not responding. recover it with:
990
1023
  sootsim close --sim <id> # force-close the wedged sim
991
1024
  sootsim list # confirm it's gone
992
- `);else{try{await je(c)}catch{}try{await O({includeTail:!0})}catch{}try{await Z({includeTail:!0})}catch{}}process.exit(1)}finally{c.close()}}export{Qs as runInspect};
1025
+ `);else{try{await Le(c)}catch{}try{await O({includeTail:!0})}catch{}try{await Z({includeTail:!0})}catch{}}process.exit(1)}finally{c.close()}}export{en as runInspect};