sootsim 0.1.188 → 0.1.190

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 (178) hide show
  1. package/README.md +9 -9
  2. package/dist-cli/bin.js +7 -7
  3. package/dist-cli/chunks/{agent-BRLC23GZ.js → agent-XZWMKC4F.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-HDWSAABN.js → agent-wrapper-CFJYDDAY.js} +2 -2
  5. package/dist-cli/chunks/{app-fonts-KQHDDWAH.js → app-fonts-64UN5GRY.js} +2 -2
  6. package/dist-cli/chunks/{assert-BA3G3DLH.js → assert-A3MQH7ZB.js} +2 -2
  7. package/dist-cli/chunks/auth-CNKNHD6U.js +10 -0
  8. package/dist-cli/chunks/beta-CDL7U2RE.js +2 -0
  9. package/dist-cli/chunks/camera-YQPIDOEN.js +20 -0
  10. package/dist-cli/chunks/{chunk-I52NHG4X.js → chunk-24OZOK2K.js} +1 -1
  11. package/dist-cli/chunks/{chunk-OXB6RPMX.js → chunk-3JVMBXLH.js} +2 -2
  12. package/dist-cli/chunks/{chunk-GAP76GG5.js → chunk-5IM3DYTZ.js} +1 -1
  13. package/dist-cli/chunks/{chunk-DBOVJCG5.js → chunk-6EFMFMJB.js} +2 -2
  14. package/dist-cli/chunks/{chunk-DKOKNFWR.js → chunk-6UQKBGI7.js} +2 -3
  15. package/dist-cli/chunks/{chunk-ERHMPVNZ.js → chunk-7TSFDDU7.js} +2 -2
  16. package/dist-cli/chunks/chunk-AAQ6AYYW.js +2 -0
  17. package/dist-cli/chunks/chunk-CD3ARXZW.js +1 -0
  18. package/dist-cli/chunks/chunk-CTP3U4WV.js +13 -0
  19. package/dist-cli/chunks/{chunk-QDUHROO5.js → chunk-CVUAT6TO.js} +1 -1
  20. package/dist-cli/chunks/chunk-DHDV2I2T.js +1 -0
  21. package/dist-cli/chunks/{chunk-TAXDBR5N.js → chunk-EBBYYBYM.js} +3 -3
  22. package/dist-cli/chunks/chunk-F6GCSGBJ.js +8 -0
  23. package/dist-cli/chunks/{chunk-HIS4TFND.js → chunk-INRO26KS.js} +2 -2
  24. package/dist-cli/chunks/{install-desktop-F43JZSJO.js → chunk-IOJDFCGV.js} +7 -7
  25. package/dist-cli/chunks/{chunk-D6GYUATH.js → chunk-ITQV76PX.js} +1 -1
  26. package/dist-cli/chunks/chunk-IUVDM73R.js +140 -0
  27. package/dist-cli/chunks/{chunk-2MRFRROI.js → chunk-K5GLQDTG.js} +2 -2
  28. package/dist-cli/chunks/{chunk-FUZNRCAR.js → chunk-K7OCH4WY.js} +2 -2
  29. package/dist-cli/chunks/{chunk-NCENLBIL.js → chunk-KLGX6B46.js} +2 -2
  30. package/dist-cli/chunks/{chunk-AUQ7FZIX.js → chunk-LRJVY7SN.js} +2 -2
  31. package/dist-cli/chunks/{chunk-2T6Z4WCN.js → chunk-MH6BMKK5.js} +1 -1
  32. package/dist-cli/chunks/{chunk-Y3I43AUV.js → chunk-MJU4XNZ3.js} +1 -1
  33. package/dist-cli/chunks/{chunk-ZZ7FODQE.js → chunk-NAI6N6SN.js} +8 -7
  34. package/dist-cli/chunks/chunk-P7MW7S62.js +87 -0
  35. package/dist-cli/chunks/chunk-PGQHNKRL.js +119 -0
  36. package/dist-cli/chunks/chunk-PR3IKD6A.js +2 -0
  37. package/dist-cli/chunks/chunk-PSETHPMH.js +565 -0
  38. package/dist-cli/chunks/{chunk-BZNPGYJQ.js → chunk-QJVITDKU.js} +1 -1
  39. package/dist-cli/chunks/{chunk-SVSZFGNA.js → chunk-QNVY6BLP.js} +1 -1
  40. package/dist-cli/chunks/{chunk-YNY3WSH4.js → chunk-R3VO3MDO.js} +1 -1
  41. package/dist-cli/chunks/{chunk-5U22ZNDP.js → chunk-SJHC6HZH.js} +1 -1
  42. package/dist-cli/chunks/{chunk-ZZTGVTE3.js → chunk-SMDCNCVZ.js} +1 -1
  43. package/dist-cli/chunks/{chunk-TPHYWQB2.js → chunk-SPYRMNAJ.js} +5 -5
  44. package/dist-cli/chunks/{chunk-B272R3FA.js → chunk-TBFBGSRV.js} +1 -1
  45. package/dist-cli/chunks/chunk-UPN7Z5XZ.js +916 -0
  46. package/dist-cli/chunks/{chunk-KOEBHC3D.js → chunk-WHYPFQIZ.js} +2 -2
  47. package/dist-cli/chunks/{chunk-NDAGMI4C.js → chunk-WR5IDCCN.js} +1 -1
  48. package/dist-cli/chunks/{chunk-BJMQRL7V.js → chunk-WT74ZUKN.js} +1 -1
  49. package/dist-cli/chunks/{chunk-5XZN2C22.js → chunk-Y6CZ5N26.js} +2 -2
  50. package/dist-cli/chunks/{chunk-IULK4TUU.js → chunk-YWQH2KQJ.js} +1 -1
  51. package/dist-cli/chunks/cli-version-PVRNMRL7.js +2 -0
  52. package/dist-cli/chunks/{compat-6QHB5UPF.js → compat-AU7EW2AY.js} +3 -3
  53. package/dist-cli/chunks/config-TNZV6ASD.js +11 -0
  54. package/dist-cli/chunks/control-TKDPQACC.js +2 -0
  55. package/dist-cli/chunks/daemon-L57B7HBL.js +2 -0
  56. package/dist-cli/chunks/{debug-OTEVKM5L.js → debug-H5UHUDC4.js} +3 -3
  57. package/dist-cli/chunks/desktop-WYPCYR3Z.js +32 -0
  58. package/dist-cli/chunks/{detox-MISIYJRV.js → detox-36VI5PZ3.js} +2 -2
  59. package/dist-cli/chunks/{device-R3BORN7B.js → device-XPSGGSM5.js} +2 -2
  60. package/dist-cli/chunks/{diagnose-G7UE2PUJ.js → diagnose-CH3VYGFO.js} +10 -10
  61. package/dist-cli/chunks/drivers-XDAXVIZF.js +2 -0
  62. package/dist-cli/chunks/flow-Q24HN25I.js +2 -0
  63. package/dist-cli/chunks/help-OPVDM7BI.js +2 -0
  64. package/dist-cli/chunks/{home-paths-EJFFLJZR.js → home-paths-IT2LCG6O.js} +2 -2
  65. package/dist-cli/chunks/inspect-FEMU6KSY.js +2 -0
  66. package/dist-cli/chunks/install-desktop-NCMJNSW7.js +2 -0
  67. package/dist-cli/chunks/{login-3ZNZJ7P4.js → login-O6XRDK26.js} +5 -5
  68. package/dist-cli/chunks/{logout-34JBFFT4.js → logout-YK7BH4AK.js} +2 -2
  69. package/dist-cli/chunks/{maestro-JYCD7OQT.js → maestro-T52UBLSK.js} +6 -6
  70. package/dist-cli/chunks/mode-L4GR563F.js +93 -0
  71. package/dist-cli/chunks/optional-demo-registry-PDFLBZMQ.js +2 -0
  72. package/dist-cli/chunks/perf-7DYLYEBO.js +43 -0
  73. package/dist-cli/chunks/{record-L54OVMQQ.js → record-MNIFB5DJ.js} +7 -7
  74. package/dist-cli/chunks/runtime-E4KWRPBT.js +2 -0
  75. package/dist-cli/chunks/screenshot-command-D77AXBND.js +190 -0
  76. package/dist-cli/chunks/{serve-D6HGTNWI.js → serve-LFPZVOVA.js} +2 -2
  77. package/dist-cli/chunks/{setup-MR7SX23V.js → setup-6FX2KQP4.js} +3 -3
  78. package/dist-cli/chunks/skills-36CRDBMN.js +48 -0
  79. package/dist-cli/chunks/storage-N45XGOMV.js +35 -0
  80. package/dist-cli/chunks/store-USJP5W6S.js +2 -0
  81. package/dist-cli/chunks/telemetry-WQ7RK6NE.js +2 -0
  82. package/dist-cli/chunks/test-GCVW3U2P.js +69 -0
  83. package/dist-cli/chunks/{timeline-SBCWQHQT.js → timeline-4ALLBESW.js} +2 -2
  84. package/dist-cli/chunks/{upgrade-RGJVNFZO.js → upgrade-75XAVSMJ.js} +2 -2
  85. package/dist-cli/chunks/upload-34BCSEFZ.js +2 -0
  86. package/dist-cli/chunks/{version-23HGJOE3.js → version-MSFDAHVF.js} +2 -2
  87. package/dist-cli/chunks/{web-YMQPB45M.js → web-IS75NWAC.js} +2 -2
  88. package/dist-cli/chunks/{what-happened-3AJBD35R.js → what-happened-TW6SN7Z7.js} +2 -2
  89. package/dist-lib/agent-daemon-client.cjs +1 -1
  90. package/dist-lib/agent-events.cjs +1 -1
  91. package/dist-lib/agent-identity.cjs +53 -0
  92. package/dist-lib/agent-sessions.cjs +1 -1
  93. package/dist-lib/attached-projects.cjs +1 -1
  94. package/dist-lib/auth/shared-session.cjs +1 -1
  95. package/dist-lib/backend-origin.cjs +1 -1
  96. package/dist-lib/beta.cjs +1 -1
  97. package/dist-lib/beta.mjs +1 -1
  98. package/dist-lib/bridge-constants.cjs +1 -1
  99. package/dist-lib/cli-constants.cjs +1 -1
  100. package/dist-lib/config.cjs +1 -1
  101. package/dist-lib/detox/index.cjs +1 -1
  102. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  103. package/dist-lib/home-paths.cjs +1 -1
  104. package/dist-lib/host/bridge-host.cjs +1 -1
  105. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  106. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  107. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  108. package/dist-lib/host/websocket-proxy.cjs +1 -1
  109. package/dist-lib/index.cjs +15 -7
  110. package/dist-lib/jump-to-source-babel.cjs +1 -1
  111. package/dist-lib/menu.cjs +1 -1
  112. package/dist-lib/menu.mjs +1 -1
  113. package/dist-lib/metro.cjs +13 -5
  114. package/dist-lib/profiles.cjs +1 -1
  115. package/dist-lib/render-mode.cjs +1 -1
  116. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  117. package/dist-lib/sdk.cjs +1 -1
  118. package/dist-lib/sdk.mjs +1 -1
  119. package/dist-lib/skills.cjs +121 -79
  120. package/dist-lib/vite.cjs +13 -5
  121. package/package.json +1 -1
  122. package/skills/{soot.md → soot/SKILL.md} +12 -25
  123. package/skills/{sootsim-debug.md → sootsim-debug/SKILL.md} +1 -1
  124. package/skills/sootsim-perf/SKILL.md +169 -0
  125. package/skills/{sootsim-test.md → sootsim-test/SKILL.md} +10 -7
  126. package/src/metro-plugin.ts +2 -2
  127. package/src/runtime-assets.ts +16 -2
  128. package/src/screenshots/orchestrate.ts +1 -1
  129. package/src/screenshots/org-deck.ts +1 -1
  130. package/src/vite-plugin-one.ts +2 -2
  131. package/dist-cli/chunks/beta-O43XI622.js +0 -2
  132. package/dist-cli/chunks/camera-22Q4QVTC.js +0 -20
  133. package/dist-cli/chunks/chunk-3ECPODR2.js +0 -382
  134. package/dist-cli/chunks/chunk-4JG6GDLB.js +0 -2
  135. package/dist-cli/chunks/chunk-5D6TXWZQ.js +0 -3
  136. package/dist-cli/chunks/chunk-6LAPS7RP.js +0 -3
  137. package/dist-cli/chunks/chunk-FHHOZTPI.js +0 -3
  138. package/dist-cli/chunks/chunk-FXHED7P5.js +0 -79
  139. package/dist-cli/chunks/chunk-HGER3AOP.js +0 -69
  140. package/dist-cli/chunks/chunk-HXEGZCLS.js +0 -118
  141. package/dist-cli/chunks/chunk-JOE4R2PO.js +0 -1
  142. package/dist-cli/chunks/chunk-MXYAGDBC.js +0 -24
  143. package/dist-cli/chunks/chunk-PCKWE63K.js +0 -987
  144. package/dist-cli/chunks/chunk-QCDWRDUC.js +0 -1
  145. package/dist-cli/chunks/chunk-SGZP6JCZ.js +0 -16
  146. package/dist-cli/chunks/chunk-V7V6WDIM.js +0 -13
  147. package/dist-cli/chunks/chunk-WST3QKHD.js +0 -180
  148. package/dist-cli/chunks/cli-version-74E3VGPF.js +0 -2
  149. package/dist-cli/chunks/control-A2KALMZE.js +0 -2
  150. package/dist-cli/chunks/cpu-profile-A3ST63G2.js +0 -2
  151. package/dist-cli/chunks/daemon-KBQK2QRU.js +0 -2
  152. package/dist-cli/chunks/drivers-4URQ5PMT.js +0 -2
  153. package/dist-cli/chunks/electron-DXMMDHR3.js +0 -19
  154. package/dist-cli/chunks/flow-OETRQOLM.js +0 -2
  155. package/dist-cli/chunks/help-FSZ5FRHV.js +0 -2
  156. package/dist-cli/chunks/hints-QJSWKWC5.js +0 -2
  157. package/dist-cli/chunks/inspect-EFTHNTN2.js +0 -2
  158. package/dist-cli/chunks/keys-P2HBCVAX.js +0 -19
  159. package/dist-cli/chunks/optional-demo-registry-MM6GWJNB.js +0 -2
  160. package/dist-cli/chunks/preview-PIEAC5MZ.js +0 -17
  161. package/dist-cli/chunks/profile-BTCKOPAU.js +0 -22
  162. package/dist-cli/chunks/react-UYKTFQZW.js +0 -30
  163. package/dist-cli/chunks/runtime-ZB7S4Z3H.js +0 -2
  164. package/dist-cli/chunks/screenshot-A5WQUFIQ.js +0 -35
  165. package/dist-cli/chunks/screenshot-mode-GBZSTZTV.js +0 -17
  166. package/dist-cli/chunks/screenshots-EHE2FKTA.js +0 -74
  167. package/dist-cli/chunks/screenshots-capture-MOZJ2RQV.js +0 -41
  168. package/dist-cli/chunks/skills-NHV2ZFOU.js +0 -48
  169. package/dist-cli/chunks/slides-WDFLQWCZ.js +0 -46
  170. package/dist-cli/chunks/store-7EYKU7RK.js +0 -2
  171. package/dist-cli/chunks/telemetry-MU23XMBJ.js +0 -2
  172. package/dist-cli/chunks/telemetry-NF6KAWA4.js +0 -2
  173. package/dist-cli/chunks/test-CVQHZHMJ.js +0 -31
  174. package/dist-cli/chunks/three-mode-UCOVUXVY.js +0 -58
  175. package/dist-cli/chunks/upload-GHIMBL2Y.js +0 -2
  176. package/dist-cli/chunks/whoami-ZM3TCPNU.js +0 -2
  177. /package/skills/{sootsim-setup.md → sootsim-setup/SKILL.md} +0 -0
  178. /package/skills/{sootsim-visual.md → sootsim-visual/SKILL.md} +0 -0
