sootsim 0.1.39 → 0.1.41

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 (150) hide show
  1. package/README.md +15 -15
  2. package/dist-cli/bin.js +16 -15
  3. package/dist-cli/chunks/{agent-HZP3LUGJ.js → agent-7BJ2ZP22.js} +2 -2
  4. package/dist-cli/chunks/{agent-wrapper-CS6TV5UR.js → agent-wrapper-OXBYRJVT.js} +2 -2
  5. package/dist-cli/chunks/{assert-WVTX4CNR.js → assert-NZTYFTTT.js} +2 -2
  6. package/dist-cli/chunks/auto-bootstrap-4KQT4TCR.js +2 -0
  7. package/dist-cli/chunks/beta-3S56PNSS.js +2 -0
  8. package/dist-cli/chunks/{chunk-NYZGZDHI.js → chunk-2T6UOHPO.js} +1 -1
  9. package/dist-cli/chunks/chunk-334L67M2.js +2 -0
  10. package/dist-cli/chunks/{chunk-7J4UIBA5.js → chunk-33R6QMNO.js} +2 -2
  11. package/dist-cli/chunks/{chunk-XYTDYBXJ.js → chunk-4UA6P3T2.js} +1 -1
  12. package/dist-cli/chunks/{chunk-GUHXSXNO.js → chunk-5JOYGXCS.js} +2 -2
  13. package/dist-cli/chunks/chunk-6PLNIOJP.js +17 -0
  14. package/dist-cli/chunks/{chunk-YGUQSPU6.js → chunk-7YZJHZ7X.js} +1 -1
  15. package/dist-cli/chunks/{chunk-4YUHJ5FX.js → chunk-ANDSHXLU.js} +2 -2
  16. package/dist-cli/chunks/chunk-AOYBIMKL.js +4 -0
  17. package/dist-cli/chunks/chunk-ASSV2FFC.js +1 -0
  18. package/dist-cli/chunks/chunk-BR6QRN7U.js +11 -0
  19. package/dist-cli/chunks/{chunk-C6GUAXKO.js → chunk-C4AMFYK3.js} +2 -2
  20. package/dist-cli/chunks/{chunk-B2SCT4DL.js → chunk-ECIRRKKE.js} +2 -2
  21. package/dist-cli/chunks/{chunk-FEMOLCB5.js → chunk-FZB4W23Y.js} +2 -2
  22. package/dist-cli/chunks/chunk-G2QUPNHI.js +2 -0
  23. package/dist-cli/chunks/chunk-GB3G5LVB.js +108 -0
  24. package/dist-cli/chunks/{chunk-NJ4WXWKO.js → chunk-GI7FXE7J.js} +2 -2
  25. package/dist-cli/chunks/{chunk-JXKW62SL.js → chunk-GOFKXREQ.js} +2 -2
  26. package/dist-cli/chunks/chunk-HAVQS3PI.js +2 -0
  27. package/dist-cli/chunks/{chunk-223TXYOC.js → chunk-HZVPHAJX.js} +20 -20
  28. package/dist-cli/chunks/{runtime-YJPWA3XA.js → chunk-I5Y4IECP.js} +3 -3
  29. package/dist-cli/chunks/{chunk-YHYSOUIJ.js → chunk-IF33CQL4.js} +2 -2
  30. package/dist-cli/chunks/chunk-IP2MARRU.js +27 -0
  31. package/dist-cli/chunks/{chunk-ECDPQ6S7.js → chunk-J3JJRXIP.js} +1 -1
  32. package/dist-cli/chunks/{chunk-2ESCYOZW.js → chunk-LMNB7NYI.js} +2 -2
  33. package/dist-cli/chunks/{chunk-YUKH7HF6.js → chunk-LX6KS6TL.js} +1 -1
  34. package/dist-cli/chunks/{chunk-RJQ73DLG.js → chunk-MBGNDWGV.js} +4 -4
  35. package/dist-cli/chunks/{chunk-WD54RD4K.js → chunk-N7DDNZTO.js} +1 -1
  36. package/dist-cli/chunks/chunk-NZ5O2OEL.js +56 -0
  37. package/dist-cli/chunks/{chunk-ZBB7YS6C.js → chunk-OJFHAMXD.js} +2 -2
  38. package/dist-cli/chunks/{chunk-VLUFTHBB.js → chunk-OPDPXAYA.js} +2 -2
  39. package/dist-cli/chunks/chunk-OXTFYLZJ.js +4 -0
  40. package/dist-cli/chunks/{chunk-MGVTLDI3.js → chunk-Q6DGMQ2V.js} +2 -2
  41. package/dist-cli/chunks/{chunk-UWRBEBML.js → chunk-S3SQITOO.js} +2 -2
  42. package/dist-cli/chunks/{chunk-P6F636LU.js → chunk-SHHUVGL2.js} +1 -1
  43. package/dist-cli/chunks/{chunk-RLGCJT2D.js → chunk-SWHWVYZS.js} +1 -1
  44. package/dist-cli/chunks/{chunk-CBPTHIJV.js → chunk-TBIGAH3T.js} +1 -1
  45. package/dist-cli/chunks/chunk-UNJTJDZZ.js +62 -0
  46. package/dist-cli/chunks/chunk-WN6YFWS5.js +117 -0
  47. package/dist-cli/chunks/{chunk-E5RYQUFB.js → chunk-WZDE344I.js} +3 -3
  48. package/dist-cli/chunks/{chunk-NF65BNJR.js → chunk-Y2YNXUBT.js} +2 -2
  49. package/dist-cli/chunks/chunk-YFX2XIR4.js +1 -0
  50. package/dist-cli/chunks/chunk-YKFRPIVC.js +1 -0
  51. package/dist-cli/chunks/chunk-ZPURE62G.js +1 -0
  52. package/dist-cli/chunks/{compat-UMJ2IXUW.js → compat-BA6HDW3Q.js} +5 -5
  53. package/dist-cli/chunks/{config-YMJK426V.js → config-QQ63IS5P.js} +2 -2
  54. package/dist-cli/chunks/control-GNJNC524.js +2 -0
  55. package/dist-cli/chunks/cpu-profile-3DDV2SYN.js +2 -0
  56. package/dist-cli/chunks/{daemon-LIVCJZR3.js → daemon-RYSVONEV.js} +2 -2
  57. package/dist-cli/chunks/{debug-EV73WC7H.js → debug-YXE4XZLP.js} +20 -20
  58. package/dist-cli/chunks/demo-app-registry-3VFEW4NV.js +2 -0
  59. package/dist-cli/chunks/{detox-NBT5BVX3.js → detox-2UI3EAXA.js} +2 -2
  60. package/dist-cli/chunks/{device-MMROWQZ3.js → device-UGDJBZKD.js} +2 -2
  61. package/dist-cli/chunks/diagnose-IRDRYKYZ.js +41 -0
  62. package/dist-cli/chunks/drivers-EAONIWG3.js +2 -0
  63. package/dist-cli/chunks/{electron-F5DT7CFY.js → electron-ZCYWIZAE.js} +3 -3
  64. package/dist-cli/chunks/flow-ECSMFTKS.js +2 -0
  65. package/dist-cli/chunks/{hints-RODH4XE4.js → hints-OWOBCWJH.js} +2 -2
  66. package/dist-cli/chunks/{home-paths-PCUMN33Z.js → home-paths-5QMCFTBP.js} +2 -2
  67. package/dist-cli/chunks/inspect-K4VXPM5J.js +995 -0
  68. package/dist-cli/chunks/install-YFE7C2NU.js +2 -0
  69. package/dist-cli/chunks/{install-desktop-ASRNFHZU.js → install-desktop-U3723T63.js} +3 -3
  70. package/dist-cli/chunks/{keys-DOOCGNTD.js → keys-IFVXJ7C2.js} +2 -2
  71. package/dist-cli/chunks/{launch-DTVAQMZG.js → launch-NDGFTRZ5.js} +3 -3
  72. package/dist-cli/chunks/{login-JA6VEDEP.js → login-KEU6RAV3.js} +4 -4
  73. package/dist-cli/chunks/{logout-H4WFWTPC.js → logout-KNFLP5OQ.js} +2 -2
  74. package/dist-cli/chunks/{maestro-4TR7U6TS.js → maestro-GBUBLS6L.js} +2 -2
  75. package/dist-cli/chunks/{preview-GP7XXDW6.js → preview-7OKMPPMN.js} +2 -2
  76. package/dist-cli/chunks/{profile-3FESGAZD.js → profile-CHKDPGJF.js} +2 -2
  77. package/dist-cli/chunks/{react-SJD2DQQV.js → react-GYI5VITJ.js} +2 -2
  78. package/dist-cli/chunks/record-DQR2TEIF.js +45 -0
  79. package/dist-cli/chunks/runtime-XXNKSGFE.js +2 -0
  80. package/dist-cli/chunks/runtime-delivery-JCAY2QVQ.js +2 -0
  81. package/dist-cli/chunks/{screenshot-45SAK7EW.js → screenshot-3T6MNPH7.js} +2 -2
  82. package/dist-cli/chunks/{screenshot-mode-TCY7FBGR.js → screenshot-mode-BUGXY7SQ.js} +2 -2
  83. package/dist-cli/chunks/{screenshots-KZ364S2O.js → screenshots-EMTXGI2Q.js} +2 -2
  84. package/dist-cli/chunks/server-46H2M4TF.js +35 -0
  85. package/dist-cli/chunks/setup-repo-P4LCPAF6.js +2 -0
  86. package/dist-cli/chunks/{skills-SMXCCJCM.js → skills-2RP2CFPD.js} +2 -2
  87. package/dist-cli/chunks/start-QFREXALP.js +23 -0
  88. package/dist-cli/chunks/store-GH77HGEB.js +2 -0
  89. package/dist-cli/chunks/telemetry-WC5J4TE5.js +2 -0
  90. package/dist-cli/chunks/{test-ZXTSA5GV.js → test-LI4PGGTE.js} +3 -3
  91. package/dist-cli/chunks/{three-mode-4Q65J2ZA.js → three-mode-PKINB46T.js} +2 -2
  92. package/dist-cli/chunks/{timeline-ISEDS6XR.js → timeline-5AREJDL5.js} +2 -2
  93. package/dist-cli/chunks/upgrade-W2AGIOSC.js +4 -0
  94. package/dist-cli/chunks/upload-RLS6KTG6.js +2 -0
  95. package/dist-cli/chunks/web-JM6WDSZQ.js +2 -0
  96. package/dist-cli/chunks/what-happened-SVCASJKT.js +15 -0
  97. package/dist-cli/chunks/whoami-5NJ6IPLT.js +2 -0
  98. package/dist-lib/agent-daemon-client.cjs +1 -1
  99. package/dist-lib/agent-events.cjs +1 -1
  100. package/dist-lib/agent-sessions.cjs +1 -1
  101. package/dist-lib/attached-projects.cjs +1 -1
  102. package/dist-lib/auth/shared-session.cjs +1 -1
  103. package/dist-lib/backend-origin.cjs +1 -1
  104. package/dist-lib/bridge-constants.cjs +1 -1
  105. package/dist-lib/cli-constants.cjs +1 -1
  106. package/dist-lib/config.cjs +1 -1
  107. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  108. package/dist-lib/home-paths.cjs +1 -1
  109. package/dist-lib/host/bridge-host.cjs +127 -88
  110. package/dist-lib/host/fetch-proxy-handler.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 +152 -94
  116. package/dist-lib/vite.cjs +1 -1
  117. package/package.json +1 -1
  118. package/dist-cli/chunks/auto-bootstrap-3TUCG2BC.js +0 -2
  119. package/dist-cli/chunks/beta-3SCMB3IN.js +0 -2
  120. package/dist-cli/chunks/chunk-4LHQRDSN.js +0 -2
  121. package/dist-cli/chunks/chunk-4UI5OHEO.js +0 -1
  122. package/dist-cli/chunks/chunk-5L5SZXXG.js +0 -2
  123. package/dist-cli/chunks/chunk-5RSSCKBF.js +0 -1
  124. package/dist-cli/chunks/chunk-6TSUQHSC.js +0 -4
  125. package/dist-cli/chunks/chunk-B3OEHV2C.js +0 -1
  126. package/dist-cli/chunks/chunk-DSDLGFWH.js +0 -61
  127. package/dist-cli/chunks/chunk-HWRR23AJ.js +0 -17
  128. package/dist-cli/chunks/chunk-MIE6NMPJ.js +0 -117
  129. package/dist-cli/chunks/chunk-NFJDHJHK.js +0 -1
  130. package/dist-cli/chunks/chunk-OB3TB4AN.js +0 -4
  131. package/dist-cli/chunks/chunk-SLQ2GTYF.js +0 -27
  132. package/dist-cli/chunks/chunk-W4QHQT64.js +0 -2
  133. package/dist-cli/chunks/chunk-WHQWINDB.js +0 -11
  134. package/dist-cli/chunks/control-DJR3DUAB.js +0 -2
  135. package/dist-cli/chunks/cpu-profile-67MCPAA2.js +0 -22
  136. package/dist-cli/chunks/demo-app-registry-NZBZVJ52.js +0 -2
  137. package/dist-cli/chunks/diagnose-WXOKGBAJ.js +0 -41
  138. package/dist-cli/chunks/drivers-NSPV5S6T.js +0 -2
  139. package/dist-cli/chunks/flow-T6DZQWHE.js +0 -2
  140. package/dist-cli/chunks/inspect-BIMFJFDR.js +0 -1101
  141. package/dist-cli/chunks/install-5YPVP466.js +0 -2
  142. package/dist-cli/chunks/record-PQUAMW5K.js +0 -37
  143. package/dist-cli/chunks/server-S5CRYXXZ.js +0 -35
  144. package/dist-cli/chunks/setup-repo-TH3GXOP7.js +0 -2
  145. package/dist-cli/chunks/start-KLSAQM3C.js +0 -23
  146. package/dist-cli/chunks/store-E2N5NOUS.js +0 -2
  147. package/dist-cli/chunks/telemetry-RJXVYJSN.js +0 -2
  148. package/dist-cli/chunks/upload-KB7INQRC.js +0 -2
  149. package/dist-cli/chunks/what-happened-STY3AOCQ.js +0 -15
  150. package/dist-cli/chunks/whoami-VKRQOG2U.js +0 -2
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as o}from"./chunk-DSDLGFWH.js";import"./chunk-OB3TB4AN.js";import"./chunk-E5RYQUFB.js";import"./chunk-VLUFTHBB.js";import"./chunk-UWRBEBML.js";import"./chunk-HWRR23AJ.js";import"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";async function t(n){console.error(" note: `sootsim install` is now `sootsim setup-repo`. forwarding\u2026\n"),await o(n)}export{t as runInstall};
@@ -1,37 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a as z}from"./chunk-SLQ2GTYF.js";import"./chunk-4YUHJ5FX.js";import"./chunk-4UI5OHEO.js";import"./chunk-UWRBEBML.js";import{d as W}from"./chunk-C6GUAXKO.js";import{c as R,e as $}from"./chunk-HWRR23AJ.js";import{b as C}from"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";import{existsSync as Z,mkdirSync as _,readFileSync as ee,rmSync as L,writeFileSync as U}from"fs";import{tmpdir as oe}from"os";import{dirname as T,extname as re,join as te,resolve as O}from"path";var D=6e4;async function ve(e,r){if((e.includes("--help")||e.includes("-h"))&&(console.log(`
3
- sootsim record \u2014 capture the running sim
4
-
5
- usage:
6
- sootsim record [options] one-shot capture (duration-bounded)
7
- sootsim record start [options] begin stateful recording
8
- sootsim record stop [--output <path>] finalize stateful recording
9
-
10
- options:
11
- --mode <kind> video | live | combined (default: video)
12
- video \u2014 local webm/mp4 file
13
- live \u2014 pointer events only, uploads /preview/<id>
14
- combined \u2014 events + video, uploads /preview/<id>
15
- --duration <sec> recording duration (default: 10, atomic mode only)
16
- --fps <n> frame rate for video/gif (default: 30)
17
- --format <fmt> webm | mp4 | gif | png (video mode; inferred from --output ext)
18
- --output <path> output file (video/gif) or directory (png frames)
19
- --frames <n> sample N png frames evenly across --duration
20
- --max-width <px> downscale gif frames to this width
21
- --no-shell exclude the simulated iOS chrome (status bar, keyboard,
22
- toasts) \u2014 records the tenant surfaces only
23
- --shell-only record only the shell chrome
24
- --open open the preview URL in the browser after stop (live/combined)
25
- --sim <sim> target a specific sim
26
-
27
- examples:
28
- sootsim record # webm, 10s, ./sootsim-<ts>.webm
29
- sootsim record --format mp4 --duration 5
30
- sootsim record --output demo.gif --duration 3
31
- sootsim record --frames 10 --output ./frames/
32
- sootsim record --mode combined --duration 8 --open
33
- sootsim record start --format mp4 # start video; interact freely
34
- sootsim record start --mode combined # start preview-share recording
35
- sootsim record stop --output flow.mp4 # finalize video
36
- sootsim record stop --open # finalize live/combined + open URL
37
- `),process.exit(0)),e[0]==="start"){await ae(e.slice(1),r);return}if(e[0]==="stop"){await le(e.slice(1),r);return}if(e[0]==="cancel"){await ce(e.slice(1),r);return}if(e[0]==="status"){de();return}let o=R(e,{port:r.port,stripBooleanFlags:["--no-shell","--shell-only","--open"],stripValueFlags:["--mode","--duration","--fps","--format","--output","--frames","--max-width"]}),t=V(c(e,"--mode")),n=e.includes("--shell-only")?"shell":e.includes("--no-shell")?"tenant":void 0,i=c(e,"--format"),s=c(e,"--output"),a=Number(c(e,"--duration")??"10"),l=Number(c(e,"--fps")??"30"),d=c(e,"--frames"),w=e.includes("--open"),h=c(e,"--max-width")?Number(c(e,"--max-width")):void 0,v=Math.max(100,Math.round(a*1e3));if(await z("record"),t==="live"||t==="combined"){let u=$({...o,commandTimeoutMs:6e4});try{await j(u),await K(u,t)||(console.error(` start failed: recording store refused to start (${t})`),process.exit(1)),console.log(` recording ${t} for ${a}s`),await new Promise(y=>setTimeout(y,v)),await G(u);let k=await H(u);Q(k,w)}finally{u.close()}return}let M=d?Number(d):null,S=se(i,s,M),p=$({...o,commandTimeoutMs:6e4});try{if(await J(p),S==="png"){let b=M??10,f=O(process.cwd(),s??`./sootsim-frames-${B()}`);_(f,{recursive:!0}),console.log(` sampling ${b} frames over ${a}s \u2192 ${f}`);let g=await p.send({type:"evaluate",code:`window.__sootsimRecorder.startFrameCapture({ count: ${b}, durationMs: ${v} })`});(!g.ok||!g.requestId)&&(console.error(` frame capture start failed: ${g.error??"unknown error"}`),process.exit(1)),await new Promise(m=>setTimeout(m,v));let X=Date.now()+Math.max(5e3,v),A=null;for(;;){let m=await p.send({type:"evaluate",code:`window.__sootsimRecorder.getFrameCaptureResult(${g.requestId})`});if(m||(console.error(" frame capture result missing"),process.exit(1)),m.done){m.ok||(console.error(` frame capture failed: ${m.error??"unknown error"}`),process.exit(1)),A=m.frames??[];break}Date.now()>=X&&(console.error(" frame capture timed out"),process.exit(1)),await new Promise(E=>setTimeout(E,100))}A.forEach((m,E)=>{let Y=`${f}/frame-${String(E+1).padStart(3,"0")}.png`;U(Y,Buffer.from(m.data,"base64"))}),console.log(` saved ${A.length} frames`);return}if(S==="gif"){let b=M??Math.max(10,Math.round(a*l/3)),f=O(process.cwd(),s??`./sootsim-${B()}.gif`);_(T(f),{recursive:!0}),console.log(` encoding gif: ${b} frames over ${a}s \u2192 ${f}`);let g=await p.send({type:"evaluate",code:`window.__sootsimRecorder.captureGif({ frames: ${b}, durationMs: ${v}${h?`, maxWidth: ${h}`:""} })`});g||(console.error(" gif capture returned no frames"),process.exit(1)),U(f,Buffer.from(g.data,"base64")),console.log(` saved: ${f} (${P(g.size)})`);return}let u=O(process.cwd(),s??`./sootsim-${B()}.${S}`);_(T(u),{recursive:!0});let I={format:S,fps:l};n&&(I.layers=n);let k=await p.send({type:"evaluate",code:`window.__sootsimRecorder.start(${JSON.stringify(I)})`});k.ok||(console.error(` start failed: ${k.error??"unknown error"}`),process.exit(1)),console.log(` recording ${S} for ${a}s \u2192 ${u}`),await new Promise(b=>setTimeout(b,v));let y=await p.send({type:"evaluate",code:"window.__sootsimRecorder.stop()"});y.ok||(console.error(` stop failed: ${y.error??"unknown error"}`),process.exit(1)),y.size||(console.error(" recorder returned an empty blob \u2014 nothing written"),process.exit(1)),await q(p,u),console.log(` saved: ${u} (${P(y.size)})`)}finally{p.close()}}async function J(e){if(!await e.send({type:"evaluate",code:'typeof window.__sootsimRecorder !== "undefined"'}))throw new Error("window.__sootsimRecorder missing \u2014 is sootsim engine running in this sim?")}async function q(e,r){let o=[],t=0;for(;;){let n=await e.send({type:"evaluate",code:`window.__sootsimRecorder.getBlobBase64({ offset: ${t}, chunk: 2097152 })`});if(!n)throw new Error("no blob available on recorder");if(o.push(Buffer.from(n.data,"base64")),t=n.offset,n.done)break}U(r,Buffer.concat(o))}function c(e,r){let o=e.indexOf(r);if(!(o<0||o===e.length-1))return e[o+1]}function ne(e){if(!e)return;let r=re(e).toLowerCase().replace(/^\./,"");if(r==="webm"||r==="mp4"||r==="gif")return r;if(r==="png")return"png"}function se(e,r,o){return e||(o!=null?"png":ne(r)??"webm")}function B(){return new Date().toISOString().replace(/[:T]/g,"-").replace(/\..+/,"")}function P(e){return e<1024?`${e}B`:e<1024*1024?`${(e/1024).toFixed(1)}KB`:`${(e/(1024*1024)).toFixed(2)}MB`}function V(e){if(!e)return"video";if(e==="video"||e==="live"||e==="combined")return e;console.error(` invalid --mode "${e}" \u2014 expected video | live | combined`),process.exit(1)}function N(){return te(oe(),`sootsim-recording-${C()}.json`)}function F(){let e=N();if(!Z(e))return null;try{return{mode:"video",...JSON.parse(ee(e,"utf8"))}}catch{return L(e,{force:!0}),null}}function ie(e){U(N(),JSON.stringify(e,null,2))}function x(){L(N(),{force:!0})}async function ae(e,r){let o=F();o&&(console.error(` recording already in progress (started ${o.startedAt}, sim ${o.simId??"?"}). run \`sootsim record stop\` first, or \`sootsim record cancel\` to discard.`),process.exit(1)),await z("record");let t=R(e,{port:r.port,stripBooleanFlags:["--no-shell","--shell-only"],stripValueFlags:["--mode","--fps","--format","--max-width"]}),n=V(c(e,"--mode")),i=e.includes("--shell-only")?"shell":e.includes("--no-shell")?"tenant":void 0,s=c(e,"--format"),a=s==="mp4"?"mp4":"webm";s&&a!==s&&(console.error(` record start only supports webm or mp4 (got: ${s}). for gif/png use atomic mode: sootsim record --format ${s} --duration <s>`),process.exit(1));let l=Number(c(e,"--fps")??"30"),d=$({...t,commandTimeoutMs:15e3});try{if(n==="live"||n==="combined")await j(d),await K(d,n)||(console.error(` start failed: recording store refused to start (${n})`),process.exit(1));else{await J(d);let w={format:a,fps:l};i&&(w.layers=i);let h=await d.send({type:"evaluate",code:`window.__sootsimRecorder.start(${JSON.stringify(w)})`});h.ok||(console.error(` start failed: ${h.error??"unknown error"}`),process.exit(1))}ie({simId:t.simId??null,mode:n,format:a,fps:l,layers:i,startedAt:new Date().toISOString()}),console.log(n==="video"?` recording ${a} @ ${l}fps${i?` (${i})`:""} \u2014 run \`sootsim record stop --output <path>\` when done`:` recording ${n} \u2014 run \`sootsim record stop\` when done (add --open to launch the preview URL)`)}finally{d.close()}}function de(){let e=F();if(!e){console.log(" no recording in progress");return}e.mode==="video"?console.log(` recording ${e.mode} (${e.format} @ ${e.fps}fps) on sim ${e.simId??"?"} since ${e.startedAt}`):console.log(` recording ${e.mode} on sim ${e.simId??"?"} since ${e.startedAt}`)}async function ce(e,r){let o=F();if(!o){console.log(" no recording in progress");return}let t=R(e,{port:r.port}),n=t.simId??o.simId??void 0,i=$({...t,simId:n,commandTimeoutMs:15e3});try{o.mode==="live"||o.mode==="combined"?await i.send({type:"evaluate",code:"void window.SootSim?.bridges?.cancelRecording?.()"}):await i.send({type:"evaluate",code:"window.__sootsimRecorder.stop()"})}catch{}finally{x(),i.close()}console.log(" recording cancelled")}async function le(e,r){let o=F();o||(console.error(" no recording in progress. start one with `sootsim record start`."),process.exit(1));let t=R(e,{port:r.port,stripBooleanFlags:["--open"],stripValueFlags:["--output"]}),n=t.simId??o.simId??void 0,i=e.includes("--open"),s=$({...t,simId:n,commandTimeoutMs:6e4});try{if(o.mode==="live"||o.mode==="combined"){await G(s);let w=await H(s);x(),Q(w,i);return}let a=c(e,"--output"),l=O(process.cwd(),a??`./sootsim-${B()}.${o.format}`);_(T(l),{recursive:!0});let d=await s.send({type:"evaluate",code:"window.__sootsimRecorder.stop()"});d.ok||(console.error(` stop failed: ${d.error??"unknown error"}`),x(),process.exit(1)),d.size||(console.error(" recorder returned an empty blob \u2014 nothing written"),x(),process.exit(1)),await q(s,l),x(),console.log(` saved: ${l} (${P(d.size)})`)}finally{s.close()}}async function j(e){if(!await e.send({type:"evaluate",code:'typeof window.SootSim?.bridges?.startRecording === "function" && typeof window.SootSim?.bridges?.stopRecording === "function"'}))throw new Error("SootSim.bridges.startRecording missing \u2014 is sootsim engine running in this sim?")}async function K(e,r){return await e.send({type:"evaluate",code:`window.SootSim.bridges.startRecording(${JSON.stringify(r)})`})===!0}async function G(e){await e.send({type:"evaluate",code:"void window.SootSim.bridges.stopRecording()"})}async function H(e){let r=Date.now()+D;for(;Date.now()<r;){let o=await e.send({type:"evaluate",code:"(() => { const s = window.SootSim?.bridges?.getRecordingState?.(); return s ? { state: s.state, lastUpload: s.lastUpload, uploadError: s.uploadError } : null })()"});if(o&&o.state==="idle"){if(o.uploadError)return{uploadError:o.uploadError};if(o.lastUpload?.previewUrl)return{previewUrl:o.lastUpload.previewUrl}}await new Promise(t=>setTimeout(t,300))}return{uploadError:`upload did not settle within ${D/1e3}s`}}function Q(e,r){e.uploadError&&(console.error(` upload failed: ${e.uploadError}`),process.exit(1)),e.previewUrl||(console.error(" upload returned no preview URL"),process.exit(1)),console.log(` preview: ${e.previewUrl}`),r&&W(e.previewUrl)}export{ne as extToFormat,se as resolveFormat,ve as runRecord,c as valueOf};
@@ -1,35 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{b as Y,c as D,d as X,e as H,f as Z,h as Q,i as w,j as ee,k as te,l as ie,p as re,s as A,t as ne,u as se,v as oe,w as ae}from"./chunk-2ESCYOZW.js";import"./chunk-NYZGZDHI.js";import{a as E}from"./chunk-ZBB7YS6C.js";import"./chunk-YUKH7HF6.js";import"./chunk-FEMOLCB5.js";import{e as z}from"./chunk-6TSUQHSC.js";import{a as V,b as G}from"./chunk-VLUFTHBB.js";import"./chunk-UWRBEBML.js";import{d as q}from"./chunk-C6GUAXKO.js";import"./chunk-B3OEHV2C.js";import{A as W,B as _,D as F,E as j,F as $,G as J,H as K,I as N,u as L,v as U,y as T,z as M}from"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";import{spawn as Te}from"child_process";import v from"fs";import{createServer as Ee}from"http";import S from"path";import{WebSocket as m,WebSocketServer as Ie}from"ws";import ce from"node:fs";import I from"node:path";var P=1;function ge(){return[Number(process.env.VITE_PORT_WEB||process.env.PORT||3e3),Number(process.env.VITE_PORT_ZERO||7849),Number(process.env.VITE_PORT_POSTGRES||7432),Number(process.env.VITE_PORT_R2||9500)].filter(a=>Number.isFinite(a)&&a>0)}var x=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof A?this.respondError(e,s,n.message,n.code):this.respondError(e,s,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await ie()}catch(e){process.stderr.write(`[sootsim-agent] seedFromDemoAppRegistry failed: ${e instanceof Error?e.message:String(e)}
3
- `)}}close(){for(let e of this.subscriptions.values())try{e.unsubscribe()}catch{}this.subscriptions.clear(),this.sessionsBySocket.clear(),this.allSockets.clear()}async dispatch(e,t,i){switch(t){case"agent:list-projects":return H();case"agent:upsert-project":return D(i.input??{});case"agent:delete-project":return Q(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return ee(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-prompt":{let n=String(i.sessionId),o=w(n);if(!o)throw new A("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await se(n,r),this.notePromptAccepted(n,r,o.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await oe(String(i.sessionId));let s=w(String(i.sessionId));return s&&this.broadcastSessionStatus(s),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(i.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(i.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(i.sessionId));default:throw new A("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!X(e.projectId))throw new A("NO_PROJECT",`no project: ${e.projectId}`);let i=await ne(e);return this.broadcastSessionStatus(i.session),i}async autoAttachForUrl(e){let t=e.bundleUrl??"",i=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!i)return{project:null};let s=this.opts.getExcludePorts?.()??ge(),o=(await E({excludePorts:s})).find(l=>String(l.port)===i);if(!o||!o.cwd)return{project:null};let r=H().find(l=>l.cwd===o.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],o.bundleUrl,t]));return{project:D({cwd:o.cwd,name:o.projectName??I.basename(o.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[o.cwd],knownBundleUrls:c,framework:r?.framework??Se(o.framework),bundleId:o.bundleId??r?.bundleId})}}getTranscript(e){let t=re(e);return ce.existsSync(t)?ce.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=Y();return{userDataDir:e,storeFile:I.join(e,"attached-projects.json"),sessionsDir:I.join(e,"sessions"),transcriptsDir:I.join(e,"transcripts")}}subscribeSocket(e,t){let i=this.sessionsBySocket.get(e);if(i||(i=new Set,this.sessionsBySocket.set(e,i)),i.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};i.add(t);let s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=ae(t,o=>{let r=this.coalescePromptEcho(t,o);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),o.type==="turn-completed"){let c=w(t);if(c)try{Z(c.projectId,{usd:o.costUsd,ts:o.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
4
- `)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let o=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,o);let r=t.displayText??t.text;return this.patchSession(e,{lastPrompt:r,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:r,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:s}),{ok:!0,queued:o>1,pendingTurns:o,queueDepth:Math.max(0,o-1)}}applySessionEvent(e,t){switch(t.type){case"prompt-received":case"turn-started":this.patchSession(e,{status:"working",needsAttention:!1});return;case"turn-completed":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"idle",needsAttention:!1,lastTurnFiles:t.filesTouched,currentlyEditing:void 0});return}case"approval-needed":this.patchSession(e,{status:"needs-attention",needsAttention:!0});return;case"error":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"needs-attention",needsAttention:i<=0,currentlyEditing:void 0});return}case"exited":this.clearPromptTracking(e),this.patchSession(e,{status:"ended",needsAttention:!1,wrapperPid:void 0,currentlyEditing:void 0});return;case"ready":case"turn-reasoning":case"turn-message":case"turn-plan":case"tool-call":case"file-edited":case"file-diff-delta":return}}patchSession(e,t){te(e,t);let i=w(e);i&&this.broadcastSessionStatus(i)}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let i=this.pendingPromptEchoes.get(e);if(!i||i.length===0)return t;for(;i.length>0&&Date.now()-i[0].sentAt>15e3;)i.shift();return i.length===0?(this.pendingPromptEchoes.delete(e),t):(i.shift(),i.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,i),null)}consumeSettledTurn(e){let t=Math.max(0,(this.pendingTurns.get(e)??1)-1);return t>0?this.pendingTurns.set(e,t):this.pendingTurns.delete(e),t}clearPromptTracking(e){this.pendingPromptEchoes.delete(e),this.pendingTurns.delete(e)}fanOutEvent(e,t){let i=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[s,n]of this.sessionsBySocket)if(n.has(e)&&s.readyState===P)try{s.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===P)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===P)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===P)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function Se(a){return a==="expo"?"expo":a==="one"||a==="vxrn"?"one":"unknown"}import ye from"http";import ve from"https";var be="sootsim",we=new Set(["host","origin","referer","user-agent","cookie","connection","keep-alive","transfer-encoding","upgrade","content-length","sec-fetch-site","sec-fetch-mode","sec-fetch-dest","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform"]),Ae={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,DELETE,PATCH,OPTIONS","access-control-allow-headers":"*","access-control-expose-headers":"*","access-control-max-age":"3600"};function k(a){for(let[e,t]of Object.entries(Ae))a.setHeader(e,t)}function ke(a,e){let t=[],i=e;i?.code&&t.push(i.code),i?.message&&t.push(i.message),i?.cause?.code&&t.push(i.cause.code),i?.cause?.message&&t.push(i.cause.message);let n=[...new Set(t.filter(Boolean))].join(" | ")||String(e);return a.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Ce(a){let e={};for(let[t,i]of Object.entries(a))i&&(we.has(t.toLowerCase())||(e[t]=Array.isArray(i)?i.join(", "):i));return e["user-agent"]=be,e}function de(a){return a?.startsWith("/__fetch-proxy?")||a?.startsWith("/__proxy?")||!1}function le(a){return a?!!(a.startsWith("/__app-api?")||a.startsWith("/__app-api/")):!1}async function ue(a,e){if(a.method==="OPTIONS"){k(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((a.url||"").split("?")[1]||"").get("url");if(!i){k(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{k(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Ce(a.headers),o;if(a.method!=="GET"&&a.method!=="HEAD"){let l=[];for await(let u of a)l.push(Buffer.isBuffer(u)?u:Buffer.from(u));l.length>0&&(o=Buffer.concat(l))}let r;try{r=await fetch(s.href,{method:a.method,headers:n,body:o,redirect:"follow"})}catch(l){k(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${ke(s.href,l)}`);return}r.headers.forEach((l,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,l)}),k(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let d=Buffer.from(await r.arrayBuffer());e.end(d)}function pe(a,e){let t=a.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(a.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":a.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":a.headers["access-control-request-headers"]||"*","Access-Control-Allow-Credentials":"true","Access-Control-Max-Age":"86400"}),e.end(),!0;let n;try{n=new URL(i,s)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let o=n.protocol==="https:"?ve:ye,r={...a.headers};delete r.host,r.host=n.host;let c=o.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:a.method,headers:r},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":a.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return c.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),a.pipe(c),!0}var Pe=new Set(["tap","keyboard","close"]);function xe(a){return!a||typeof a.type!="string"?!1:a.acquireLock===!0?!0:a.readOnly===!0?!1:Pe.has(a.type)}var Re=5e3,Be=3600*1e3,Oe="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",Le={".html":"text/html; charset=utf-8",".js":"application/javascript",".cjs":"application/javascript",".mjs":"application/javascript",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".wasm":"application/wasm",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2",".map":"application/json",".txt":"text/plain; charset=utf-8"};function he(a){let e;try{let s=L();e=JSON.stringify(s)}catch{e="{}"}let t=`<script>window.__sootsimSharedConfig=${e};</script>`,i=a.toString("utf8");return i.includes("</head>")?i.replace("</head>",t+"</head>"):i.includes("</body>")?i.replace("</body>",t+"</body>"):t+i}var R=class a{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextSimNumber=161;sims=new Map;primarySimId=null;pendingCommands=new Map;cliBySentId=new Map;cliSimBySocket=new Map;cliLastCommandAt=new Map;cliIdentityKeyBySocket=new Map;cliLabelBySocket=new Map;restorableSims=new Map;nextCliFallbackId=1;cliIdleTimer=null;agentHost;static CLI_IDLE_TIMEOUT_MS=6e4;static CLI_LEASE_TTL_MS=6e5;static USER_ACTIVE_LEASE_TTL_MS=8e3;static USER_BOOT_LEASE_TTL_MS=6e4;static SIM_RECONNECT_TTL_MS=3e4;preferredPort;portFallbackCount;shouldWriteLockfile;effectivePort=0;startedAt=0;heartbeatTimer=null;wsHeartbeatTimer=null;wsIsAlive=new WeakMap;static WS_HEARTBEAT_INTERVAL_MS=3e4;runtimeUpdateTimer=null;runtimeUpdateInFlight=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;scanCache=null;scanCacheAt=0;inflightScan=null;static SCAN_FRESH_MS=2e3;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0,this.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new x({getExcludePorts:e.agentScanExcludes})}getAgentHost(){return this.agentHost}start(e){this.startAsync(e)}async startAsync(e){if(this.httpServer||this.wss)return this.effectivePort;this.refreshActiveRuntime();for(let t=0;t<this.portFallbackCount;t++){let i=this.preferredPort+t;try{return await this.bindOnce(i,e?.silent===!0),this.effectivePort=i,this.port=i,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${i} (preferred ${this.preferredPort} was taken)
5
- `),this.afterBind(),i}catch(s){if(s?.code!=="EADDRINUSE")throw s;e?.silent||process.stderr.write(`ws bridge port ${i} already in use, trying ${i+1}
6
- `)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,s)=>{let n=Ee((c,d)=>this.handleHttpRequest(c,d)),o=!1,r=c=>{if(!o){o=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{o||(o=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
7
- `)}),this.httpServer=n,this.wss=new Ie({server:n}),this.wireWebSocketServer(),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,s=i?"sim":"cli",n=null;if(e.on("error",()=>{}),this.wsIsAlive.set(e,!0),e.on("pong",()=>{this.wsIsAlive.set(e,!0)}),this.agentHost.registerSocket(e),s==="sim")n={id:this.allocateSimId(),ws:e,origin:i,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.sims.set(n.id,n),this.shouldPromoteSim(n)&&(this.primarySimId=n.id),this.broadcastSimAssignments(),this.broadcastSimClientStates();else{let o=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,o)}e.on("message",o=>{let r;try{r=JSON.parse(o.toString())}catch{return}if(!(!r||typeof r!="object")){if(typeof r.type=="string"&&r.type.startsWith("agent:")){this.agentHost.handleMessage(e,r);return}if(r.type==="runtime:list"){let c=_(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:c,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!_().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let c=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:c.version,activeRuntimeDir:c.runtimeDir}))}catch{}return}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,u&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l.focused===!0);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let l=r.patch&&typeof r.patch=="object"?r.patch:null;if(!l)return;let u;try{u=U(l)}catch(h){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${h instanceof Error?h.message:String(h)}
8
- `);return}let p=JSON.stringify({type:"bridge:shared-config-changed",config:u});for(let h of this.sims.values())if(h.ws.readyState===m.OPEN)try{h.ws.send(p)}catch{}return}if(r.type==="bridge:open-path"){let l=typeof r.path=="string"?r.path:"",u=typeof r.line=="number"&&Number.isFinite(r.line)?r.line:void 0,p=typeof r.column=="number"&&Number.isFinite(r.column)?r.column:void 0;l&&this.openPathInEditor(l,u,p);return}if(r.type==="bridge:boot-clients"&&n){let l=[];for(let[p,h]of this.cliSimBySocket)h===n.id&&l.push(p);for(let p of l){this.cliSimBySocket.delete(p);try{p.close(1e3,"booted by sim")}catch{}}let u=!!n.cliLease;n.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+a.USER_BOOT_LEASE_TTL_MS},process.stderr.write(`sootsim booted ${l.length} cli client(s)${u?" (overrode prior lease)":""}; held sim for user [${n.id}]
9
- `),this.recordSimAction(n.id,"sim booted cli clients"),this.broadcastSimClientStates();return}let c=this.pendingCommands.get(r.id);if(c){this.pendingCommands.delete(r.id),r.error?c.reject(new Error(r.error)):c.resolve(r.result);return}let d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===m.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,i:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[h,g]of this.cliBySentId)g.ws===e&&this.cliBySentId.delete(h);p&&this.broadcastSimClientStates();return}if(r.type==="bridge:hello"){let p=typeof r.cliIdentityKey=="string"&&r.cliIdentityKey.trim()?r.cliIdentityKey.trim():this.cliIdentityKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,p),typeof r.cliLabel=="string"&&r.cliLabel.trim()&&this.cliLabelBySocket.set(e,r.cliLabel.trim()),e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,result:{cliIdentityKey:p,leaseTtlMs:a.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(r.type==="bridge:list-sims"){e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,result:this.listSims()}));return}if(r.type==="bridge:open"){if(typeof r.url!="string"||!r.url)throw new Error("bridge:open requires a url");await this.openUrl(r.url,{newWindow:r.newWindow===!0}),e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,result:{ok:!0,url:r.url}}));return}if(r.type==="bridge:claim"){let p=await this.waitForSim(r.simId),h=this.tryAcquireLease(e,p,{force:r.force===!0});if(!h.granted){e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,o:h.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,h.bootedCount>0?`cli force-claimed sim (booted ${h.bootedCount})`:"cli claimed sim"),e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:h.lease.cliIdentityKey,lockExpiresAt:h.lease.expiresAt,bootedCount:h.bootedCount}}));return}let c=await this.waitForSim(r.simId);if(xe(r)){let p=this.tryAcquireLease(e,c);if(!p.granted){e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${c.id} is locked by another cli \u2014 use \`sootsim claim ${c.id} --force\` or \`sootsim open --new\``,o:p.lock}));return}}else this.ensureCliIdentityKey(e);this.setCliSimTarget(e,c.id),this.recordSimAction(c.id,this.describeForwardedCommand(r));let d=this.nextCommandId++;this.cliBySentId.set(d,{simId:c.id,ws:e,originalId:r.id});let{simId:l,...u}=r;c.ws.send(JSON.stringify({...u,id:d}))}catch(c){e.readyState===m.OPEN&&e.send(JSON.stringify({id:r.id,error:c instanceof Error?c.message:String(c)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),s==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[o,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(o));for(let[o,r]of this.cliBySentId)r.simId===n.id&&(r.ws.readyState===m.OPEN&&r.ws.send(JSON.stringify({id:r.originalId,error:"sim disconnected before responding"})),this.cliBySentId.delete(o));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let o=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[r,c]of this.cliBySentId)c.ws===e&&this.cliBySentId.delete(r);o&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
10
- `),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),a.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(T(),!K(this.buildLockfileSnapshot()))throw new Error("another sootsim daemon wrote the lockfile during startup \u2014 aborting")}catch(e){throw process.stderr.write(`ws bridge failed to claim daemon lockfile: ${String(e)}
11
- `),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},Re),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}this.agentHost.seedOnBoot()}bootstrapping=!0;buildLockfileSnapshot(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,activeRuntimeDir:this.activeRuntimeDirPath,startedAt:this.startedAt,heartbeatAt:Date.now(),bootstrapping:this.bootstrapping}}writeLockfileSnapshot(){J(this.buildLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=M(),this.activeRuntimeDirPath=F()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=E({excludePorts:e,buildIconProxyUrl:t=>`/__bundle-proxy?url=${encodeURIComponent(t)}`}).then(t=>(this.scanCache=t,this.scanCacheAt=Date.now(),t)).catch(t=>{let i=t instanceof Error?t.message:String(t);return console.error("[sootsim] /__server-scan failed:",i),this.scanCache??[]}).finally(()=>{this.inflightScan=null}),this.inflightScan}handleServerScan(e){let t=s=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(s))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<a.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(s=>t(s))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[Oe]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):Be}startRuntimeUpdater(){if(!this.shouldWriteLockfile||this.runtimeUpdateTimer)return;this.runRuntimeUpdate("startup");let e=this.resolveRuntimeUpdateIntervalMs();this.runtimeUpdateTimer=setInterval(()=>{this.runRuntimeUpdate("periodic")},e),this.runtimeUpdateTimer.unref()}runRuntimeUpdate(e){return this.runtimeUpdateInFlight?this.runtimeUpdateInFlight:(this.runtimeUpdateInFlight=(async()=>{try{e==="startup"&&process.stderr.write(`sootsim: checking for runtime updates\u2026
12
- `);let t=await z();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
13
- `);return}let i=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${i.version} (${e})
14
- `)}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
15
- `)}finally{if(this.runtimeUpdateInFlight=null,e==="startup"&&this.bootstrapping){if(this.bootstrapping=!1,this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}process.stderr.write(`sootsim: ready
16
- `)}}})(),this.runtimeUpdateInFlight)}setActiveRuntime(e){if(W(e),this.refreshActiveRuntime(),this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}let t=JSON.stringify({type:"runtime:changed",version:e,runtimeDir:this.activeRuntimeDirPath});for(let i of this.sims.values())if(i.ws.readyState===m.OPEN)try{i.ws.send(t)}catch{}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{N()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy","credentialless"),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),de(e.url)){ue(e,t);return}if(le(e.url)&&pe(e,t))return;let i=(e.method||"GET").toUpperCase();if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let s=new URL(e.url||"/","http://localhost");if(s.pathname==="/__bundle-proxy"){let d=s.searchParams.get("url");if(!d){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let l;try{l=new URL(d)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=l.hostname;if(!(u==="localhost"||u==="127.0.0.1"||u==="::1"||u.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let h=await fetch(l.toString(),{redirect:"follow"}),g={},f=h.headers.get("content-type");if(f&&(g["Content-Type"]=f),g["Cache-Control"]="no-store",t.writeHead(h.status,g),!h.body){t.end();return}let b=h.body.getReader();for(;;){let{done:C,value:y}=await b.read();if(C)break;t.write(Buffer.from(y))}t.end()}catch(h){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${h instanceof Error?h.message:String(h)}`)}})();return}if(s.pathname==="/__server-scan"){this.handleServerScan(t);return}if(s.pathname==="/healthz"){t.writeHead(200,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify({ok:!0,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}if(s.pathname==="/__sootsim/shared-config"){if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Cache-Control","no-store"),i==="GET"||i==="HEAD"){let d="{}";try{d=JSON.stringify(L())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(d);return}t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed (use the bridge over WS for writes)");return}this.refreshActiveRuntime();let n=this.activeRuntimeDirPath;if(!n){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end("sootsim: no active runtime installed. run `sootsim runtime install` to fetch one.");return}let o=s.pathname;if(o==="/runtime"||o==="/runtime/"?o="/":o.startsWith("/runtime/")&&(o=o.slice(8)),(o===""||o==="/")&&(o="/index.html"),o.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&o.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let d of o.split("/"))if(d===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+o),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}v.realpath(r,(d,l)=>{let u=d?r:l,p=u.endsWith(S.sep)?u:u+S.sep;if(!d){let h=(()=>{try{let g=v.realpathSync(n);return g.endsWith(S.sep)?g:g+S.sep}catch{return c}})();if(!p.startsWith(h)&&u+S.sep!==h){t.writeHead(403),t.end("forbidden");return}}v.stat(u,(h,g)=>{if(h||!g?.isFile()){let y=S.extname(o).toLowerCase();if(y&&y!==".html"){t.writeHead(404),t.end("not found");return}if(o.startsWith("/__")||o.startsWith("/api/")||o==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let O=S.join(n,"index.html");v.readFile(O,(me,fe)=>{if(me){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),i==="HEAD"){t.end();return}t.end(he(fe))});return}let f=S.extname(u).toLowerCase(),b=Le[f]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":b,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(f===".html"){v.readFile(u,(y,O)=>{if(y){try{t.end()}catch{}return}t.end(he(O))});return}let C=v.createReadStream(u);C.pipe(t),C.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,s]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(!(e-n<a.CLI_IDLE_TIMEOUT_MS)){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[o,r]of this.cliBySentId)r.ws===i&&this.cliBySentId.delete(o);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e)}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==m.OPEN)continue;if(this.wsIsAlive.get(e)===!1){try{e.terminate()}catch{}continue}this.wsIsAlive.set(e,!1);try{e.ping()}catch{try{e.terminate()}catch{}}}}listSims(){return Array.from(this.sims.values()).sort((e,t)=>e.id===this.primarySimId?-1:t.id===this.primarySimId?1:e.connectedAt-t.connectedAt).map(e=>this.describeSim(e))}async sendCommand(e){let t=await this.waitForSim(e.simId),i=this.nextCommandId++;return new Promise((s,n)=>{let o=setTimeout(()=>{this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(i,{simId:t.id,resolve:d=>{clearTimeout(o),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(o),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...c}=e;t.ws.send(JSON.stringify({...c,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,o=(c,d)=>new Promise(l=>{try{let u=Te(c,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let c=r.split(" ").filter(Boolean);if(c.length&&await o(c[0],[...c.slice(1),"-g",n]))return}await o("cursor",["-g",n])||await o("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await q(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{N()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,s]of this.pendingCommands)s.reject(new Error("server closing")),this.pendingCommands.delete(i);for(let i of this.sims.values())i.ws.close();this.sims.clear(),this.primarySimId=null;let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}describeSim(e){let t;try{t=e.ws.readyState}catch{t=m.CLOSED}let i=this.getActiveLease(e);return{id:e.id,origin:e.origin,url:e.url,title:e.title,userAgent:e.userAgent,connectedAt:e.connectedAt,lastSeenAt:e.lastSeenAt,lastActiveAt:e.lastActiveAt||void 0,isPrimary:e.id===this.primarySimId,readyState:t===m.OPEN?"open":t===m.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:i?i.cliLabel||i.cliIdentityKey:void 0,lockedByKind:i?i.kind:void 0,lockExpiresAt:i?i.expiresAt:void 0,userFocused:e.userFocused||void 0}}getActiveLease(e){let t=e.cliLease;return t?Date.now()>=t.expiresAt?(e.cliLease=void 0,null):t:null}tryAcquireLease(e,t,i={}){let s=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),o=Date.now(),r=this.getActiveLease(t),c=r&&r.cliIdentityKey===s,d=0;if(r&&!c&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-o)},bootedCount:0};if(r&&!c&&i.force)for(let[u,p]of this.cliSimBySocket){if(p!==t.id)continue;let h=this.cliIdentityKeyBySocket.get(u);if(h&&h!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:o+a.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}updateUserFocusLease(e,t){let i=t;e.userFocused!==i&&(e.userFocused=i,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+a.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,s):s;e.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:n},this.broadcastSimClientStates()}ensureCliIdentityKey(e){let t=this.cliIdentityKeyBySocket.get(e);if(t)return t;let i=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,i),i}getOpenSim(e){if(e){let i=this.sims.get(e);return i?.ws.readyState===m.OPEN?i:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===m.OPEN)return t;for(let i of this.sims.values())if(i.ws.readyState===m.OPEN)return i;return null}async waitForSim(e,t={}){let i=t.attempts??10,s=t.intervalMs??200;for(let n=0;n<i;n++){let o=this.getOpenSim(e);if(o)return o;await new Promise(r=>setTimeout(r,s))}throw new Error(e?`no sim connected with id ${e}`:"no sim connected")}shouldPromoteSim(e){let t=this.primarySimId?this.sims.get(this.primarySimId):null,i=e.origin?.includes(":5173"),s=t?.origin?.includes(":5173");return!t||t.ws.readyState!==m.OPEN||!!i||!s}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===m.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",simId:e.id,isPrimary:e.id===this.primarySimId}))}broadcastSimClientStates(){for(let e of this.sims.values()){if(e.ws.readyState!==m.OPEN)continue;let t=this.getActiveLease(e),i={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliIdentityKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0};e.ws.send(JSON.stringify(i))}}setCliSimTarget(e,t){let i=this.cliSimBySocket.get(e);i!==t&&(this.cliSimBySocket.set(e,t),this.recordSimAction(t,i?"cli switched sims":"cli connected",!1),this.broadcastSimClientStates())}recordSimAction(e,t,i=!0){let s=t?.trim();if(!s)return;let n=this.sims.get(e);if(!n)return;let o=Date.now();n.lastActiveAt=o,n.recentActions=[{label:s,at:o},...n.recentActions.filter(r=>r.label!==s)].slice(0,4),i&&this.broadcastSimClientStates()}describeForwardedCommand(e){switch(e?.type){case"evaluate":return"evaluated page state";case"screenshot":return"captured screenshot";case"tap":return"sent tap event";case"keyboard":return e?.action==="type"?"typed text":"used keyboard";case"tree":return"dumped tree";case"focus":return"focused sim";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[i,s]of this.cliSimBySocket){if(s!==e||i.readyState!==m.OPEN)continue;let n=this.cliIdentityKeyBySocket.get(i);t.add(n??`ws-unknown-${t.size}`)}return t.size}getOtherCliIdentityCount(e,t){let i=this.cliIdentityKeyBySocket.get(e),s=new Set;for(let[n,o]of this.cliSimBySocket){if(o!==t||n.readyState!==m.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||s.add(r??`ws-unknown-${s.size}`)}return s.size}getActiveAgentCommandCount(e){let t=0;for(let i of this.pendingCommands.values())i.simId===e&&t++;return t}allocateSimId(){for(;;){let e=this.nextSimNumber.toString(16);if(this.nextSimNumber++,!this.sims.has(e)&&!this.restorableSims.has(e))return e}}tryRestoreSimId(e,t){let i=t?.trim();if(!i||i===e.id)return!1;let s=this.sims.get(i);if(s&&s!==e&&s.ws.readyState===m.OPEN)return!1;let n=this.getRestorableSimState(i),o=e.id;this.sims.delete(o),e.id=i,n&&(e.recentActions=n.recentActions.map(r=>({...r})),e.lastActiveAt=n.lastActiveAt,e.cliLease=n.cliLease?{...n.cliLease}:void 0,this.restorableSims.delete(i)),this.sims.set(e.id,e),this.primarySimId===o&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===o&&this.cliSimBySocket.set(r,e.id);return!0}rememberDisconnectedSim(e){let t=this.getActiveLease(e);this.restorableSims.set(e.id,{recentActions:e.recentActions.map(i=>({...i})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+a.SIM_RECONNECT_TTL_MS}),this.sims.delete(e.id)}getRestorableSimState(e){let t=this.restorableSims.get(e);return t?t.expiresAt<=Date.now()?(this.restorableSims.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableSims(e=Date.now()){for(let[t,i]of this.restorableSims)if(!(i.expiresAt>e)){this.restorableSims.delete(t);for(let[s,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(s)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null);let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}};function _e(){let a=process.env.XPC_SERVICE_NAME||"";return!!(a.includes("dev.sootsim.daemon")||a.includes("dev.sootsim.server")||process.env.INVOCATION_ID)}async function at(a,e={}){(a.includes("--help")||a.includes("-h"))&&(console.log(`
17
- sootsim server \u2014 run the sootsim bridge daemon in the foreground
18
-
19
- hosts the WS bridge that CLI commands talk to. once running, any sootsim
20
- renderer (browser, electron, headless playwright) that connects to port 7668
21
- becomes drivable from 'sootsim describe', 'sootsim tap', etc.
22
-
23
- usage:
24
- sootsim server [options]
25
-
26
- options:
27
- --port <n> bridge port (defaults to ${7668})
28
- --quiet suppress per-connection logging
29
-
30
- examples:
31
- sootsim server
32
- sootsim server --port 7668 --quiet
33
- `),process.exit(0));let t=a.indexOf("--port"),i=t>=0&&a[t+1]?Number(a[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${a[t+1]}`),process.exit(1));let s=a.includes("--quiet")||a.includes("-q"),n=j();n&&$(n)&&(console.error(` a sootsim daemon is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),T();let o=new R({port:i,writeLockfile:!0}),r=await o.startAsync({silent:s}),c=Date.now(),d=h=>{s||process.stdout.write(`${h}
34
- `)},l=new Set,u=setInterval(()=>{let h=o.listSims(),g=new Set(h.map(f=>f.id));for(let f of h)if(!l.has(f.id)){let b=f.title||f.url||f.origin||"(unknown)";d(` + ${f.id} ${b}`)}for(let f of l)g.has(f)||d(` - ${f}`);l.clear();for(let f of g)l.add(f)},500);V({event:"daemon_heartbeat",properties:{bridge_port:r,under_daemon:_e(),platform:process.platform,subsource:"daemon"}}),G(),d(`sootsim bridge listening on ws://localhost:${r} (runtime http on same port)`),r!==i&&d(` (preferred port ${i} was taken \u2014 fell back to ${r})`),d(" ready for browser, electron, or headless playwright sims to connect"),d(" (ctrl-c to stop)");let p=async h=>{clearInterval(u),d(`
35
- ${h} received \u2014 shutting down after ${Math.round((Date.now()-c)/1e3)}s`);try{await o.close()}catch{}process.exit(0)};process.on("SIGINT",()=>p("SIGINT")),process.on("SIGTERM",()=>p("SIGTERM")),process.on("SIGHUP",()=>p("SIGHUP")),process.on("exit",()=>{try{o.removeLockfile()}catch{}}),await new Promise(()=>{})}export{at as runServer};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a}from"./chunk-DSDLGFWH.js";import"./chunk-OB3TB4AN.js";import"./chunk-E5RYQUFB.js";import"./chunk-VLUFTHBB.js";import"./chunk-UWRBEBML.js";import"./chunk-HWRR23AJ.js";import"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";export{a as runSetupRepo};
@@ -1,23 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{d as _}from"./chunk-C6GUAXKO.js";import"./chunk-HWRR23AJ.js";import"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import{E as b,F as v,i as D,y as O,z as $}from"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";import{spawn as N}from"child_process";import{existsSync as F}from"fs";import{WebSocket as B}from"ws";var k=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];var A={reset:"\x1B[0m",dim:"\x1B[2m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",bold:"\x1B[1m"};function T(){return process.stderr.isTTY===!0}function l(t,e){return T()?`${A[t]}${e}${A.reset}`:e}function L(t,e){switch(t){case"pending":return l("dim","\xB7");case"running":return l("cyan",e);case"done":return l("green","\u2713");case"fail":return l("red","\u2717");case"skip":return l("yellow","\u25CB")}}var E=class{constructor(e,s){this.stepper=e;this.data=s}start(e){this.data.state="running",e!==void 0&&(this.data.detail=e),this.stepper.render()}update(e){this.data.detail=e,this.stepper.render()}done(e){this.data.state="done",e!==void 0&&(this.data.detail=e),this.stepper.render()}fail(e){this.data.state="fail",e!==void 0&&(this.data.detail=e),this.stepper.render()}skip(e){this.data.state="skip",e!==void 0&&(this.data.detail=e),this.stepper.render()}},S=class{steps=[];bannerText="";frame=0;timer=null;lastLineCount=0;paused=!1;finished=!1;banner(e){this.bannerText=e}add(e){let s={label:e,state:"pending"};return this.steps.push(s),new E(this,s)}render(){this.paused||this.finished||(this.startSpinner(),this.draw())}pause(){this.paused||(this.paused=!0,this.stopSpinner(),this.eraseRendered(),this.lastLineCount=0)}resume(){this.paused&&(this.paused=!1,this.draw(),this.startSpinner())}finish(){this.finished||(this.finished=!0,this.stopSpinner(),this.draw())}startSpinner(){this.timer||!T()||this.steps.some(e=>e.state==="running")&&(this.timer=setInterval(()=>{this.frame=(this.frame+1)%k.length,this.draw()},80),this.timer?.unref?.())}stopSpinner(){this.timer&&(clearInterval(this.timer),this.timer=null)}draw(){if(!T()){this.drawForwardOnly();return}this.eraseRendered();let e=[];this.bannerText&&(e.push(l("bold",this.bannerText)),e.push(""));let s=k[this.frame],i=Math.max(...this.steps.map(r=>r.label.length),0);for(let r of this.steps){let n=L(r.state,s),u=r.label.padEnd(i),y=r.detail?` ${l("dim",r.detail)}`:"";e.push(` ${n} ${u}${y}`)}process.stderr.write(e.join(`
3
- `)+`
4
- `),this.lastLineCount=e.length,this.steps.some(r=>r.state==="running")||this.stopSpinner()}bannerPrinted=!1;lastEmitted=new Map;drawForwardOnly(){this.bannerText&&!this.bannerPrinted&&(process.stderr.write(this.bannerText+`
5
-
6
- `),this.bannerPrinted=!0);for(let e of this.steps){let s=`${e.state}:${e.detail||""}`;if(this.lastEmitted.get(e.label)===s)continue;if(e.state==="pending"){this.lastEmitted.set(e.label,s);continue}let r=L(e.state,k[0]),n=e.detail?` ${e.detail}`:"";process.stderr.write(` ${r} ${e.label}${n}
7
- `),this.lastEmitted.set(e.label,s)}}eraseRendered(){this.lastLineCount!==0&&(process.stderr.write(`\x1B[${this.lastLineCount}A\x1B[0J`),this.lastLineCount=0)}};var U=3e4,I=1e4;async function Z(t,e={}){if(t.includes("--help")||t.includes("-h")){console.log(`
8
- sootsim start \u2014 install + run sootsim, open it in your browser
9
-
10
- bare \`sootsim\` (or \`npx sootsim\`) defaults to this command. it makes sure
11
- the engine runtime is on disk, ensures the bridge daemon is up (or falls
12
- back to a detached server), then opens the iOS shell in your browser.
13
-
14
- usage:
15
- sootsim start [options]
16
- sootsim # same thing
17
-
18
- options:
19
- --port <n> bridge port (default: ${7668})
20
- --no-open don't open the browser at the end
21
- `);return}O();let s=t.indexOf("--port"),i=s>=0&&t[s+1]?Number(t[s+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${t[s+1]}`),process.exit(1));let r=t.includes("--no-open"),n=new S,{IS_BETA:u,BETA_TAGLINE:y}=await import("./beta-3SCMB3IN.js");n.banner(u?`sootsim \u2014 ${y}`:"sootsim \u2014 starting up");let c=n.add("runtime"),d=n.add("server"),x=n.add("ready"),f=n.add("open");n.render();let g=null;try{c.start("checking\u2026");let a=$();if(a&&F(D(a)))g=a,c.done(`v${a}`);else{c.start("downloading engine (~6 MB)\u2026");let{runRuntime:h}=await import("./runtime-YJPWA3XA.js");n.pause(),await h(["install"],{}),n.resume(),g=$(),c.done(g?`v${g}`:"installed")}}catch(a){c.fail(m(a)),n.finish(),process.exit(1)}let o=i,p="standalone";try{d.start("checking\u2026");let a=b();if(v(a)&&await P(a.bridgePort,800))o=a.bridgePort,p="daemon-existing",d.done(`already running (port ${o})`);else if(process.platform==="darwin"||process.platform==="linux"){d.start("registering background daemon\u2026");try{let{daemonInstall:h}=await import("./daemon-LIVCJZR3.js");n.pause(),await h({port:i,force:!0}),n.resume();let R=b();o=v(R)?R.bridgePort:i,p="daemon-installed",d.done(`daemon registered (port ${o})`)}catch(h){n.resume(),d.start("daemon unavailable, starting standalone server\u2026"),o=await C(i),p="standalone",d.done(`standalone (port ${o}) \u2014 ${m(h)}`)}}else d.start("starting standalone server\u2026"),o=await C(i),p="standalone",d.done(`standalone (port ${o})`)}catch(a){d.fail(m(a)),n.finish(),process.exit(1)}try{if(x.start("waiting for bridge\u2026"),!await V(o,U))throw new Error(`bridge never came online on port ${o}`);x.done(`ws://localhost:${o}`)}catch(a){x.fail(m(a)),n.finish(),process.exit(1)}let w=`http://localhost:${o}/`;if(r){f.skip(w),n.finish();return}try{f.start("launching browser\u2026"),await _(w),f.done(w)}catch(a){f.skip(`${w} (open it manually \u2014 ${m(a)})`)}n.finish(),p==="standalone"?(console.log(`
22
- running in standalone mode. sootsim will exit when this process does.
23
- press ctrl-c to stop.`),await new Promise(()=>{})):p==="daemon-installed"&&console.log("\n installed as a background daemon \u2014 it'll restart on login.\n manage it with `sootsim daemon status / restart / uninstall`.")}function P(t,e){return new Promise(s=>{let i=new B(`ws://127.0.0.1:${t}`,{handshakeTimeout:e}),r=!1,n=u=>{if(!r){r=!0;try{i.close()}catch{}s(u)}};i.once("open",()=>n(!0)),i.once("error",()=>n(!1)),setTimeout(()=>n(!1),e)})}async function V(t,e){let s=Date.now()+e;for(;Date.now()<s;){if(await P(t,500))return!0;await new Promise(i=>setTimeout(i,200))}return!1}async function C(t){let e=W();N(e,["server","--quiet","--port",String(t)],{detached:!0,stdio:"ignore",env:process.env}).unref();let i=Date.now()+I;for(;Date.now()<i;){let r=b();if(v(r))return r.bridgePort;await new Promise(n=>setTimeout(n,150))}if(await P(t,800))return t;throw new Error(`standalone server didn't come online within ${Math.round(I/1e3)}s`)}function W(){let t=process.argv[1];return t&&F(t)?t:"sootsim"}function m(t){return t instanceof Error?t.message:String(t)}export{Z as runStart};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a}from"./chunk-W4QHQT64.js";import"./chunk-7J4UIBA5.js";import"./chunk-WD54RD4K.js";export{a as settingsStore};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b}from"./chunk-VLUFTHBB.js";import"./chunk-UWRBEBML.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";export{b as flushCliTelemetry,a as trackCliEvent};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{a,b,c}from"./chunk-NF65BNJR.js";import"./chunk-4YUHJ5FX.js";import"./chunk-4UI5OHEO.js";import"./chunk-VLUFTHBB.js";import"./chunk-UWRBEBML.js";import"./chunk-C6GUAXKO.js";import"./chunk-HWRR23AJ.js";import"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};
@@ -1,15 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{c as w,e as b,h as d}from"./chunk-HWRR23AJ.js";import{b as S}from"./chunk-RLGCJT2D.js";import"./chunk-B3OEHV2C.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";function T(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--since"&&t+1<n.length){e.push(t,t+1);let o=n[t+1].trim(),i=/^(\d+(?:\.\d+)?)(ms|s|m)?$/.exec(o);if(i){let l=Number(i[1]),u=i[2]??"ms",r=u==="s"?l*1e3:u==="m"?l*6e4:l;return{since:Date.now()-r,consumed:e}}let s=Number(o);if(Number.isFinite(s)&&s>1e12)return{since:s,consumed:e}}return{consumed:e}}function x(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--kinds"&&t+1<n.length)return e.push(t,t+1),{kinds:n[t+1].split(",").map(o=>o.trim()).filter(Boolean),consumed:e};return{consumed:e}}function A(n){let e=[];for(let t=0;t<n.length;t++)if(n[t]==="--limit"&&t+1<n.length){e.push(t,t+1);let o=Number(n[t+1]);if(Number.isFinite(o)&&o>0)return{limit:o,consumed:e}}return{consumed:e}}function M(n,e){if(e===null)return new Date(n).toLocaleTimeString();let t=(n-e)/1e3;return`${t>=0?"+":""}${t.toFixed(2)}s`}function E(n,e){switch(n){case"app-launch":return e.phase==="launch"?`launch ${e.appName??e.toAppId??""}`:`dismiss ${e.appName??e.fromAppId??""} \u2192 ${e.toAppId??""}`;case"toast":return`"${e.text??""}"${e.durationMs?` (${e.durationMs}ms)`:""}`;case"keyboard":return`${e.phase??"?"}${e.heightPx?` h=${e.heightPx}`:""}${e.mode?` ${e.mode}`:""}`;case"screen":return`${e.phase??"?"} ${e.name??e.activeName??""}`;case"route":return`${e.phase??"?"} ${e.path??e.pathname??""}`;case"alert":case"actionsheet":case"picker":return`${e.phase??"?"} ${e.title??e.message??""}`;case"notification":return`${e.title??""}${e.body?` \u2014 ${e.body}`:""}`;case"fetch":return`${e.method??"GET"} ${e.url??""}${e.status?` -> ${e.status}`:""}`;case"console":return`${e.level??"log"}: ${(e.message??"").toString().slice(0,120)}`;case"shell":return`${e.event??e.type??e.phase??""}`;case"scroll":return`${e.phase??"?"} ${e.target??""}`;case"gesture":return`${e.phase??"?"} ${e.type??""}`;case"text-input":return`${e.phase??"?"}${e.value!==void 0?` "${String(e.value).slice(0,40)}"`:""}`;case"react-commit":{let t=e.slowest;return`${e.fiberCount??"?"} fibers ${e.durationMs??"?"}ms${t?.displayName?` \xB7 ${t.displayName} ${t.durationMs??"?"}ms`:""}`}case"reanimated":case"animation":return`${e.kind??""} ${e.target??""}${e.durationMs?` ${e.durationMs}ms`:""}`}}function y(n,e){let t=M(n.t,e).padStart(8),o=n.context.padEnd(6),i=`[${n.kind}]`.padEnd(15),s="",l=n.data;return l&&typeof l=="object"&&(s=E(n.kind,l)),` ${t} ${o} ${i} ${s}`}function k(n){let e=[],t={label:"initial state",events:[],startedAt:n[0]?.t??null};e.push(t);for(let o of n)if(t.events.push(o),o.kind==="screen"||o.kind==="route"){let i=o.data,s=i?.phase;if(!s||s==="enter"||s==="appear"||s==="active"){let l=i?.name||i?.activeName||i?.path||i?.pathname||o.kind;e.length===1&&t.events.length===1?t.label=`${o.kind}: ${l}`:(t={label:`${o.kind}: ${l}`,events:[],startedAt:o.t},e.push(t))}}return e}function R(n){if(n.total===0)return"nothing recorded";let e=[],t=["error","warning","console","fetch","toast","alert","actionsheet","picker","notification","screen","route","keyboard","app-launch","shell","scroll","gesture","text-input","react-commit","animation","reanimated"],o=new Set;for(let i of t){let s=n.byKind[i];s&&(e.push(`${s} ${i}${s===1?"":"s"}`),o.add(i))}for(let[i,s]of Object.entries(n.byKind))!o.has(i)&&s&&e.push(`${s} ${i}${s===1?"":"s"}`);return e.join(" \xB7 ")}async function B(n,e){let t=w(n,{port:e.port,stripBooleanFlags:["--summary","--all","--json","--no-advance","--help","-h","--flow"],stripValueFlags:["--since","--kinds","--limit"]});(n.includes("--help")||n.includes("-h"))&&(console.log(`
3
- sootsim what-happened \u2014 show recent events from the semantic timeline
4
-
5
- usage:
6
- sootsim what-happened # since last CLI call
7
- sootsim what-happened --summary # one-line counts
8
- sootsim what-happened --all # full ring (ignore cursor)
9
- sootsim what-happened --since 5s # absolute window
10
- sootsim what-happened --kinds toast,fetch
11
- sootsim what-happened --limit 50
12
- sootsim what-happened --json
13
- sootsim what-happened --no-advance # don't advance cursor after read
14
- `),process.exit(0));let o=n.includes("--summary"),i=n.includes("--flow"),s=n.includes("--all"),l=n.includes("--json"),u=n.includes("--no-advance"),{since:r}=T(n),{kinds:f}=x(n),{limit:F}=A(n),$=S(),v={limit:F??200,...f&&f.length?{kinds:f}:{},...r!==void 0?{since:r}:s?{}:{sinceCursor:$}},m=b(t);try{if(o){let c=await d(m,"SootSim.bridges.timeline.summary",v);if(l)console.log(JSON.stringify(c));else{let p=s?"all time":r!==void 0?`last ${((Date.now()-r)/1e3).toFixed(1)}s`:"since last call";console.log(` ${p}: ${R(c)}`)}!u&&!s&&c.lastAt&&await d(m,"SootSim.bridges.timeline.cursorAdvance",$,c.lastAt);return}let a=await d(m,"SootSim.bridges.timeline.recent",v);if(l)console.log(JSON.stringify(i?k(a.events):a,null,2));else if(a.events.length===0)console.log(s?" no events recorded":r!==void 0?" no events in window":" no new events since last call");else if(i){let c=a.events[0]?.t??null,p=k(a.events),g=s?`\u2500\u2500\u2500 ${a.events.length} event(s) total \u2014 flow view \u2500\u2500\u2500`:r!==void 0?`\u2500\u2500\u2500 ${a.events.length} event(s) in last ${((Date.now()-r)/1e3).toFixed(1)}s \u2014 flow view \u2500\u2500\u2500`:`\u2500\u2500\u2500 ${a.events.length} event(s) since last call \u2014 flow view \u2500\u2500\u2500`;console.log(` ${g}`);for(let h of p){console.log(`
15
- \u2500\u2500 ${h.label} (${h.events.length} event${h.events.length===1?"":"s"}) \u2500\u2500`);for(let N of h.events)console.log(y(N,c))}}else{let c=a.events[0]?.t??null,p=s?`\u2500\u2500\u2500 ${a.events.length} event(s) total \u2500\u2500\u2500`:r!==void 0?`\u2500\u2500\u2500 ${a.events.length} event(s) in last ${((Date.now()-r)/1e3).toFixed(1)}s \u2500\u2500\u2500`:`\u2500\u2500\u2500 ${a.events.length} event(s) since last call \u2500\u2500\u2500`;console.log(` ${p}`);for(let g of a.events)console.log(y(g,c))}!u&&!s&&a.watermark>0&&await d(m,"SootSim.bridges.timeline.cursorAdvance",$,a.watermark)}finally{m.close()}}export{B as runWhatHappened};
@@ -1,2 +0,0 @@
1
- /*! sootsim v0.1.39 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
- import{d as n}from"./chunk-UWRBEBML.js";import"./chunk-ECDPQ6S7.js";import"./chunk-WD54RD4K.js";async function s(){let o=await n();o?.token||(console.log(" not signed in"),process.exit(1));let e=o.user;console.log(` ${e?.email||e?.name||e?.id||"signed in"}`),console.log(` origin: ${o.origin}`),console.log(` updated: ${o.updatedAt}`)}export{s as runWhoami};