sootsim 0.0.3 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +4 -4
- package/dist-cli/bin.js +12 -12
- package/dist-cli/chunks/{agent-D5NBV32O.js → agent-YZB6D3DR.js} +4 -4
- package/dist-cli/chunks/agent-wrapper-VHCVS22I.js +15 -0
- package/dist-cli/chunks/{assert-EJ7DQS2H.js → assert-AIVCKKLG.js} +2 -2
- package/dist-cli/chunks/auto-bootstrap-MLNTX23H.js +2 -0
- package/dist-cli/chunks/chunk-27P763IZ.js +61 -0
- package/dist-cli/chunks/chunk-3UIWOHC2.js +62 -0
- package/dist-cli/chunks/chunk-5KGFHWVR.js +1 -0
- package/dist-cli/chunks/chunk-5QIUJNT3.js +5 -0
- package/dist-cli/chunks/{chunk-RLS6PHBW.js → chunk-6GGMKFWJ.js} +1 -1
- package/dist-cli/chunks/{chunk-CQ6PX2EU.js → chunk-6Z275LCY.js} +2 -2
- package/dist-cli/chunks/chunk-75LBYBKW.js +11 -0
- package/dist-cli/chunks/chunk-A5BRCXYE.js +2 -0
- package/dist-cli/chunks/{chunk-FTRI7SVV.js → chunk-CYCXOAVZ.js} +2 -2
- package/dist-cli/chunks/{chunk-5IPP4HAW.js → chunk-DFN3GGH7.js} +2 -2
- package/dist-cli/chunks/chunk-EBEHZJRG.js +117 -0
- package/dist-cli/chunks/{chunk-3SLEIN6B.js → chunk-EJLNUMMP.js} +1 -1
- package/dist-cli/chunks/{chunk-3K6VDPVD.js → chunk-EWSQSALM.js} +2 -2
- package/dist-cli/chunks/{chunk-NKJLTISU.js → chunk-FE7UI3MT.js} +4 -4
- package/dist-cli/chunks/chunk-G663654J.js +1 -0
- package/dist-cli/chunks/chunk-G7XQD4KC.js +4 -0
- package/dist-cli/chunks/chunk-GW7XY5KC.js +2 -0
- package/dist-cli/chunks/{chunk-O2HBPZW5.js → chunk-H2QO4TDV.js} +2 -2
- package/dist-cli/chunks/{chunk-UZL5ZZ4E.js → chunk-HWCKZXNJ.js} +2 -2
- package/dist-cli/chunks/{chunk-BYLX2DO4.js → chunk-HWFHBMAQ.js} +2 -2
- package/dist-cli/chunks/chunk-IJMYFYDZ.js +2 -0
- package/dist-cli/chunks/chunk-J7CTD37P.js +1 -0
- package/dist-cli/chunks/{chunk-44CBTM22.js → chunk-KAXZHEKM.js} +1 -1
- package/dist-cli/chunks/{chunk-P5C3UASK.js → chunk-LHDWH7VS.js} +1 -1
- package/dist-cli/chunks/{chunk-H3JVJXOC.js → chunk-N32NCVL2.js} +2 -2
- package/dist-cli/chunks/{chunk-D4JFMCXD.js → chunk-NIZBR7EK.js} +2 -2
- package/dist-cli/chunks/{chunk-XJBPH4JR.js → chunk-NYY36OKU.js} +12 -12
- package/dist-cli/chunks/{chunk-SUZR2SZZ.js → chunk-OXN2PEB7.js} +1 -1
- package/dist-cli/chunks/{chunk-46LRF7PH.js → chunk-PJL25JQV.js} +1 -1
- package/dist-cli/chunks/{chunk-OG5CKIPC.js → chunk-RMW5BO3S.js} +2 -2
- package/dist-cli/chunks/chunk-SHO54NET.js +2 -0
- package/dist-cli/chunks/chunk-SMVJOWSV.js +16 -0
- package/dist-cli/chunks/chunk-TC6V7YFC.js +3 -0
- package/dist-cli/chunks/{chunk-VI3VW5BL.js → chunk-VFDRZNPN.js} +1 -1
- package/dist-cli/chunks/{chunk-AFTHIY3L.js → chunk-YIO6S3R5.js} +1 -1
- package/dist-cli/chunks/{chunk-X2W4IRXK.js → chunk-YLIIVTTQ.js} +2 -2
- package/dist-cli/chunks/chunk-YR7BGGYE.js +2 -0
- package/dist-cli/chunks/chunk-ZEW3RF5Q.js +1 -0
- package/dist-cli/chunks/{compat-5KSMOWLB.js → compat-Y2O2U7FL.js} +2 -2
- package/dist-cli/chunks/{config-NJB6PQHU.js → config-SRBOFUCI.js} +2 -2
- package/dist-cli/chunks/control-PL2V2O6S.js +2 -0
- package/dist-cli/chunks/daemon-IZC32PZW.js +50 -0
- package/dist-cli/chunks/{debug-QVOBTTLP.js → debug-BIDMW2PE.js} +3 -3
- package/dist-cli/chunks/demo-app-registry-5JFOUU3D.js +2 -0
- package/dist-cli/chunks/{detox-ZZSNZL4T.js → detox-B3FDOIS3.js} +2 -2
- package/dist-cli/chunks/{device-PQB3YGHN.js → device-ZZSI363W.js} +2 -2
- package/dist-cli/chunks/drivers-S4NGK4DB.js +2 -0
- package/dist-cli/chunks/{electron-JB26VHOO.js → electron-5YFHXEOI.js} +3 -3
- package/dist-cli/chunks/flow-JJBO6TFY.js +2 -0
- package/dist-cli/chunks/{hints-IGYDXXDS.js → hints-G5HBBV2O.js} +2 -2
- package/dist-cli/chunks/home-paths-VWC3FWA3.js +2 -0
- package/dist-cli/chunks/{inspect-DSU6ELRM.js → inspect-POOPWUQI.js} +66 -62
- package/dist-cli/chunks/install-MP6FHXNZ.js +2 -0
- package/dist-cli/chunks/install-desktop-2MYEI4FM.js +23 -0
- package/dist-cli/chunks/{install-dev-desktop-4DP3UY2X.js → install-dev-desktop-SKH3KEHY.js} +2 -2
- package/dist-cli/chunks/{keys-R5LAPAAL.js → keys-7PNASIQR.js} +2 -2
- package/dist-cli/chunks/{launch-K3WJV4QA.js → launch-JNS47LAQ.js} +3 -3
- package/dist-cli/chunks/login-YWZWUHBS.js +26 -0
- package/dist-cli/chunks/logout-O6SXMSBP.js +2 -0
- package/dist-cli/chunks/{maestro-YALWKKGU.js → maestro-CW6XVUKV.js} +3 -3
- package/dist-cli/chunks/{preview-D35EEONY.js → preview-WGKJO5FS.js} +2 -2
- package/dist-cli/chunks/{profile-MAF7NM5Q.js → profile-SUOBRPIC.js} +2 -2
- package/dist-cli/chunks/{record-ZCPQNGFW.js → record-QPWLYH5R.js} +2 -2
- package/dist-cli/chunks/runtime-KEMO2MSB.js +25 -0
- package/dist-cli/chunks/{screenshot-NQVZYC3C.js → screenshot-JTY46V7G.js} +2 -2
- package/dist-cli/chunks/{screenshot-mode-E45D2ZFH.js → screenshot-mode-7OYBBX6D.js} +2 -2
- package/dist-cli/chunks/{screenshots-I4SQI4DA.js → screenshots-QISKC4GD.js} +2 -2
- package/dist-cli/chunks/server-YSFJAKAV.js +34 -0
- package/dist-cli/chunks/setup-repo-LFB3HBEO.js +2 -0
- package/dist-cli/chunks/{skills-N4U63E5W.js → skills-MO7BFNVM.js} +2 -2
- package/dist-cli/chunks/store-6MFL53I4.js +2 -0
- package/dist-cli/chunks/telemetry-CN42GMVC.js +2 -0
- package/dist-cli/chunks/{test-VBD6N3AR.js → test-XUI3KNNQ.js} +3 -3
- package/dist-cli/chunks/upload-6FUT7AX5.js +2 -0
- package/dist-cli/chunks/{whoami-4K6JGMWH.js → whoami-TQFHY42N.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +3 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +2 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +3 -1
- package/dist-lib/home-paths.cjs +29 -3
- package/dist-lib/host/bridge-host.cjs +499 -59
- package/dist-lib/index.cjs +2 -2
- package/dist-lib/metro.cjs +2 -2
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/vite-base.cjs +800 -102
- package/dist-lib/vite.cjs +1 -1
- package/package.json +5 -3
- package/dist-cli/chunks/agent-wrapper-Y7I5QGHM.js +0 -15
- package/dist-cli/chunks/auto-bootstrap-Q7GNLISM.js +0 -2
- package/dist-cli/chunks/chunk-2FPPPJE5.js +0 -2
- package/dist-cli/chunks/chunk-3WPAEUOO.js +0 -1
- package/dist-cli/chunks/chunk-4RYT6AQV.js +0 -16
- package/dist-cli/chunks/chunk-5AG24UFX.js +0 -119
- package/dist-cli/chunks/chunk-BU3TZP4Y.js +0 -11
- package/dist-cli/chunks/chunk-CPMW2QLM.js +0 -1
- package/dist-cli/chunks/chunk-EEBR5YP5.js +0 -62
- package/dist-cli/chunks/chunk-EQ7G3UHS.js +0 -4
- package/dist-cli/chunks/chunk-LV5U7TI4.js +0 -1
- package/dist-cli/chunks/chunk-REYWQVAH.js +0 -2
- package/dist-cli/chunks/chunk-USRNDVQ3.js +0 -2
- package/dist-cli/chunks/chunk-WUYJFYOW.js +0 -2
- package/dist-cli/chunks/chunk-ZSRMXBGK.js +0 -2
- package/dist-cli/chunks/control-2F3AGZAO.js +0 -2
- package/dist-cli/chunks/daemon-MLG65V4S.js +0 -49
- package/dist-cli/chunks/demo-app-registry-XRYNJ4GC.js +0 -2
- package/dist-cli/chunks/drivers-GWDQEGWD.js +0 -2
- package/dist-cli/chunks/flow-7JRQXMFV.js +0 -2
- package/dist-cli/chunks/home-paths-CEGSGQTD.js +0 -2
- package/dist-cli/chunks/install-K6IJKADG.js +0 -65
- package/dist-cli/chunks/install-desktop-SC3LNFFF.js +0 -23
- package/dist-cli/chunks/login-A23PYJAW.js +0 -26
- package/dist-cli/chunks/logout-AJ24PH5O.js +0 -2
- package/dist-cli/chunks/runtime-Z2WIXYUN.js +0 -25
- package/dist-cli/chunks/server-ZUXKJRR5.js +0 -29
- package/dist-cli/chunks/store-4A6X4GBJ.js +0 -2
- package/dist-cli/chunks/upload-Y6FZ5XF2.js +0 -2
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
async function o(e){let{spawn:t}=await import("child_process");if(process.platform==="darwin"){t("open",["-g",e],{detached:!0,stdio:"ignore"}).unref();return}if(process.platform==="win32"){t("cmd",["/c","start","",e],{detached:!0,stdio:"ignore"}).unref();return}t("xdg-open",[e],{detached:!0,stdio:"ignore"}).unref()}export{o as a};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{h as s,p as a}from"./chunk-EQ7G3UHS.js";import{spawn as l}from"child_process";import{existsSync as f}from"fs";import{WebSocket as d}from"ws";async function w(){let e=a();if(e&&f(s(e)))return;console.log(" first run \u2014 installing sootsim engine runtime (~6 MB)...");let{runRuntime:o}=await import("./runtime-Z2WIXYUN.js");await o(["install"],{})}async function p(e=7668,o=5e3){if(await m(e,250))return;console.log(" starting sootsim bridge..."),l(process.execPath,[process.argv[1],"server","--quiet"],{detached:!0,stdio:"ignore"}).unref();let n=Date.now()+o;for(;Date.now()<n;){if(await m(e,200))return;await new Promise(t=>setTimeout(t,100))}throw new Error(`sootsim bridge failed to come up within ${o}ms \u2014 try \`sootsim server\` to debug`)}async function y(e=7668){await w(),await p(e)}function m(e,o){return new Promise(i=>{let n=new d(`ws://127.0.0.1:${e}`,{handshakeTimeout:o}),t=!1,r=u=>{if(!t){t=!0;try{n.close()}catch{}i(u)}};n.once("open",()=>r(!0)),n.once("error",()=>r(!1)),setTimeout(()=>r(!1),o)})}export{w as a,p as b,y as c};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{b as a,c as b,d as c,e as d,f as e,g as f,h as g,i as h,j as i,k as j,l as k,m as l,n as m}from"./chunk-BU3TZP4Y.js";import"./chunk-REYWQVAH.js";import"./chunk-SUZR2SZZ.js";import"./chunk-USRNDVQ3.js";import"./chunk-WUYJFYOW.js";import"./chunk-4RYT6AQV.js";import"./chunk-RLS6PHBW.js";import"./chunk-LV5U7TI4.js";import"./chunk-EQ7G3UHS.js";import"./chunk-2FPPPJE5.js";import"./chunk-46LRF7PH.js";import"./chunk-P5C3UASK.js";export{d as buildOpenUrl,c as buildShellUrl,f as printConnectedBrowsers,a as resolveBundleTarget,b as resolveDefaultShellBaseUrl,l as runClaimCommand,m as runCloseCommand,k as runFocusCommand,h as runListCommand,i as runOpenCommand,j as runUseCommand,e as summarizeBrowserUrl,g as waitForBrowserMatch};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import"./chunk-LV5U7TI4.js";import"./chunk-P5C3UASK.js";import{execFileSync as k,spawnSync as o}from"child_process";import{existsSync as i,mkdirSync as d,readFileSync as v,rmSync as f,writeFileSync as y}from"fs";import{homedir as p}from"os";import{dirname as $,resolve as c}from"path";var l="dev.sootsim.server",a="sootsim-server",u=c(p(),"Library/Logs/sootsim"),b=c(p(),".local/state/sootsim");async function F(t,s={}){let[r,...e]=t,n=s.port??7668;if(!r||r==="--help"||r==="-h"){h();return}switch(r){case"install":return P({port:n,force:e.includes("--force")});case"uninstall":return D();case"status":return E();case"restart":return I();case"start":return A();case"stop":return R();default:console.error(` unknown daemon subcommand: ${r}`),h(),process.exit(1)}}function h(){console.log(`
|
|
3
|
-
sootsim daemon \u2014 manage the sootsim bridge as a login agent
|
|
4
|
-
|
|
5
|
-
usage:
|
|
6
|
-
sootsim daemon install [--force] register the login agent and start it
|
|
7
|
-
sootsim daemon uninstall stop and remove the login agent
|
|
8
|
-
sootsim daemon status show whether the agent is installed + running
|
|
9
|
-
sootsim daemon restart restart the agent (use after 'npm update -g sootsim')
|
|
10
|
-
sootsim daemon start start the installed agent
|
|
11
|
-
sootsim daemon stop stop the running agent
|
|
12
|
-
|
|
13
|
-
examples:
|
|
14
|
-
sootsim daemon install
|
|
15
|
-
sootsim daemon status
|
|
16
|
-
sootsim daemon restart
|
|
17
|
-
`)}function x(){try{let s=k("which",["sootsim"],{encoding:"utf8"}).trim();if(s&&i(s))return s}catch{}let t=process.argv[1];if(t&&i(t))return t;throw new Error("could not locate the sootsim binary")}function S(t,s){d(u,{recursive:!0});let r=c(u,"server.out.log"),e=c(u,"server.err.log");return`<?xml version="1.0" encoding="UTF-8"?>
|
|
18
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19
|
-
<plist version="1.0">
|
|
20
|
-
<dict>
|
|
21
|
-
<key>Label</key><string>${l}</string>
|
|
22
|
-
<key>ProgramArguments</key>
|
|
23
|
-
<array>
|
|
24
|
-
<string>${t}</string>
|
|
25
|
-
<string>server</string>
|
|
26
|
-
<string>--quiet</string>
|
|
27
|
-
<string>--port</string>
|
|
28
|
-
<string>${s}</string>
|
|
29
|
-
</array>
|
|
30
|
-
<key>RunAtLoad</key><true/>
|
|
31
|
-
<key>KeepAlive</key><true/>
|
|
32
|
-
<key>ProcessType</key><string>Background</string>
|
|
33
|
-
<key>StandardOutPath</key><string>${r}</string>
|
|
34
|
-
<key>StandardErrorPath</key><string>${e}</string>
|
|
35
|
-
</dict>
|
|
36
|
-
</plist>
|
|
37
|
-
`}function L(t,s){return d(b,{recursive:!0}),`[Unit]
|
|
38
|
-
Description=sootsim bridge daemon
|
|
39
|
-
After=default.target
|
|
40
|
-
|
|
41
|
-
[Service]
|
|
42
|
-
Type=simple
|
|
43
|
-
ExecStart=${t} server --quiet --port ${s}
|
|
44
|
-
Restart=always
|
|
45
|
-
RestartSec=3
|
|
46
|
-
|
|
47
|
-
[Install]
|
|
48
|
-
WantedBy=default.target
|
|
49
|
-
`}function m(){return c(p(),"Library/LaunchAgents",`${l}.plist`)}function g(){return c(p(),".config/systemd/user",`${a}.service`)}async function P({port:t,force:s}){let r=x();if(console.log(` binary: ${r}`),console.log(` port: ${t}`),process.platform==="darwin"){let e=m();if(i(e)&&!s){console.log(` already installed at ${e}`),console.log(" pass --force to overwrite, or use 'sootsim daemon restart' to reload");return}d($(e),{recursive:!0}),y(e,S(r,t)),console.log(` wrote ${e}`),o("launchctl",["bootstrap",`gui/${process.getuid()}`,e],{stdio:"ignore"});let n=o("launchctl",["kickstart","-k",`gui/${process.getuid()}/${l}`],{stdio:"pipe",encoding:"utf8"});n.status!==0&&console.warn(` warning: kickstart returned ${n.status}: ${n.stderr?.trim()}`),console.log(` started (log: ${c(u,"server.err.log")})`);return}if(process.platform==="linux"){let e=g();if(i(e)&&!s){console.log(` already installed at ${e}`),console.log(" pass --force to overwrite, or use 'sootsim daemon restart' to reload");return}d($(e),{recursive:!0}),y(e,L(r,t)),console.log(` wrote ${e}`),o("systemctl",["--user","daemon-reload"],{stdio:"ignore"});let n=o("systemctl",["--user","enable","--now",a],{stdio:"pipe",encoding:"utf8"});n.status!==0&&(console.warn(` warning: systemctl enable --now exited ${n.status}`),n.stderr&&console.warn(` ${n.stderr.trim()}`)),console.log(` started (journalctl --user -u ${a} to tail logs)`);return}console.error(` sootsim daemon install is not supported on ${process.platform}`),console.error(" run 'sootsim server' in a persistent shell instead"),process.exit(1)}async function D(){if(process.platform==="darwin"){let t=m();if(!i(t)){console.log(" not installed");return}o("launchctl",["bootout",`gui/${process.getuid()}/${l}`],{stdio:"ignore"}),f(t,{force:!0}),console.log(` removed ${t}`);return}if(process.platform==="linux"){let t=g();if(!i(t)){console.log(" not installed");return}o("systemctl",["--user","disable","--now",a],{stdio:"ignore"}),f(t,{force:!0}),o("systemctl",["--user","daemon-reload"],{stdio:"ignore"}),console.log(` removed ${t}`);return}console.error(` unsupported platform: ${process.platform}`),process.exit(1)}async function E(){if(process.platform==="darwin"){let t=m();if(!i(t)){console.log(" installed: no");return}console.log(` installed: yes (${t})`);let s=T(t);s&&console.log(` binary: ${s}`);let r=o("launchctl",["print",`gui/${process.getuid()}/${l}`],{encoding:"utf8"});if(r.status===0){let e=r.stdout.match(/state\s*=\s*(\w+)/)?.[1],n=r.stdout.match(/pid\s*=\s*(\d+)/)?.[1];console.log(` state: ${e||"unknown"}${n?` (pid ${n})`:""}`)}else console.log(" state: not running");return}if(process.platform==="linux"){let t=g();if(!i(t)){console.log(" installed: no");return}console.log(` installed: yes (${t})`);let s=o("systemctl",["--user","is-active",a],{encoding:"utf8"});console.log(` state: ${s.stdout.trim()||"unknown"}`);return}console.error(` unsupported platform: ${process.platform}`),process.exit(1)}async function I(){if(process.platform==="darwin"){let t=m();i(t)||(console.error(" not installed \u2014 run `sootsim daemon install` first"),process.exit(1));let s=o("launchctl",["kickstart","-k",`gui/${process.getuid()}/${l}`],{stdio:"pipe",encoding:"utf8"});s.status!==0&&(console.error(` kickstart failed: ${s.stderr?.trim()}`),process.exit(1)),console.log(" restarted");return}if(process.platform==="linux"){let t=g();i(t)||(console.error(" not installed \u2014 run `sootsim daemon install` first"),process.exit(1));let s=o("systemctl",["--user","restart",a],{stdio:"pipe",encoding:"utf8"});s.status!==0&&(console.error(` restart failed: ${s.stderr?.trim()}`),process.exit(1)),console.log(" restarted");return}console.error(` unsupported platform: ${process.platform}`),process.exit(1)}async function A(){if(process.platform==="darwin"){o("launchctl",["kickstart",`gui/${process.getuid()}/${l}`],{stdio:"inherit"});return}if(process.platform==="linux"){o("systemctl",["--user","start",a],{stdio:"inherit"});return}console.error(` unsupported platform: ${process.platform}`),process.exit(1)}async function R(){if(process.platform==="darwin"){o("launchctl",["bootout",`gui/${process.getuid()}/${l}`],{stdio:"inherit"});return}if(process.platform==="linux"){o("systemctl",["--user","stop",a],{stdio:"inherit"});return}console.error(` unsupported platform: ${process.platform}`),process.exit(1)}function T(t){try{return v(t,"utf8").match(/<array>\s*<string>([^<]+)<\/string>/)?.[1]||null}catch{return null}}export{F as runDaemon};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import"./chunk-CPMW2QLM.js";import{a,b,c,d,e,f,g,h,i}from"./chunk-2FPPPJE5.js";import"./chunk-46LRF7PH.js";import"./chunk-P5C3UASK.js";export{e as ALL_DRIVERS,i as buildDriverListRows,a as chromiumDriver,b as electronDriver,f as getAllDrivers,g as getDriver,c as playwrightDriver,h as resolveDriver,d as systemDriver};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a,b,c,d}from"./chunk-XJBPH4JR.js";import"./chunk-5IPP4HAW.js";import"./chunk-BYLX2DO4.js";import"./chunk-3K6VDPVD.js";import"./chunk-3WPAEUOO.js";import"./chunk-O2HBPZW5.js";import"./chunk-EEBR5YP5.js";import"./chunk-X2W4IRXK.js";import"./chunk-3SLEIN6B.js";import"./chunk-OG5CKIPC.js";import"./chunk-D4JFMCXD.js";import"./chunk-CQ6PX2EU.js";import"./chunk-UZL5ZZ4E.js";import"./chunk-BU3TZP4Y.js";import"./chunk-REYWQVAH.js";import"./chunk-SUZR2SZZ.js";import"./chunk-USRNDVQ3.js";import"./chunk-WUYJFYOW.js";import"./chunk-4RYT6AQV.js";import"./chunk-RLS6PHBW.js";import"./chunk-LV5U7TI4.js";import"./chunk-EQ7G3UHS.js";import"./chunk-2FPPPJE5.js";import"./chunk-46LRF7PH.js";import"./chunk-P5C3UASK.js";export{b as discoverSootsimUrl,a as parseFlowFile,d as runFlow,c as runFlowPlayback};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y}from"./chunk-EQ7G3UHS.js";import"./chunk-P5C3UASK.js";export{b as ACTIVE_RUNTIME_FILE,d as CONFIG_FILE,e as DAEMON_HEARTBEAT_STALE_MS,c as DAEMON_LOCKFILE,a as SOOTSIM_HOME_ENV,t as activeRuntimeDir,i as activeRuntimeFile,l as cacheDir,x as claimDaemonLockfile,s as compareSemver,n as configFilePath,m as daemonLockfilePath,j as electronDir,k as electronVersionDir,o as ensureSootsimHome,v as isDaemonLockfileFresh,r as listInstalledRuntimes,p as readActiveRuntime,u as readDaemonLockfile,y as removeDaemonLockfile,h as runtimeDir,g as runtimesDir,f as sootsimHomeDir,q as writeActiveRuntime,w as writeDaemonLockfile};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a as j,b as P}from"./chunk-VI3VW5BL.js";import{c as b}from"./chunk-ZSRMXBGK.js";import"./chunk-LV5U7TI4.js";import"./chunk-EQ7G3UHS.js";import"./chunk-P5C3UASK.js";import{execSync as V}from"child_process";import{existsSync as w,readFileSync as C,writeFileSync as x}from"fs";import{relative as A,resolve as u}from"path";import{existsSync as a,readFileSync as d,readdirSync as O,statSync as L}from"fs";import{basename as R,dirname as T,join as c}from"path";function S(e){let n=e;for(;;){if(a(c(n,"turbo.json"))||a(c(n,"nx.json"))||a(c(n,"lerna.json"))||a(c(n,"pnpm-workspace.yaml")))return n;let s=c(n,"package.json");if(a(s))try{if(JSON.parse(d(s,"utf8")).workspaces)return n}catch{}let i=T(n);if(i===n)break;n=i}return e}function W(e){return a(c(e,"bun.lock"))||a(c(e,"bun.lockb"))?"bun":a(c(e,"pnpm-lock.yaml"))?"pnpm":a(c(e,"yarn.lock"))?"yarn":"npm"}function _(e){if(a(c(e,"turbo.json")))return"turbo";if(a(c(e,"nx.json")))return"nx";if(a(c(e,"pnpm-workspace.yaml")))return"pnpm";let n=c(e,"package.json");if(a(n))try{if(JSON.parse(d(n,"utf8")).workspaces)return"npm-workspaces"}catch{}return"single"}function J(e){return e.one?"one":e.expo?"expo":e["react-native"]?"bare":"unknown"}function y(e){let n=c(e,"package.json");if(!a(n))return null;let s;try{s=JSON.parse(d(n,"utf8"))}catch{return null}let i={...s.dependencies,...s.devDependencies},r=J(i);return r==="unknown"?null:{dir:e,name:s.name||R(e),framework:r,hasViteConfig:a(c(e,"vite.config.ts"))||a(c(e,"vite.config.js")),hasMetroConfig:a(c(e,"metro.config.js"))||a(c(e,"metro.config.ts")),hasSootsimDependency:!!i.sootsim,devCommand:s.scripts?.dev||null}}function N(e){let n=[],s=c(e,"pnpm-workspace.yaml");if(a(s)){let o=d(s,"utf8").match(/packages:\s*\n((?:\s+-\s+.+\n?)+)/);if(o){let t=o[1].split(`
|
|
3
|
-
`).filter(Boolean);for(let g of t){let l=g.replace(/^\s*-\s*['"]?/,"").replace(/['"]?\s*$/,"");l&&n.push(...v(e,l))}}return n}let i=c(e,"package.json");if(a(i))try{let r=JSON.parse(d(i,"utf8")),o=Array.isArray(r.workspaces)?r.workspaces:r.workspaces?.packages||[];for(let t of o)n.push(...v(e,t))}catch{}return n}function v(e,n){let s=n.replace(/\/\*\*?$/,"").replace(/\*$/,""),i=c(e,s);if(!a(i))return[];try{return O(i).map(o=>c(i,o)).filter(o=>{try{return L(o).isDirectory()&&a(c(o,"package.json"))}catch{return!1}})}catch{return[]}}function D(e){let n=_(e),s=W(e);if(n==="single"){let t=y(e);return{root:e,type:n,packageManager:s,apps:t?[t]:[]}}let i=N(e),r=[],o=y(e);o&&r.push(o);for(let t of i){if(t===e)continue;let g=y(t);g&&r.push(g)}return{root:e,type:n,packageManager:s,apps:r}}function M(e){switch(e){case"bun":return"bun add -d sootsim";case"pnpm":return"pnpm add -D sootsim";case"yarn":return"yarn add -D sootsim";case"npm":return"npm install -D sootsim"}}async function re(e){(e.includes("--help")||e.includes("-h"))&&(console.log(`
|
|
4
|
-
sootsim install \u2014 set up sootsim in your project
|
|
5
|
-
|
|
6
|
-
detects your bundler (one, expo, metro), adds sootsim as a
|
|
7
|
-
dependency, configures the bundler plugin, and adds dev scripts.
|
|
8
|
-
|
|
9
|
-
usage:
|
|
10
|
-
sootsim install interactive setup
|
|
11
|
-
sootsim install --yes skip confirmations
|
|
12
|
-
sootsim install --dry-run show what would be done
|
|
13
|
-
|
|
14
|
-
works with monorepos (turbo, pnpm, nx) \u2014 scans for app packages.
|
|
15
|
-
`),process.exit(0));let n=e.includes("--yes")||e.includes("-y"),s=e.includes("--dry-run"),i=process.cwd(),r=S(i),o=D(r);if(console.log(`
|
|
16
|
-
sootsim \u2014 project setup
|
|
17
|
-
`),!s)try{await b()}catch(p){console.error(` bootstrap failed: ${p instanceof Error?p.message:String(p)}`),console.error(" continuing with project setup; rerun later if needed.")}o.apps.length===0&&(console.log(" no react native apps found in this project."),console.log(` sootsim works with one, expo, and react-native projects.
|
|
18
|
-
`),process.exit(1));let t;if(o.type!=="single"&&o.apps.length>1){console.log(` monorepo detected (${o.type} + ${o.packageManager})
|
|
19
|
-
`);let p=await P("which app?",o.apps.map(f=>`${(A(r,f.dir)||".").padEnd(30)} (${f.framework})`));t=o.apps[p]}else t=o.apps[0];let g=t.framework==="one"?"metro (via one)":t.framework==="expo"?"metro (via expo)":"metro";console.log(" detected:"),console.log(` framework: ${t.framework}`),console.log(` bundler: ${g}`),console.log(` package: ${t.name}`),console.log(` manager: ${o.packageManager}`),console.log();let l=[];if(!t.hasSootsimDependency){let p=M(o.packageManager);l.push({label:"add sootsim as devDependency",run:()=>{V(p,{cwd:t.dir,stdio:"pipe"})}})}t.framework==="one"&&t.hasViteConfig?l.push({label:"add sootsimPlugin() to vite.config.ts",run:()=>$(t.dir)}):(t.framework==="expo"||t.framework==="bare")&&t.hasMetroConfig?l.push({label:"add withSootsim() to metro.config.js",run:()=>B(t.dir)}):t.framework==="one"?l.push({label:"add sootsimPlugin() to vite.config.ts",run:()=>$(t.dir)}):l.push({label:"create metro.config.js with withSootsim()",run:()=>G(t.dir,t.framework)}),console.log(" will:"),l.forEach((p,f)=>console.log(` ${f+1}. ${p.label}`)),console.log(),s&&(console.log(` (dry run \u2014 no changes made)
|
|
20
|
-
`),process.exit(0)),n||(await j("continue?")||(console.log(`
|
|
21
|
-
cancelled.
|
|
22
|
-
`),process.exit(0)),console.log());for(let p=0;p<l.length;p++){let f=l[p];process.stdout.write(` [${p+1}/${l.length}] ${f.label}...`);try{f.run(),console.log(" done")}catch(h){console.log(` failed: ${h.message}`),(f.label.includes("vite.config")||f.label.includes("metro.config"))&&U(t)}}console.log(`
|
|
23
|
-
done! run your app normally and hit:
|
|
24
|
-
|
|
25
|
-
then open:
|
|
26
|
-
http://localhost:8081/__soot/
|
|
27
|
-
`)}function $(e){let n=u(e,"vite.config.ts")||u(e,"vite.config.js"),s=u(e,"vite.config.ts"),i=u(e,"vite.config.js"),r=w(s)?s:i;if(!w(r))throw new Error(`no vite config found at ${e}`);let o=C(r,"utf8");if(o.includes("sootsimPlugin")){console.log(" (already configured)");return}let t="import { sootsimPlugin } from 'sootsim/vite'",g=/^(import\s+.+)$/gm,l=0,p;for(;(p=g.exec(o))!==null;)l=p.index+p[0].length;l>0?o=o.slice(0,l)+`
|
|
28
|
-
`+t+o.slice(l):o=t+`
|
|
29
|
-
`+o;let f=o.match(/plugins\s*:\s*\[/);if(f&&f.index!==void 0){let h=f.index+f[0].length,k=1,m=h;for(;m<o.length&&k>0;)o[m]==="["&&k++,o[m]==="]"&&k--,k>0&&m++;let q=o.slice(0,m),E=o.slice(m),I=o.slice(h).match(/\n(\s+)\S/)?.[1]||" ",F=o.slice(o.lastIndexOf(`
|
|
30
|
-
`,m),m+1).match(/\n(\s*)/)?.[1]||" ";o=q.trimEnd()+`
|
|
31
|
-
`+I+`sootsimPlugin(),
|
|
32
|
-
`+F+E}else throw new Error("could not find plugins array in vite config");x(r,o)}function B(e){let n=u(e,"metro.config.js"),s=u(e,"metro.config.ts"),i=w(n)?n:s;if(!w(i))throw new Error(`no metro config found at ${e}`);let r=C(i,"utf8");if(r.includes("withSootsim")){console.log(" (already configured)");return}r="const { withSootsim } = require('sootsim/metro')"+`
|
|
33
|
-
`+r,r=r.replace(/(module\.exports\s*=\s*)([^;]+)/,(t,g,l)=>`${g}withSootsim(${l.trim()})`),x(i,r)}function G(e,n){let s=u(e,"metro.config.js"),i;n==="expo"?i=`const { getDefaultConfig } = require('expo/metro-config')
|
|
34
|
-
const { withSootsim } = require('sootsim/metro')
|
|
35
|
-
|
|
36
|
-
const config = getDefaultConfig(__dirname)
|
|
37
|
-
|
|
38
|
-
module.exports = withSootsim(config)
|
|
39
|
-
`:i=`const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config')
|
|
40
|
-
const { withSootsim } = require('sootsim/metro')
|
|
41
|
-
|
|
42
|
-
const config = {}
|
|
43
|
-
|
|
44
|
-
module.exports = withSootsim(mergeConfig(getDefaultConfig(__dirname), config))
|
|
45
|
-
`,x(s,i)}function U(e){e.framework==="one"?console.log(`
|
|
46
|
-
manual setup \u2014 add to your vite.config.ts:
|
|
47
|
-
|
|
48
|
-
import { sootsimPlugin } from 'sootsim/vite'
|
|
49
|
-
|
|
50
|
-
export default {
|
|
51
|
-
plugins: [
|
|
52
|
-
one({ /* ... */ }),
|
|
53
|
-
sootsimPlugin(),
|
|
54
|
-
],
|
|
55
|
-
}
|
|
56
|
-
`):console.log(`
|
|
57
|
-
manual setup \u2014 add to your metro.config.js:
|
|
58
|
-
|
|
59
|
-
const { withSootsim } = require('sootsim/metro')
|
|
60
|
-
module.exports = withSootsim(config)
|
|
61
|
-
`)}async function ie(){console.log(`
|
|
62
|
-
sootsim uninstall is no longer needed.
|
|
63
|
-
to remove sootsim, just remove the plugin from your config
|
|
64
|
-
and remove sootsim from your dependencies.
|
|
65
|
-
`)}export{re as runInstall,ie as runUninstall};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a as x}from"./chunk-VI3VW5BL.js";import{a as $}from"./chunk-46LRF7PH.js";import"./chunk-P5C3UASK.js";import{spawn as v,spawnSync as u}from"child_process";import{chmodSync as k,createWriteStream as S,existsSync as f,mkdirSync as y,renameSync as P,rmSync as w,statSync as T}from"fs";import{tmpdir as E}from"os";import{dirname as D,join as m,resolve as b}from"path";var h="https://sootbean.com/api/electron-release";function M(){let r=process.arch;if(process.platform==="darwin"){let o=r==="arm64"?"mac-arm64":"mac-x64",n=`sootsim-latest-${o}.dmg`;return{platform:o,filename:n,url:`${h}/${n}`,install:I}}if(process.platform==="linux"){let o="sootsim-latest-linux-x64.AppImage";return{platform:"linux-x64",filename:o,url:`${h}/${o}`,install:L}}if(process.platform==="win32"){let o="sootsim-latest-win-x64.exe";return{platform:"win-x64",filename:o,url:`${h}/${o}`,install:B}}return null}async function A({url:r,dest:o,onProgress:n}){let s=await fetch(r,{redirect:"follow"});if(!s.ok)throw new Error(`download failed: ${s.status} ${s.statusText} (${r})`);let e=s.headers.get("content-length"),l=e?Number(e):null;if(!s.body)throw new Error("download failed: empty response body");y(D(o),{recursive:!0});let i=S(o),d=s.body.getReader(),a=0;try{for(;;){let{done:t,value:c}=await d.read();if(t)break;i.write(Buffer.from(c)),a+=c.byteLength,n?.(a,l)}}finally{await new Promise((t,c)=>{i.end(p=>p?c(p):t())})}}function O(r,o){let n=(r/1048576).toFixed(1);if(!o)return` ${n} MB`;let s=Math.min(100,Math.round(r/o*100)),e=(o/(1024*1024)).toFixed(1),l=24,i=Math.round(s/100*l);return` ${"\u2588".repeat(i)+"\u2591".repeat(l-i)} ${s}% ${n} / ${e} MB`}async function I(r){let o=u("hdiutil",["attach","-nobrowse","-readonly",r],{encoding:"utf8"});if(o.status!==0)throw new Error(`hdiutil attach failed: ${o.stderr||o.stdout}`.trim());let n=o.stdout.trim().split(`
|
|
3
|
-
`),e=n[n.length-1].split(" ").pop()?.trim();if(!e||!f(e))throw new Error(`could not determine dmg mount point (output: ${o.stdout})`);let l=m(e,"sootsim.app");if(!f(l))throw u("hdiutil",["detach","-force",e]),new Error(`sootsim.app not found inside ${e}`);let i="/Applications",d=b(process.env.HOME||"","Applications"),a=i;try{let g=m(i,`.sootsim-write-probe-${process.pid}`);u("touch",[g]),f(g)?w(g,{force:!0}):a=d}catch{a=d}a===d&&y(a,{recursive:!0});let t=m(a,"sootsim.app");f(t)&&w(t,{recursive:!0,force:!0});let c=u("cp",["-R",l,t]),p=u("hdiutil",["detach","-force",e]);if(c.status!==0)throw new Error(`copy to ${t} failed: ${c.stderr?.toString()||""}`.trim());return p.status!==0&&console.warn(` warning: failed to unmount ${e} (${p.stderr?.toString().trim()||"unknown error"})`),u("xattr",["-dr","com.apple.quarantine",t]),t}async function L(r){let o=b(process.env.HOME||"","Applications");y(o,{recursive:!0});let n=m(o,"sootsim.AppImage");return f(n)&&w(n,{force:!0}),P(r,n),k(n,493),n}async function B(r){return await new Promise((o,n)=>{let s=v("cmd",["/c","start",'""',"/wait",r],{stdio:"inherit"});s.once("error",n),s.once("exit",e=>{e===0?o():n(new Error(`installer exited with code ${e}`))})}),r}async function _(r){(r.includes("--help")||r.includes("-h"))&&(console.log(`
|
|
4
|
-
sootsim install-desktop \u2014 download and install the optional desktop GUI
|
|
5
|
-
|
|
6
|
-
the CLI + daemon are the canonical sootsim surface; the GUI is optional.
|
|
7
|
-
if you just want to drive a running metro/expo dev server from the
|
|
8
|
-
terminal, you don't need this.
|
|
9
|
-
|
|
10
|
-
usage:
|
|
11
|
-
sootsim install-desktop [options]
|
|
12
|
-
|
|
13
|
-
options:
|
|
14
|
-
-y, --yes skip confirmation and install immediately
|
|
15
|
-
--force reinstall even if the companion is already present
|
|
16
|
-
|
|
17
|
-
examples:
|
|
18
|
-
sootsim install-desktop
|
|
19
|
-
sootsim install-desktop --yes
|
|
20
|
-
`),process.exit(0));let o=r.includes("--yes")||r.includes("-y")||process.env.SOOTSIM_NO_PROMPT==="1"||process.env.CI==="1"||!process.stdin.isTTY,n=r.includes("--force"),s=$();if(s&&!n){console.log(` sootsim desktop already installed at: ${s.path}`),console.log(" pass --force to reinstall.");return}let e=M();if(e||(console.error(` no desktop build available for ${process.platform}/${process.arch}.`),console.error(" supported: darwin-arm64, darwin-x64, linux-x64, win32-x64"),process.exit(1)),console.log(` platform: ${e.platform}`),console.log(` download: ${e.url}`),console.log(),!o){if(!await x("download and install now?",!0)){console.log(" cancelled.");return}console.log()}let l=m(E(),`sootsim-install-${Date.now()}`),i=m(l,e.filename),d=0;process.stdout.write(` downloading ${e.filename}...
|
|
21
|
-
`);try{await A({url:e.url,dest:i,onProgress:(t,c)=>{let p=Date.now();p-d<100&&t<(c??1/0)||(d=p,process.stdout.isTTY&&process.stdout.write(`\r\x1B[2K${O(t,c)}`))}})}catch(t){w(l,{recursive:!0,force:!0}),console.error(`
|
|
22
|
-
download failed: ${t instanceof Error?t.message:String(t)}`),process.exit(1)}process.stdout.isTTY&&process.stdout.write(`
|
|
23
|
-
`);let a=T(i).size;console.log(` downloaded ${(a/(1024*1024)).toFixed(1)} MB`),console.log(),console.log(" installing...");try{let t=await e.install(i);console.log(` installed: ${t}`)}catch(t){console.error(` install failed: ${t instanceof Error?t.message:String(t)}`),console.error(` keeping download at ${i} for manual install.`),process.exit(1)}finally{w(l,{recursive:!0,force:!0})}console.log(),console.log(" next steps:"),console.log(" sootsim electron launch the desktop app"),console.log(" sootsim open <target> open a demo or bundle in it")}export{_ as runInstallDesktop};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{b as g,d as f}from"./chunk-3SLEIN6B.js";import"./chunk-P5C3UASK.js";import{exec as S}from"node:child_process";import{randomBytes as v}from"node:crypto";import w from"node:http";var I=process.env.SOOTSIM_AUTH_ORIGIN||"https://sootbean.com",m="http://localhost:3000";async function $(e){if(e)return e;if(process.env.SOOTSIM_AUTH_ORIGIN)return process.env.SOOTSIM_AUTH_ORIGIN;if(process.env.SOOTSIM_UPLOAD_ORIGIN)return process.env.SOOTSIM_UPLOAD_ORIGIN;try{if((await fetch(`${m}/api/auth/me`)).ok)return m}catch{}return I}function x(){console.log(`
|
|
3
|
-
sootsim login \u2014 sign in so desktop uploads can attach to your account
|
|
4
|
-
|
|
5
|
-
usage:
|
|
6
|
-
sootsim login [--origin <url>]
|
|
7
|
-
|
|
8
|
-
options:
|
|
9
|
-
--origin <url> auth host (default: auto)
|
|
10
|
-
prefers ${m} when available, otherwise
|
|
11
|
-
falls back to ${I}
|
|
12
|
-
override with SOOTSIM_AUTH_ORIGIN env var
|
|
13
|
-
-h, --help
|
|
14
|
-
`)}function R(e,o){let t=e.findIndex(i=>i===o);if(t<0)return;let c=e[t+1];return e.splice(t,2),c}function L(e){let o=process.platform==="darwin"?`open "${e}"`:process.platform==="win32"?`start "" "${e}"`:`xdg-open "${e}"`;S(o,t=>{t&&(console.log(" could not open browser automatically."),console.log(` open this URL manually:
|
|
15
|
-
${e}
|
|
16
|
-
`))})}function u(e){return`<!doctype html>
|
|
17
|
-
<html>
|
|
18
|
-
<body style="font-family:system-ui;background:#000;color:#fff;display:flex;align-items:center;justify-content:center;height:100vh;margin:0">
|
|
19
|
-
<div style="max-width:480px;text-align:center">
|
|
20
|
-
<h1 style="font-size:28px;margin:0 0 12px">SootSim</h1>
|
|
21
|
-
<p style="color:#ccc">${e}</p>
|
|
22
|
-
</div>
|
|
23
|
-
</body>
|
|
24
|
-
</html>`}async function _(e){try{let o=await fetch(`${e.replace(/\/$/,"")}/api/dev-login`,{method:"POST"});if(o.status===403)return{ok:!1,error:"dev-login disabled (not in dev mode)"};if(!o.ok){let c=await o.text().catch(()=>"");return{ok:!1,error:`dev-login ${o.status}: ${c}`}}let t=await o.json();return t.token?{ok:!0,token:t.token,userId:t.user?.id,email:t.email}:{ok:!1,error:"dev-login response missing token"}}catch(o){return{ok:!1,error:o instanceof Error?o.message:"dev-login fetch failed"}}}function P(e){try{let o=new URL(e).hostname;return o==="localhost"||o==="127.0.0.1"||o.endsWith(".local")}catch{return!1}}async function G(e){(e.includes("--help")||e.includes("-h"))&&(x(),process.exit(0));let o=[...e],t=await $(R(o,"--origin"));if(P(t)){console.log(` detected local origin (${t}) \u2014 signing in as dev user`);let n=await _(t);if(n.ok){g({token:n.token,user:n.userId?{id:n.userId,email:n.email}:null,origin:t,source:"cli"});let s=await f(t),a=s?.user?.email||n.email||s?.user?.id||n.userId;console.log(` signed in${a?` as ${a}`:""} (dev)`);return}console.log(` dev-login not available (${n.error}); falling back to browser`)}let c=v(16).toString("hex"),i=await new Promise(n=>{let s=w.createServer((a,r)=>{try{let l=new URL(a.url||"/","http://127.0.0.1"),y=l.searchParams.get("state"),k=l.searchParams.get("token"),b=l.searchParams.get("email")||void 0,O=l.searchParams.get("userId")||void 0,d=l.searchParams.get("error");if(r.setHeader("content-type","text/html; charset=utf-8"),d){r.end(u(`sign-in failed: ${d}`)),n({ok:!1,error:d}),s.close();return}if(y!==c){r.end(u("state mismatch. close this tab and retry `sootsim login`.")),n({ok:!1,error:"state mismatch"}),s.close();return}if(!k){r.end(u("missing token. close this tab and retry `sootsim login`.")),n({ok:!1,error:"missing token"}),s.close();return}r.end(u("sign-in complete. you can return to the terminal.")),n({ok:!0,token:k,email:b,userId:O}),s.close()}catch(l){r.statusCode=500,r.end(u("sign-in callback failed. retry `sootsim login`.")),n({ok:!1,error:l instanceof Error?l.message:"callback failed"}),s.close()}});s.listen(0,"127.0.0.1",()=>{let a=s.address();if(!a||typeof a=="string"){n({ok:!1,error:"failed to bind callback server"}),s.close();return}let r=new URL(`${t.replace(/\/$/,"")}/auth/sootsim-cli`);r.searchParams.set("state",c),r.searchParams.set("port",String(a.port)),r.searchParams.set("sootbean",t),console.log(" opening browser for sootsim login..."),console.log(` waiting for callback on 127.0.0.1:${a.port}`),console.log(` if nothing opens, visit:
|
|
25
|
-
${r.toString()}
|
|
26
|
-
`),L(r.toString())})});i.ok||(console.error(` login failed: ${i.error}`),process.exit(1)),g({token:i.token,user:i.userId?{id:i.userId,email:i.email}:null,origin:t,source:"cli"});let h=await f(t),p=h?.user?.email||i.email||h?.user?.id||i.userId;console.log(` signed in${p?` as ${p}`:""}`)}export{G as runLogin};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a as e,c as t}from"./chunk-3SLEIN6B.js";import"./chunk-P5C3UASK.js";async function r(){let o=e();if(!o?.token){console.log(" not signed in");return}try{await fetch(`${o.origin.replace(/\/$/,"")}/api/auth/sign-out`,{method:"POST",headers:{authorization:`Bearer ${o.token}`}})}catch{}t(),console.log(" signed out")}export{r as runLogout};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a as k}from"./chunk-4RYT6AQV.js";import"./chunk-RLS6PHBW.js";import"./chunk-LV5U7TI4.js";import{h as v,l as S,o as p,p as d,q as R,r as w}from"./chunk-EQ7G3UHS.js";import"./chunk-P5C3UASK.js";import{spawn as T}from"child_process";import N from"crypto";import i from"fs";import g from"path";import{Readable as A}from"stream";import{pipeline as C}from"stream/promises";import{WebSocket as M}from"ws";var O="https://sootbean.com",P="SOOTSIM_CDN_ORIGIN";function y(){let e=process.env[P];return e&&e.length>0?e.replace(/\/+$/,""):O}function j(){let e=new URL(`${y()}/runtimes/manifest.json`);return e.searchParams.set("t",String(Date.now())),e.toString()}function _(e){return`${y()}/runtimes/sootsim-runtime-${e}.tar.gz`}async function se(e,n={}){let[s,...t]=e;if(!s||s==="--help"||s==="-h"){I();return}switch(s){case"install":return E(t,n);case"list":case"ls":return U(t);case"use":return L(t);case"remove":case"rm":return W(t);case"which":case"active":return V();default:console.error(` unknown runtime subcommand: ${s}`),I(),process.exit(1)}}function I(){console.log(`
|
|
3
|
-
sootsim runtime \u2014 manage engine runtimes under ~/.sootsim/runtimes/
|
|
4
|
-
|
|
5
|
-
usage:
|
|
6
|
-
sootsim runtime install [version] install a version (default: channel latest)
|
|
7
|
-
sootsim runtime list show installed + available versions
|
|
8
|
-
sootsim runtime use <version> switch active runtime
|
|
9
|
-
sootsim runtime remove <version> delete an installed runtime
|
|
10
|
-
sootsim runtime which print active runtime version
|
|
11
|
-
|
|
12
|
-
flags:
|
|
13
|
-
--channel <name> channel to resolve 'latest' from (default: stable)
|
|
14
|
-
--force reinstall even if the version is already on disk
|
|
15
|
-
--set-active=false do not switch active runtime after install
|
|
16
|
-
|
|
17
|
-
environment:
|
|
18
|
-
SOOTSIM_CDN_ORIGIN override the CDN base URL (default: ${O})
|
|
19
|
-
|
|
20
|
-
examples:
|
|
21
|
-
sootsim runtime install
|
|
22
|
-
sootsim runtime install 1.2.3
|
|
23
|
-
sootsim runtime install --channel beta
|
|
24
|
-
sootsim runtime use 1.2.3
|
|
25
|
-
`)}async function E(e,n){let{version:s,flags:t}=z(e),o=t.channel??n.channel??"stable",a=t.force===!0,f=t.setActive!==!1;p(),console.log("sootsim runtime install"),console.log(` cdn: ${y()}`);let l=await D(),m=s||l.channels[o]?.latest;m||(console.error(` no version specified and channel '${o}' has no latest entry in the manifest`),process.exit(1));let r=m,u=l.versions[r];u||(console.error(` version ${r} not found in manifest`),console.error(` available: ${Object.keys(l.versions).slice(-10).join(", ")||"(none)"}`),process.exit(1)),console.log(` version: ${r} (channel: ${o})`);let c=v(r);if(!a&&i.existsSync(g.join(c,"index.html"))){console.log(` already installed at ${c}`),f&&await $(r);return}let b=u.tarball||_(r),h=g.join(S(),`sootsim-runtime-${r}.tar.gz`);console.log(` fetch: ${b}`),await G(b,h),console.log(" verify: sha256");let x=await H(h);x!==u.sha256&&(i.rmSync(h,{force:!0}),console.error(" sha256 mismatch"),console.error(` expected: ${u.sha256}`),console.error(` actual: ${x}`),process.exit(1)),console.log(` extract: ${c}`),i.rmSync(c,{recursive:!0,force:!0}),i.mkdirSync(c,{recursive:!0}),await q(h,c),i.existsSync(g.join(c,"index.html"))||(console.error(" extracted tarball is missing index.html \u2014 corrupted runtime"),process.exit(1)),console.log(` installed ${r}`),f&&await $(r)}async function $(e){R(e),console.log(` active: ${e}`),await F(e)||console.log(` (no daemon running \u2014 next sootsim/electron launch will pick up ${e})`)}async function F(e){let{isDaemonLockfileFresh:n,readDaemonLockfile:s}=await import("./home-paths-CEGSGQTD.js"),t=s();if(!n(t))return!1;let o=k();return new Promise(a=>{let f=!1,l=!1,m=c=>{f||(f=!0,a(c))},r=new M(`ws://127.0.0.1:${o}`,{handshakeTimeout:800}),u=setTimeout(()=>{try{r.close()}catch{}m(l)},1500);r.on("open",()=>{try{r.send(JSON.stringify({type:"runtime:use",version:e,id:0})),l=!0}catch{}setTimeout(()=>{try{r.close()}catch{}},100)}),r.on("close",()=>{clearTimeout(u),m(l)}),r.on("error",()=>{clearTimeout(u),m(!1)})})}async function U(e){p();let n=w(),s=d();if(console.log("installed:"),n.length===0)console.log(" (none)");else for(let t of n)console.log(` ${t===s?"*":" "} ${t}`);try{let t=await D();console.log("available (latest per channel):");for(let[o,a]of Object.entries(t.channels))console.log(` ${o.padEnd(8)} ${a.latest}`)}catch(t){console.log(`available: (could not fetch manifest: ${B(t)})`)}}async function L(e){let n=e[0];n||(console.error(" usage: sootsim runtime use <version>"),process.exit(1));let s=w();s.includes(n)||(console.error(` version ${n} is not installed`),console.error(` installed: ${s.join(", ")||"(none)"}`),console.error(` run \`sootsim runtime install ${n}\` first`),process.exit(1)),await $(n)}async function W(e){let n=e[0];n||(console.error(" usage: sootsim runtime remove <version>"),process.exit(1)),d()===n&&(console.error(` cannot remove active runtime ${n}`),console.error(" switch with `sootsim runtime use <other>` first, or install another version"),process.exit(1));let t=v(n);if(!i.existsSync(t)){console.error(` ${n} is not installed`);return}i.rmSync(t,{recursive:!0,force:!0}),console.log(` removed ${n}`)}async function V(){let e=d();if(!e){console.log(" no active runtime");return}console.log(e)}function z(e){let n={},s=[];for(let t=0;t<e.length;t++){let o=e[t];if(o==="--channel"&&t+1<e.length){n.channel=e[t+1],t++;continue}if(o.startsWith("--channel=")){n.channel=o.slice(10);continue}if(o==="--force"){n.force=!0;continue}if(o==="--set-active=false"||o==="--no-set-active"){n.setActive=!1;continue}s.push(o)}return{version:s[0]??null,flags:n}}async function D(){let e=j(),n=await fetch(e,{headers:{Accept:"application/json"}});if(!n.ok)throw new Error(`manifest fetch failed: ${n.status} ${n.statusText} (${e})`);return await n.json()}async function G(e,n){let s=await fetch(e);if(!s.ok||!s.body)throw new Error(`download failed: ${s.status} ${s.statusText} (${e})`);i.mkdirSync(g.dirname(n),{recursive:!0});let t=`${n}.partial`;try{await C(A.fromWeb(s.body),i.createWriteStream(t)),i.renameSync(t,n)}catch(o){try{i.unlinkSync(t)}catch{}throw o}}function H(e){return new Promise((n,s)=>{let t=N.createHash("sha256"),o=i.createReadStream(e);o.on("data",a=>t.update(a)),o.on("error",s),o.on("end",()=>n(t.digest("hex")))})}function q(e,n){return new Promise((s,t)=>{let o=T("tar",["-xzf",e,"-C",n],{stdio:["ignore","inherit","inherit"]});o.on("error",t),o.on("exit",a=>{a===0?s():t(new Error(`tar exited with code ${a}`))})})}function B(e){return e instanceof Error?e.message:String(e)}export{se as runRuntime};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{b as U,c as R,d as K,e as N,f as J,h as q,i as w,j as G,k as V,l as z,p as Y,s as b,t as Z,u as Q,v as X,w as ee}from"./chunk-NKJLTISU.js";import"./chunk-44CBTM22.js";import{a as $}from"./chunk-5IPP4HAW.js";import"./chunk-O2HBPZW5.js";import"./chunk-REYWQVAH.js";import"./chunk-LV5U7TI4.js";import{o as A,p as D,q as _,r as L,t as M,u as W,v as F,w as j,x as H,y as O}from"./chunk-EQ7G3UHS.js";import"./chunk-P5C3UASK.js";import{spawn as T}from"child_process";import v from"fs";import{createServer as ae}from"http";import y from"path";import{WebSocket as f,WebSocketServer as ce}from"ws";import te from"node:fs";import C from"node:path";var E=1;function ne(){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(h=>Number.isFinite(h)&&h>0)}var P=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 r of t)this.decrementSubscription(r);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let r=t?.type;if(typeof r!="string"||!r.startsWith("agent:"))return!1;let o=t.id;try{let s=await this.dispatch(e,r,t);this.respond(e,o,s)}catch(s){s instanceof b?this.respondError(e,o,s.message,s.code):this.respondError(e,o,s instanceof Error?s.message:String(s))}return!0}async seedOnBoot(){try{await z()}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,r){switch(t){case"agent:list-projects":return N();case"agent:upsert-project":return R(r.input??{});case"agent:delete-project":return q(String(r.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(r.input??{});case"agent:list-sessions":return G(r.projectId?String(r.projectId):void 0);case"agent:start-session":return this.doStartSession(r.input??{});case"agent:send-prompt":{let s=String(r.sessionId),n=w(s);if(!n)throw new b("NO_SESSION",`no session: ${s}`);let i=this.normalizePromptEnvelope(r);return await Q(s,i),this.notePromptAccepted(s,i,n.status==="working")}case"agent:end-session":this.dropSessionFanout(String(r.sessionId)),await X(String(r.sessionId));let o=w(String(r.sessionId));return o&&this.broadcastSessionStatus(o),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(r.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(r.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(r.sessionId));default:throw new b("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async doStartSession(e){if(!K(e.projectId))throw new b("NO_PROJECT",`no project: ${e.projectId}`);let r=await Z(e);return this.broadcastSessionStatus(r.session),r}async autoAttachForUrl(e){let t=e.bundleUrl??"",r=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!r)return{project:null};let o=this.opts.getExcludePorts?.()??ne(),n=(await $({excludePorts:o})).find(d=>String(d.port)===r);if(!n||!n.cwd)return{project:null};let i=N().find(d=>d.cwd===n.cwd)??null,a=Array.from(new Set([...i?.knownBundleUrls??[],n.bundleUrl,t]));return{project:R({cwd:n.cwd,name:n.projectName??C.basename(n.cwd),preferredProvider:e.provider??i?.preferredProvider,sourceRoots:i?.sourceRoots??[n.cwd],knownBundleUrls:a,framework:i?.framework??oe(n.framework),bundleId:n.bundleId??i?.bundleId})}}getTranscript(e){let t=Y(e);return te.existsSync(t)?te.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=U();return{userDataDir:e,storeFile:C.join(e,"attached-projects.json"),sessionsDir:C.join(e,"sessions"),transcriptsDir:C.join(e,"transcripts")}}subscribeSocket(e,t){let r=this.sessionsBySocket.get(e);if(r||(r=new Set,this.sessionsBySocket.set(e,r)),r.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};r.add(t);let o=this.subscriptions.get(t);if(o)return o.refCount++,{ok:!0,refCount:o.refCount};let s=ee(t,n=>{let i=this.coalescePromptEcho(t,n);if(i&&(this.applySessionEvent(t,i),this.fanOutEvent(t,i)),n.type==="turn-completed"){let a=w(t);if(a)try{J(a.projectId,{usd:n.costUsd,ts:n.ts})}catch(c){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${c instanceof Error?c.message:String(c)}
|
|
4
|
-
`)}}});return this.subscriptions.set(t,{unsubscribe:s,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let r=this.sessionsBySocket.get(e);return!r||!r.has(t)?{ok:!0,refCount:0}:(r.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 r of this.sessionsBySocket.values())r.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,r){let o=Date.now(),s=this.pendingPromptEchoes.get(e)??[];s.push({sentAt:o}),this.pendingPromptEchoes.set(e,s);let n=Math.max(this.pendingTurns.get(e)??0,r?1:0)+1;this.pendingTurns.set(e,n);let i=t.displayText??t.text;return this.patchSession(e,{lastPrompt:i,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:i,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:o}),{ok:!0,queued:n>1,pendingTurns:n,queueDepth:Math.max(0,n-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 r=this.consumeSettledTurn(e);this.patchSession(e,{status:r>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 r=this.consumeSettledTurn(e);this.patchSession(e,{status:r>0?"working":"needs-attention",needsAttention:r<=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){V(e,t);let r=w(e);r&&this.broadcastSessionStatus(r)}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let r=this.pendingPromptEchoes.get(e);if(!r||r.length===0)return t;for(;r.length>0&&Date.now()-r[0].sentAt>15e3;)r.shift();return r.length===0?(this.pendingPromptEchoes.delete(e),t):(r.shift(),r.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,r),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 r=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[o,s]of this.sessionsBySocket)if(s.has(e)&&o.readyState===E)try{o.send(r)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let r of this.allSockets)if(r.readyState===E)try{r.send(t)}catch{}}respond(e,t,r){if(e.readyState===E)try{e.send(JSON.stringify({id:t,result:r}))}catch{}}respondError(e,t,r,o){if(e.readyState===E)try{e.send(JSON.stringify({id:t,error:r,...o?{code:o}:{}}))}catch{}}};function oe(h){return h==="expo"?"expo":h==="one"||h==="vxrn"?"one":"unknown"}var de=new Set(["tap","keyboard","close"]);function le(h){return!h||typeof h.type!="string"?!1:h.acquireLock===!0?!0:h.readOnly===!0?!1:de.has(h.type)}var ue=5e3,pe={".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"},I=class h{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextBrowserId=1;browsers=new Map;primaryBrowserId=null;pendingCommands=new Map;cliBySentId=new Map;cliBrowserBySocket=new Map;cliLastCommandAt=new Map;cliSessionKeyBySocket=new Map;cliLabelBySocket=new Map;restorableBrowsers=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 BROWSER_RECONNECT_TTL_MS=3e4;preferredPort;portFallbackCount;shouldWriteLockfile;effectivePort=0;startedAt=0;heartbeatTimer=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0;let t=this.shouldWriteLockfile?1:10;this.portFallbackCount=Math.max(1,e.portFallbackCount??t),this.openUrlHandler=e.openUrl,this.agentHost=new P({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 r=this.preferredPort+t;try{return await this.bindOnce(r,e?.silent===!0),this.effectivePort=r,this.port=r,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${r} (preferred ${this.preferredPort} was taken)
|
|
5
|
-
`),this.afterBind(),r}catch(o){if(o?.code!=="EADDRINUSE")throw o;e?.silent||process.stderr.write(`ws bridge port ${r} already in use, trying ${r+1}
|
|
6
|
-
`)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((r,o)=>{let s=ae((a,c)=>this.handleHttpRequest(a,c)),n=!1,i=a=>{if(!n){n=!0;try{s.close()}catch{}this.httpServer=null,this.wss=null,o(a)}};s.once("error",i),s.listen(e,"127.0.0.1",()=>{n||(n=!0,s.removeListener("error",i),s.on("error",a=>{process.stderr.write(`ws bridge http error: ${String(a)}
|
|
7
|
-
`)}),this.httpServer=s,this.wss=new ce({server:s}),this.wireWebSocketServer(),r())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let r=t.headers.origin,o=r?"browser":"cli",s=null;if(this.agentHost.registerSocket(e),o==="browser")s={id:`tab-${this.nextBrowserId++}`,ws:e,origin:r,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.browsers.set(s.id,s),this.shouldPromoteBrowser(s)&&(this.primaryBrowserId=s.id),this.broadcastBrowserAssignments(),this.broadcastBrowserClientStates();else{let n=`ws-${this.nextCliFallbackId++}`;this.cliSessionKeyBySocket.set(e,n)}e.on("message",n=>{let i;try{i=JSON.parse(n.toString())}catch{return}if(!(!i||typeof i!="object")){if(typeof i.type=="string"&&i.type.startsWith("agent:")){this.agentHost.handleMessage(e,i);return}if(i.type==="runtime:list"){let a=L(),c=this.getActiveRuntime(),d={type:"runtime:list:ok",id:i.id,installed:a,active:c.version,activeRuntimeDir:c.runtimeDir};try{e.send(JSON.stringify(d))}catch{}return}if(i.type==="runtime:use"){let a=typeof i.version=="string"?i.version:"";if(!L().includes(a)){try{e.send(JSON.stringify({type:"runtime:use:error",id:i.id,error:`runtime ${a||"(missing)"} is not installed`}))}catch{}return}let d=this.setActiveRuntime(a);try{e.send(JSON.stringify({type:"runtime:use:ok",id:i.id,version:d.version,runtimeDir:d.runtimeDir}))}catch{}return}if(i.type==="runtime:get"){let a=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:i.id,active:a.version,activeRuntimeDir:a.runtimeDir}))}catch{}return}if(o==="browser"){if(s&&(s.lastSeenAt=Date.now()),i.type==="bridge:register"&&s){let d=i,l=this.tryRestoreBrowserId(s,d.browserId);s.url=d.url,s.title=d.title,s.userAgent=d.userAgent,l&&(this.broadcastBrowserAssignments(),this.broadcastBrowserClientStates());return}if(i.type==="bridge:user-focus-state"&&s){let d=i;this.updateUserFocusLease(s,d.focused===!0);return}if(i.type==="bridge:user-interact"&&s){this.updateUserActivity(s);return}if(i.type==="bridge:open-path"){let d=typeof i.path=="string"?i.path:"",l=typeof i.line=="number"&&Number.isFinite(i.line)?i.line:void 0,p=typeof i.column=="number"&&Number.isFinite(i.column)?i.column:void 0;d&&this.openPathInEditor(d,l,p);return}if(i.type==="bridge:boot-clients"&&s){let d=[];for(let[p,u]of this.cliBrowserBySocket)u===s.id&&d.push(p);for(let p of d){this.cliBrowserBySocket.delete(p);try{p.close(1e3,"booted by browser")}catch{}}let l=!!s.cliLease;s.cliLease=void 0,(d.length>0||l)&&(process.stderr.write(`sootsim booted ${d.length} cli client(s)${l?" + cleared lease":""} from [${s.id}]
|
|
8
|
-
`),this.recordBrowserAction(s.id,"browser booted cli clients"),this.broadcastBrowserClientStates());return}let a=this.pendingCommands.get(i.id);if(a){this.pendingCommands.delete(i.id),i.error?a.reject(new Error(i.error)):a.resolve(i.result);return}let c=this.cliBySentId.get(i.id);if(c&&(this.cliBySentId.delete(i.id),c.ws.readyState===f.OPEN)){let d=this.getOtherCliSessionCount(c.ws,c.browserId),l=d>0?{...i,id:c.originalId,i:d}:{...i,id:c.originalId};c.ws.send(JSON.stringify(l))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(i.type==="bridge:bye"){let p=this.cliBrowserBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliSessionKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[u,m]of this.cliBySentId)m.ws===e&&this.cliBySentId.delete(u);p&&this.broadcastBrowserClientStates();return}if(i.type==="bridge:hello"){let p=typeof i.cliSessionKey=="string"&&i.cliSessionKey.trim()?i.cliSessionKey.trim():this.cliSessionKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliSessionKeyBySocket.set(e,p),typeof i.cliLabel=="string"&&i.cliLabel.trim()&&this.cliLabelBySocket.set(e,i.cliLabel.trim()),e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,result:{cliSessionKey:p,leaseTtlMs:h.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(i.type==="bridge:list-browsers"){e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,result:this.listBrowsers()}));return}if(i.type==="bridge:open"){if(typeof i.url!="string"||!i.url)throw new Error("bridge:open requires a url");await this.openUrl(i.url),e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,result:{ok:!0,url:i.url}}));return}if(i.type==="bridge:claim"){let p=await this.waitForBrowser(i.browserId),u=this.tryAcquireLease(e,p,{force:i.force===!0});if(!u.granted){e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,error:`tab ${p.id} is locked by another cli`,o:u.lock}));return}this.setCliBrowserTarget(e,p.id),this.recordBrowserAction(p.id,u.bootedCount>0?`cli force-claimed tab (booted ${u.bootedCount})`:"cli claimed tab"),e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,result:{browserId:p.id,lockedBy:u.lease.cliSessionKey,lockExpiresAt:u.lease.expiresAt,bootedCount:u.bootedCount}}));return}let a=await this.waitForBrowser(i.browserId);if(le(i)){let p=this.tryAcquireLease(e,a);if(!p.granted){e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,error:`tab ${a.id} is locked by another cli \u2014 use \`sootsim claim ${a.id} --force\` or \`sootsim open --new\``,o:p.lock}));return}}else this.ensureCliSessionKey(e);this.setCliBrowserTarget(e,a.id),this.recordBrowserAction(a.id,this.describeForwardedCommand(i));let c=this.nextCommandId++;this.cliBySentId.set(c,{browserId:a.id,ws:e,originalId:i.id});let{browserId:d,...l}=i;a.ws.send(JSON.stringify({...l,id:c}))}catch(a){e.readyState===f.OPEN&&e.send(JSON.stringify({id:i.id,error:a instanceof Error?a.message:String(a)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),o==="browser"&&s){this.rememberDisconnectedBrowser(s),this.primaryBrowserId===s.id&&(this.primaryBrowserId=this.getOpenBrowser()?.id??null);for(let[n,i]of this.pendingCommands)i.browserId===s.id&&(i.reject(new Error("browser disconnected")),this.pendingCommands.delete(n));for(let[n,i]of this.cliBySentId)i.browserId===s.id&&(i.ws.readyState===f.OPEN&&i.ws.send(JSON.stringify({id:i.originalId,error:"browser disconnected before responding"})),this.cliBySentId.delete(n));this.broadcastBrowserAssignments(),this.broadcastBrowserClientStates()}else if(o==="cli"){let n=this.cliBrowserBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliSessionKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[i,a]of this.cliBySentId)a.ws===e&&this.cliBySentId.delete(i);n&&this.broadcastBrowserClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
|
|
9
|
-
`),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.shouldWriteLockfile){try{if(A(),!H(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)}
|
|
10
|
-
`),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},ue),this.heartbeatTimer.unref()}this.agentHost.seedOnBoot()}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()}}writeLockfileSnapshot(){j(this.buildLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=D(),this.activeRuntimeDirPath=M()}setActiveRuntime(e){if(_(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 r of this.browsers.values())if(r.ws.readyState===f.OPEN)try{r.ws.send(t)}catch{}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{O()}catch{}}handleHttpRequest(e,t){let r=(e.method||"GET").toUpperCase();if(r!=="GET"&&r!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let o=new URL(e.url||"/","http://localhost");if(o.pathname==="/__bundle-proxy"){let c=o.searchParams.get("url");if(!c){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let d;try{d=new URL(c)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let l=d.hostname;if(!(l==="localhost"||l==="127.0.0.1"||l==="::1"||l.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let u=await fetch(d.toString(),{redirect:"follow"}),m={},g=u.headers.get("content-type");if(g&&(m["Content-Type"]=g),m["Cache-Control"]="no-store",t.writeHead(u.status,m),!u.body){t.end();return}let S=u.body.getReader();for(;;){let{done:B,value:k}=await S.read();if(B)break;t.write(Buffer.from(k))}t.end()}catch(u){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${u instanceof Error?u.message:String(u)}`)}})();return}if(o.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}this.refreshActiveRuntime();let s=this.activeRuntimeDirPath;if(!s){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 n=o.pathname;if(n==="/runtime"||n==="/runtime/"?n="/":n.startsWith("/runtime/")&&(n=n.slice(8)),(n===""||n==="/")&&(n="/index.html"),n.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&n.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let c of n.split("/"))if(c===".."){t.writeHead(403),t.end("forbidden");return}let i=y.resolve(s,"."+n),a=s.endsWith(y.sep)?s:s+y.sep;if(!i.startsWith(a)&&i!==s){t.writeHead(403),t.end("forbidden");return}v.realpath(i,(c,d)=>{let l=c?i:d,p=l.endsWith(y.sep)?l:l+y.sep;if(!c){let u=(()=>{try{let m=v.realpathSync(s);return m.endsWith(y.sep)?m:m+y.sep}catch{return a}})();if(!p.startsWith(u)&&l+y.sep!==u){t.writeHead(403),t.end("forbidden");return}}v.stat(l,(u,m)=>{if(u||!m?.isFile()){let k=y.extname(n).toLowerCase();if(k&&k!==".html"){t.writeHead(404),t.end("not found");return}let re=y.join(s,"index.html");v.readFile(re,(ie,se)=>{if(ie){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),r==="HEAD"){t.end();return}t.end(se)});return}let g=y.extname(l).toLowerCase(),S=pe[g]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":S}),r==="HEAD"){t.end();return}let B=v.createReadStream(l);B.pipe(t),B.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[r,o]of this.cliBrowserBySocket){let s=this.cliLastCommandAt.get(r)??0;if(!(e-s<h.CLI_IDLE_TIMEOUT_MS)){this.cliBrowserBySocket.delete(r),this.cliLastCommandAt.delete(r);for(let[n,i]of this.cliBySentId)i.ws===r&&this.cliBySentId.delete(n);try{r.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastBrowserClientStates(),this.sweepRestorableBrowsers(e)}listBrowsers(){return Array.from(this.browsers.values()).sort((e,t)=>e.id===this.primaryBrowserId?-1:t.id===this.primaryBrowserId?1:e.connectedAt-t.connectedAt).map(e=>this.describeBrowser(e))}async sendCommand(e){let t=await this.waitForBrowser(e.browserId),r=this.nextCommandId++;return new Promise((o,s)=>{let n=setTimeout(()=>{this.pendingCommands.delete(r),this.broadcastBrowserClientStates(),s(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(r,{browserId:t.id,resolve:c=>{clearTimeout(n),this.pendingCommands.delete(r),this.broadcastBrowserClientStates(),o(c)},reject:c=>{clearTimeout(n),this.pendingCommands.delete(r),this.broadcastBrowserClientStates(),s(c)}}),this.broadcastBrowserClientStates();let{browserId:i,...a}=e;t.ws.send(JSON.stringify({...a,id:r}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,browserId:t})}async focusBrowser(e){return this.sendCommand({type:"focus",browserId:e})}async closeBrowser(e){return this.sendCommand({type:"close",browserId:e})}async openPathInEditor(e,t,r){let o=t!=null?`:${t}${r!=null?`:${r}`:""}`:"",s=`${e}${o}`,n=(a,c)=>new Promise(d=>{try{let l=T(a,c,{detached:!0,stdio:"ignore"}),p=!1;l.on("error",()=>{p||(p=!0,d(!1))}),l.on("spawn",()=>{p||(p=!0,l.unref(),d(!0))})}catch{d(!1)}}),i=process.env.REACT_EDITOR||process.env.EDITOR;if(i){let a=i.split(" ").filter(Boolean);if(a.length&&await n(a[0],[...a.slice(1),"-g",s]))return}await n("cursor",["-g",s])||await n("code",["-g",s])||await this.openUrl(e)}async openUrl(e){if(this.openUrlHandler){await this.openUrlHandler(e);return}if(process.platform==="darwin"){T("open",["-g",e],{detached:!0,stdio:"ignore"}).unref();return}if(process.platform==="win32"){T("cmd",["/c","start","",e],{detached:!0,stdio:"ignore"}).unref();return}T("xdg-open",[e],{detached:!0,stdio:"ignore"}).unref()}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.shouldWriteLockfile)try{O()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[r,o]of this.pendingCommands)o.reject(new Error("server closing")),this.pendingCommands.delete(r);for(let r of this.browsers.values())r.ws.close();this.browsers.clear(),this.primaryBrowserId=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{}}describeBrowser(e){let t;try{t=e.ws.readyState}catch{t=f.CLOSED}let r=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.primaryBrowserId,readyState:t===f.OPEN?"open":t===f.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:r?r.cliLabel||r.cliSessionKey:void 0,lockedByKind:r?r.kind:void 0,lockExpiresAt:r?r.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,r={}){let o=this.cliSessionKeyBySocket.get(e)??(()=>{let l=`ws-${this.nextCliFallbackId++}`;return this.cliSessionKeyBySocket.set(e,l),l})(),s=this.cliLabelBySocket.get(e),n=Date.now(),i=this.getActiveLease(t),a=i&&i.cliSessionKey===o,c=0;if(i&&!a&&!r.force)return{granted:!1,lease:i,lock:{by:i.cliLabel||i.cliSessionKey,expiresInMs:Math.max(0,i.expiresAt-n)},bootedCount:0};if(i&&!a&&r.force)for(let[l,p]of this.cliBrowserBySocket){if(p!==t.id)continue;let u=this.cliSessionKeyBySocket.get(l);if(u&&u!==o){this.cliBrowserBySocket.delete(l);try{l.close(1e3,"lease claimed by another cli")}catch{}c++}}let d={kind:"cli",cliSessionKey:o,cliLabel:s,expiresAt:n+h.CLI_LEASE_TTL_MS};return t.cliLease=d,{granted:!0,lease:d,bootedCount:c}}updateUserFocusLease(e,t){let r=t;e.userFocused!==r&&(e.userFocused=r,this.broadcastBrowserClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);t&&t.kind==="cli"||(e.cliLease={kind:"user-active",cliSessionKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+h.USER_ACTIVE_LEASE_TTL_MS},this.broadcastBrowserClientStates())}ensureCliSessionKey(e){let t=this.cliSessionKeyBySocket.get(e);if(t)return t;let r=`ws-${this.nextCliFallbackId++}`;return this.cliSessionKeyBySocket.set(e,r),r}getOpenBrowser(e){if(e){let r=this.browsers.get(e);return r?.ws.readyState===f.OPEN?r:null}let t=this.primaryBrowserId!=null?this.browsers.get(this.primaryBrowserId):null;if(t?.ws.readyState===f.OPEN)return t;for(let r of this.browsers.values())if(r.ws.readyState===f.OPEN)return r;return null}async waitForBrowser(e,t={}){let r=t.attempts??10,o=t.intervalMs??200;for(let s=0;s<r;s++){let n=this.getOpenBrowser(e);if(n)return n;await new Promise(i=>setTimeout(i,o))}throw new Error(e?`no browser connected with id ${e}`:"no browser connected")}shouldPromoteBrowser(e){let t=this.primaryBrowserId?this.browsers.get(this.primaryBrowserId):null,r=e.origin?.includes(":5173"),o=t?.origin?.includes(":5173");return!t||t.ws.readyState!==f.OPEN||!!r||!o}broadcastBrowserAssignments(){for(let e of this.browsers.values())e.ws.readyState===f.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",browserId:e.id,isPrimary:e.id===this.primaryBrowserId}))}broadcastBrowserClientStates(){for(let e of this.browsers.values()){if(e.ws.readyState!==f.OPEN)continue;let t=this.getActiveLease(e),r={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliSessionKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0};e.ws.send(JSON.stringify(r))}}setCliBrowserTarget(e,t){let r=this.cliBrowserBySocket.get(e);r!==t&&(this.cliBrowserBySocket.set(e,t),this.recordBrowserAction(t,r?"cli switched tabs":"cli connected",!1),this.broadcastBrowserClientStates())}recordBrowserAction(e,t,r=!0){let o=t?.trim();if(!o)return;let s=this.browsers.get(e);if(!s)return;let n=Date.now();s.lastActiveAt=n,s.recentActions=[{label:o,at:n},...s.recentActions.filter(i=>i.label!==o)].slice(0,4),r&&this.broadcastBrowserClientStates()}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 tab";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[r,o]of this.cliBrowserBySocket){if(o!==e||r.readyState!==f.OPEN)continue;let s=this.cliSessionKeyBySocket.get(r);t.add(s??`ws-unknown-${t.size}`)}return t.size}getOtherCliSessionCount(e,t){let r=this.cliSessionKeyBySocket.get(e),o=new Set;for(let[s,n]of this.cliBrowserBySocket){if(n!==t||s.readyState!==f.OPEN)continue;let i=this.cliSessionKeyBySocket.get(s);i&&i===r||o.add(i??`ws-unknown-${o.size}`)}return o.size}getActiveAgentCommandCount(e){let t=0;for(let r of this.pendingCommands.values())r.browserId===e&&t++;return t}tryRestoreBrowserId(e,t){let r=t?.trim();if(!r||r===e.id)return!1;let o=this.browsers.get(r);if(o&&o!==e&&o.ws.readyState===f.OPEN)return!1;let s=this.getRestorableBrowserState(r),n=e.id;this.browsers.delete(n),e.id=r,s&&(e.recentActions=s.recentActions.map(i=>({...i})),e.lastActiveAt=s.lastActiveAt,e.cliLease=s.cliLease?{...s.cliLease}:void 0,this.restorableBrowsers.delete(r)),this.browsers.set(e.id,e),this.primaryBrowserId===n&&(this.primaryBrowserId=e.id);for(let[i,a]of this.cliBrowserBySocket)a===n&&this.cliBrowserBySocket.set(i,e.id);return!0}rememberDisconnectedBrowser(e){let t=this.getActiveLease(e);this.restorableBrowsers.set(e.id,{recentActions:e.recentActions.map(r=>({...r})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+h.BROWSER_RECONNECT_TTL_MS}),this.browsers.delete(e.id)}getRestorableBrowserState(e){let t=this.restorableBrowsers.get(e);return t?t.expiresAt<=Date.now()?(this.restorableBrowsers.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableBrowsers(e=Date.now()){for(let[t,r]of this.restorableBrowsers)if(!(r.expiresAt>e)){this.restorableBrowsers.delete(t);for(let[o,s]of this.cliBrowserBySocket)s===t&&this.cliBrowserBySocket.delete(o)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=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{}}};async function Le(h,e={}){(h.includes("--help")||h.includes("-h"))&&(console.log(`
|
|
11
|
-
sootsim server \u2014 run the sootsim bridge daemon in the foreground
|
|
12
|
-
|
|
13
|
-
hosts the WS bridge that CLI commands talk to. once running, any sootsim
|
|
14
|
-
tab (browser, electron, headless playwright) that connects to port 7668
|
|
15
|
-
becomes drivable from 'sootsim describe', 'sootsim tap', etc.
|
|
16
|
-
|
|
17
|
-
usage:
|
|
18
|
-
sootsim server [options]
|
|
19
|
-
|
|
20
|
-
options:
|
|
21
|
-
--port <n> bridge port (defaults to ${7668})
|
|
22
|
-
--quiet suppress per-connection logging
|
|
23
|
-
|
|
24
|
-
examples:
|
|
25
|
-
sootsim server
|
|
26
|
-
sootsim server --port 7668 --quiet
|
|
27
|
-
`),process.exit(0));let t=h.indexOf("--port"),r=t>=0&&h[t+1]?Number(h[t+1]):e.port??7668;Number.isNaN(r)&&(console.error(` invalid --port value: ${h[t+1]}`),process.exit(1));let o=h.includes("--quiet")||h.includes("-q"),s=W();s&&F(s)&&(console.error(` a sootsim daemon is already running (pid ${s.pid}, port ${s.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),A();let n=new I({port:r,writeLockfile:!0}),i=await n.startAsync({silent:o}),a=Date.now(),c=u=>{o||process.stdout.write(`${u}
|
|
28
|
-
`)},d=new Set,l=setInterval(()=>{let u=n.listBrowsers(),m=new Set(u.map(g=>g.id));for(let g of u)if(!d.has(g.id)){let S=g.title||g.url||g.origin||"(unknown)";c(` + ${g.id} ${S}`)}for(let g of d)m.has(g)||c(` - ${g}`);d.clear();for(let g of m)d.add(g)},500);c(`sootsim bridge listening on ws://localhost:${i} (runtime http on same port)`),i!==r&&c(` (preferred port ${r} was taken \u2014 fell back to ${i})`),c(" ready for browser tabs, electron, or headless playwright to connect"),c(" (ctrl-c to stop)");let p=async u=>{clearInterval(l),c(`
|
|
29
|
-
${u} received \u2014 shutting down after ${Math.round((Date.now()-a)/1e3)}s`);try{await n.close()}catch{}process.exit(0)};process.on("SIGINT",()=>p("SIGINT")),process.on("SIGTERM",()=>p("SIGTERM")),process.on("SIGHUP",()=>p("SIGHUP")),process.on("exit",()=>{try{n.removeLockfile()}catch{}}),await new Promise(()=>{})}export{Le as runServer};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.0.3 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{c as a,d as b}from"./chunk-EEBR5YP5.js";import"./chunk-X2W4IRXK.js";import"./chunk-3SLEIN6B.js";import"./chunk-USRNDVQ3.js";import"./chunk-4RYT6AQV.js";import"./chunk-RLS6PHBW.js";import"./chunk-LV5U7TI4.js";import"./chunk-EQ7G3UHS.js";import"./chunk-P5C3UASK.js";export{a as resolveDefaultUploadOrigin,b as runUpload};
|