@@ -1,4 +1,4 @@
1
- /*! sootsim v0.1.188 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.190 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  import t from"node:fs";import{homedir as A}from"node:os";import o from"node:path";var E="SOOTSIM_HOME",_="active",I="daemon.json",N="dev-bridge.json",P="config.json",x=3e4;function u(){let e=process.env[E];return e&&e.length>0?o.resolve(e):o.join(A(),".sootsim")}function j(){if(process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1")return!1;let e=process.env.SOOTSIM_DEV;if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;let r=process.argv[1];if(!r)return!1;try{return t.realpathSync(r).includes(`${o.sep}packages${o.sep}sootsim${o.sep}`)}catch{return!1}}function F(){return process.env.SOOTSIM_FORCE_DAEMON_INSTALL==="1"?!1:process.env.IS_TAMAGUI_DEV==="1"}function W(){return j()||F()}function f(){return o.join(u(),"runtimes")}function w(e){return o.join(f(),e)}function k(){return o.join(f(),_)}function D(){return o.join(u(),"electron")}function X(){return o.join(D(),"userData")}function q(e){return o.join(D(),e)}function T(){return o.join(u(),"profiles")}function B(){return o.join(u(),"daemon-app")}function M(){return o.join(B(),"SootSim Daemon.app")}function z(){return o.join(M(),"Contents","MacOS","sootsim-daemon")}function C(){return o.join(u(),"cache")}function p(){return o.join(u(),I)}function m(){return o.join(u(),N)}function b(){return o.join(u(),P)}function L(){try{let e=t.readFileSync(b(),"utf8"),r=JSON.parse(e);return r&&typeof r=="object"?r:{}}catch{return{}}}function R(e){g();let r=L(),i={...r,...e};e.settings&&typeof e.settings=="object"&&(i.settings={...r.settings&&typeof r.settings=="object"?r.settings:{},...e.settings});let c=`${b()}.tmp`;return t.writeFileSync(c,`${JSON.stringify(i,null,2)}
3
3
  `,"utf8"),t.renameSync(c,b()),i}function Q(){return L().telemetry!==!1}function Z(e){R({telemetry:e})}function g(){t.mkdirSync(u(),{recursive:!0}),t.mkdirSync(f(),{recursive:!0}),t.mkdirSync(D(),{recursive:!0}),t.mkdirSync(T(),{recursive:!0}),t.mkdirSync(C(),{recursive:!0})}function $(){try{let e=t.readFileSync(k(),"utf8").trim();return e.length>0?e:null}catch{return null}}function ee(e){t.mkdirSync(f(),{recursive:!0}),t.writeFileSync(k(),`${e}
4
4
  `,"utf8")}function re(){try{return t.readdirSync(f(),{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name).sort(J)}catch{return[]}}function J(e,r){let i=s=>{let a=s.indexOf("-"),l=a>=0?s.slice(0,a):s,O=a>=0?s.slice(a+1):"",v=l.split(".").map(S=>Number.parseInt(S,10));return v.some(S=>!Number.isFinite(S))?[[Number.POSITIVE_INFINITY],s]:[v,O]},[c,n]=i(e),[h,y]=i(r);for(let s=0;s<Math.max(c.length,h.length);s++){let a=c[s]??0,l=h[s]??0;if(a!==l)return a-l}return n===y?0:n?y?n<y?-1:1:-1:1}function te(){let e=$();if(!e)return null;let r=w(e);try{if(t.statSync(r).isDirectory())return r}catch{}return null}var d=16*1024;function V(){try{let e=t.openSync(p(),"r");try{let r=Buffer.alloc(d),i=t.readSync(e,r,0,d,0),c=r.subarray(0,i).toString("utf8"),n=JSON.parse(c);return n&&n.schema===1&&typeof n.pid=="number"&&typeof n.bridgePort=="number"&&typeof n.runtimePort=="number"&&typeof n.startedAt=="number"&&typeof n.heartbeatAt=="number"?n:null}finally{t.closeSync(e)}}catch{return null}}function ne(){try{let e=t.openSync(m(),"r");try{let r=Buffer.alloc(d),i=t.readSync(e,r,0,d,0),c=r.subarray(0,i).toString("utf8"),n=JSON.parse(c);return n&&n.schema===1&&n.source==="vite-dev"&&typeof n.pid=="number"&&typeof n.bridgePort=="number"&&typeof n.runtimePort=="number"&&typeof n.cwd=="string"&&typeof n.startedAt=="number"&&typeof n.heartbeatAt=="number"&&(n.shellPort===void 0||typeof n.shellPort=="number")?n:null}finally{t.closeSync(e)}}catch{return null}}function H(e,r=Date.now()){if(!e||r-e.heartbeatAt>x)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function oe(e,r=Date.now()){if(!e||r-e.heartbeatAt>x)return!1;try{return process.kill(e.pid,0),!0}catch{return!1}}function G(e){g();let r=`${p()}.tmp`;t.writeFileSync(r,`${JSON.stringify(e,null,2)}
@@ -1,2 +1,2 @@
1
- /*! sootsim v0.1.188 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! sootsim v0.1.190 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var t="./demo-app-registry.ts",o=null;async function n(){if(o)return o;try{let r=await import(t);o=Array.isArray(r.APPS)?r.APPS:[]}catch{o=[]}return o}function e(){return o??[]}export{n as a,e as b};
@@ -1,5 +1,6 @@
1
- /*! sootsim v0.1.188 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as u,b as w}from"./chunk-B272R3FA.js";import{a as h,b as g,c as v}from"./chunk-BZNPGYJQ.js";import{a as m,c as f}from"./chunk-FHHOZTPI.js";import{c as p}from"./chunk-5U22ZNDP.js";function T(){let e=h();return e?{available:!0,reason:null,detail:e}:{available:!1,reason:"no chromium-family browser found (chrome, chromium, edge, brave, arc)"}}async function I(e){if(e.headless)return{launched:!1,message:"the chromium driver launches a visible browser window and cannot run headless \u2014 a headless `chrome --headless=new` process exits immediately and the sim never connects. for headless automation use `--driver playwright`."};let r=h();if(!r)return{launched:!1,message:"chromium not found \u2014 install chrome or run `sootsim list --drivers`"};if(!e.url)return{launched:!1,message:"chromium driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current Chrome profile"};try{let t=await v(e.url,{detached:e.detached??!0});return{launched:!0,message:`chromium launched \u2192 ${e.url}`,pid:t.pid,target:t.target??r,attachUrl:e.url}}catch(t){return{launched:!1,message:`chromium spawn failed: ${t instanceof Error?t.message:String(t)}`}}}var y={id:"chromium",name:"chromium",description:"system chrome / chromium / edge \u2014 visible window (headless: use playwright)",kind:"browser",availability:T,launch:I};function _(){let e=u();return e?{available:!0,reason:null,detail:`${e.kind} @ ${e.path}`}:{available:!1,reason:"sootsim desktop app not installed (run `sootsim install-desktop`)"}}async function M(e){let r=u();if(!r)return{launched:!1,message:"sootsim desktop app not installed"};try{let t=await w(e.url,r,{device:e.device,profileId:e.profileId,ephemeralProfile:e.ephemeralProfile});return t.launched?{launched:!0,message:e.url?`electron launched via ${t.via} \u2192 ${e.url}`:`electron launched via ${t.via}`,target:t.target,attachUrl:e.url}:{launched:!1,message:"desktop companion failed to start"}}catch(t){return{launched:!1,message:`electron launch failed: ${t instanceof Error?t.message:String(t)}`}}}var b={id:"electron",name:"electron",description:"sootsim desktop companion app (native window, menu bar)",kind:"native",availability:_,launch:M};import{spawn as C}from"child_process";import{closeSync as E,mkdtempSync as A,openSync as L,readFileSync as W}from"fs";import{createRequire as R}from"module";import{tmpdir as S}from"os";import{join as P}from"path";var N=`
1
+ /*! sootsim v0.1.190 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as m,b as I}from"./chunk-TBFBGSRV.js";import{a as w,b as T,c as _}from"./chunk-QJVITDKU.js";import{c as O}from"./chunk-SJHC6HZH.js";import{C as k,o as x,q as f}from"./chunk-MH6BMKK5.js";import h from"fs";import v from"path";var c="default",U="profiles.json",a=1;function s(e){let r=e.trim();if(!r)throw new Error("profile id is required");if(!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(r))throw new Error("profile ids must start with a letter or number and contain only letters, numbers, dot, dash, or underscore");if(r==="."||r==="..")throw new Error(`invalid profile id: ${r}`);return r}function g(){return v.join(f(),U)}function q(e){return`sootsim-profile-${s(e)}`}function H(e){return v.join(x(),"Partitions",q(e))}function y(e){return v.join(f(),"playwright",s(e))}function b(){try{let e=JSON.parse(h.readFileSync(g(),"utf8"));if(!e||e.version!==a)return{version:a,profiles:[]};let r=Array.isArray(e.profiles)?e.profiles.filter(t=>!!t&&typeof t.id=="string"&&typeof t.createdAt=="string"&&typeof t.updatedAt=="string").map(t=>({id:s(t.id),createdAt:t.createdAt,updatedAt:t.updatedAt})):[];return{version:a,profiles:r}}catch{return{version:a,profiles:[]}}}function A(e){return[...e].sort((r,t)=>r.id===c?-1:t.id===c?1:r.id.localeCompare(t.id))}function P(e){if(e.profiles.some(t=>t.id===c))return{...e,profiles:A(e.profiles)};let r=new Date().toISOString();return{version:a,profiles:A([{id:c,createdAt:r,updatedAt:r},...e.profiles])}}function S(e){k();let r=P(e),t=`${g()}.tmp`;return h.writeFileSync(t,`${JSON.stringify(r,null,2)}
3
+ `,"utf8"),h.renameSync(t,g()),r}function G(){return S(b()).profiles}function z(e){let r=s(e);return G().find(t=>t.id===r)??null}function E(e=c){let r=s(e),t=z(r);return t||B(r)}function B(e){let r=s(e),t=P(b());if(t.profiles.some(n=>n.id===r))throw new Error(`profile already exists: ${r}`);let o=new Date().toISOString(),i={id:r,createdAt:o,updatedAt:o};return S({version:a,profiles:[...t.profiles,i]}),i}function pe(e){let r=s(e);if(r===c)throw new Error("the default profile cannot be deleted; clear it instead");let t=P(b()),o=t.profiles.find(i=>i.id===r);if(!o)throw new Error(`profile not found: ${r}`);return S({version:a,profiles:t.profiles.filter(i=>i.id!==r)}),j(r),o}function j(e){let r=s(e);for(let t of[H(r),y(r)])try{h.rmSync(t,{recursive:!0,force:!0})}catch{}}function Y(){let e=w();return e?{available:!0,reason:null,detail:e}:{available:!1,reason:"no chromium-family browser found (chrome, chromium, edge, brave, arc)"}}async function K(e){if(e.headless)return{launched:!1,message:"the chromium driver launches a visible browser window and cannot run headless \u2014 a headless `chrome --headless=new` process exits immediately and the sim never connects. for headless automation use `--driver playwright`."};let r=w();if(!r)return{launched:!1,message:"chromium not found \u2014 install chrome or run `sootsim list --drivers`"};if(!e.url)return{launched:!1,message:"chromium driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current Chrome profile"};try{let t=await _(e.url,{detached:e.detached??!0});return{launched:!0,message:`chromium launched \u2192 ${e.url}`,pid:t.pid,target:t.target??r,attachUrl:e.url}}catch(t){return{launched:!1,message:`chromium spawn failed: ${t instanceof Error?t.message:String(t)}`}}}var M={id:"chromium",name:"chromium",description:"system chrome / chromium / edge \u2014 visible window (headless: use playwright)",kind:"browser",availability:Y,launch:K};function V(){let e=m();return e?{available:!0,reason:null,detail:`${e.kind} @ ${e.path}`}:{available:!1,reason:"sootsim desktop app not installed (run `sootsim desktop install`)"}}async function J(e){let r=m();if(!r)return{launched:!1,message:"sootsim desktop app not installed"};try{let t=await I(e.url,r,{device:e.device,profileId:e.profileId,ephemeralProfile:e.ephemeralProfile});return t.launched?{launched:!0,message:e.url?`electron launched via ${t.via} \u2192 ${e.url}`:`electron launched via ${t.via}`,target:t.target,attachUrl:e.url}:{launched:!1,message:"desktop companion failed to start"}}catch(t){return{launched:!1,message:`electron launch failed: ${t instanceof Error?t.message:String(t)}`}}}var L={id:"electron",name:"electron",description:"sootsim desktop companion app (native window, menu bar)",kind:"native",availability:V,launch:J};import{spawn as X}from"child_process";import{closeSync as Z,mkdtempSync as Q,openSync as ee,readFileSync as re}from"fs";import{createRequire as te}from"module";import{tmpdir as C}from"os";import{join as W}from"path";var oe=`
3
4
  const modulePath = process.env.SOOTSIM_PW_MODULE;
4
5
  const url = process.env.SOOTSIM_PW_URL;
5
6
  const headless = process.env.SOOTSIM_PW_HEADLESS === '1';
@@ -11,7 +12,7 @@ const callerUserDataDir = process.env.SOOTSIM_PW_USERDATADIR || '';
11
12
  const ownerPid = Number(process.env.SOOTSIM_PW_OWNER_PID || 0);
12
13
  const ownerPollMs = Number(process.env.SOOTSIM_PW_OWNER_POLL_MS || 5000);
13
14
  // optional CDP port \u2014 exposes Chrome's remote-debugging endpoint so a
14
- // bridge-driven sim can also be cpu-profiled (sootsim cpu-profile --cdp-port).
15
+ // bridge-driven sim can also be cpu-profiled (sootsim perf cpu --cdp-port).
15
16
  // playwright keeps its own pipe connection; the port is an additional endpoint.
16
17
  const cdpPort = process.env.SOOTSIM_PW_CDP_PORT || '';
17
18
  // browser engine: 'chromium' (default) | 'webkit' | 'firefox'. webkit is the
@@ -216,7 +217,7 @@ const cleanupProfile = () => {
216
217
  // errors with "not supported on Linux Arm64"), fall back to Playwright's
217
218
  // bundled chromium so the driver still works rather than crashing the
218
219
  // sim out entirely. set SOOTSIM_PW_CHANNEL=chrome|chromium|msedge|... to
219
- // pin the channel. NOTE: this is NOT enough to make \`sootsim cpu-profile\`
220
+ // pin the channel. NOTE: this is NOT enough to make \`sootsim perf cpu\`
220
221
  // work \u2014 that profiles the tenant *worker*, and the JS Self-Profiler API
221
222
  // cannot be constructed in a dedicated worker (see
222
223
  // worker-handlers/cpu-profile.ts). cpu-profile needs a CDP-based profiler
@@ -343,6 +344,6 @@ const cleanupProfile = () => {
343
344
  process.stderr.write(String((err && err.stack) || err) + '\\n');
344
345
  process.exit(1);
345
346
  });
346
- `;function k(){let e=[process.cwd()+"/"];try{process.argv[1]&&e.push(process.argv[1])}catch{}for(let r of e)try{let t=R(r);for(let o of["playwright","playwright-chromium","playwright-core"])try{return{spec:o,modulePath:t.resolve(o)}}catch{}}catch{}return null}function $(){let e=k();return e?{available:!0,reason:null,detail:`resolved via ${e.spec}`}:{available:!1,reason:"playwright not installed in the current workspace"}}function U(e,r){return process.platform!=="linux"||e.headless||process.env.DISPLAY||process.env.WAYLAND_DISPLAY||!/missing x server|cannot open display|x server|x11/i.test(r)?null:" hint: linux without DISPLAY/WAYLAND_DISPLAY \u2014 rerun without --headed (or add --headless) to run playwright headless."}function F(e){return e.profileId?m(f(e.profileId).id):e.ephemeralProfile?A(P(S(),"sootsim-playwright-profile-")):""}async function q(e){let r=k();if(!r)return{launched:!1,message:"playwright not installed \u2014 run `bun add -D playwright` first"};if(!e.url)return{launched:!1,message:"playwright driver requires a target url"};let t=P(S(),`sootsim-playwright-host-${Date.now().toString(36)}-${process.pid}.log`),o=`${t}.connected`,a=L(t,"a");try{let n=p(),c=C(process.execPath,["-e",N],{detached:!0,stdio:["ignore","ignore",a],env:{...process.env,SOOTSIM_PW_MODULE:r.modulePath,SOOTSIM_PW_URL:e.url,SOOTSIM_PW_HEADLESS:e.headless??!0?"1":"0",SOOTSIM_PW_USERDATADIR:F(e),SOOTSIM_PW_CDP_PORT:e.cdpPort?String(e.cdpPort):"",SOOTSIM_PW_BROWSER:e.browser??"",SOOTSIM_PW_VIEWPORT:e.viewport?`${e.viewport.width}x${e.viewport.height}`:"",SOOTSIM_PW_CONNECTED_ACK_FILE:o,SOOTSIM_PW_CONNECT_TIMEOUT_MS:String(e.connectTimeoutMs??12e4),SOOTSIM_PW_OWNER_PID:n&&n>1?String(n):""}});c.unref();let d=await new Promise(i=>{let l=setTimeout(()=>i(null),4e3);c.once("exit",x=>{clearTimeout(l),i(x??0)})});if(d!==null){let i=W(t,"utf8").trim(),l=U(e,i);return{launched:!1,message:`playwright host exited early (code ${d}) \u2014 host log ${t}${i?`:
347
- ${i}`:""}${l?`
348
- ${l}`:""}`}}return{launched:!0,message:`playwright chrome launched \u2192 ${e.url}`,pid:c.pid,target:r.spec,attachUrl:e.url,connectAckFile:o,diagnosticLogPath:t}}catch(n){return{launched:!1,message:`playwright launch failed: ${n instanceof Error?n.message:String(n)}`}}finally{E(a)}}var D={id:"playwright",name:"playwright",description:"programmatic chromium via the playwright package \u2014 headless default",kind:"automation",availability:$,launch:q};function H(){return process.platform!=="darwin"&&process.platform!=="linux"&&process.platform!=="win32"?{available:!1,reason:`unsupported platform: ${process.platform}`}:{available:!0,reason:null,detail:process.platform==="darwin"?"open(1)":process.platform==="win32"?"cmd /c start":"xdg-open(1)"}}async function G(e){if(e.headless)return{launched:!1,message:"system driver does not support --headless; use chromium or playwright"};if(!e.url)return{launched:!1,message:"system driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current browser profile"};try{let r=await g(e.url,{detached:e.detached??!0,newWindow:e.newWindow});return{launched:!0,message:`${r.via} launch \u2192 ${e.url}`,pid:r.pid,target:r.target,attachUrl:e.url}}catch(r){return{launched:!1,message:`system launch failed: ${r instanceof Error?r.message:String(r)}`}}}var O={id:"system",name:"system",description:"shared browser launcher \u2014 system default or chromium window",kind:"delegate",availability:H,launch:G};var s=[y,b,D,O];function le(){return s}function ce(e){return s.find(r=>r.id===e)??null}function ue(e,r){if(e)return s.find(o=>o.id===e)??null;for(let t of r){let o=s.find(a=>a.id===t);if(o&&o.availability().available)return o}return null}function he(){return s.map(e=>{let r=e.availability();return{id:e.id,name:e.name,kind:e.kind,description:e.description,available:r.available,reason:r.reason,detail:r.detail??null}})}export{y as a,b,D as c,O as d,s as e,le as f,ce as g,ue as h,he as i};
347
+ `;function R(){let e=[process.cwd()+"/"];try{process.argv[1]&&e.push(process.argv[1])}catch{}for(let r of e)try{let t=te(r);for(let o of["playwright","playwright-chromium","playwright-core"])try{return{spec:o,modulePath:t.resolve(o)}}catch{}}catch{}return null}function ie(){let e=R();return e?{available:!0,reason:null,detail:`resolved via ${e.spec}`}:{available:!1,reason:"playwright not installed in the current workspace"}}function ne(e,r){return process.platform!=="linux"||e.headless||process.env.DISPLAY||process.env.WAYLAND_DISPLAY||!/missing x server|cannot open display|x server|x11/i.test(r)?null:" hint: linux without DISPLAY/WAYLAND_DISPLAY \u2014 rerun without --headed (or add --headless) to run playwright headless."}function se(e){return e.profileId?y(E(e.profileId).id):e.ephemeralProfile?Q(W(C(),"sootsim-playwright-profile-")):""}async function ae(e){let r=R();if(!r)return{launched:!1,message:"playwright not installed \u2014 run `bun add -D playwright` first"};if(!e.url)return{launched:!1,message:"playwright driver requires a target url"};let t=W(C(),`sootsim-playwright-host-${Date.now().toString(36)}-${process.pid}.log`),o=`${t}.connected`,i=ee(t,"a");try{let n=O(),p=X(process.execPath,["-e",oe],{detached:!0,stdio:["ignore","ignore",i],env:{...process.env,SOOTSIM_PW_MODULE:r.modulePath,SOOTSIM_PW_URL:e.url,SOOTSIM_PW_HEADLESS:e.headless??!0?"1":"0",SOOTSIM_PW_USERDATADIR:se(e),SOOTSIM_PW_CDP_PORT:e.cdpPort?String(e.cdpPort):"",SOOTSIM_PW_BROWSER:e.browser??"",SOOTSIM_PW_VIEWPORT:e.viewport?`${e.viewport.width}x${e.viewport.height}`:"",SOOTSIM_PW_CONNECTED_ACK_FILE:o,SOOTSIM_PW_CONNECT_TIMEOUT_MS:String(e.connectTimeoutMs??12e4),SOOTSIM_PW_OWNER_PID:n&&n>1?String(n):""}});p.unref();let D=await new Promise(l=>{let d=setTimeout(()=>l(null),4e3);p.once("exit",F=>{clearTimeout(d),l(F??0)})});if(D!==null){let l=re(t,"utf8").trim(),d=ne(e,l);return{launched:!1,message:`playwright host exited early (code ${D}) \u2014 host log ${t}${l?`:
348
+ ${l}`:""}${d?`
349
+ ${d}`:""}`}}return{launched:!0,message:`playwright chrome launched \u2192 ${e.url}`,pid:p.pid,target:r.spec,attachUrl:e.url,connectAckFile:o,diagnosticLogPath:t}}catch(n){return{launched:!1,message:`playwright launch failed: ${n instanceof Error?n.message:String(n)}`}}finally{Z(i)}}var N={id:"playwright",name:"playwright",description:"programmatic chromium via the playwright package \u2014 headless default",kind:"automation",availability:ie,launch:ae};function le(){return process.platform!=="darwin"&&process.platform!=="linux"&&process.platform!=="win32"?{available:!1,reason:`unsupported platform: ${process.platform}`}:{available:!0,reason:null,detail:process.platform==="darwin"?"open(1)":process.platform==="win32"?"cmd /c start":"xdg-open(1)"}}async function ce(e){if(e.headless)return{launched:!1,message:"system driver does not support --headless; use chromium or playwright"};if(!e.url)return{launched:!1,message:"system driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current browser profile"};try{let r=await T(e.url,{detached:e.detached??!0,newWindow:e.newWindow});return{launched:!0,message:`${r.via} launch \u2192 ${e.url}`,pid:r.pid,target:r.target,attachUrl:e.url}}catch(r){return{launched:!1,message:`system launch failed: ${r instanceof Error?r.message:String(r)}`}}}var $={id:"system",name:"system",description:"shared browser launcher \u2014 system default or chromium window",kind:"delegate",availability:le,launch:ce};var u=[M,L,N,$];function Le(){return u}function Ce(e){return u.find(r=>r.id===e)??null}function We(e,r){if(e)return u.find(o=>o.id===e)??null;for(let t of r){let o=u.find(i=>i.id===t);if(o&&o.availability().available)return o}return null}function Re(){return u.map(e=>{let r=e.availability();return{id:e.id,name:e.name,kind:e.kind,description:e.description,available:r.available,reason:r.reason,detail:r.detail??null}})}export{G as a,E as b,B as c,pe as d,j as e,M as f,L as g,N as h,$ as i,u as j,Le as k,Ce as l,We as m,Re as n};
@@ -0,0 +1,87 @@
1
+ /*! sootsim v0.1.190 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
+ import{a as ve,b as Te,c as Se}from"./chunk-AAQ6AYYW.js";import{c as he}from"./chunk-R3VO3MDO.js";import{d as ge}from"./chunk-WR5IDCCN.js";import{g as ye,i as be,k as x}from"./chunk-Y6CZ5N26.js";import{d as we}from"./chunk-QJVITDKU.js";import{a as me,b as S}from"./chunk-KLGX6B46.js";import{a as fe}from"./chunk-K5GLQDTG.js";import{createHash as rt}from"crypto";import{readFileSync as te}from"fs";import{gzipSync as Ue}from"zlib";function xe(e){let t=(e||"").toLowerCase().split(";")[0].trim();return t?!(t.startsWith("image/")||t.startsWith("video/")||t.startsWith("audio/")||t==="font/woff2"||t==="application/font-woff2"||t==="application/zip"||t==="application/gzip"):!0}import{brotliCompressSync as Ke,constants as je}from"node:zlib";var Ge=9;function Ie(e){return Ke(e,{params:{[je.BROTLI_PARAM_QUALITY]:Ge}})}function ee(e,t){let r=new AbortController,s=setTimeout(()=>r.abort(new Error(`${t} timed out after ${e/1e3}s`)),e);return{signal:r.signal,cancel:()=>clearTimeout(s)}}async function Ye(e){let t=ee(12e4,`PUT ${e.url}`),r;try{r=await fetch(e.url,{method:"PUT",headers:{"content-type":e.contentType},body:e.bytes,signal:t.signal})}finally{t.cancel()}if(!r.ok){let s=await r.text().catch(()=>"");throw new Error(`PUT ${e.url} failed ${r.status}: ${s.slice(0,200)}`)}}async function Qe(e,t=8,r){let s=0,i=0,a=e.length;await Promise.all(Array.from({length:Math.min(t,a)},async()=>{for(;s<a;){let c=e[s++];await Ye(c),i++,r?.(i,a)}}))}function Xe(e,t,r,s){let i=[];i.push({url:e.bundle.putUrl,contentType:e.bundle.contentType,bytes:t});for(let a of e.files){let c=r.get(a.urlhash);c&&i.push({url:a.putUrl,contentType:a.contentType,bytes:c})}e.events&&s?.eventsBytes&&i.push({url:e.events.putUrl,contentType:e.events.contentType,bytes:s.eventsBytes}),e.timeline&&s?.timelineBytes&&i.push({url:e.timeline.putUrl,contentType:e.timeline.contentType,bytes:s.timelineBytes}),e.flowVideo&&s?.videoBytes&&i.push({url:e.flowVideo.putUrl,contentType:e.flowVideo.contentType,bytes:s.videoBytes}),e.storage&&s?.storageBytes&&i.push({url:e.storage.putUrl,contentType:e.storage.contentType,bytes:s.storageBytes});for(let a of e.snapshots??[]){let c=s?.snapshotBytes?.get(a.id);c&&i.push({url:a.putUrl,contentType:a.contentType,bytes:c})}return i}function Ze(e){return e.replace(/\/+$/,"")}var N=class extends Error{constructor(r,s,i,a=""){super(r);this.status=s;this.phase=i;this.responseText=a;this.name="PresignedUploadError"}};async function Me(e){let t=Ze(e.originBase),r={"content-type":"application/json"};e.authHeader&&(r.authorization=e.authHeader),e.adminBypassToken&&(r["x-soot-admin-upload-bypass"]=e.adminBypassToken);let s=ee(3e4,"init"),i;try{i=await fetch(`${t}/api/preview/upload/init`,{method:"POST",headers:r,body:JSON.stringify(e.initBody),signal:s.signal})}finally{s.cancel()}if(!i.ok){let y=await i.text().catch(()=>"");throw new N(`init failed: ${i.status} ${y.slice(0,200)}`,i.status,"init",y)}let a=await i.json(),c=Xe(a,e.bundleBytes,e.filesByHash,e.extras);await Qe(c,e.concurrency??8,e.onPutProgress);let h=ee(3e4,"finalize"),p;try{p=await fetch(`${t}/api/preview/upload/finalize`,{method:"POST",headers:r,body:JSON.stringify({token:a.token}),signal:h.signal})}finally{h.cancel()}if(!p.ok){let y=await p.text().catch(()=>"");throw new N(`finalize failed: ${p.status} ${y.slice(0,200)}`,p.status,"finalize",y)}let _=await p.json();return{init:a,finalize:_}}function et(e){return e!==null&&typeof e=="object"?e:null}function Re(e){return typeof e=="number"&&Number.isFinite(e)?e:void 0}function Ee(e){let t=et(e);return t?t.schemaVersion===1&&Re(t.t)!==void 0&&Re(t.seq)!==void 0&&typeof t.context=="string"&&typeof t.kind=="string"&&"data"in t:!1}function ot(e){if(!e)return null;try{let t=JSON.parse(e);return typeof t.message=="string"&&t.message?t.message:null}catch{return null}}var ke=process.env.SOOTSIM_UPLOAD_ORIGIN||"https://sootbean.com",$e=process.env.SOOTSIM_PREVIEW_ORIGIN||"https://sootsim.com",re="http://localhost:3000",st=2e3;async function it(e){if(e)return e;if(process.env.SOOTSIM_UPLOAD_ORIGIN)return process.env.SOOTSIM_UPLOAD_ORIGIN;try{let t=await fetch(`${re}/api/preview/upload/init`,{method:"OPTIONS",signal:AbortSignal.timeout(st)});if(t.ok||t.status===204||t.status===405)return re}catch{}return ke}function B(e){return e.replace(/\/$/,"")}function at(e){try{let r=new URL(e).hostname.replace(/^\[|\]$/g,"").toLowerCase();return r==="localhost"||r.endsWith(".localhost")||r==="0.0.0.0"||r==="::1"||/^127(?:\.\d{1,3}){3}$/.test(r)}catch{return!1}}function lt(e){try{let t=new URL(e).hostname.toLowerCase();return t==="sootbean.com"||t.endsWith(".sootbean.com")}catch{return!1}}function ut(e,t){return t?B(t):process.env.SOOTSIM_PREVIEW_ORIGIN?B(process.env.SOOTSIM_PREVIEW_ORIGIN):at(e)?B(e):lt(e)?B($e):B(e)}function ct(){console.log(`
3
+ sootsim record upload \u2014 publish the current recorded bundle as a /preview/<id> link
4
+
5
+ usage:
6
+ sootsim record upload [--origin <url>] [--public-origin <url>] (--events <path> | --video <path>) [--screenshot <path>] [--owner <org> --repo <repo>] [--sim <sim>] [--open] [--assets-only]
7
+
8
+ options:
9
+ --origin <url> upload target (default: auto)
10
+ prefers ${re} when available, otherwise
11
+ falls back to ${ke}
12
+ override with SOOTSIM_UPLOAD_ORIGIN env var
13
+ --public-origin <url>
14
+ public /preview link origin (default: ${$e}
15
+ for prod uploads, upload origin for localhost/custom origins).
16
+ override with SOOTSIM_PREVIEW_ORIGIN env var
17
+ --events <path> path to a gzipped events .jsonl.gz file to attach
18
+ required unless --video is present; previews must
19
+ have replay or recording playback data
20
+ --screenshot <path>
21
+ path to a PNG thumbnail to attach to the share
22
+ --video <path> path to a mp4/gif flow recording. embedded inline
23
+ in the pr sticky comment served at
24
+ /api/preview/flow-video?id=<share-id>
25
+ --video-duration-ms <ms>
26
+ duration hint for attached flow video
27
+ --owner <org> associate a session upload with a linked org repo
28
+ --repo <repo> repo name for --owner; the signed-in user must belong
29
+ to the local/org team that owns the link
30
+ --billing-kind test_run
31
+ meter this upload as a natural-language test run
32
+ --sim <sim> target a specific sim (see: sootsim list)
33
+ --open open the resulting /preview/<id> url in the browser
34
+ --assets-only drop API/JSON/HTML records before upload; keep images,
35
+ fonts, css, js, and binary blobs. live-data demos hit
36
+ the real network at replay time instead of serving
37
+ recorded API snapshots
38
+ -h, --help
39
+
40
+ examples:
41
+ sootsim record upload --events ./my-session.jsonl.gz
42
+ sootsim record upload --origin http://localhost:3000 --events ./my-session.jsonl.gz --open
43
+ sootsim record upload --video /tmp/soot-flow.mp4 --video-duration-ms 12000
44
+ `)}function d(e,t){let r=e.findIndex(i=>i===t);if(r<0)return;let s=e[r+1];return e.splice(r,2),s}function Be(e,t){let r=e.findIndex(s=>s===t);return r<0?!1:(e.splice(r,1),!0)}function Pe(e,t){if(!e)return;let r=Number(e);return(!Number.isFinite(r)||r<=0)&&(console.error(` invalid ${t}: ${e}`),process.exit(1)),Math.round(r)}function Ae(e){let t=(e||"").toLowerCase().split(";")[0].trim();return t?!!(t.startsWith("image/")||t.startsWith("font/")||t.startsWith("video/")||t.startsWith("audio/")||t.startsWith("model/")||t==="text/css"||t==="application/javascript"||t==="text/javascript"||t==="application/wasm"||t==="application/font-woff"||t==="application/font-woff2"||t==="application/octet-stream"):!1}async function _e(e){let t=await fetch(e);if(!t.ok)throw new Error(`fetch ${e} -> ${t.status} ${t.statusText}`);return new Uint8Array(await t.arrayBuffer())}function dt(e){return/\.bundle($|\?)/.test(e)||/\.js($|\?)/.test(e)?"application/javascript":/\.zip($|\?)/.test(e)?"application/zip":"application/javascript"}function pt(e){try{return new URL(e).searchParams.get("appFonts")||""}catch{return""}}function ft(e){try{return new URL(e).searchParams.get("appSplash")||""}catch{return""}}function mt(e){try{let t=new URL(e);return t.searchParams.get("lazy")==="true"?(t.searchParams.set("lazy","false"),t.toString()):e}catch{return e}}async function gt(e,t){let s=[];for(let i=0;i<t;i+=15e5){let a=Math.min(i+15e5,t),c=await x(e,`(window.__sootsimLastTransformedBundle?.text || "").slice(${i}, ${a})`);if(typeof c!="string")return null;s.push(c)}return s.join("")}function ht(e){return e.recordedDurationMs&&e.recordingStartedAtMs?{since:e.recordingStartedAtMs-1e4,until:e.recordingStartedAtMs+e.recordedDurationMs+5e3,limit:2e3}:{limit:2e3}}function ne(e){let t=new Map;for(let r of e)t.set(r.urlhash||r.url,r);return Array.from(t.values())}async function Ft(e,t){(e.includes("--help")||e.includes("-h"))&&(ct(),process.exit(0));let r=[...e],s=await it(d(r,"--origin")),i=ut(s,d(r,"--public-origin")),a=d(r,"--events"),c=d(r,"--screenshot"),h=d(r,"--video"),p=d(r,"--video-duration-ms"),_=Pe(d(r,"--recorded-duration-ms"),"--recorded-duration-ms"),y=Pe(d(r,"--recording-started-at-ms"),"--recording-started-at-ms"),z=d(r,"--owner"),D=d(r,"--repo"),k=d(r,"--billing-kind"),Le=Be(r,"--open");(z&&!D||!z&&D)&&(console.error(" --owner and --repo must be provided together"),process.exit(1)),k&&k!=="test_run"&&(console.error(` invalid --billing-kind: ${k}`),process.exit(1)),!a&&!h&&(console.error(" preview uploads require playback data: pass --events or --video.\n for a normal local preview, use `sootsim record --mode combined --open`\n or `sootsim flow --preview` instead of uploading a bundle-only snapshot."),process.exit(1));let oe=Be(r,"--assets-only"),Oe=ye(r,{stripBooleanFlags:[],stripValueFlags:[]}),b=be(Oe),u,se=[],w=[],$=[],H=null;try{if(u=await x(b,'(typeof window.__sootsimCaptureBundle === "function") ? window.__sootsimCaptureBundle() : null'),u?.bundleUrl){let l=new URL(u.bundleUrl).origin,[Y,Q]=await Promise.all([x(b,`(window.__sootsimPreviewRecorder?.list?.(${JSON.stringify(l)}) || [])`),x(b,`(async () => {
45
+ const list = window.__sootsimListWorkerFetchRecorder
46
+ return typeof list === 'function'
47
+ ? await list(${JSON.stringify(l)})
48
+ : []
49
+ })()`)]);se=ne([...Y,...Q]).filter(f=>{try{return!new URL(f.url).pathname.startsWith("/api/")}catch{return!0}});let U=await x(b,`(async () => {
50
+ const rec = window.__sootsimPreviewRecorder
51
+ const workerList = window.__sootsimListWorkerFetchRecorder
52
+ return {
53
+ main: rec?.list ? rec.list() : [],
54
+ worker: typeof workerList === 'function' ? await workerList() : [],
55
+ }
56
+ })()`),A=(U?ne([...U.main,...U.worker]):[]).filter(f=>{try{return new URL(f.url).origin!==l}catch{return!1}}),T=A.length>0?{count:A.length,totalBytes:A.reduce((f,X)=>f+(X.size||0),0)}:null;if(T&&T.count>0){console.log(` ${T.count} recorded cross-origin responses (${(T.totalBytes/1024).toFixed(1)} KiB)`);let f=await x(b,`(async () => {
57
+ const rec = window.__sootsimPreviewRecorder
58
+ const workerDump = window.__sootsimDumpWorkerFetchRecorder
59
+ const bundleUrl = ${JSON.stringify(u.bundleUrl)}
60
+ const keep = (r) => {
61
+ try {
62
+ const u = new URL(r.url)
63
+ if (u.origin !== ${JSON.stringify(l)}) return true
64
+ // bundle-origin api responses came from the rewritten
65
+ // /__app-api proxy at record time (re-keyed by the
66
+ // recorder's unwrap step). they need bodies attached the
67
+ // same way as cross-origin records \u2014 direct re-fetch from
68
+ // the dev server lacks the bundle's session cookies.
69
+ if (r.url !== bundleUrl && u.pathname.startsWith('/api/')) return true
70
+ return false
71
+ } catch { return false }
72
+ }
73
+ return {
74
+ main: rec?.dump ? rec.dump().filter(keep) : [],
75
+ worker: typeof workerDump === 'function'
76
+ ? (await workerDump()).filter(keep)
77
+ : [],
78
+ }
79
+ })()`);if(w=ne([...f.main,...f.worker]),oe){let X=w.length;w=w.filter(Z=>Ae(Z.contentType));let qe=T.totalBytes-w.reduce((Z,Je)=>Z+(Je.size||0),0);console.log(` --assets-only: kept ${w.length}/${X} records (dropped ${(qe/1024).toFixed(1)} KiB of API responses)`)}}}u?.transformedBundle&&(H=await gt(b,u.transformedBundle.byteLength));let n=await x(b,`(() => {
80
+ const bridge = window.SootSim?.bridges?.timeline ?? window.__sootsimTimeline
81
+ if (!bridge || typeof bridge.recent !== 'function') return null
82
+ return bridge.recent(${JSON.stringify(ht({recordedDurationMs:_,recordingStartedAtMs:y}))})
83
+ })()`).catch(l=>(console.warn(` warning: failed to capture trace timeline: ${l instanceof Error?l.message:String(l)}`),null));$=(Array.isArray(n?.events)?n.events:[]).filter(Ee)}finally{b.close()}u||(console.error(" could not read bundle snapshot \u2014 is sootsim running and is the bundle loaded?"),process.exit(2)),u.bundleUrl||(console.error(` no ?bundle= URL on the current sootsim tab.
84
+ open the app you want to share first (e.g. sootsim open 8082), then run upload.`),process.exit(2));let m,V=!1;if(H!==null)m=new TextEncoder().encode(H),V=!0,console.log(` using post-transform bundle: ${(m.byteLength/1024).toFixed(1)} KiB`);else{let n=mt(u.bundleUrl);n!==u.bundleUrl&&console.log(" forcing lazy=false for self-contained bundle"),console.log(` capturing: ${n}`),m=await _e(n),console.log(` main bundle: ${(m.byteLength/1024).toFixed(1)} KiB`)}let L=se.filter(n=>n.url!==u.bundleUrl);oe&&(L=L.filter(n=>Ae(n.contentType))),console.log(` fetching ${L.length} extra files\u2026`);let O=(await Promise.all(L.map(async n=>{try{let o=await _e(n.url);return{...n,bytes:o}}catch(o){return console.error(` warning: failed to re-fetch ${n.url}: ${o instanceof Error?o.message:o}`),null}}))).filter(n=>!!n),Fe=O.reduce((n,o)=>n+o.bytes.byteLength,0);console.log(` ${O.length} extra files: ${(Fe/1024).toFixed(1)} KiB`);let I;a&&(I=te(a));let ie=$.map(n=>JSON.stringify(n)).join(`
85
+ `),W=Ue(ie?`${ie}
86
+ `:"");console.log(` trace timeline: ${$.length} events`);let g;c&&(g=te(c),console.log(` attaching screenshot: ${(g.byteLength/1024).toFixed(1)} KiB`));let v,P,ae;if(h){if(v=te(h),P=h.endsWith(".mp4")?"video/mp4":h.endsWith(".gif")?"image/gif":void 0,P||(console.error(" preview flow videos must be mp4 or gif"),await S(),process.exit(1)),p){let n=Number(p);(!Number.isFinite(n)||n<=0)&&(console.error(` invalid --video-duration-ms: ${p}`),await S(),process.exit(1)),ae=Math.round(n)}console.log(` attaching flow video: ${(v.byteLength/1024).toFixed(1)} KiB (${P})`)}let M=ve(),R=Se(M),Ce=fe();me({event:"preview_upload_started",identity:{userId:M?.kind==="session"?Ce?.user?.id??null:null,repoId:R?.repoId??null,installationId:R?.installationId??null},properties:{origin:s,hasAuth:!!M,authMode:M?.kind??"none",bundleBytes:m.byteLength,isTransformed:V,extraFiles:O.length,recordedFetches:w.length,hasEvents:!!I,traceTimelineEvents:$.length,hasScreenshot:!!g,hasVideo:!!v}}),M||(console.error(" preview uploads need auth."),console.error(" set SOOTSIM_API_KEY=sk_sootsim_..., run `sootsim login`, or use the soot github runner."),await S(),process.exit(1));let Ne=Te(M),ze=(()=>{try{return new URL(u.bundleUrl).origin}catch{return null}})(),F=(n,o,l,Y,Q,U,pe,A)=>{let T=xe(U),f=T?Ue(n):n;return{url:o,urlhash:l,method:Y,bodyHash:Q,requestVaryHash:A,contentType:U,responseHeaders:pe,bytes:f,encoding:T?"gzip":void 0}},le=[],q=pt(u.pageHref)||"";if(q){let n=await ge(q,{onStaged:({url:o,byteLength:l})=>console.log(` staged app font: ${o} (${(l/1024).toFixed(1)} KiB)`),onError:(o,l)=>console.error(` warning: failed to fetch app font ${o}: ${l instanceof Error?l.message:l}`)});for(let o of n)le.push(F(Buffer.from(o.bytes),o.url,o.urlhash,"GET","-",o.contentType))}let ue=[],J=ft(u.pageHref)||"";if(J){let n=await he(J,{onStaged:({url:o,byteLength:l})=>console.log(` staged splash image: ${o} (${(l/1024).toFixed(1)} KiB)`),onError:(o,l)=>console.error(` warning: failed to fetch splash image ${o}: ${l instanceof Error?l.message:l}`)});for(let o of n)ue.push(F(Buffer.from(o.bytes),o.url,o.urlhash,"GET","-",o.contentType))}let K=[...O.map(n=>F(n.bytes,n.url,n.urlhash,"GET","-",n.contentType,n.responseHeaders,n.requestVaryHash)),...w.map(n=>F(Buffer.from(n.bodyBase64,"base64"),n.url,n.urlhash,n.method||"GET",n.bodyHash||"-",n.contentType,n.responseHeaders,n.requestVaryHash)),...le,...ue],j=Ie(m),De=rt("sha256").update(m).digest("hex");console.log(` bundle raw=${(m.byteLength/1024).toFixed(1)} KiB br=${(j.byteLength/1024).toFixed(1)} KiB`);let He={contentHash:De,bundleSizeBytes:m.byteLength,bundleContentType:dt(u.bundleUrl),bundleEncoding:"br",bundleOrigin:ze,runtimeVersion:u.runtimeVersion??void 0,appFonts:q||void 0,appSplash:J||void 0,entry:u.entry,isTransformed:V,deviceSpec:u.deviceSpec,installationId:R?.installationId??void 0,repoId:R?.repoId,owner:z??R?.owner,repo:D??R?.repo,billingKind:k==="test_run"?"test_run":void 0,files:K.map(n=>({url:n.url,urlhash:n.urlhash,method:n.method,bodyHash:n.bodyHash,contentType:n.contentType,responseHeaders:n.responseHeaders,requestVaryHash:n.requestVaryHash,encoding:n.encoding,sizeBytes:n.bytes.byteLength})),events:I?{sizeBytes:I.byteLength}:void 0,timeline:{sizeBytes:W.byteLength,encoding:"gzip"},recordedDurationMs:_,recordingStartedAtMs:y,snapshots:g?[{id:"landing",label:"Landing",kind:"landing",t:0,contentType:"image/png",sizeBytes:g.byteLength}]:void 0,flowVideo:v&&P?{sizeBytes:v.byteLength,contentType:P,durationMs:ae}:void 0},ce=new Map;for(let n of K)ce.set(n.urlhash,n.bytes);let de=new Map;g&&de.set("landing",g);let Ve=Date.now(),E=j.byteLength;for(let n of K)E+=n.bytes.byteLength;I&&(E+=I.byteLength),E+=W.byteLength,g&&(E+=g.byteLength),v&&(E+=v.byteLength);let We=`${B(s)}/api/preview/upload/init`;console.log(` init: ${We}`);let C;try{let n=await Me({originBase:s,initBody:He,bundleBytes:j,filesByHash:ce,extras:{eventsBytes:I,timelineBytes:W,videoBytes:v,snapshotBytes:de},authHeader:Ne,concurrency:16});C=n.finalize;let o=1+n.init.files.length+(n.init.events?1:0)+(n.init.timeline?1:0)+n.init.snapshots.length+(n.init.flowVideo?1:0);console.log(` PUT ${o} objects in ${Date.now()-Ve}ms (${(E/1024).toFixed(1)} KiB)`)}catch(n){let o=n;o.phase==="init"&&o.status===401&&(console.error(" preview upload requires a valid login."),console.error(" run `sootsim login` and retry."),await S(),process.exit(1)),o.status===402&&(console.error(` ${ot(o.responseText)??"preview uploads require Personal, Team, or an active trial \u2014 upgrade from the billing dialog."}`),await S(),process.exit(1)),console.error(` ${o.message??`${o.phase??"upload"} failed: ${String(n)}`}`),await S(),process.exit(1)}let G=`${i}${C.url}`;return console.log(`
87
+ stored ${C.filesStored??0} extra files`),console.log(` preview: ${G}`),Le&&await we(G),await S(),{previewUrl:G,shareId:C.id}}export{it as a,ut as b,Ft as c};