sootsim 0.1.139 → 0.1.141
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/dist-cli/bin.js +3 -3
- package/dist-cli/chunks/{agent-AMV3XDZN.js → agent-BFN5TIRU.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-GHQLZH5R.js → agent-wrapper-A4UNOJOD.js} +2 -2
- package/dist-cli/chunks/{app-fonts-DLEYOBO5.js → app-fonts-KEAMDLYZ.js} +2 -2
- package/dist-cli/chunks/{assert-Y5JVYKGT.js → assert-BWBAKX5N.js} +2 -2
- package/dist-cli/chunks/auto-bootstrap-WJH44ZIE.js +2 -0
- package/dist-cli/chunks/beta-VFKZHKER.js +2 -0
- package/dist-cli/chunks/{camera-R5LLADTA.js → camera-P5TTGC72.js} +2 -2
- package/dist-cli/chunks/{chunk-ZX23A5IN.js → chunk-33EJL7CG.js} +2 -2
- package/dist-cli/chunks/{chunk-TBSHXKZT.js → chunk-3LN2PP4L.js} +2 -2
- package/dist-cli/chunks/{chunk-XJAWWHYR.js → chunk-4ISWLDJG.js} +1 -1
- package/dist-cli/chunks/{chunk-E625N74G.js → chunk-53DRW635.js} +3 -3
- package/dist-cli/chunks/{chunk-WWSCWKNE.js → chunk-7A7VFR2C.js} +1 -1
- package/dist-cli/chunks/{chunk-FXTYQW4H.js → chunk-7SO2SJ4H.js} +1 -1
- package/dist-cli/chunks/{chunk-H4HHC2JY.js → chunk-A5W3HB44.js} +1 -1
- package/dist-cli/chunks/{chunk-IQ6KSDIL.js → chunk-AJGTCVQX.js} +1 -1
- package/dist-cli/chunks/{chunk-R5AS67IW.js → chunk-AMSIP5PD.js} +3 -3
- package/dist-cli/chunks/{chunk-VU7RMAQ4.js → chunk-AQVB4G34.js} +2 -2
- package/dist-cli/chunks/{chunk-ICQKMKDM.js → chunk-DM5KNA7Q.js} +2 -2
- package/dist-cli/chunks/{chunk-ACFQGYVP.js → chunk-EIZ6LJP2.js} +2 -2
- package/dist-cli/chunks/{chunk-7EKN4S4H.js → chunk-ETB6DHJM.js} +2 -2
- package/dist-cli/chunks/{chunk-AQBTE6OT.js → chunk-HDCTWR2Q.js} +2 -2
- package/dist-cli/chunks/chunk-I3JPJMJB.js +5 -0
- package/dist-cli/chunks/{chunk-ZUUM47FA.js → chunk-I6SWX7OI.js} +2 -2
- package/dist-cli/chunks/{chunk-TK3G654S.js → chunk-IILFDOSF.js} +1 -1
- package/dist-cli/chunks/{chunk-BMB7ZFSG.js → chunk-IITPPGBS.js} +1 -1
- package/dist-cli/chunks/{chunk-RXT2MXRM.js → chunk-ITJLXD4X.js} +2 -2
- package/dist-cli/chunks/{chunk-TA3BB6DU.js → chunk-JJBNA2JO.js} +2 -2
- package/dist-cli/chunks/{chunk-TCUZT7HW.js → chunk-JM5XCDBF.js} +52 -4
- package/dist-cli/chunks/{chunk-T367DMWW.js → chunk-JQTHQOPS.js} +2 -2
- package/dist-cli/chunks/{chunk-7IBHD3FE.js → chunk-KMQWCYU7.js} +2 -2
- package/dist-cli/chunks/{chunk-O5VKZEYP.js → chunk-LHIPDN4B.js} +1 -1
- package/dist-cli/chunks/chunk-LHS4PEAA.js +79 -0
- package/dist-cli/chunks/{chunk-MLQRWULD.js → chunk-M7S4VLEL.js} +55 -55
- package/dist-cli/chunks/{chunk-BUY6HG6I.js → chunk-MENSR2TZ.js} +1 -1
- package/dist-cli/chunks/chunk-MHUNWWWS.js +412 -0
- package/dist-cli/chunks/chunk-MYKHUFW2.js +1 -0
- package/dist-cli/chunks/chunk-NOAONZTZ.js +119 -0
- package/dist-cli/chunks/{chunk-JWBMOFM4.js → chunk-NQJD2WTM.js} +1 -1
- package/dist-cli/chunks/{chunk-PL55QQ5Z.js → chunk-PVPWCA2K.js} +1 -1
- package/dist-cli/chunks/{chunk-C2RSKTRR.js → chunk-RBUJZXNR.js} +5 -5
- package/dist-cli/chunks/chunk-RUXWU3UH.js +2 -0
- package/dist-cli/chunks/chunk-SXHBK5IJ.js +69 -0
- package/dist-cli/chunks/chunk-SYRS7NKN.js +1 -0
- package/dist-cli/chunks/chunk-TUZVZ5QS.js +1 -0
- package/dist-cli/chunks/{chunk-ZNHSTLAY.js → chunk-URPQTI2I.js} +2 -2
- package/dist-cli/chunks/{chunk-MGQ35ZJX.js → chunk-UYQDGXHQ.js} +1 -1
- package/dist-cli/chunks/chunk-WUQHVDJU.js +4 -0
- package/dist-cli/chunks/{chunk-65GV253M.js → chunk-XD7XHQUO.js} +2 -2
- package/dist-cli/chunks/{chunk-LFPX2KK4.js → chunk-XERRDQLM.js} +1 -1
- package/dist-cli/chunks/{chunk-OWI2ZHZE.js → chunk-XQRCVSK3.js} +1 -1
- package/dist-cli/chunks/{chunk-WCKN6BE2.js → chunk-YOJ6BZCH.js} +1 -1
- package/dist-cli/chunks/chunk-ZBN3P5JE.js +2 -0
- package/dist-cli/chunks/cli-version-3G6HHMRW.js +2 -0
- package/dist-cli/chunks/{compat-2EQAHCNM.js → compat-3Z67EPSJ.js} +3 -3
- package/dist-cli/chunks/{config-NBVL6FYM.js → config-SH3NTYZ2.js} +2 -2
- package/dist-cli/chunks/{control-V273ZZ3M.js → control-2XVEDKYZ.js} +2 -2
- package/dist-cli/chunks/{cpu-profile-5XNWKK3A.js → cpu-profile-FANLHU4S.js} +2 -2
- package/dist-cli/chunks/{daemon-NA3DX4ZX.js → daemon-QGDVR4JT.js} +2 -2
- package/dist-cli/chunks/{debug-EFOPNXRQ.js → debug-EIUEPLFN.js} +3 -3
- package/dist-cli/chunks/{detox-KVXJMO6N.js → detox-EV3KYFKR.js} +2 -2
- package/dist-cli/chunks/{device-CT3OAKPD.js → device-UC5DAVA6.js} +2 -2
- package/dist-cli/chunks/{diagnose-7V6YJI6N.js → diagnose-Q2M2AJBD.js} +2 -2
- package/dist-cli/chunks/drivers-VJIWLDTC.js +2 -0
- package/dist-cli/chunks/{electron-JYEQ2OSP.js → electron-PXKF52Q6.js} +3 -3
- package/dist-cli/chunks/flow-RGMXGVLL.js +2 -0
- package/dist-cli/chunks/help-TBZZP4SA.js +2 -0
- package/dist-cli/chunks/{hints-BSLK5WFF.js → hints-HS7X2FIO.js} +2 -2
- package/dist-cli/chunks/{home-paths-O6YSN6UP.js → home-paths-KPMXMJQ7.js} +2 -2
- package/dist-cli/chunks/{inspect-D3QA6IZ7.js → inspect-ZUWEMCIG.js} +3 -3
- package/dist-cli/chunks/install-FPYDDDQ4.js +2 -0
- package/dist-cli/chunks/{install-desktop-5TDP7V6G.js → install-desktop-H6ZTTVXC.js} +7 -7
- package/dist-cli/chunks/{keys-PASWSEEO.js → keys-6OBZZLCJ.js} +2 -2
- package/dist-cli/chunks/{launch-QZQEGABG.js → launch-7JASEDHP.js} +3 -3
- package/dist-cli/chunks/{login-XY4M72YJ.js → login-JWMB6JNS.js} +4 -4
- package/dist-cli/chunks/{logout-YVNSQJSF.js → logout-LWVFUKF5.js} +2 -2
- package/dist-cli/chunks/maestro-WX22SLCR.js +94 -0
- package/dist-cli/chunks/optional-demo-registry-52MHQCYV.js +2 -0
- package/dist-cli/chunks/{preview-PTCJZJLX.js → preview-SDMLCW3U.js} +2 -2
- package/dist-cli/chunks/{profile-CR7H6TKR.js → profile-MQVLCO7R.js} +2 -2
- package/dist-cli/chunks/{react-Q7TN57VS.js → react-2JFP5W4W.js} +2 -2
- package/dist-cli/chunks/{record-LH43WKXK.js → record-IJJ3SPXP.js} +2 -2
- package/dist-cli/chunks/runtime-JJMZ4AF3.js +2 -0
- package/dist-cli/chunks/{runtime-delivery-EJUR3Y37.js → runtime-delivery-5M2P7LEI.js} +2 -2
- package/dist-cli/chunks/{screenshot-H6KGQMSK.js → screenshot-4QAGJCPZ.js} +2 -2
- package/dist-cli/chunks/{screenshot-mode-7YJNNJZZ.js → screenshot-mode-PSAU7TH4.js} +2 -2
- package/dist-cli/chunks/{screenshots-AR3C2NR2.js → screenshots-73VI4UUL.js} +2 -2
- package/dist-cli/chunks/{server-YG3GY22N.js → server-BXD5WKQS.js} +3 -3
- package/dist-cli/chunks/setup-repo-F2P5RZ4R.js +2 -0
- package/dist-cli/chunks/{skills-TUYB6WUS.js → skills-IEJOURWM.js} +2 -2
- package/dist-cli/chunks/{start-D5HVPGC5.js → start-CLBAJ4LJ.js} +4 -4
- package/dist-cli/chunks/store-7DIOVJNK.js +2 -0
- package/dist-cli/chunks/telemetry-3XHPQYOQ.js +2 -0
- package/dist-cli/chunks/{test-CHBKMHLB.js → test-42YWJ5ZT.js} +3 -3
- package/dist-cli/chunks/{three-mode-SXAD2GWI.js → three-mode-5DU4IBF5.js} +2 -2
- package/dist-cli/chunks/{timeline-BFF2I7CC.js → timeline-WJYQRW5S.js} +2 -2
- package/dist-cli/chunks/{upgrade-XLLL34R2.js → upgrade-F7ADMCLU.js} +2 -2
- package/dist-cli/chunks/upload-TJ2XKWDS.js +2 -0
- package/dist-cli/chunks/{version-ABW7HY2I.js → version-SLA5P34B.js} +2 -2
- package/dist-cli/chunks/web-OGC6GSKM.js +2 -0
- package/dist-cli/chunks/{what-happened-PHMTRHXF.js → what-happened-VYXK3O2C.js} +2 -2
- package/dist-cli/chunks/{whoami-K6RYDVQK.js → whoami-QL2LTKOF.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +42 -820
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +5 -2
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +180 -957
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +30 -798
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +1261 -1362
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -6
- package/scripts/dev-server-scanner.ts +10 -2
- package/scripts/optional-demo-registry.ts +54 -0
- package/src/attached-projects.ts +6 -27
- package/src/config.ts +13 -0
- package/dist-cli/chunks/auto-bootstrap-FGBI5CJ7.js +0 -2
- package/dist-cli/chunks/beta-52CSPPUC.js +0 -2
- package/dist-cli/chunks/chunk-25SHAK5L.js +0 -62
- package/dist-cli/chunks/chunk-4FZ7V6NP.js +0 -1
- package/dist-cli/chunks/chunk-5JA6QRQR.js +0 -380
- package/dist-cli/chunks/chunk-BGJDSWVB.js +0 -5
- package/dist-cli/chunks/chunk-DSQZJPSK.js +0 -79
- package/dist-cli/chunks/chunk-OESWG4DQ.js +0 -1
- package/dist-cli/chunks/chunk-P73XFXAI.js +0 -4
- package/dist-cli/chunks/chunk-PREGMTVP.js +0 -119
- package/dist-cli/chunks/chunk-TB5WPL7Q.js +0 -2
- package/dist-cli/chunks/chunk-VJ2PPTZJ.js +0 -64
- package/dist-cli/chunks/chunk-VR23KNQD.js +0 -1
- package/dist-cli/chunks/cli-version-QJGRKUNQ.js +0 -2
- package/dist-cli/chunks/demo-app-registry-3N4MPKCB.js +0 -2
- package/dist-cli/chunks/drivers-ALPQZSFQ.js +0 -2
- package/dist-cli/chunks/flow-KMYJNXG3.js +0 -2
- package/dist-cli/chunks/help-Q4U3HFXF.js +0 -2
- package/dist-cli/chunks/install-T7PQXSEL.js +0 -2
- package/dist-cli/chunks/maestro-BWLFDA2J.js +0 -80
- package/dist-cli/chunks/runtime-U3YSH5S6.js +0 -2
- package/dist-cli/chunks/setup-repo-VDA2UFDB.js +0 -2
- package/dist-cli/chunks/store-UG47OKR6.js +0 -2
- package/dist-cli/chunks/telemetry-276DYSYW.js +0 -2
- package/dist-cli/chunks/upload-JGRABYUF.js +0 -2
- package/dist-cli/chunks/web-V76A7KM4.js +0 -2
- package/dist-lib/scripts/demo-app-registry.cjs +0 -818
- package/scripts/demo-app-registry.ts +0 -1006
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
2
|
-
import{a as d,b as
|
|
1
|
+
/*! sootsim v0.1.141 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a as d,b as g}from"./chunk-AJGTCVQX.js";import{a as f,c as w}from"./chunk-XD7XHQUO.js";import{a as u,b as h,c as m}from"./chunk-LHIPDN4B.js";import{c as p}from"./chunk-A5W3HB44.js";function I(){let e=u();return e?{available:!0,reason:null,detail:e}:{available:!1,reason:"no chromium-family browser found (chrome, chromium, edge, brave, arc)"}}async function M(e){if(e.headless)return{launched:!1,message:"the chromium driver launches a visible browser window and cannot run headless \u2014 a headless `chrome --headless=new` process exits immediately and the sim never connects. for headless automation use `--driver playwright`."};let r=u();if(!r)return{launched:!1,message:"chromium not found \u2014 install chrome or run `sootsim list --drivers`"};if(!e.url)return{launched:!1,message:"chromium driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current Chrome profile"};try{let t=await m(e.url,{detached:e.detached??!0});return{launched:!0,message:`chromium launched \u2192 ${e.url}`,pid:t.pid,target:t.target??r,attachUrl:e.url}}catch(t){return{launched:!1,message:`chromium spawn failed: ${t instanceof Error?t.message:String(t)}`}}}var v={id:"chromium",name:"chromium",description:"system chrome / chromium / edge \u2014 visible window (headless: use playwright)",kind:"browser",availability:I,launch:M};function _(){let e=d();return e?{available:!0,reason:null,detail:`${e.kind} @ ${e.path}`}:{available:!1,reason:"sootsim desktop app not installed (run `sootsim install-desktop`)"}}async function x(e){let r=d();if(!r)return{launched:!1,message:"sootsim desktop app not installed"};try{let t=await g(e.url,r,{device:e.device,profileId:e.profileId,ephemeralProfile:e.ephemeralProfile});return t.launched?{launched:!0,message:e.url?`electron launched via ${t.via} \u2192 ${e.url}`:`electron launched via ${t.via}`,target:t.target,attachUrl:e.url}:{launched:!1,message:"desktop companion failed to start"}}catch(t){return{launched:!1,message:`electron launch failed: ${t instanceof Error?t.message:String(t)}`}}}var y={id:"electron",name:"electron",description:"sootsim desktop companion app (native window, menu bar)",kind:"native",availability:_,launch:x};import{spawn as C}from"child_process";import{closeSync as E,mkdtempSync as A,openSync as L,readFileSync as R}from"fs";import{createRequire as W}from"module";import{tmpdir as b}from"os";import{join as S}from"path";var N=`
|
|
3
3
|
const modulePath = process.env.SOOTSIM_PW_MODULE;
|
|
4
4
|
const url = process.env.SOOTSIM_PW_URL;
|
|
5
5
|
const headless = process.env.SOOTSIM_PW_HEADLESS === '1';
|
|
@@ -17,6 +17,40 @@ const cdpPort = process.env.SOOTSIM_PW_CDP_PORT || '';
|
|
|
17
17
|
const closeTimeoutMs = Number(process.env.SOOTSIM_PW_CLOSE_TIMEOUT_MS || 2500);
|
|
18
18
|
const connectAckFile = process.env.SOOTSIM_PW_CONNECTED_ACK_FILE || '';
|
|
19
19
|
const { existsSync, unlinkSync } = require('fs');
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
// chromium tree reaper \u2014 playwright's browser.close() does not reliably reap
|
|
22
|
+
// the chromium helper tree (gpu/renderer/zygote/utility reparent to init and
|
|
23
|
+
// survive), and a SIGTERM/SIGKILL of just the root leaves them behind too.
|
|
24
|
+
// repeated/aborted opens then accumulate orphan chromiums until the machine
|
|
25
|
+
// OOMs (31 leaked processes thrashed a 4GB VM in one smoke run). mirror the
|
|
26
|
+
// proven pid-diff + recursive killTree pattern from scripts/lib/reap-browser.ts:
|
|
27
|
+
// only pids matching the playwright-managed chromium install are ever touched
|
|
28
|
+
// (a system Chrome launched via channel:'chrome' lives outside ms-playwright/
|
|
29
|
+
// and is never killed), and the whole thing is skipped on windows where pgrep
|
|
30
|
+
// does not exist \u2014 there plain close() remains the only teardown.
|
|
31
|
+
const reapEnabled = process.platform !== 'win32';
|
|
32
|
+
const chromiumPids = () => {
|
|
33
|
+
if (!reapEnabled) return [];
|
|
34
|
+
try {
|
|
35
|
+
// [c]hromium: this host runs as \`node -e <script>\`, so its OWN cmdline
|
|
36
|
+
// contains this source \u2014 a plain pattern would match every sibling host
|
|
37
|
+
// process and a concurrent launch could cross-kill another host's tree.
|
|
38
|
+
// the character class keeps the pattern from matching its own literal.
|
|
39
|
+
return execSync('pgrep -f "ms-playwright/[c]hromium" || true', { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
40
|
+
.toString().split('\\n').filter(Boolean);
|
|
41
|
+
} catch { return []; }
|
|
42
|
+
};
|
|
43
|
+
const killTree = (pid) => {
|
|
44
|
+
let kids = [];
|
|
45
|
+
try {
|
|
46
|
+
kids = execSync('pgrep -P ' + pid + ' || true', { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
47
|
+
.toString().split('\\n').filter(Boolean);
|
|
48
|
+
} catch {}
|
|
49
|
+
for (const k of kids) killTree(Number(k));
|
|
50
|
+
try { process.kill(pid, 'SIGKILL'); } catch {}
|
|
51
|
+
};
|
|
52
|
+
const myChromiumRoots = new Set();
|
|
53
|
+
const reapChromium = () => { for (const pid of myChromiumRoots) killTree(pid); };
|
|
20
54
|
(async () => {
|
|
21
55
|
const pw = require(modulePath);
|
|
22
56
|
let browser = null;
|
|
@@ -118,6 +152,9 @@ const { existsSync, unlinkSync } = require('fs');
|
|
|
118
152
|
const b = maybeBrowser();
|
|
119
153
|
if (b) await bounded('browser.close', () => b.close(), timeoutMs);
|
|
120
154
|
await terminateBrowserProcess();
|
|
155
|
+
// close() / root-SIGTERM above handle the graceful case; this sweeps any
|
|
156
|
+
// helper processes they left behind. no-op for already-dead pids.
|
|
157
|
+
reapChromium();
|
|
121
158
|
if (connectAckFile) {
|
|
122
159
|
try { unlinkSync(connectAckFile); } catch {}
|
|
123
160
|
}
|
|
@@ -125,6 +162,9 @@ const { existsSync, unlinkSync } = require('fs');
|
|
|
125
162
|
};
|
|
126
163
|
process.once('SIGTERM', () => { void shutdown(0); });
|
|
127
164
|
process.once('SIGINT', () => { void shutdown(0); });
|
|
165
|
+
// the launch-failure path at the bottom of this script exits without going
|
|
166
|
+
// through shutdown(); the exit hook (sync killTree) still reaps the tree.
|
|
167
|
+
process.on('exit', () => { reapChromium(); });
|
|
128
168
|
// owner-liveness watchdog \u2014 the load-bearing fix for leaked Chrome hosts.
|
|
129
169
|
// we are spawned detached + unref'd so \`sootsim open\` returns immediately,
|
|
130
170
|
// which means nothing in the OS process tree ties Chrome's lifetime to the
|
|
@@ -187,7 +227,15 @@ const { existsSync, unlinkSync } = require('fs');
|
|
|
187
227
|
let launchedChannel = null;
|
|
188
228
|
for (const channel of channelsToTry) {
|
|
189
229
|
try {
|
|
230
|
+
// bracket the launch with a chromium pid-diff so only the tree THIS
|
|
231
|
+
// host spawned is ever reaped (playwright's Browser exposes no pid, so
|
|
232
|
+
// the diff is the portable way to find our roots \u2014 same approach as
|
|
233
|
+
// scripts/lib/reap-browser.ts).
|
|
234
|
+
const pidsBefore = new Set(chromiumPids());
|
|
190
235
|
const launched = await launchWith(channel);
|
|
236
|
+
for (const p of chromiumPids()) {
|
|
237
|
+
if (!pidsBefore.has(p)) myChromiumRoots.add(Number(p));
|
|
238
|
+
}
|
|
191
239
|
launchedChannel = channel || 'chromium';
|
|
192
240
|
if (launched.kind === 'persistent') {
|
|
193
241
|
context = launched.value;
|
|
@@ -269,5 +317,5 @@ const { existsSync, unlinkSync } = require('fs');
|
|
|
269
317
|
process.stderr.write(String((err && err.stack) || err) + '\\n');
|
|
270
318
|
process.exit(1);
|
|
271
319
|
});
|
|
272
|
-
`;function
|
|
273
|
-
${i}`:""}`}}return{launched:!0,message:`playwright chrome launched \u2192 ${e.url}`,pid:l.pid,target:r.spec,attachUrl:e.url,connectAckFile:n,diagnosticLogPath:t}}catch(o){return{launched:!1,message:`playwright launch failed: ${o instanceof Error?o.message:String(o)}`}}finally{E(a)}}var
|
|
320
|
+
`;function P(){let e=[process.cwd()+"/"];try{process.argv[1]&&e.push(process.argv[1])}catch{}for(let r of e)try{let t=W(r);for(let n of["playwright","playwright-chromium","playwright-core"])try{return{spec:n,modulePath:t.resolve(n)}}catch{}}catch{}return null}function $(){let e=P();return e?{available:!0,reason:null,detail:`resolved via ${e.spec}`}:{available:!1,reason:"playwright not installed in the current workspace"}}function F(e){return e.profileId?f(w(e.profileId).id):e.ephemeralProfile?A(S(b(),"sootsim-playwright-profile-")):""}async function U(e){let r=P();if(!r)return{launched:!1,message:"playwright not installed \u2014 run `bun add -D playwright` first"};if(!e.url)return{launched:!1,message:"playwright driver requires a target url"};let t=S(b(),`sootsim-playwright-host-${Date.now().toString(36)}-${process.pid}.log`),n=`${t}.connected`,a=L(t,"a");try{let o=p(),l=C(process.execPath,["-e",N],{detached:!0,stdio:["ignore","ignore",a],env:{...process.env,SOOTSIM_PW_MODULE:r.modulePath,SOOTSIM_PW_URL:e.url,SOOTSIM_PW_HEADLESS:e.headless??!0?"1":"0",SOOTSIM_PW_USERDATADIR:F(e),SOOTSIM_PW_CDP_PORT:e.cdpPort?String(e.cdpPort):"",SOOTSIM_PW_CONNECTED_ACK_FILE:n,SOOTSIM_PW_CONNECT_TIMEOUT_MS:String(e.connectTimeoutMs??12e4),SOOTSIM_PW_OWNER_PID:o&&o>1?String(o):""}});l.unref();let c=await new Promise(i=>{let O=setTimeout(()=>i(null),4e3);l.once("exit",T=>{clearTimeout(O),i(T??0)})});if(c!==null&&c!==0){let i=R(t,"utf8").trim();return{launched:!1,message:`playwright host exited early (code ${c}) \u2014 host log ${t}${i?`:
|
|
321
|
+
${i}`:""}`}}return{launched:!0,message:`playwright chrome launched \u2192 ${e.url}`,pid:l.pid,target:r.spec,attachUrl:e.url,connectAckFile:n,diagnosticLogPath:t}}catch(o){return{launched:!1,message:`playwright launch failed: ${o instanceof Error?o.message:String(o)}`}}finally{E(a)}}var k={id:"playwright",name:"playwright",description:"programmatic chromium via the playwright package \u2014 headless default",kind:"automation",availability:$,launch:U};function H(){return process.platform!=="darwin"&&process.platform!=="linux"&&process.platform!=="win32"?{available:!1,reason:`unsupported platform: ${process.platform}`}:{available:!0,reason:null,detail:process.platform==="darwin"?"open(1)":process.platform==="win32"?"cmd /c start":"xdg-open(1)"}}async function B(e){if(e.headless)return{launched:!1,message:"system driver does not support --headless; use chromium or playwright"};if(!e.url)return{launched:!1,message:"system driver requires a target url"};if(e.profileId||e.ephemeralProfile)return{launched:!1,message:"profiles require electron or playwright; browser tabs use your current browser profile"};try{let r=await h(e.url,{detached:e.detached??!0,newWindow:e.newWindow});return{launched:!0,message:`${r.via} launch \u2192 ${e.url}`,pid:r.pid,target:r.target,attachUrl:e.url}}catch(r){return{launched:!1,message:`system launch failed: ${r instanceof Error?r.message:String(r)}`}}}var D={id:"system",name:"system",description:"shared browser launcher \u2014 system default or chromium window",kind:"delegate",availability:H,launch:B};var s=[v,y,k,D];function ae(){return s}function le(e){return s.find(r=>r.id===e)??null}function ce(e,r){if(e)return s.find(n=>n.id===e)??null;for(let t of r){let n=s.find(a=>a.id===t);if(n&&n.availability().available)return n}return null}function ue(){return s.map(e=>{let r=e.availability();return{id:e.id,name:e.name,kind:e.kind,description:e.description,available:r.available,reason:r.reason,detail:r.detail??null}})}export{v as a,y as b,k as c,D as d,s as e,ae as f,le as g,ce as h,ue as i};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
2
|
-
import{a as P,d as T,f as C}from"./chunk-
|
|
1
|
+
/*! sootsim v0.1.141 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{a as P,d as T,f as C}from"./chunk-A5W3HB44.js";import{G as k,H as v}from"./chunk-7SO2SJ4H.js";import{WebSocket as I}from"ws";function x(){let e=k();return e&&v(e)?e.bridgePort:7668}var w=class extends Error{lock;constructor(r,i){super(r),this.name="BridgeSimLockedError",this.lock=i}};function $(e){return e==="flag"?"via --sim":e==="saved"?"saved via `sootsim use`":"primary fallback \u2014 no sim pinned"}function N(e,r={}){let i=new Set,a=r.port??x(),l=r.commandTimeoutMs??15e3,t,m="none",h=new Set(r.stripBooleanFlags??[]),b=new Set(r.stripValueFlags??[]);for(let n=0;n<e.length;n++){let d=e[n];if(d==="--port"||d==="-p"){i.add(n),n+1<e.length&&(i.add(n+1),a=Number(e[n+1])),n++;continue}if(d.startsWith("--port=")){i.add(n),a=Number(d.slice(7));continue}if(d==="--timeout"){i.add(n),n+1<e.length&&(i.add(n+1),l=Number(e[n+1])),n++;continue}if(d==="--sim"||d==="--session"||d==="--tab"){i.add(n),n+1<e.length&&(i.add(n+1),t=e[n+1]?.trim()||void 0,m="flag"),n++;continue}let s=d.startsWith("--sim=")?d.slice(6):d.startsWith("--session=")?d.slice(10):d.startsWith("--tab=")?d.slice(6):void 0;if(s!==void 0){i.add(n),t=s.trim()||void 0,m="flag";continue}if(h.has(d)){i.add(n);continue}b.has(d)&&(i.add(n),n+1<e.length&&i.add(n+1),n++)}if(!t){let n=T();n&&(t=n.trim()||void 0,m="saved")}return{positional:e.filter((n,d)=>!i.has(d)),wsPort:a,simId:t,simIdSource:m,commandTimeoutMs:l}}function E(e,r={}){let i=1,a=r.commandTimeoutMs??15e3,l=new Map,t=new I(`ws://localhost:${e}`),m=P(),h=new Promise((s,o)=>{t.on("open",()=>{try{t.send(JSON.stringify({type:"bridge:hello",id:0,cliIdentityKey:m.key,cliIdentitySource:m.source,cliLabel:r.cliLabel}))}catch{}s()}),t.on("error",c=>{let g=c.message?`: ${c.message}`:"";o(new Error(`could not connect to ws://localhost:${e}${g}`))})}),b=!1,n=!1;function d(s,o){if(n||process.env.SOOTSIM_QUIET_TARGET_NOTICE==="1"||s.startsWith("bridge:")||s==="focus"||s==="close")return;n=!0;let c=o??"primary",g=$(o?r.simIdSource:"none");process.stderr.write(` \u2192 ${c} (${g})
|
|
3
3
|
`)}return t.on("message",s=>{let o;try{o=JSON.parse(s.toString())}catch{return}if(o.id===0)return;let c=l.get(o.id);c&&(l.delete(o.id),o._otherCliCount>0&&!b&&(b=!0,process.stderr.write(`
|
|
4
4
|
\u26A0 ${o._otherCliCount} other CLI identity/identities are driving this sim
|
|
5
5
|
taps, scrolls, and keyboard input from multiple agents will collide on
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
2
|
-
import{c as i,e as d,h as c}from"./chunk-
|
|
1
|
+
/*! sootsim v0.1.141 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{c as i,e as d,h as c}from"./chunk-JQTHQOPS.js";function g(r){let e=r[0]?.toLowerCase()??"toggle";return e!=="on"&&e!=="off"&&e!=="toggle"&&(console.error(` unknown argument: "${e}" (expected on | off | toggle)`),process.exit(1)),e}async function u(r,e,t){let l=i(r,{port:e.port}),s=g(l.positional),a=d({...l,commandTimeoutMs:5e3});try{let n=!!(await c(a,"SootSim.bridges.settings.get"))?.[t.modeKey],o=s==="on"?!0:s==="off"?!1:!n;if(n===o)return console.log(` ${t.displayName}: already ${o?"on":"off"}`),{current:n,target:o,changed:!1};if(!await a.send({type:"evaluate",acquireLock:!0,code:`(async () => {
|
|
3
3
|
const modeKey = ${JSON.stringify(t.modeKey)}
|
|
4
4
|
const target = ${JSON.stringify(o)}
|
|
5
5
|
window.dispatchEvent(new CustomEvent('sootsim:shell-command', {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.141 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
import{execFileSync as p,spawn as l}from"child_process";import{existsSync as s}from"fs";import{homedir as u}from"os";import{join as d}from"path";var g=["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium","~/Applications/Chromium.app/Contents/MacOS/Chromium","/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","~/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge","/Applications/Brave Browser.app/Contents/MacOS/Brave Browser","~/Applications/Brave Browser.app/Contents/MacOS/Brave Browser","/Applications/Arc.app/Contents/MacOS/Arc","~/Applications/Arc.app/Contents/MacOS/Arc"],f=["/usr/bin/google-chrome","/usr/bin/chromium","/usr/bin/chromium-browser","/usr/bin/microsoft-edge","/usr/bin/brave-browser","/snap/bin/chromium"],h=["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe","C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe","C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe","C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"],C=["google-chrome","chromium","chromium-browser","microsoft-edge","brave-browser"],O=["chrome","msedge","brave"];function w(r){return r.startsWith("~/")?d(u(),r.slice(2)):r}function a(r){for(let n of r){let o=w(n);if(s(o))return o}return null}function U(r,n){try{let e=p(n==="win32"?"where":"which",[r],{encoding:"utf8",timeout:1500,stdio:["ignore","pipe","ignore"]}).trim();return e?e.split(/\r?\n/)[0]:null}catch{return null}}function M(r=process.platform){let n=process.env.CHROME_PATH||process.env.CHROMIUM_PATH;if(n&&s(n))return n;let o=a(r==="darwin"?g:r==="win32"?h:f);if(o)return o;let e=r==="win32"?O:C;for(let t of e){let i=U(t,r);if(i)return i}return null}function A(r,n={}){if(!r)throw new Error("openUrl requires a url");let o=n.platform??process.platform;return n.newWindow?c(r,{...n,platform:o,newWindow:!0}):o==="darwin"?{command:"open",args:n.background===!1?[r]:["-g",r],via:"system"}:o==="win32"?{command:"cmd",args:["/c","start","",r],via:"system"}:{command:"xdg-open",args:[r],via:"system"}}function c(r,n={}){if(!r)throw new Error("openUrl requires a url");let o=n.platform??process.platform,e="chromiumBinary"in n?n.chromiumBinary:M(o);if(!e)throw new Error("browser launch requires Chrome, Chromium, Edge, Brave, or Arc");let t=[];return n.newWindow!==!1&&t.push("--new-window"),t.push(r),{command:e,args:t,via:"chromium",target:e}}async function m(r,n,o){return new Promise((e,t)=>{let i=l(r,n,{detached:o,stdio:"ignore"});i.once("error",t),i.once("spawn",()=>{o&&i.unref(),e(i.pid)})})}async function x(r,n={}){let o=A(r,n),e=await m(o.command,o.args,n.detached??!0);return{...o,pid:e,attachUrl:r}}async function y(r,n={}){let o=c(r,n),e=await m(o.command,o.args,n.detached??!0);return{...o,pid:e,attachUrl:r}}async function E(r,n={}){await x(r,n)}export{M as a,x as b,y as c,E as d};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/*! sootsim v0.1.141 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
+
import{d as ue,e as de,f as pe}from"./chunk-I6SWX7OI.js";import{d as ce}from"./chunk-MENSR2TZ.js";import{c as ae,e as le,g as P}from"./chunk-JQTHQOPS.js";import{d as ie}from"./chunk-LHIPDN4B.js";import{a as se,b}from"./chunk-ITJLXD4X.js";import{a as oe}from"./chunk-DM5KNA7Q.js";import{createHash as He}from"crypto";import{readFileSync as K}from"fs";import{gzipSync as Ce}from"zlib";function fe(e){let t=(e||"").toLowerCase().split(";")[0].trim();return t?!(t.startsWith("image/")||t.startsWith("video/")||t.startsWith("audio/")||t==="font/woff2"||t==="application/font-woff2"||t==="application/zip"||t==="application/gzip"):!0}import{brotliCompressSync as Le,constants as Ee}from"node:zlib";var ke=9;function ge(e){return Le(e,{params:{[Ee.BROTLI_PARAM_QUALITY]:ke}})}function G(e,t){let r=new AbortController,o=setTimeout(()=>r.abort(new Error(`${t} timed out after ${e/1e3}s`)),e);return{signal:r.signal,cancel:()=>clearTimeout(o)}}async function Ae(e){let t=G(12e4,`PUT ${e.url}`),r;try{r=await fetch(e.url,{method:"PUT",headers:{"content-type":e.contentType},body:e.bytes,signal:t.signal})}finally{t.cancel()}if(!r.ok){let o=await r.text().catch(()=>"");throw new Error(`PUT ${e.url} failed ${r.status}: ${o.slice(0,200)}`)}}async function Fe(e,t=8,r){let o=0,i=0,a=e.length;await Promise.all(Array.from({length:Math.min(t,a)},async()=>{for(;o<a;){let c=e[o++];await Ae(c),i++,r?.(i,a)}}))}function ze(e,t,r,o){let i=[];i.push({url:e.bundle.putUrl,contentType:e.bundle.contentType,bytes:t});for(let a of e.files){let c=r.get(a.urlhash);c&&i.push({url:a.putUrl,contentType:a.contentType,bytes:c})}e.events&&o?.eventsBytes&&i.push({url:e.events.putUrl,contentType:e.events.contentType,bytes:o.eventsBytes}),e.flowVideo&&o?.videoBytes&&i.push({url:e.flowVideo.putUrl,contentType:e.flowVideo.contentType,bytes:o.videoBytes}),e.storage&&o?.storageBytes&&i.push({url:e.storage.putUrl,contentType:e.storage.contentType,bytes:o.storageBytes});for(let a of e.snapshots??[]){let c=o?.snapshotBytes?.get(a.id);c&&i.push({url:a.putUrl,contentType:a.contentType,bytes:c})}return i}function Me(e){return e.replace(/\/+$/,"")}var F=class extends Error{constructor(r,o,i,a=""){super(r);this.status=o;this.phase=i;this.responseText=a;this.name="PresignedUploadError"}};async function he(e){let t=Me(e.originBase),r={"content-type":"application/json"};e.authHeader&&(r.authorization=e.authHeader),e.adminBypassToken&&(r["x-soot-admin-upload-bypass"]=e.adminBypassToken);let o=G(3e4,"init"),i;try{i=await fetch(`${t}/api/preview/upload/init`,{method:"POST",headers:r,body:JSON.stringify(e.initBody),signal:o.signal})}finally{o.cancel()}if(!i.ok){let p=await i.text().catch(()=>"");throw new F(`init failed: ${i.status} ${p.slice(0,200)}`,i.status,"init",p)}let a=await i.json(),c=ze(a,e.bundleBytes,e.filesByHash,e.extras);await Fe(c,e.concurrency??8,e.onPutProgress);let y=G(3e4,"finalize"),u;try{u=await fetch(`${t}/api/preview/upload/finalize`,{method:"POST",headers:r,body:JSON.stringify({token:a.token}),signal:y.signal})}finally{y.cancel()}if(!u.ok){let p=await u.text().catch(()=>"");throw new F(`finalize failed: ${u.status} ${p.slice(0,200)}`,u.status,"finalize",p)}let S=await u.json();return{init:a,finalize:S}}function Ne(e){if(!e)return null;try{let t=JSON.parse(e);return typeof t.message=="string"&&t.message?t.message:null}catch{return null}}var be=process.env.SOOTSIM_UPLOAD_ORIGIN||"https://sootbean.com",ve=process.env.SOOTSIM_PREVIEW_ORIGIN||"https://sootsim.com",J="http://localhost:3000",We=2e3;async function Ve(e){if(e)return e;if(process.env.SOOTSIM_UPLOAD_ORIGIN)return process.env.SOOTSIM_UPLOAD_ORIGIN;try{let t=await fetch(`${J}/api/preview/upload/init`,{method:"OPTIONS",signal:AbortSignal.timeout(We)});if(t.ok||t.status===204||t.status===405)return J}catch{}return be}function O(e){return e.replace(/\/$/,"")}function qe(e){try{let r=new URL(e).hostname.replace(/^\[|\]$/g,"").toLowerCase();return r==="localhost"||r.endsWith(".localhost")||r==="0.0.0.0"||r==="::1"||/^127(?:\.\d{1,3}){3}$/.test(r)}catch{return!1}}function De(e){try{let t=new URL(e).hostname.toLowerCase();return t==="sootbean.com"||t.endsWith(".sootbean.com")}catch{return!1}}function Ge(e,t){return t?O(t):process.env.SOOTSIM_PREVIEW_ORIGIN?O(process.env.SOOTSIM_PREVIEW_ORIGIN):qe(e)?O(e):De(e)?O(ve):O(e)}function Ke(){console.log(`
|
|
3
|
+
sootsim upload \u2014 publish the current recorded bundle as a /preview/<id> link
|
|
4
|
+
|
|
5
|
+
usage:
|
|
6
|
+
sootsim upload [--origin <url>] [--public-origin <url>] (--events <path> | --video <path>) [--screenshot <path>] [--owner <org> --repo <repo>] [--sim <sim>] [--open] [--assets-only]
|
|
7
|
+
|
|
8
|
+
options:
|
|
9
|
+
--origin <url> upload target (default: auto)
|
|
10
|
+
prefers ${J} when available, otherwise
|
|
11
|
+
falls back to ${be}
|
|
12
|
+
override with SOOTSIM_UPLOAD_ORIGIN env var
|
|
13
|
+
--public-origin <url>
|
|
14
|
+
public /preview link origin (default: ${ve}
|
|
15
|
+
for prod uploads, upload origin for localhost/custom origins).
|
|
16
|
+
override with SOOTSIM_PREVIEW_ORIGIN env var
|
|
17
|
+
--events <path> path to a gzipped events .jsonl.gz file to attach
|
|
18
|
+
required unless --video is present; previews must
|
|
19
|
+
have replay or recording playback data
|
|
20
|
+
--screenshot <path>
|
|
21
|
+
path to a PNG thumbnail to attach to the share
|
|
22
|
+
--video <path> path to a mp4/gif flow recording. embedded inline
|
|
23
|
+
in the pr sticky comment served at
|
|
24
|
+
/api/preview/flow-video?id=<share-id>
|
|
25
|
+
--video-duration-ms <ms>
|
|
26
|
+
duration hint for attached flow video
|
|
27
|
+
--owner <org> associate a session upload with a linked org repo
|
|
28
|
+
--repo <repo> repo name for --owner; the signed-in user must belong
|
|
29
|
+
to the local/org team that owns the link
|
|
30
|
+
--sim <sim> target a specific sim (see: sootsim list)
|
|
31
|
+
--open open the resulting /preview/<id> url in the browser
|
|
32
|
+
--assets-only drop API/JSON/HTML records before upload; keep images,
|
|
33
|
+
fonts, css, js, and binary blobs. live-data demos hit
|
|
34
|
+
the real network at replay time instead of serving
|
|
35
|
+
recorded API snapshots
|
|
36
|
+
-h, --help
|
|
37
|
+
|
|
38
|
+
examples:
|
|
39
|
+
sootsim upload --events ./my-session.jsonl.gz
|
|
40
|
+
sootsim upload --origin http://localhost:3000 --events ./my-session.jsonl.gz --open
|
|
41
|
+
sootsim upload --video /tmp/soot-flow.mp4 --video-duration-ms 12000
|
|
42
|
+
`)}function v(e,t){let r=e.findIndex(i=>i===t);if(r<0)return;let o=e[r+1];return e.splice(r,2),o}function ye(e,t){let r=e.findIndex(o=>o===t);return r<0?!1:(e.splice(r,1),!0)}function me(e){let t=(e||"").toLowerCase().split(";")[0].trim();return t?!!(t.startsWith("image/")||t.startsWith("font/")||t.startsWith("video/")||t.startsWith("audio/")||t.startsWith("model/")||t==="text/css"||t==="application/javascript"||t==="text/javascript"||t==="application/wasm"||t==="application/font-woff"||t==="application/font-woff2"||t==="application/octet-stream"):!1}async function we(e){let t=await fetch(e);if(!t.ok)throw new Error(`fetch ${e} -> ${t.status} ${t.statusText}`);return new Uint8Array(await t.arrayBuffer())}function je(e){return/\.bundle($|\?)/.test(e)||/\.js($|\?)/.test(e)?"application/javascript":/\.zip($|\?)/.test(e)?"application/zip":"application/javascript"}function Je(e){try{return new URL(e).searchParams.get("appFonts")||""}catch{return""}}function Ye(e){try{let t=new URL(e);return t.searchParams.get("lazy")==="true"?(t.searchParams.set("lazy","false"),t.toString()):e}catch{return e}}async function Qe(e,t){let o=[];for(let i=0;i<t;i+=15e5){let a=Math.min(i+15e5,t),c=await P(e,`(window.__sootsimLastTransformedBundle?.text || "").slice(${i}, ${a})`);if(typeof c!="string")return null;o.push(c)}return o.join("")}function j(e){let t=new Map;for(let r of e)t.set(r.urlhash||r.url,r);return Array.from(t.values())}async function ht(e,t){(e.includes("--help")||e.includes("-h"))&&(Ke(),process.exit(0));let r=[...e],o=await Ve(v(r,"--origin")),i=Ge(o,v(r,"--public-origin")),a=v(r,"--events"),c=v(r,"--screenshot"),y=v(r,"--video"),u=v(r,"--video-duration-ms"),S=v(r,"--owner"),p=v(r,"--repo"),Ue=ye(r,"--open");(S&&!p||!S&&p)&&(console.error(" --owner and --repo must be provided together"),process.exit(1)),!a&&!y&&(console.error(" preview uploads require playback data: pass --events or --video.\n for a normal local preview, use `sootsim record --mode combined --open`\n or `sootsim flow --preview` instead of uploading a bundle-only snapshot."),process.exit(1));let Y=ye(r,"--assets-only"),Be=ae(r,{stripBooleanFlags:[],stripValueFlags:[]}),U=le(Be),l,Q=[],m=[],z=null;try{if(l=await P(U,'(typeof window.__sootsimCaptureBundle === "function") ? window.__sootsimCaptureBundle() : null'),l?.bundleUrl){let n=new URL(l.bundleUrl).origin,[s,h]=await Promise.all([P(U,`(window.__sootsimPreviewRecorder?.list?.(${JSON.stringify(n)}) || [])`),P(U,`(async () => {
|
|
43
|
+
const list = window.__sootsimListWorkerFetchRecorder
|
|
44
|
+
return typeof list === 'function'
|
|
45
|
+
? await list(${JSON.stringify(n)})
|
|
46
|
+
: []
|
|
47
|
+
})()`)]);Q=j([...s,...h]).filter(d=>{try{return!new URL(d.url).pathname.startsWith("/api/")}catch{return!0}});let E=await P(U,`(async () => {
|
|
48
|
+
const rec = window.__sootsimPreviewRecorder
|
|
49
|
+
const workerList = window.__sootsimListWorkerFetchRecorder
|
|
50
|
+
return {
|
|
51
|
+
main: rec?.list ? rec.list() : [],
|
|
52
|
+
worker: typeof workerList === 'function' ? await workerList() : [],
|
|
53
|
+
}
|
|
54
|
+
})()`),_=(E?j([...E.main,...E.worker]):[]).filter(d=>{try{return new URL(d.url).origin!==n}catch{return!1}}),T=_.length>0?{count:_.length,totalBytes:_.reduce((d,x)=>d+(x.size||0),0)}:null;if(T&&T.count>0){console.log(` ${T.count} recorded cross-origin responses (${(T.totalBytes/1024).toFixed(1)} KiB)`);let d=await P(U,`(async () => {
|
|
55
|
+
const rec = window.__sootsimPreviewRecorder
|
|
56
|
+
const workerDump = window.__sootsimDumpWorkerFetchRecorder
|
|
57
|
+
const bundleUrl = ${JSON.stringify(l.bundleUrl)}
|
|
58
|
+
const keep = (r) => {
|
|
59
|
+
try {
|
|
60
|
+
const u = new URL(r.url)
|
|
61
|
+
if (u.origin !== ${JSON.stringify(n)}) return true
|
|
62
|
+
// bundle-origin api responses came from the rewritten
|
|
63
|
+
// /__app-api proxy at record time (re-keyed by the
|
|
64
|
+
// recorder's unwrap step). they need bodies attached the
|
|
65
|
+
// same way as cross-origin records \u2014 direct re-fetch from
|
|
66
|
+
// the dev server lacks the bundle's session cookies.
|
|
67
|
+
if (r.url !== bundleUrl && u.pathname.startsWith('/api/')) return true
|
|
68
|
+
return false
|
|
69
|
+
} catch { return false }
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
main: rec?.dump ? rec.dump().filter(keep) : [],
|
|
73
|
+
worker: typeof workerDump === 'function'
|
|
74
|
+
? (await workerDump()).filter(keep)
|
|
75
|
+
: [],
|
|
76
|
+
}
|
|
77
|
+
})()`);if(m=j([...d.main,...d.worker]),Y){let x=m.length;m=m.filter(D=>me(D.contentType));let q=T.totalBytes-m.reduce((D,$e)=>D+($e.size||0),0);console.log(` --assets-only: kept ${m.length}/${x} records (dropped ${(q/1024).toFixed(1)} KiB of API responses)`)}}}l?.transformedBundle&&(z=await Qe(U,l.transformedBundle.byteLength))}finally{U.close()}l||(console.error(" could not read bundle snapshot \u2014 is sootsim running and is the bundle loaded?"),process.exit(2)),l.bundleUrl||(console.error(` no ?bundle= URL on the current sootsim tab.
|
|
78
|
+
open the app you want to share first (e.g. sootsim open 8082), then run upload.`),process.exit(2));let f,M=!1;if(z!==null)f=new TextEncoder().encode(z),M=!0,console.log(` using post-transform bundle: ${(f.byteLength/1024).toFixed(1)} KiB`);else{let n=Ye(l.bundleUrl);n!==l.bundleUrl&&console.log(" forcing lazy=false for self-contained bundle"),console.log(` capturing: ${n}`),f=await we(n),console.log(` main bundle: ${(f.byteLength/1024).toFixed(1)} KiB`)}let k=Q.filter(n=>n.url!==l.bundleUrl);Y&&(k=k.filter(n=>me(n.contentType))),console.log(` fetching ${k.length} extra files\u2026`);let A=(await Promise.all(k.map(async n=>{try{let s=await we(n.url);return{...n,bytes:s}}catch(s){return console.error(` warning: failed to re-fetch ${n.url}: ${s instanceof Error?s.message:s}`),null}}))).filter(n=>!!n),Te=A.reduce((n,s)=>n+s.bytes.byteLength,0);console.log(` ${A.length} extra files: ${(Te/1024).toFixed(1)} KiB`);let B;a&&(B=K(a));let g;c&&(g=K(c),console.log(` attaching screenshot: ${(g.byteLength/1024).toFixed(1)} KiB`));let w,$,X;if(y){if(w=K(y),$=y.endsWith(".mp4")?"video/mp4":y.endsWith(".gif")?"image/gif":void 0,$||(console.error(" preview flow videos must be mp4 or gif"),await b(),process.exit(1)),u){let n=Number(u);(!Number.isFinite(n)||n<=0)&&(console.error(` invalid --video-duration-ms: ${u}`),await b(),process.exit(1)),X=Math.round(n)}console.log(` attaching flow video: ${(w.byteLength/1024).toFixed(1)} KiB (${$})`)}let I=ue(),R=pe(I),Pe=oe();se({event:"preview_upload_started",identity:{userId:I?.kind==="session"?Pe?.user?.id??null:null,repoId:R?.repoId??null,installationId:R?.installationId??null},properties:{origin:o,hasAuth:!!I,authMode:I?.kind??"none",bundleBytes:f.byteLength,isTransformed:M,extraFiles:A.length,recordedFetches:m.length,hasEvents:!!B,hasScreenshot:!!g,hasVideo:!!w}}),I||(console.error(" preview uploads need auth."),console.error(" set SOOTSIM_API_KEY=sk_sootsim_..., run `sootsim login`, or use the soot github runner."),await b(),process.exit(1));let Ie=de(I),Re=(()=>{try{return new URL(l.bundleUrl).origin}catch{return null}})(),H=(n,s,h,E,re,_,T,d)=>{let x=fe(_),q=x?Ce(n):n;return{url:s,urlhash:h,method:E,bodyHash:re,requestVaryHash:d,contentType:_,responseHeaders:T,bytes:q,encoding:x?"gzip":void 0}},Z=[],C=Je(l.pageHref)||"";if(C){let n=await ce(C,{onStaged:({url:s,byteLength:h})=>console.log(` staged app font: ${s} (${(h/1024).toFixed(1)} KiB)`),onError:(s,h)=>console.error(` warning: failed to fetch app font ${s}: ${h instanceof Error?h.message:h}`)});for(let s of n)Z.push(H(Buffer.from(s.bytes),s.url,s.urlhash,"GET","-",s.contentType))}let N=[...A.map(n=>H(n.bytes,n.url,n.urlhash,"GET","-",n.contentType,n.responseHeaders,n.requestVaryHash)),...m.map(n=>H(Buffer.from(n.bodyBase64,"base64"),n.url,n.urlhash,n.method||"GET",n.bodyHash||"-",n.contentType,n.responseHeaders,n.requestVaryHash)),...Z],W=ge(f),_e=He("sha256").update(f).digest("hex");console.log(` bundle raw=${(f.byteLength/1024).toFixed(1)} KiB br=${(W.byteLength/1024).toFixed(1)} KiB`);let xe={contentHash:_e,bundleSizeBytes:f.byteLength,bundleContentType:je(l.bundleUrl),bundleEncoding:"br",bundleOrigin:Re,runtimeVersion:l.runtimeVersion??void 0,appFonts:C||void 0,entry:l.entry,isTransformed:M,deviceSpec:l.deviceSpec,installationId:R?.installationId??void 0,repoId:R?.repoId,owner:S??R?.owner,repo:p??R?.repo,files:N.map(n=>({url:n.url,urlhash:n.urlhash,method:n.method,bodyHash:n.bodyHash,contentType:n.contentType,responseHeaders:n.responseHeaders,requestVaryHash:n.requestVaryHash,encoding:n.encoding,sizeBytes:n.bytes.byteLength})),events:B?{sizeBytes:B.byteLength}:void 0,snapshots:g?[{id:"landing",label:"Landing",kind:"landing",t:0,contentType:"image/png",sizeBytes:g.byteLength}]:void 0,flowVideo:w&&$?{sizeBytes:w.byteLength,contentType:$,durationMs:X}:void 0},ee=new Map;for(let n of N)ee.set(n.urlhash,n.bytes);let te=new Map;g&&te.set("landing",g);let Oe=Date.now(),L=W.byteLength;for(let n of N)L+=n.bytes.byteLength;B&&(L+=B.byteLength),g&&(L+=g.byteLength),w&&(L+=w.byteLength);let Se=`${O(o)}/api/preview/upload/init`;console.log(` init: ${Se}`);let V;try{let n=await he({originBase:o,initBody:xe,bundleBytes:W,filesByHash:ee,extras:{eventsBytes:B,videoBytes:w,snapshotBytes:te},authHeader:Ie,concurrency:16});V=n.finalize;let s=1+n.init.files.length+(n.init.events?1:0)+n.init.snapshots.length+(n.init.flowVideo?1:0);console.log(` PUT ${s} objects in ${Date.now()-Oe}ms (${(L/1024).toFixed(1)} KiB)`)}catch(n){let s=n;s.phase==="init"&&s.status===401&&(console.error(" preview upload requires a valid login."),console.error(" run `sootsim login` and retry."),await b(),process.exit(1)),s.status===402&&(console.error(` ${Ne(s.responseText)??"preview uploads require Personal, Team, or an active trial \u2014 upgrade from the billing dialog."}`),await b(),process.exit(1)),console.error(` ${s.message??`${s.phase??"upload"} failed: ${String(n)}`}`),await b(),process.exit(1)}let ne=`${i}${V.url}`;console.log(`
|
|
79
|
+
stored ${V.filesStored??0} extra files`),console.log(` preview: ${ne}`),Ue&&await ie(ne),await b()}export{Ve as a,Ge as b,ht as c};
|