sootsim 0.1.239 → 0.1.240
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 +4 -4
- package/dist-cli/chunks/{agent-5KVGVFXJ.js → agent-YS355M7O.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-YVXMSV3X.js → agent-wrapper-DJJH2DE5.js} +2 -2
- package/dist-cli/chunks/{app-fonts-IXF6YPQZ.js → app-fonts-2KURCNO7.js} +2 -2
- package/dist-cli/chunks/{assert-FMNM5VTT.js → assert-Y7SV6LAY.js} +2 -2
- package/dist-cli/chunks/{auth-LNSDYZU4.js → auth-5VMBSD6F.js} +2 -2
- package/dist-cli/chunks/beta-KMI4GCCN.js +2 -0
- package/dist-cli/chunks/{camera-INMAD3CG.js → camera-WCQNMZRH.js} +2 -2
- package/dist-cli/chunks/{chunk-SBSL3DUQ.js → chunk-2QILUPQJ.js} +1 -1
- package/dist-cli/chunks/{chunk-SOZIIFPY.js → chunk-2ZEVD46I.js} +3 -3
- package/dist-cli/chunks/{chunk-HJW6SASW.js → chunk-3RYTIG4Y.js} +1 -1
- package/dist-cli/chunks/{chunk-QYVGMN3I.js → chunk-3ULI43M6.js} +1 -1
- package/dist-cli/chunks/{chunk-HE5NBBLH.js → chunk-4F63QBYN.js} +3 -3
- package/dist-cli/chunks/{chunk-UZRZGXQ4.js → chunk-4FUKKXDQ.js} +2 -2
- package/dist-cli/chunks/{chunk-BKDHODNB.js → chunk-5LCZXDDX.js} +1 -1
- package/dist-cli/chunks/{chunk-EQYRXSBE.js → chunk-6XHVSTMH.js} +2 -2
- package/dist-cli/chunks/{chunk-D4YH5KNQ.js → chunk-7ZTOWAQF.js} +2 -2
- package/dist-cli/chunks/{chunk-HV2ZRFGP.js → chunk-AX56F2Z5.js} +1 -1
- package/dist-cli/chunks/{chunk-ZL2KSYJP.js → chunk-BWR3AJZ3.js} +1 -1
- package/dist-cli/chunks/{chunk-CJRALJVV.js → chunk-C4MSUAGM.js} +1 -1
- package/dist-cli/chunks/{chunk-JPNTLGLA.js → chunk-DEO54ZY3.js} +2 -2
- package/dist-cli/chunks/{chunk-LWE27HF7.js → chunk-DQEI7LOC.js} +3 -3
- package/dist-cli/chunks/{chunk-JOSDTQZ3.js → chunk-EJ6ULQFO.js} +2 -2
- package/dist-cli/chunks/{chunk-DJIWF2SR.js → chunk-GI36DI2I.js} +1 -1
- package/dist-cli/chunks/{chunk-VIM3WDAA.js → chunk-GW7REFUB.js} +1 -1
- package/dist-cli/chunks/{chunk-5VCOEPSJ.js → chunk-GYWIGJB7.js} +2 -2
- package/dist-cli/chunks/{chunk-544G2PCM.js → chunk-H6GS5C4F.js} +2 -2
- package/dist-cli/chunks/{chunk-P5JIE7R6.js → chunk-HIFBYPJK.js} +2 -2
- package/dist-cli/chunks/{chunk-SRMYUHBI.js → chunk-ILU6JNUJ.js} +1 -1
- package/dist-cli/chunks/{chunk-R5I2OBQM.js → chunk-JDRG4T3G.js} +2 -2
- package/dist-cli/chunks/{chunk-MDOTB5DP.js → chunk-KENWUOKC.js} +2 -2
- package/dist-cli/chunks/{chunk-QHJLYAOH.js → chunk-KY2HHVDG.js} +2 -2
- package/dist-cli/chunks/{chunk-YIS2RXPE.js → chunk-LBOSTYWQ.js} +1 -1
- package/dist-cli/chunks/{chunk-GI2S43VF.js → chunk-M2MJXMTO.js} +1 -1
- package/dist-cli/chunks/{chunk-44WCYVFQ.js → chunk-M2OTE66X.js} +2 -2
- package/dist-cli/chunks/{chunk-6XF2EHL2.js → chunk-M3VY5LEN.js} +1 -1
- package/dist-cli/chunks/{chunk-SLIYVKRX.js → chunk-NJYDI627.js} +1 -1
- package/dist-cli/chunks/{chunk-BWKVAEAJ.js → chunk-OBQJXFV3.js} +1 -1
- package/dist-cli/chunks/{chunk-PVIUYYIS.js → chunk-OKHNWLZ7.js} +2 -2
- package/dist-cli/chunks/{chunk-NJQSCTFC.js → chunk-OUW757HM.js} +3 -3
- package/dist-cli/chunks/chunk-R54EGANH.js +1 -0
- package/dist-cli/chunks/{chunk-XWPQVHOL.js → chunk-SFNTUDIP.js} +2 -2
- package/dist-cli/chunks/{chunk-VBO7OQLR.js → chunk-SW5HPJC7.js} +2 -2
- package/dist-cli/chunks/{chunk-CUDTQFGP.js → chunk-T7BLBFPG.js} +2 -2
- package/dist-cli/chunks/{chunk-X7JZ4KTU.js → chunk-TFXCEOCW.js} +1 -1
- package/dist-cli/chunks/chunk-U3VMQUN6.js +1 -0
- package/dist-cli/chunks/{chunk-ECPEYFHV.js → chunk-VU5WTUZJ.js} +2 -2
- package/dist-cli/chunks/{chunk-FOTAUF7Q.js → chunk-WYT6JDAV.js} +1 -1
- package/dist-cli/chunks/{chunk-NDU5EJFW.js → chunk-XSSTKHK7.js} +2 -2
- package/dist-cli/chunks/{chunk-KCS6OYQV.js → chunk-XV4VXQDA.js} +2 -2
- package/dist-cli/chunks/{chunk-JBUMYCFR.js → chunk-XVE2O2IR.js} +2 -2
- package/dist-cli/chunks/{chunk-WXYRA447.js → chunk-ZYMOUSJC.js} +1 -1
- package/dist-cli/chunks/cli-version-2BXTYTLJ.js +2 -0
- package/dist-cli/chunks/{compat-VYOIJUW6.js → compat-LUERFKMW.js} +3 -3
- package/dist-cli/chunks/{config-ZJIIQF6K.js → config-U4Z6TYT6.js} +2 -2
- package/dist-cli/chunks/{control-KFAL3LD7.js → control-I5YB63IZ.js} +2 -2
- package/dist-cli/chunks/daemon-VTG3XKWA.js +2 -0
- package/dist-cli/chunks/{debug-RCY6BSLW.js → debug-HXECWDLV.js} +3 -3
- package/dist-cli/chunks/{desktop-FRZILY3U.js → desktop-NZJLDJIO.js} +3 -3
- package/dist-cli/chunks/{detox-W2HOZRDP.js → detox-LUOT4TIA.js} +2 -2
- package/dist-cli/chunks/{device-WRWT7SEE.js → device-7TZ7BD36.js} +2 -2
- package/dist-cli/chunks/{diagnose-3KSX2NJC.js → diagnose-DW2ANEGF.js} +2 -2
- package/dist-cli/chunks/drivers-RDXY5SDO.js +2 -0
- package/dist-cli/chunks/{film-QN7NUW6Z.js → film-6MYMKZ3N.js} +3 -3
- package/dist-cli/chunks/flow-KS77CBEA.js +2 -0
- package/dist-cli/chunks/help-H3ZD3LVG.js +2 -0
- package/dist-cli/chunks/{hidden-runtime-alias-NIH62HCH.js → hidden-runtime-alias-FUDVEMFB.js} +2 -2
- package/dist-cli/chunks/{home-paths-3CPTCZDU.js → home-paths-KU4MY22X.js} +2 -2
- package/dist-cli/chunks/inspect-ACDDO276.js +2 -0
- package/dist-cli/chunks/install-desktop-UQVXJAXS.js +2 -0
- package/dist-cli/chunks/{login-HQ3356B6.js → login-EVS4SZQN.js} +4 -4
- package/dist-cli/chunks/{logout-LVVXQS5S.js → logout-K5MLSAWM.js} +2 -2
- package/dist-cli/chunks/{maestro-34Y7GOG5.js → maestro-OEDT2T7V.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-XBIZ7Z6U.js → maestro-generate-T4RZSVSM.js} +3 -3
- package/dist-cli/chunks/{mode-VXZR6I46.js → mode-TZU7JML2.js} +2 -2
- package/dist-cli/chunks/optional-demo-registry-NIJ3MA5N.js +2 -0
- package/dist-cli/chunks/{perf-IBHKDDFN.js → perf-YNBU57WH.js} +2 -2
- package/dist-cli/chunks/{record-S5WYHPNR.js → record-V6T2INPF.js} +3 -3
- package/dist-cli/chunks/runtime-7XBSKGNO.js +2 -0
- package/dist-cli/chunks/{screenshot-command-T65M2SYC.js → screenshot-command-CZZ6IXSD.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-75AHIYWA.js → screenshots-capture-WVR5FCHX.js} +2 -2
- package/dist-cli/chunks/serve-6I35UUFI.js +41 -0
- package/dist-cli/chunks/{setup-TLQ2VM3F.js → setup-O7GD6GME.js} +3 -3
- package/dist-cli/chunks/{skills-LZZDB6V5.js → skills-GBTBS2OK.js} +2 -2
- package/dist-cli/chunks/{storage-G2IZ2WAD.js → storage-FI2YOPQE.js} +2 -2
- package/dist-cli/chunks/store-FU7T5NPV.js +2 -0
- package/dist-cli/chunks/telemetry-REPVX6LA.js +2 -0
- package/dist-cli/chunks/{timeline-L4CFSXX3.js → timeline-E5DVVATK.js} +2 -2
- package/dist-cli/chunks/{upgrade-5USALUAU.js → upgrade-QKOI3Q4U.js} +2 -2
- package/dist-cli/chunks/upload-IFQM3FG4.js +2 -0
- package/dist-cli/chunks/{version-RQZPUNJO.js → version-UANAPNZM.js} +2 -2
- package/dist-cli/chunks/{web-YQ6XAB5F.js → web-4LZ7DUUS.js} +2 -2
- package/dist-cli/chunks/{what-happened-JLAM7TBD.js → what-happened-JOLNICMX.js} +2 -2
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -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/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 +1 -1
- 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 +77 -33
- package/dist-lib/host/fetch-proxy-handler.cjs +77 -33
- 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/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +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 +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +78 -34
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/src/host/fetch-proxy-handler.ts +104 -52
- package/dist-cli/chunks/beta-BH6RPXQU.js +0 -2
- package/dist-cli/chunks/chunk-J7SEKMNI.js +0 -1
- package/dist-cli/chunks/chunk-NO6RQXYN.js +0 -1
- package/dist-cli/chunks/cli-version-7KCROGJR.js +0 -2
- package/dist-cli/chunks/daemon-TJXAVVUE.js +0 -2
- package/dist-cli/chunks/drivers-SJOWPOA3.js +0 -2
- package/dist-cli/chunks/flow-Q4XCAPIT.js +0 -2
- package/dist-cli/chunks/help-FRVJH7SB.js +0 -2
- package/dist-cli/chunks/inspect-5ZZN4UJN.js +0 -2
- package/dist-cli/chunks/install-desktop-MIY6DLN6.js +0 -2
- package/dist-cli/chunks/optional-demo-registry-5JSIUIMF.js +0 -2
- package/dist-cli/chunks/runtime-5K5JFYOZ.js +0 -2
- package/dist-cli/chunks/serve-OJVA6PNV.js +0 -41
- package/dist-cli/chunks/store-X6HDJ5SE.js +0 -2
- package/dist-cli/chunks/telemetry-AHMOJS6L.js +0 -2
- package/dist-cli/chunks/upload-OWMPT3Z7.js +0 -2
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.240 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
@@ -12894,12 +12894,6 @@ function formatFetchProxyError(targetUrl, err) {
|
|
|
12894
12894
|
}
|
|
12895
12895
|
return message;
|
|
12896
12896
|
}
|
|
12897
|
-
function isTextProxyContentType(contentType) {
|
|
12898
|
-
const value = Array.isArray(contentType) ? contentType[0] : contentType;
|
|
12899
|
-
const normalized = value?.split(";", 1)[0]?.trim().toLowerCase();
|
|
12900
|
-
if (!normalized) return false;
|
|
12901
|
-
return normalized.startsWith("text/") || normalized === "application/json" || normalized.endsWith("+json") || normalized === "application/x-www-form-urlencoded" || normalized === "application/xml" || normalized.endsWith("+xml") || normalized === "application/javascript" || normalized === "application/graphql";
|
|
12902
|
-
}
|
|
12903
12897
|
function buildFetchProxyHeaders(reqHeaders, targetUrl) {
|
|
12904
12898
|
const headers = {};
|
|
12905
12899
|
for (const [key, value] of Object.entries(reqHeaders)) {
|
|
@@ -12958,7 +12952,6 @@ async function handleFetchProxyRequest(req, res) {
|
|
|
12958
12952
|
res.end("invalid url param");
|
|
12959
12953
|
return;
|
|
12960
12954
|
}
|
|
12961
|
-
const headers = buildFetchProxyHeaders(req.headers, upstreamUrl);
|
|
12962
12955
|
let body;
|
|
12963
12956
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
12964
12957
|
const chunks = [];
|
|
@@ -12966,39 +12959,89 @@ async function handleFetchProxyRequest(req, res) {
|
|
|
12966
12959
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
12967
12960
|
}
|
|
12968
12961
|
if (chunks.length > 0) {
|
|
12969
|
-
|
|
12970
|
-
body = isTextProxyContentType(req.headers["content-type"]) ? bytes.toString("utf8") : bytes;
|
|
12962
|
+
body = Buffer.concat(chunks);
|
|
12971
12963
|
}
|
|
12972
12964
|
}
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12965
|
+
const originalMethod = req.method || "GET";
|
|
12966
|
+
const proxy = async (targetUrl2, method, nextBody, redirects) => {
|
|
12967
|
+
const transport = targetUrl2.protocol === "https:" ? import_https.default : import_http2.default;
|
|
12968
|
+
const targetHeaders = buildFetchProxyHeaders(req.headers, targetUrl2);
|
|
12969
|
+
if (targetUrl2.origin !== upstreamUrl.origin) {
|
|
12970
|
+
delete targetHeaders.authorization;
|
|
12971
|
+
delete targetHeaders["proxy-authorization"];
|
|
12972
|
+
}
|
|
12973
|
+
if (method === "GET" || method === "HEAD") {
|
|
12974
|
+
delete targetHeaders["content-length"];
|
|
12975
|
+
delete targetHeaders["content-type"];
|
|
12976
|
+
} else if (nextBody) {
|
|
12977
|
+
targetHeaders["content-length"] = String(nextBody.byteLength);
|
|
12978
|
+
}
|
|
12979
|
+
const proxyRes = await new Promise((resolve5, reject) => {
|
|
12980
|
+
const proxyReq = transport.request(
|
|
12981
|
+
{
|
|
12982
|
+
hostname: targetUrl2.hostname,
|
|
12983
|
+
port: targetUrl2.port || (targetUrl2.protocol === "https:" ? 443 : 80),
|
|
12984
|
+
path: targetUrl2.pathname + targetUrl2.search,
|
|
12985
|
+
method,
|
|
12986
|
+
headers: targetHeaders
|
|
12987
|
+
},
|
|
12988
|
+
resolve5
|
|
12989
|
+
);
|
|
12990
|
+
const abort = () => proxyReq.destroy(new Error("fetch proxy client disconnected"));
|
|
12991
|
+
req.once("aborted", abort);
|
|
12992
|
+
proxyReq.once("close", () => req.off("aborted", abort));
|
|
12993
|
+
proxyReq.once("error", reject);
|
|
12994
|
+
if (nextBody === void 0) proxyReq.end();
|
|
12995
|
+
else proxyReq.end(nextBody);
|
|
12980
12996
|
});
|
|
12997
|
+
const status = proxyRes.statusCode ?? 502;
|
|
12998
|
+
const location = proxyRes.headers.location;
|
|
12999
|
+
if (location && (status === 301 || status === 302 || status === 303 || status === 307 || status === 308)) {
|
|
13000
|
+
if (redirects >= 10) {
|
|
13001
|
+
proxyRes.destroy();
|
|
13002
|
+
throw new Error("too many redirects");
|
|
13003
|
+
}
|
|
13004
|
+
const switchToGet = (status === 301 || status === 302) && method === "POST" || status === 303 && method !== "GET" && method !== "HEAD";
|
|
13005
|
+
const redirectUrl = new URL(location, targetUrl2);
|
|
13006
|
+
proxyRes.resume();
|
|
13007
|
+
await (0, import_promises2.finished)(proxyRes);
|
|
13008
|
+
await proxy(
|
|
13009
|
+
redirectUrl,
|
|
13010
|
+
switchToGet ? "GET" : method,
|
|
13011
|
+
switchToGet ? void 0 : nextBody,
|
|
13012
|
+
redirects + 1
|
|
13013
|
+
);
|
|
13014
|
+
return;
|
|
13015
|
+
}
|
|
13016
|
+
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
13017
|
+
const lowerKey = key.toLowerCase();
|
|
13018
|
+
if (value === void 0 || lowerKey === "set-cookie" || lowerKey === "connection" || lowerKey === "keep-alive" || lowerKey === "proxy-authenticate" || lowerKey === "proxy-authorization" || lowerKey === "te" || lowerKey === "trailer" || lowerKey === "transfer-encoding" || lowerKey === "upgrade" || lowerKey.startsWith("access-control-")) {
|
|
13019
|
+
continue;
|
|
13020
|
+
}
|
|
13021
|
+
res.setHeader(key, value);
|
|
13022
|
+
}
|
|
13023
|
+
applyFetchProxyCors(res);
|
|
13024
|
+
const setCookie = proxyRes.headers["set-cookie"] ?? [];
|
|
13025
|
+
if (setCookie.length > 0) {
|
|
13026
|
+
res.setHeader(
|
|
13027
|
+
"x-sootsim-set-cookie",
|
|
13028
|
+
(Array.isArray(setCookie) ? setCookie : [setCookie]).join(", ")
|
|
13029
|
+
);
|
|
13030
|
+
}
|
|
13031
|
+
res.statusCode = status;
|
|
13032
|
+
await (0, import_promises2.pipeline)(proxyRes, res);
|
|
13033
|
+
};
|
|
13034
|
+
try {
|
|
13035
|
+
await proxy(upstreamUrl, originalMethod, body, 0);
|
|
12981
13036
|
} catch (err) {
|
|
13037
|
+
if (res.headersSent) {
|
|
13038
|
+
res.destroy(err instanceof Error ? err : new Error(String(err)));
|
|
13039
|
+
return;
|
|
13040
|
+
}
|
|
12982
13041
|
applyFetchProxyCors(res);
|
|
12983
13042
|
res.writeHead(502, { "Content-Type": "text/plain" });
|
|
12984
13043
|
res.end(`fetch proxy error: ${formatFetchProxyError(upstreamUrl.href, err)}`);
|
|
12985
|
-
return;
|
|
12986
|
-
}
|
|
12987
|
-
upstream.headers.forEach((value, key) => {
|
|
12988
|
-
const lowerKey = key.toLowerCase();
|
|
12989
|
-
if (lowerKey === "content-encoding" || lowerKey === "transfer-encoding" || lowerKey === "content-length" || lowerKey === "set-cookie" || lowerKey.startsWith("access-control-")) {
|
|
12990
|
-
return;
|
|
12991
|
-
}
|
|
12992
|
-
res.setHeader(key, value);
|
|
12993
|
-
});
|
|
12994
|
-
applyFetchProxyCors(res);
|
|
12995
|
-
const setCookie = upstream.headers.getSetCookie?.() ?? [];
|
|
12996
|
-
if (setCookie.length > 0) {
|
|
12997
|
-
res.setHeader("x-sootsim-set-cookie", setCookie.join(", "));
|
|
12998
13044
|
}
|
|
12999
|
-
res.statusCode = upstream.status;
|
|
13000
|
-
const buf = Buffer.from(await upstream.arrayBuffer());
|
|
13001
|
-
res.end(buf);
|
|
13002
13045
|
}
|
|
13003
13046
|
function handleAppApiRequest(req, res) {
|
|
13004
13047
|
const reqUrl = req.url || "";
|
|
@@ -13068,12 +13111,13 @@ function handleAppApiRequest(req, res) {
|
|
|
13068
13111
|
req.pipe(proxyReq);
|
|
13069
13112
|
return true;
|
|
13070
13113
|
}
|
|
13071
|
-
var import_http2, import_https, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS, APP_API_HEADER_REWRITES;
|
|
13114
|
+
var import_http2, import_https, import_promises2, STRIP_FETCH_PROXY_HEADERS, FETCH_PROXY_CORS_HEADERS, APP_API_HEADER_REWRITES;
|
|
13072
13115
|
var init_fetch_proxy_handler = __esm({
|
|
13073
13116
|
"src/host/fetch-proxy-handler.ts"() {
|
|
13074
13117
|
"use strict";
|
|
13075
13118
|
import_http2 = __toESM(require("http"), 1);
|
|
13076
13119
|
import_https = __toESM(require("https"), 1);
|
|
13120
|
+
import_promises2 = require("stream/promises");
|
|
13077
13121
|
init_fetch_proxy_overrides();
|
|
13078
13122
|
STRIP_FETCH_PROXY_HEADERS = /* @__PURE__ */ new Set([
|
|
13079
13123
|
"host",
|
package/dist-lib/vite.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.240 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
let __sootsim_import_meta_url = ''; try { __sootsim_import_meta_url = require('url').pathToFileURL(__filename).href; } catch {}
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
package/package.json
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import http, { type IncomingMessage, type ServerResponse } from 'http'
|
|
27
27
|
import https from 'https'
|
|
28
|
+
import { finished, pipeline } from 'stream/promises'
|
|
28
29
|
import {
|
|
29
30
|
FETCH_PROXY_BROWSER_USER_AGENT,
|
|
30
31
|
getFetchProxyTargetHeaders,
|
|
@@ -98,22 +99,6 @@ function formatFetchProxyError(targetUrl: string, err: unknown): string {
|
|
|
98
99
|
return message
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
function isTextProxyContentType(contentType: string | string[] | undefined): boolean {
|
|
102
|
-
const value = Array.isArray(contentType) ? contentType[0] : contentType
|
|
103
|
-
const normalized = value?.split(';', 1)[0]?.trim().toLowerCase()
|
|
104
|
-
if (!normalized) return false
|
|
105
|
-
return (
|
|
106
|
-
normalized.startsWith('text/') ||
|
|
107
|
-
normalized === 'application/json' ||
|
|
108
|
-
normalized.endsWith('+json') ||
|
|
109
|
-
normalized === 'application/x-www-form-urlencoded' ||
|
|
110
|
-
normalized === 'application/xml' ||
|
|
111
|
-
normalized.endsWith('+xml') ||
|
|
112
|
-
normalized === 'application/javascript' ||
|
|
113
|
-
normalized === 'application/graphql'
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
102
|
export function buildFetchProxyHeaders(
|
|
118
103
|
reqHeaders: Record<string, string | string[] | undefined>,
|
|
119
104
|
targetUrl?: URL,
|
|
@@ -190,60 +175,127 @@ export async function handleFetchProxyRequest(
|
|
|
190
175
|
return
|
|
191
176
|
}
|
|
192
177
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
let body: BodyInit | undefined
|
|
178
|
+
let body: Buffer | undefined
|
|
196
179
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
197
180
|
const chunks: Buffer[] = []
|
|
198
181
|
for await (const chunk of req) {
|
|
199
182
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))
|
|
200
183
|
}
|
|
201
184
|
if (chunks.length > 0) {
|
|
202
|
-
|
|
203
|
-
body = isTextProxyContentType(req.headers['content-type'])
|
|
204
|
-
? bytes.toString('utf8')
|
|
205
|
-
: bytes
|
|
185
|
+
body = Buffer.concat(chunks)
|
|
206
186
|
}
|
|
207
187
|
}
|
|
208
188
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
189
|
+
const originalMethod = req.method || 'GET'
|
|
190
|
+
const proxy = async (
|
|
191
|
+
targetUrl: URL,
|
|
192
|
+
method: string,
|
|
193
|
+
nextBody: Buffer | undefined,
|
|
194
|
+
redirects: number,
|
|
195
|
+
): Promise<void> => {
|
|
196
|
+
const transport = targetUrl.protocol === 'https:' ? https : http
|
|
197
|
+
const targetHeaders = buildFetchProxyHeaders(req.headers, targetUrl)
|
|
198
|
+
if (targetUrl.origin !== upstreamUrl.origin) {
|
|
199
|
+
delete targetHeaders.authorization
|
|
200
|
+
delete targetHeaders['proxy-authorization']
|
|
201
|
+
}
|
|
202
|
+
if (method === 'GET' || method === 'HEAD') {
|
|
203
|
+
delete targetHeaders['content-length']
|
|
204
|
+
delete targetHeaders['content-type']
|
|
205
|
+
} else if (nextBody) {
|
|
206
|
+
targetHeaders['content-length'] = String(nextBody.byteLength)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const proxyRes = await new Promise<IncomingMessage>((resolve, reject) => {
|
|
210
|
+
const proxyReq = transport.request(
|
|
211
|
+
{
|
|
212
|
+
hostname: targetUrl.hostname,
|
|
213
|
+
port: targetUrl.port || (targetUrl.protocol === 'https:' ? 443 : 80),
|
|
214
|
+
path: targetUrl.pathname + targetUrl.search,
|
|
215
|
+
method,
|
|
216
|
+
headers: targetHeaders,
|
|
217
|
+
},
|
|
218
|
+
resolve,
|
|
219
|
+
)
|
|
220
|
+
const abort = () => proxyReq.destroy(new Error('fetch proxy client disconnected'))
|
|
221
|
+
req.once('aborted', abort)
|
|
222
|
+
proxyReq.once('close', () => req.off('aborted', abort))
|
|
223
|
+
proxyReq.once('error', reject)
|
|
224
|
+
if (nextBody === undefined) proxyReq.end()
|
|
225
|
+
else proxyReq.end(nextBody)
|
|
216
226
|
})
|
|
217
|
-
} catch (err) {
|
|
218
|
-
applyFetchProxyCors(res)
|
|
219
|
-
res.writeHead(502, { 'Content-Type': 'text/plain' })
|
|
220
|
-
res.end(`fetch proxy error: ${formatFetchProxyError(upstreamUrl.href, err)}`)
|
|
221
|
-
return
|
|
222
|
-
}
|
|
223
227
|
|
|
224
|
-
|
|
225
|
-
const
|
|
228
|
+
const status = proxyRes.statusCode ?? 502
|
|
229
|
+
const location = proxyRes.headers.location
|
|
226
230
|
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
location &&
|
|
232
|
+
(status === 301 ||
|
|
233
|
+
status === 302 ||
|
|
234
|
+
status === 303 ||
|
|
235
|
+
status === 307 ||
|
|
236
|
+
status === 308)
|
|
232
237
|
) {
|
|
238
|
+
if (redirects >= 10) {
|
|
239
|
+
proxyRes.destroy()
|
|
240
|
+
throw new Error('too many redirects')
|
|
241
|
+
}
|
|
242
|
+
const switchToGet =
|
|
243
|
+
((status === 301 || status === 302) && method === 'POST') ||
|
|
244
|
+
(status === 303 && method !== 'GET' && method !== 'HEAD')
|
|
245
|
+
const redirectUrl = new URL(location, targetUrl)
|
|
246
|
+
proxyRes.resume()
|
|
247
|
+
await finished(proxyRes)
|
|
248
|
+
await proxy(
|
|
249
|
+
redirectUrl,
|
|
250
|
+
switchToGet ? 'GET' : method,
|
|
251
|
+
switchToGet ? undefined : nextBody,
|
|
252
|
+
redirects + 1,
|
|
253
|
+
)
|
|
233
254
|
return
|
|
234
255
|
}
|
|
235
|
-
res.setHeader(key, value)
|
|
236
|
-
})
|
|
237
|
-
applyFetchProxyCors(res)
|
|
238
256
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
257
|
+
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
258
|
+
const lowerKey = key.toLowerCase()
|
|
259
|
+
if (
|
|
260
|
+
value === undefined ||
|
|
261
|
+
lowerKey === 'set-cookie' ||
|
|
262
|
+
lowerKey === 'connection' ||
|
|
263
|
+
lowerKey === 'keep-alive' ||
|
|
264
|
+
lowerKey === 'proxy-authenticate' ||
|
|
265
|
+
lowerKey === 'proxy-authorization' ||
|
|
266
|
+
lowerKey === 'te' ||
|
|
267
|
+
lowerKey === 'trailer' ||
|
|
268
|
+
lowerKey === 'transfer-encoding' ||
|
|
269
|
+
lowerKey === 'upgrade' ||
|
|
270
|
+
lowerKey.startsWith('access-control-')
|
|
271
|
+
) {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
res.setHeader(key, value)
|
|
275
|
+
}
|
|
276
|
+
applyFetchProxyCors(res)
|
|
277
|
+
const setCookie = proxyRes.headers['set-cookie'] ?? []
|
|
278
|
+
if (setCookie.length > 0) {
|
|
279
|
+
res.setHeader(
|
|
280
|
+
'x-sootsim-set-cookie',
|
|
281
|
+
(Array.isArray(setCookie) ? setCookie : [setCookie]).join(', '),
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
res.statusCode = status
|
|
285
|
+
await pipeline(proxyRes, res)
|
|
242
286
|
}
|
|
243
287
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
288
|
+
try {
|
|
289
|
+
await proxy(upstreamUrl, originalMethod, body, 0)
|
|
290
|
+
} catch (err) {
|
|
291
|
+
if (res.headersSent) {
|
|
292
|
+
res.destroy(err instanceof Error ? err : new Error(String(err)))
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
applyFetchProxyCors(res)
|
|
296
|
+
res.writeHead(502, { 'Content-Type': 'text/plain' })
|
|
297
|
+
res.end(`fetch proxy error: ${formatFetchProxyError(upstreamUrl.href, err)}`)
|
|
298
|
+
}
|
|
247
299
|
}
|
|
248
300
|
|
|
249
301
|
export function handleAppApiRequest(req: IncomingMessage, res: ServerResponse): boolean {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a,b,c,d,e}from"./chunk-R5I2OBQM.js";import"./chunk-UZRZGXQ4.js";import"./chunk-JOSDTQZ3.js";import"./chunk-VBO7OQLR.js";import"./chunk-KCS6OYQV.js";import"./chunk-ECPEYFHV.js";import"./chunk-CUDTQFGP.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-HJW6SASW.js";import"./chunk-FOTAUF7Q.js";import"./chunk-YIS2RXPE.js";import"./chunk-BKDHODNB.js";import"./chunk-CJRALJVV.js";import"./chunk-BWKVAEAJ.js";export{c as daemonInstall,b as getDaemonServiceStatus,a as runDaemon,d as teardownDaemonService,e as teardownSootsimHome};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import"./chunk-NO6RQXYN.js";import{f as a,g as b,h as c,i as d,j as e,k as f,l as g,m as h,n as i}from"./chunk-QHJLYAOH.js";import"./chunk-X7JZ4KTU.js";import"./chunk-ZL2KSYJP.js";import"./chunk-SLIYVKRX.js";import"./chunk-FOTAUF7Q.js";import"./chunk-BWKVAEAJ.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.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{c,d,e,f,g,h}from"./chunk-HE5NBBLH.js";import"./chunk-5VCOEPSJ.js";import"./chunk-DJIWF2SR.js";import{c as a,d as b}from"./chunk-NJQSCTFC.js";import"./chunk-P5JIE7R6.js";import"./chunk-D4YH5KNQ.js";import"./chunk-JPNTLGLA.js";import"./chunk-NDU5EJFW.js";import"./chunk-MDOTB5DP.js";import"./chunk-J7SEKMNI.js";import"./chunk-QHJLYAOH.js";import"./chunk-X7JZ4KTU.js";import"./chunk-SRMYUHBI.js";import"./chunk-6XF2EHL2.js";import"./chunk-ZL2KSYJP.js";import"./chunk-SBSL3DUQ.js";import"./chunk-XWPQVHOL.js";import"./chunk-QYVGMN3I.js";import"./chunk-544G2PCM.js";import"./chunk-WXYRA447.js";import"./chunk-UZRZGXQ4.js";import"./chunk-JOSDTQZ3.js";import"./chunk-ECPEYFHV.js";import"./chunk-CUDTQFGP.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-HJW6SASW.js";import"./chunk-FOTAUF7Q.js";import"./chunk-44WCYVFQ.js";import"./chunk-CJRALJVV.js";import"./chunk-BWKVAEAJ.js";export{e as discoverSootsimUrl,c as getLastFlowPreviewUploadResult,d as getLastFlowTraceSteps,g as hoistLeadingSimFlag,a as parseFlowFile,f as runFlowPlayback,h as runMaestroAuthoring,b as validateFlowFile};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a,b,c}from"./chunk-VBO7OQLR.js";import"./chunk-KCS6OYQV.js";import"./chunk-ECPEYFHV.js";import"./chunk-CUDTQFGP.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-HJW6SASW.js";import"./chunk-FOTAUF7Q.js";import"./chunk-YIS2RXPE.js";import"./chunk-BKDHODNB.js";import"./chunk-CJRALJVV.js";import"./chunk-BWKVAEAJ.js";export{c as printCommandHelp,b as printGroupHelp,a as printHelp};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{j as a,k as b}from"./chunk-NJQSCTFC.js";import"./chunk-P5JIE7R6.js";import"./chunk-NDU5EJFW.js";import"./chunk-MDOTB5DP.js";import"./chunk-J7SEKMNI.js";import"./chunk-QHJLYAOH.js";import"./chunk-X7JZ4KTU.js";import"./chunk-SRMYUHBI.js";import"./chunk-6XF2EHL2.js";import"./chunk-ZL2KSYJP.js";import"./chunk-SBSL3DUQ.js";import"./chunk-XWPQVHOL.js";import"./chunk-QYVGMN3I.js";import"./chunk-544G2PCM.js";import"./chunk-WXYRA447.js";import"./chunk-ECPEYFHV.js";import"./chunk-CUDTQFGP.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-HJW6SASW.js";import"./chunk-FOTAUF7Q.js";import"./chunk-44WCYVFQ.js";import"./chunk-CJRALJVV.js";import"./chunk-BWKVAEAJ.js";export{a as printShellPerfReport,b as runInspect};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{a}from"./chunk-SOZIIFPY.js";import"./chunk-PVIUYYIS.js";import"./chunk-544G2PCM.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-FOTAUF7Q.js";import"./chunk-BWKVAEAJ.js";export{a as runRuntime};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{b as le,c as H,d as de,e as F,f as ue,h as pe,i as C,j as me,k as he,l as fe,p as ge,s as v,t as Se,u as ye,v as ve,w as be}from"./chunk-JBUMYCFR.js";import"./chunk-VIM3WDAA.js";import{e as ce}from"./chunk-D4YH5KNQ.js";import"./chunk-JPNTLGLA.js";import{h as ae}from"./chunk-PVIUYYIS.js";import{f as P,g as se}from"./chunk-MDOTB5DP.js";import"./chunk-SRMYUHBI.js";import"./chunk-6XF2EHL2.js";import{d as oe}from"./chunk-ZL2KSYJP.js";import"./chunk-SBSL3DUQ.js";import"./chunk-544G2PCM.js";import{a as ee,b as te}from"./chunk-UZRZGXQ4.js";import"./chunk-JOSDTQZ3.js";import{a as re,b as ne}from"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import{E as J,G as E,H as K,I as V,J as D,L as G,M as q,O as z,Q as X,R as Y,S as Z,T as U,U as Q,y as M,z as j}from"./chunk-FOTAUF7Q.js";import{a as ie}from"./chunk-YIS2RXPE.js";import"./chunk-BWKVAEAJ.js";import{spawn as ut}from"child_process";import I from"fs";import{createServer as pt}from"http";import S from"path";import{WebSocket as h,WebSocketServer as mt}from"ws";import Ie from"node:fs";import R from"node:path";import{spawn as Me}from"node:child_process";import De from"node:fs";import Ue from"node:os";import He from"node:path";var we=/^[A-Za-z0-9._:-]{1,160}$/;function W(o){if(!o?.startsWith("AGENTBUS_SESSION:"))return null;let e=o.slice(17).trim();return we.test(e)?e:null}function Ae(o){return we.test(o)}function Fe(o){return typeof o.text=="string"?o.text.trim():""}function We(o){let e=o?.trim();if(e)return e;let t=process.env.AGENTBUS_COMMAND?.trim();if(t)return t;let i=He.join(Ue.homedir(),".local","bin","agentbus");return De.existsSync(i)?i:"agentbus"}async function ke(o){let e=o.sessionId.trim();if(!Ae(e))throw new Error(`invalid agentbus session id: ${e||"<empty>"}`);let t=Fe(o.prompt);if(!t)throw new Error("prompt text is empty");let i=We(o.command),s=o.timeoutMs??15e3;await new Promise((n,a)=>{let r=Me(i,["send",e,t],{stdio:["ignore","ignore","pipe"],env:process.env}),c="",d=setTimeout(()=>{try{r.kill("SIGTERM")}catch{}a(new Error(`agentbus send timed out after ${Math.round(s/1e3)}s`))},s);r.stderr?.setEncoding("utf8"),r.stderr?.on("data",l=>{c.length<4e3&&(c+=String(l))}),r.on("error",l=>{clearTimeout(d),a(l)}),r.on("exit",(l,u)=>{if(clearTimeout(d),l===0){n();return}let p=c.trim();a(new Error(p||`agentbus send exited with ${u?`signal ${u}`:`code ${l??"unknown"}`}`))})})}var x=1;function $e(){return[Number(process.env.VITE_PORT_WEB||process.env.PORT||3e3),Number(process.env.VITE_PORT_ZERO||7849),Number(process.env.VITE_PORT_R2||9500)].filter(o=>Number.isFinite(o)&&o>0)}var _=class{subscriptions=new Map;sessionsBySocket=new Map;allSockets=new Set;pendingPromptEchoes=new Map;pendingTurns=new Map;opts;constructor(e={}){this.opts=e}registerSocket(e){this.allSockets.add(e)}unregisterSocket(e){let t=this.sessionsBySocket.get(e);if(t){for(let i of t)this.decrementSubscription(i);this.sessionsBySocket.delete(e)}this.allSockets.delete(e)}async handleMessage(e,t){let i=t?.type;if(typeof i!="string"||!i.startsWith("agent:"))return!1;let s=t.id;try{let n=await this.dispatch(e,i,t);this.respond(e,s,n)}catch(n){n instanceof v?this.respondError(e,s,n.message,n.code):this.respondError(e,s,n instanceof Error?n.message:String(n))}return!0}async seedOnBoot(){try{await fe()}catch(e){process.stderr.write(`[sootsim-agent] seedFromDemoAppRegistry failed: ${e instanceof Error?e.message:String(e)}
|
|
3
|
-
`)}}close(){for(let e of this.subscriptions.values())try{e.unsubscribe()}catch{}this.subscriptions.clear(),this.sessionsBySocket.clear(),this.allSockets.clear()}async dispatch(e,t,i){switch(t){case"agent:list-projects":return F();case"agent:upsert-project":return H(i.input??{});case"agent:delete-project":return pe(String(i.projectId)),{ok:!0};case"agent:auto-attach-for-url":return this.autoAttachForUrl(i.input??{});case"agent:list-sessions":return me(i.projectId?String(i.projectId):void 0);case"agent:start-session":return this.doStartSession(i.input??{});case"agent:send-claimed-prompt":return this.sendClaimedPrompt(i);case"agent:send-prompt":{let n=String(i.sessionId),a=C(n);if(!a)throw new v("NO_SESSION",`no session: ${n}`);let r=this.normalizePromptEnvelope(i);return await ye(n,r),this.notePromptAccepted(n,r,a.status==="working")}case"agent:end-session":this.dropSessionFanout(String(i.sessionId)),await ve(String(i.sessionId));let s=C(String(i.sessionId));return s&&this.broadcastSessionStatus(s),{ok:!0};case"agent:get-transcript":return this.getTranscript(String(i.sessionId));case"agent:get-paths":return this.getPaths();case"agent:subscribe-events":return this.subscribeSocket(e,String(i.sessionId));case"agent:unsubscribe-events":return this.unsubscribeSocket(e,String(i.sessionId));default:throw new v("UNKNOWN_AGENT_MSG",`unknown agent message: ${t}`)}}async sendClaimedPrompt(e){let t=typeof e.simId=="string"?e.simId.trim():"";if(!t)throw new v("NO_SIM","agent:send-claimed-prompt requires simId");let i=this.opts.resolveCliLease?.(t)??null;if(!i||i.kind!=="cli"||i.expiresAt<=Date.now())throw new v("NO_CLAIM",`sim ${t} has no active CLI claim`);let s=W(i.cliIdentityKey);if(!s)throw new v("UNSUPPORTED_CLAIM",`sim ${t} is claimed by a CLI identity that is not promptable`);return await ke({sessionId:s,prompt:this.normalizePromptEnvelope(e)}),{ok:!0,routed:"agentbus",sessionId:s}}async doStartSession(e){if(!de(e.projectId))throw new v("NO_PROJECT",`no project: ${e.projectId}`);let i=await Se(e);return this.broadcastSessionStatus(i.session),i}async autoAttachForUrl(e){let t=e.bundleUrl??"",i=(()=>{try{return new URL(t).port||null}catch{return null}})();if(!i)return{project:null};let s=this.opts.getExcludePorts?.()??$e(),a=(await P({excludePorts:s})).find(l=>String(l.port)===i);if(!a||!a.cwd)return{project:null};let r=F().find(l=>l.cwd===a.cwd)??null,c=Array.from(new Set([...r?.knownBundleUrls??[],a.bundleUrl,t]));return{project:H({cwd:a.cwd,name:a.projectName??R.basename(a.cwd),preferredProvider:e.provider??r?.preferredProvider,sourceRoots:r?.sourceRoots??[a.cwd],knownBundleUrls:c,framework:r?.framework??je(a.framework),bundleId:a.bundleId??r?.bundleId})}}getTranscript(e){let t=ge(e);return Ie.existsSync(t)?Ie.readFileSync(t,"utf8"):{error:"transcript not found",code:"NO_TRANSCRIPT"}}getPaths(){let e=le();return{userDataDir:e,storeFile:R.join(e,"attached-projects.json"),sessionsDir:R.join(e,"sessions"),transcriptsDir:R.join(e,"transcripts")}}subscribeSocket(e,t){let i=this.sessionsBySocket.get(e);if(i||(i=new Set,this.sessionsBySocket.set(e,i)),i.has(t))return{ok:!0,refCount:this.subscriptions.get(t)?.refCount??1};i.add(t);let s=this.subscriptions.get(t);if(s)return s.refCount++,{ok:!0,refCount:s.refCount};let n=be(t,a=>{let r=this.coalescePromptEcho(t,a);if(r&&(this.applySessionEvent(t,r),this.fanOutEvent(t,r)),a.type==="turn-completed"){let c=C(t);if(c)try{ue(c.projectId,{usd:a.costUsd,ts:a.ts})}catch(d){process.stderr.write(`[sootsim-agent] recordTurnTelemetry failed: ${d instanceof Error?d.message:String(d)}
|
|
4
|
-
`)}}});return this.subscriptions.set(t,{unsubscribe:n,refCount:1}),{ok:!0,refCount:1}}unsubscribeSocket(e,t){let i=this.sessionsBySocket.get(e);return!i||!i.has(t)?{ok:!0,refCount:0}:(i.delete(t),this.decrementSubscription(t))}decrementSubscription(e){let t=this.subscriptions.get(e);if(!t)return{ok:!0,refCount:0};if(t.refCount--,t.refCount<=0){try{t.unsubscribe()}catch{}return this.subscriptions.delete(e),{ok:!0,refCount:0}}return{ok:!0,refCount:t.refCount}}dropSessionFanout(e){let t=this.subscriptions.get(e);if(t){try{t.unsubscribe()}catch{}this.subscriptions.delete(e)}for(let i of this.sessionsBySocket.values())i.delete(e);this.clearPromptTracking(e)}normalizePromptEnvelope(e){if(e?.prompt&&typeof e.prompt=="object"){let t=e.prompt;return{text:String(t.text??""),...typeof t.displayText=="string"?{displayText:t.displayText}:{},...typeof t.inspectSummary=="string"?{inspectSummary:t.inspectSummary}:{},...typeof t.inspectTrace=="string"?{inspectTrace:t.inspectTrace}:{}}}return{text:String(e?.text??""),...typeof e?.displayText=="string"?{displayText:e.displayText}:{},...typeof e?.inspectSummary=="string"?{inspectSummary:e.inspectSummary}:{},...typeof e?.inspectTrace=="string"?{inspectTrace:e.inspectTrace}:{}}}notePromptAccepted(e,t,i){let s=Date.now(),n=this.pendingPromptEchoes.get(e)??[];n.push({sentAt:s}),this.pendingPromptEchoes.set(e,n);let a=Math.max(this.pendingTurns.get(e)??0,i?1:0)+1;this.pendingTurns.set(e,a);let r=t.displayText??t.text;return this.patchSession(e,{lastPrompt:r,status:"working",needsAttention:!1}),this.fanOutEvent(e,{type:"prompt-received",text:r,...t.inspectSummary?{inspectSummary:t.inspectSummary}:{},...t.inspectTrace?{inspectTrace:t.inspectTrace}:{},ts:s}),{ok:!0,queued:a>1,pendingTurns:a,queueDepth:Math.max(0,a-1)}}applySessionEvent(e,t){switch(t.type){case"prompt-received":case"turn-started":this.patchSession(e,{status:"working",needsAttention:!1});return;case"turn-completed":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"idle",needsAttention:!1,lastTurnFiles:t.filesTouched,currentlyEditing:void 0});return}case"approval-needed":this.patchSession(e,{status:"needs-attention",needsAttention:!0});return;case"error":{let i=this.consumeSettledTurn(e);this.patchSession(e,{status:i>0?"working":"needs-attention",needsAttention:i<=0,currentlyEditing:void 0});return}case"exited":this.clearPromptTracking(e),this.patchSession(e,{status:"ended",needsAttention:!1,wrapperPid:void 0,currentlyEditing:void 0});return;case"ready":case"turn-reasoning":case"turn-message":case"turn-plan":case"tool-call":case"file-edited":case"file-diff-delta":return}}patchSession(e,t){he(e,t);let i=C(e);i&&this.broadcastSessionStatus(i)}coalescePromptEcho(e,t){if(t.type!=="prompt-received")return t;let i=this.pendingPromptEchoes.get(e);if(!i||i.length===0)return t;for(;i.length>0&&Date.now()-i[0].sentAt>15e3;)i.shift();return i.length===0?(this.pendingPromptEchoes.delete(e),t):(i.shift(),i.length===0?this.pendingPromptEchoes.delete(e):this.pendingPromptEchoes.set(e,i),null)}consumeSettledTurn(e){let t=Math.max(0,(this.pendingTurns.get(e)??1)-1);return t>0?this.pendingTurns.set(e,t):this.pendingTurns.delete(e),t}clearPromptTracking(e){this.pendingPromptEchoes.delete(e),this.pendingTurns.delete(e)}fanOutEvent(e,t){let i=JSON.stringify({type:"agent:event",sessionId:e,event:t});for(let[s,n]of this.sessionsBySocket)if(n.has(e)&&s.readyState===x)try{s.send(i)}catch{}}broadcastSessionStatus(e){let t=JSON.stringify({type:"agent:session-status",session:e});for(let i of this.allSockets)if(i.readyState===x)try{i.send(t)}catch{}}respond(e,t,i){if(e.readyState===x)try{e.send(JSON.stringify({id:t,result:i}))}catch{}}respondError(e,t,i,s){if(e.readyState===x)try{e.send(JSON.stringify({id:t,error:i,...s?{code:s}:{}}))}catch{}}};function je(o){return o==="expo"?"expo":o==="one"||o==="vxrn"?"one":"unknown"}import Ve from"http";import Ge from"https";var $="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",Je=[{hostSuffix:"uniswap.org",headers:{origin:"https://app.uniswap.org",referer:"https://app.uniswap.org/"},suppressBrowserUserAgent:!0}];function Ke(o){let e=o.toLowerCase();for(let t of Je)if(e===t.hostSuffix||e.endsWith(`.${t.hostSuffix}`))return t}function Ce(o){let e=Ke(o.hostname);return{"accept-encoding":"identity",...e?.suppressBrowserUserAgent?{}:{"user-agent":$},...e?.headers}}var qe=new Set(["host","origin","referer","user-agent","accept-encoding","cookie","connection","keep-alive","transfer-encoding","upgrade","content-length","sec-fetch-site","sec-fetch-mode","sec-fetch-dest","sec-ch-ua","sec-ch-ua-mobile","sec-ch-ua-platform"]),ze={"access-control-allow-origin":"*","access-control-allow-methods":"GET,POST,PUT,DELETE,PATCH,OPTIONS","access-control-allow-headers":"*","access-control-expose-headers":"*","access-control-max-age":"3600"},Xe=new Set(["host","origin","referer","sec-fetch-site","sec-fetch-mode","sec-fetch-dest"]);function T(o){for(let[e,t]of Object.entries(ze))o.setHeader(e,t)}function Ye(o,e){let t=[],i=e;i?.code&&t.push(i.code),i?.message&&t.push(i.message),i?.cause?.code&&t.push(i.cause.code),i?.cause?.message&&t.push(i.cause.message);let n=[...new Set(t.filter(Boolean))].join(" | ")||String(e);return o.includes("stored-in-.env.local")?`${n} | upstream url still contains placeholder env values`:n}function Ze(o){let t=(Array.isArray(o)?o[0]:o)?.split(";",1)[0]?.trim().toLowerCase();return t?t.startsWith("text/")||t==="application/json"||t.endsWith("+json")||t==="application/x-www-form-urlencoded"||t==="application/xml"||t.endsWith("+xml")||t==="application/javascript"||t==="application/graphql":!1}function Qe(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(qe.has(i.toLowerCase())||(t[i]=Array.isArray(s)?s.join(", "):s));return Object.assign(t,e?Ce(e):{"user-agent":$}),t}function et(o,e){let t={};for(let[i,s]of Object.entries(o))s&&(Xe.has(i.toLowerCase())||(t[i]=s));return t.host=e.host,t.origin=e.origin,t.referer=`${e.origin}/`,t}function Te(o){return o?.startsWith("/__fetch-proxy?")||o?.startsWith("/__proxy?")||!1}function Ee(o){return o?!!(o.startsWith("/__app-api?")||o.startsWith("/__app-api/")):!1}async function Pe(o,e){if(o.method==="OPTIONS"){T(e),e.writeHead(204),e.end();return}let i=new URLSearchParams((o.url||"").split("?")[1]||"").get("url");if(!i){T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("missing url param");return}let s;try{s=new URL(i)}catch{T(e),e.writeHead(400,{"Content-Type":"text/plain"}),e.end("invalid url param");return}let n=Qe(o.headers,s),a;if(o.method!=="GET"&&o.method!=="HEAD"){let l=[];for await(let u of o)l.push(Buffer.isBuffer(u)?u:Buffer.from(u));if(l.length>0){let u=Buffer.concat(l);a=Ze(o.headers["content-type"])?u.toString("utf8"):u}}let r;try{r=await fetch(s.href,{method:o.method,headers:n,body:a,redirect:"follow"})}catch(l){T(e),e.writeHead(502,{"Content-Type":"text/plain"}),e.end(`fetch proxy error: ${Ye(s.href,l)}`);return}r.headers.forEach((l,u)=>{let p=u.toLowerCase();p==="content-encoding"||p==="transfer-encoding"||p==="content-length"||p==="set-cookie"||p.startsWith("access-control-")||e.setHeader(u,l)}),T(e);let c=r.headers.getSetCookie?.()??[];c.length>0&&e.setHeader("x-sootsim-set-cookie",c.join(", ")),e.statusCode=r.status;let d=Buffer.from(await r.arrayBuffer());e.end(d)}function Re(o,e){let t=o.url||"",i="",s="";if(t.startsWith("/__app-api?")){let d=new URL(t,"http://sootsim.local");i=d.searchParams.get("path")||"",s=d.searchParams.get("origin")?.trim()||""}else if(t.startsWith("/__app-api/"))i=t.slice(10);else return!1;if(!s)return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: missing origin query param"),!0;if(o.method==="OPTIONS")return e.writeHead(204,{"Access-Control-Allow-Origin":o.headers.origin||"*","Access-Control-Allow-Methods":"GET,POST,PUT,PATCH,DELETE,OPTIONS","Access-Control-Allow-Headers":o.headers["access-control-request-headers"]||"*","Access-Control-Allow-Credentials":"true","Access-Control-Max-Age":"86400"}),e.end(),!0;let n;try{n=new URL(i,s)}catch{return e.writeHead(400,{"Content-Type":"text/plain"}),e.end("app-api: invalid origin or path"),!0}let a=n.protocol==="https:"?Ge:Ve,r=et(o.headers,n),c=a.request({hostname:n.hostname,port:n.port||(n.protocol==="https:"?443:80),path:n.pathname+n.search,method:o.method,headers:r},d=>{let l=Object.keys(d.headers).filter(u=>{let p=u.toLowerCase();return!p.startsWith("access-control-")&&p!=="set-cookie"}).join(", ");e.writeHead(d.statusCode??502,{...d.headers,"access-control-allow-origin":o.headers.origin||"*","access-control-allow-credentials":"true","access-control-expose-headers":l}),d.pipe(e)});return c.on("error",d=>{e.statusCode=502,e.end(`app proxy error: ${d.message}`)}),o.pipe(c),!0}import{WebSocket as b,WebSocketServer as tt}from"ws";var it="/__websocket-proxy",rt=new Set(["host","connection","upgrade","transfer-encoding","content-length","sec-websocket-accept","sec-websocket-extensions","sec-websocket-key","sec-websocket-protocol","sec-websocket-version"]);function k(o,e,t){try{o.write(`HTTP/1.1 ${e} ${t}\r
|
|
5
|
-
Connection: close\r
|
|
6
|
-
Content-Type: text/plain\r
|
|
7
|
-
Content-Length: ${t.length}\r
|
|
8
|
-
\r
|
|
9
|
-
${t}`)}catch{}o.destroy()}function nt(o){let e=o.headers.origin,t=o.headers.host;if(!e||!t)return!1;try{return new URL(e).host===t}catch{return!1}}function st(o){if(!o)return{};let e=o.replace(/-/g,"+").replace(/_/g,"/"),t=e+"=".repeat((4-e.length%4)%4),i=JSON.parse(Buffer.from(t,"base64").toString("utf8"));if(!i||typeof i!="object"||Array.isArray(i))return{};let s={};for(let[n,a]of Object.entries(i))a!=null&&(rt.has(n.toLowerCase())||(s[n]=Array.isArray(a)?a.join(", "):String(a)));return s}function ot(o){let e=new URL(o.href);return e.protocol=o.protocol==="wss:"?"https:":"http:",e.origin}function at(o){let e=o.headers["sec-websocket-protocol"];return(Array.isArray(e)?e.join(","):e||"").split(",").map(i=>i.trim()).filter(Boolean)}function O(o,e,t){if(!(o.readyState===b.CLOSED||o.readyState===b.CLOSING))try{o.close(e,t)}catch{o.terminate()}}function ct(o,e){let t=!1,i=(s,n,a,r)=>{t||(t=!0,O(n,a,r.toString()),s.readyState===b.OPEN&&O(s,a,r.toString()))};o.on("message",(s,n)=>{e.readyState===b.OPEN&&e.send(s,{binary:n})}),e.on("message",(s,n)=>{o.readyState===b.OPEN&&o.send(s,{binary:n})}),o.on("close",(s,n)=>i(o,e,s,n)),e.on("close",(s,n)=>i(e,o,s,n)),o.on("error",()=>O(e,1011,"proxy client error")),e.on("error",()=>O(o,1011,"upstream websocket error"))}function lt(o,e,t,i){let s={...t},n=Object.keys(s).filter(a=>a.toLowerCase()==="origin");if(i&&n.length===0)s.origin=ot(o);else if(!i)for(let a of n)delete s[a];return Object.keys(s).length===0?new b(o.href,e):new b(o.href,e,{headers:s})}function dt(o){if(!o)return!1;try{return new URL(o,"http://localhost").pathname===it}catch{return!1}}function xe(o,e,t,i=!0){if(!dt(o.url))return!1;if(!nt(o))return k(e,403,"forbidden websocket proxy origin"),!0;let s,n;try{let d=new URL(o.url||"/","http://localhost"),l=d.searchParams.get("url");if(!l)return k(e,400,"missing websocket proxy url"),!0;if(s=new URL(l),s.protocol!=="ws:"&&s.protocol!=="wss:")return k(e,400,"invalid websocket proxy protocol"),!0;n=st(d.searchParams.get("headers"))}catch{return k(e,400,"invalid websocket proxy request"),!0}let a=at(o),r=lt(s,a,n,i),c=!1;return e.once("close",()=>{c||r.terminate()}),r.once("open",()=>{if(c)return;c=!0;let d=r.protocol;new tt({noServer:!0,clientTracking:!1,handleProtocols(u){return d||u.values().next().value||!1}}).handleUpgrade(o,e,t,u=>{ct(u,r)})}),r.once("error",()=>{c||(c=!0,k(e,502,"upstream websocket error"))}),r.once("close",()=>{c||(c=!0,k(e,502,"upstream websocket closed"))}),!0}var ht="require-corp",ft=new Set(["tap","keyboard"]),gt=2e3,St=1e3;function yt(o){return!o||typeof o.type!="string"?!1:o.acquireLock===!0?!0:o.readOnly===!0?!1:ft.has(o.type)}var _e=5e3,vt=3600*1e3,bt="SOOTSIM_RUNTIME_UPDATE_INTERVAL_MS",wt={".html":"text/html; charset=utf-8",".js":"application/javascript",".cjs":"application/javascript",".mjs":"application/javascript",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".wasm":"application/wasm",".ttf":"font/ttf",".otf":"font/otf",".woff":"font/woff",".woff2":"font/woff2",".map":"application/json",".txt":"text/plain; charset=utf-8"};function Oe(o,e,t){let i;try{let c=M();i=JSON.stringify(c)}catch{i="{}"}let s=e>0?`window.__sootsimBridgePort=${e};`:"",n=t?`window.__sootsimContrastOrigin=${JSON.stringify(t)};`:"",a=`<script>window.__sootsimSharedConfig=${i};`+s+n+`window.__sootsimCliVersion=${JSON.stringify(ie())};</script>`,r=o.toString("utf8");return r.includes("<head>")?r.replace("<head>",`<head>${a}`):r.includes("</head>")?r.replace("</head>",a+"</head>"):r.includes("</body>")?r.replace("</body>",a+"</body>"):a+r}function Le(o){typeof o=="object"&&o!==null&&"unref"in o&&o.unref()}var L=class o{port;openUrlHandler;httpServer=null;wss=null;nextCommandId=1;nextSimNumber=161;sims=new Map;primarySimId=null;pendingCommands=new Map;cliBySentId=new Map;cliSimBySocket=new Map;cliLastCommandAt=new Map;cliIdentityKeyBySocket=new Map;cliLabelBySocket=new Map;restorableSims=new Map;nextCliFallbackId=1;cliIdleTimer=null;agentHost;static CLI_IDLE_TIMEOUT_MS=6e4;static CLI_LEASE_TTL_MS=6e5;static USER_ACTIVE_LEASE_TTL_MS=8e3;static USER_BOOT_LEASE_TTL_MS=6e4;static SIM_RECONNECT_TTL_MS=3e4;static SIM_IDLE_REAP_TTL_MS=30*6e4;static AUTOMATION_SIM_IDLE_REAP_TTL_MS=10*6e4;static MAX_CONCURRENT_AUTOMATION_SIMS=6;static AUTOMATION_SIM_ACTIVE_GRACE_MS=6e4;preferredPort;portFallbackCount;simIdleReapTtlMs;automationSimIdleReapTtlMs;maxConcurrentAutomationSims;automationSimActiveGraceMs;shouldWriteLockfile;shouldWriteDevLockfile;getShellPort;contrastOrigin=null;effectivePort=0;startedAt=0;heartbeatTimer=null;devHeartbeatTimer=null;wsHeartbeatTimer=null;wsIsAlive=new WeakMap;static WS_HEARTBEAT_INTERVAL_MS=3e4;runtimeUpdateTimer=null;runtimeUpdateInFlight=null;activeRuntimeVersion=null;activeRuntimeDirPath=null;scanCache=null;scanCacheAt=0;inflightScan=null;static SCAN_FRESH_MS=2e3;constructor(e={}){this.preferredPort=e.port||7668,this.port=this.preferredPort,this.shouldWriteLockfile=e.writeLockfile===!0,this.shouldWriteDevLockfile=e.writeDevLockfile===!0,this.getShellPort=e.getShellPort??null,this.portFallbackCount=Math.max(1,e.portFallbackCount??10),this.openUrlHandler=e.openUrl,this.agentHost=new _({getExcludePorts:e.agentScanExcludes,resolveCliLease:t=>{let i=this.sims.get(t),s=i?this.getActiveLease(i):null;return s?{kind:s.kind,cliIdentityKey:s.cliIdentityKey,expiresAt:s.expiresAt}:null}}),this.contrastOrigin=e.contrastOrigin?.replace(/\/$/,"")||null,this.simIdleReapTtlMs=e.simIdleReapTtlMs??o.SIM_IDLE_REAP_TTL_MS,this.automationSimIdleReapTtlMs=e.automationSimIdleReapTtlMs??o.AUTOMATION_SIM_IDLE_REAP_TTL_MS,this.maxConcurrentAutomationSims=e.maxConcurrentAutomationSims??o.MAX_CONCURRENT_AUTOMATION_SIMS,this.automationSimActiveGraceMs=e.automationSimActiveGraceMs??o.AUTOMATION_SIM_ACTIVE_GRACE_MS}getAgentHost(){return this.agentHost}reapIdleSimsForTest(e=Date.now()){this.reapIdleSims(e)}start(e){this.startAsync(e)}async startAsync(e){if(this.httpServer||this.wss)return this.effectivePort;this.refreshActiveRuntime();for(let t=0;t<this.portFallbackCount;t++){let i=this.preferredPort+t;try{return await this.bindOnce(i,e?.silent===!0),this.effectivePort=i,this.port=i,this.startedAt=Date.now(),t>0&&!e?.silent&&process.stderr.write(`ws bridge bound to port ${i} (preferred ${this.preferredPort} was taken)
|
|
10
|
-
`),this.afterBind(),i}catch(s){if(s?.code!=="EADDRINUSE")throw s;e?.silent||process.stderr.write(`ws bridge port ${i} already in use, trying ${i+1}
|
|
11
|
-
`)}}throw new Error(`could not bind ws bridge after ${this.portFallbackCount} attempts starting at ${this.preferredPort}`)}bindOnce(e,t){return new Promise((i,s)=>{let n=pt((c,d)=>this.handleHttpRequest(c,d)),a=!1,r=c=>{if(!a){a=!0;try{n.close()}catch{}this.httpServer=null,this.wss=null,s(c)}};n.once("error",r),n.listen(e,"127.0.0.1",()=>{a||(a=!0,n.removeListener("error",r),n.on("error",c=>{process.stderr.write(`ws bridge http error: ${String(c)}
|
|
12
|
-
`)}),this.httpServer=n,this.wss=new mt({noServer:!0}),this.wireWebSocketServer(),n.on("upgrade",(c,d,l)=>{xe(c,d,l)||this.wss?.handleUpgrade(c,d,l,u=>{this.wss?.emit("connection",u,c)})}),i())})})}wireWebSocketServer(){this.wss&&this.wss.on("connection",(e,t)=>{let i=t.headers.origin,s=i?"sim":"cli",n=null;if(e.on("error",()=>{}),this.wsIsAlive.set(e,!0),e.on("pong",()=>{this.wsIsAlive.set(e,!0)}),this.agentHost.registerSocket(e),s==="sim")n={id:this.allocateSimId(),ws:e,origin:i,connectedAt:Date.now(),lastSeenAt:Date.now(),lastActiveAt:0,recentActions:[]},this.sims.set(n.id,n),this.shouldPromoteSim(n)&&(this.primarySimId=n.id),this.broadcastSimAssignments(),this.broadcastSimClientStates();else{let a=`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,a)}e.on("message",a=>{let r;try{r=JSON.parse(a.toString())}catch{return}if(!(!r||typeof r!="object")){if(typeof r.type=="string"&&r.type.startsWith("agent:")){this.agentHost.handleMessage(e,r);return}if(r.type==="runtime:list"){let c=D(),d=this.getActiveRuntime(),l={type:"runtime:list:ok",id:r.id,installed:c,active:d.version,activeRuntimeDir:d.runtimeDir};try{e.send(JSON.stringify(l))}catch{}return}if(r.type==="runtime:use"){let c=typeof r.version=="string"?r.version:"";if(!D().includes(c)){try{e.send(JSON.stringify({type:"runtime:use:error",id:r.id,error:`runtime ${c||"(missing)"} is not installed`}))}catch{}return}let l=this.setActiveRuntime(c);try{e.send(JSON.stringify({type:"runtime:use:ok",id:r.id,version:l.version,runtimeDir:l.runtimeDir}))}catch{}return}if(r.type==="runtime:get"){let c=this.getActiveRuntime();try{e.send(JSON.stringify({type:"runtime:get:ok",id:r.id,active:c.version,activeRuntimeDir:c.runtimeDir}))}catch{}return}if(s==="sim"&&r.type==="bridge:hello"&&n&&!n.url){let c=n.id;this.sims.delete(c),this.primarySimId===c&&(this.primarySimId=this.getOpenSim()?.id??null),n=null,s="cli",this.cliIdentityKeyBySocket.set(e,`ws-${this.nextCliFallbackId++}`),this.broadcastSimAssignments(),this.broadcastSimClientStates()}if(s==="sim"){if(n&&(n.lastSeenAt=Date.now()),r.type==="bridge:register"&&n){let l=r,u=this.tryRestoreSimId(n,l.simId);n.url=l.url,n.title=l.title,n.userAgent=l.userAgent,typeof l.kind=="string"&&l.kind.trim()&&(n.kind=l.kind.trim()),l.meta&&typeof l.meta=="object"&&(n.meta=l.meta);let p=this.primarySimId!==n.id&&this.shouldPromoteSim(n);p&&(this.primarySimId=n.id),(u||p)&&(this.broadcastSimAssignments(),this.broadcastSimClientStates());return}if(r.type==="bridge:user-focus-state"&&n){let l=r;this.updateUserFocusLease(n,l);return}if(r.type==="bridge:user-interact"&&n){this.updateUserActivity(n);return}if(r.type==="bridge:write-shared-config"){let l=r.patch&&typeof r.patch=="object"?r.patch:null;if(!l)return;let u;try{u=j(l)}catch(m){process.stderr.write(`sootsim: bridge:write-shared-config failed: ${m instanceof Error?m.message:String(m)}
|
|
13
|
-
`);return}let p=JSON.stringify({type:"bridge:shared-config-changed",config:u});for(let m of this.sims.values())if(m.ws.readyState===h.OPEN)try{m.ws.send(p)}catch{}return}if(r.type==="bridge:open-path"){let l=typeof r.path=="string"?r.path:"",u=typeof r.line=="number"&&Number.isFinite(r.line)?r.line:void 0,p=typeof r.column=="number"&&Number.isFinite(r.column)?r.column:void 0;l&&this.openPathInEditor(l,u,p);return}if(r.type==="bridge:boot-clients"&&n){let l=[];for(let[p,m]of this.cliSimBySocket)m===n.id&&l.push(p);for(let p of l){this.cliSimBySocket.delete(p);try{p.close(1e3,"booted by sim")}catch{}}let u=!!n.cliLease;n.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:Date.now()+o.USER_BOOT_LEASE_TTL_MS},process.stderr.write(`sootsim booted ${l.length} cli client(s)${u?" (overrode prior lease)":""}; held sim for user [${n.id}]
|
|
14
|
-
`),this.recordSimAction(n.id,"sim booted cli clients"),this.broadcastSimClientStates();return}let c=this.pendingCommands.get(r.id);if(c){this.pendingCommands.delete(r.id),r.error?c.reject(new Error(r.error)):c.resolve(r.result);return}let d=this.cliBySentId.get(r.id);if(d&&(this.cliBySentId.delete(r.id),d.ws.readyState===h.OPEN)){let l=this.getOtherCliIdentityCount(d.ws,d.simId),u=l>0?{...r,id:d.originalId,_otherCliCount:l}:{...r,id:d.originalId};d.ws.send(JSON.stringify(u))}return}(async()=>{this.cliLastCommandAt.set(e,Date.now());try{if(r.type==="bridge:bye"){let p=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[m,f]of this.cliBySentId)f.ws===e&&this.cliBySentId.delete(m);p&&this.broadcastSimClientStates();return}if(r.type==="bridge:hello"){let p=typeof r.cliIdentityKey=="string"&&r.cliIdentityKey.trim()?r.cliIdentityKey.trim():this.cliIdentityKeyBySocket.get(e)||`ws-${this.nextCliFallbackId++}`;this.cliIdentityKeyBySocket.set(e,p),typeof r.cliLabel=="string"&&r.cliLabel.trim()&&this.cliLabelBySocket.set(e,r.cliLabel.trim()),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{cliIdentityKey:p,leaseTtlMs:o.CLI_LEASE_TTL_MS,leasing:!0}}));return}if(r.type==="bridge:list-sims"){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:this.listSims()}));return}if(r.type==="bridge:open"){if(typeof r.url!="string"||!r.url)throw new Error("bridge:open requires a url");await this.openUrl(r.url,{newWindow:r.newWindow===!0}),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{ok:!0,url:r.url}}));return}if(r.type==="bridge:claim"){let p=await this.waitForSim(r.simId),m=this.tryAcquireLease(e,p,{force:r.force===!0});if(!m.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${p.id} is locked by another cli`,_locked:m.lock}));return}this.setCliSimTarget(e,p.id),this.recordSimAction(p.id,m.bootedCount>0?`cli force-claimed sim (booted ${m.bootedCount})`:"cli claimed sim"),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{simId:p.id,lockedBy:m.lease.cliIdentityKey,lockExpiresAt:m.lease.expiresAt,bootedCount:m.bootedCount}}));return}let c=await this.waitForSim(r.simId);if(yt(r)){let p=this.tryAcquireLease(e,c);if(!p.granted){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:`sim ${c.id} is locked by another cli \u2014 use \`sootsim claim ${c.id} --force\` or \`sootsim open --new\``,_locked:p.lock}));return}}else this.ensureCliIdentityKey(e);this.setCliSimTarget(e,c.id),this.recordSimAction(c.id,this.describeForwardedCommand(r));let d=this.nextCommandId++;this.cliBySentId.set(d,{simId:c.id,ws:e,originalId:r.id});let{simId:l,...u}=r;if(c.ws.send(JSON.stringify({...u,id:d})),u.type==="close"){this.cliBySentId.delete(d),e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,result:{requested:!0,simId:c.id}}));let p=c.ws,m=setTimeout(()=>{this.closeSimSocketFromHost(p)},gt);Le(m)}}catch(c){e.readyState===h.OPEN&&e.send(JSON.stringify({id:r.id,error:c instanceof Error?c.message:String(c)}))}})()}}),e.on("close",()=>{if(this.agentHost.unregisterSocket(e),s==="sim"&&n){this.rememberDisconnectedSim(n),this.primarySimId===n.id&&(this.primarySimId=this.getOpenSim()?.id??null);for(let[a,r]of this.pendingCommands)r.simId===n.id&&(r.reject(new Error("sim disconnected")),this.pendingCommands.delete(a));for(let[a,r]of this.cliBySentId)r.simId===n.id&&(r.ws.readyState===h.OPEN&&r.ws.send(JSON.stringify({id:r.originalId,error:"sim disconnected before responding"})),this.cliBySentId.delete(a));this.broadcastSimAssignments(),this.broadcastSimClientStates()}else if(s==="cli"){let a=this.cliSimBySocket.delete(e);this.cliLastCommandAt.delete(e),this.cliIdentityKeyBySocket.delete(e),this.cliLabelBySocket.delete(e);for(let[r,c]of this.cliBySentId)c.ws===e&&this.cliBySentId.delete(r);a&&this.broadcastSimClientStates()}})})}afterBind(){if(process.stderr.write(`ws bridge listening on port ${this.port}
|
|
15
|
-
`),this.cliIdleTimer=setInterval(()=>this.sweepIdleCliClients(),3e4),this.cliIdleTimer.unref(),this.wsHeartbeatTimer=setInterval(()=>this.sweepDeadWebSockets(),o.WS_HEARTBEAT_INTERVAL_MS),this.wsHeartbeatTimer.unref(),this.shouldWriteLockfile){try{if(E(),!Z(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)}
|
|
16
|
-
`),e}this.heartbeatTimer=setInterval(()=>{try{this.writeLockfileSnapshot()}catch{}},_e),this.heartbeatTimer.unref(),this.startRuntimeUpdater()}if(this.shouldWriteDevLockfile){try{this.writeDevLockfileSnapshot()}catch(e){process.stderr.write(`ws bridge failed to write dev bridge lockfile: ${String(e)}
|
|
17
|
-
`)}this.devHeartbeatTimer=setInterval(()=>{try{this.writeDevLockfileSnapshot()}catch{}},_e),this.devHeartbeatTimer.unref()}this.agentHost.seedOnBoot()}bootstrapping=!0;buildLockfileSnapshot(){return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,activeRuntimeDir:this.activeRuntimeDirPath,startedAt:this.startedAt,heartbeatAt:Date.now(),bootstrapping:this.bootstrapping}}buildDevLockfileSnapshot(){let e=this.getShellPort?.()??null;return{schema:1,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,...e&&e>0?{shellPort:e}:{},cwd:process.cwd(),startedAt:this.startedAt,heartbeatAt:Date.now(),source:"vite-dev"}}writeLockfileSnapshot(){X(this.buildLockfileSnapshot())}writeDevLockfileSnapshot(){Y(this.buildDevLockfileSnapshot())}refreshActiveRuntime(){this.activeRuntimeVersion=K(),this.activeRuntimeDirPath=se()??G()}runServerScan(){if(this.inflightScan)return this.inflightScan;let e=this.effectivePort>0?[this.effectivePort]:[];return this.inflightScan=P({excludePorts:e,buildIconProxyUrl:t=>`/__bundle-proxy?url=${encodeURIComponent(t)}`}).then(t=>(this.scanCache=t,this.scanCacheAt=Date.now(),t)).catch(t=>{let i=t instanceof Error?t.message:String(t);return console.error("[sootsim] /__server-scan failed:",i),this.scanCache??[]}).finally(()=>{this.inflightScan=null}),this.inflightScan}handleServerScan(e){let t=s=>{e.writeHead(200,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(s))},i=Date.now()-this.scanCacheAt;if(this.scanCache&&i<o.SCAN_FRESH_MS){t(this.scanCache);return}if(this.scanCache){t(this.scanCache),this.runServerScan().catch(()=>{});return}this.runServerScan().then(s=>t(s))}resolveRuntimeUpdateIntervalMs(){let e=Number(process.env[bt]);return Number.isFinite(e)&&e>0?Math.max(100,Math.round(e)):vt}startRuntimeUpdater(){if(!this.shouldWriteLockfile||this.runtimeUpdateTimer)return;this.runRuntimeUpdate("startup");let e=this.resolveRuntimeUpdateIntervalMs();this.runtimeUpdateTimer=setInterval(()=>{this.runRuntimeUpdate("periodic")},e),this.runtimeUpdateTimer.unref()}runRuntimeUpdate(e){return this.runtimeUpdateInFlight?this.runtimeUpdateInFlight:(this.runtimeUpdateInFlight=(async()=>{try{e==="startup"&&process.stderr.write(`sootsim: checking for runtime updates\u2026
|
|
18
|
-
`);let t=await ae();if(!t.updated||!t.latestVersion){e==="startup"&&process.stderr.write(`sootsim: runtime ${this.activeRuntimeVersion??"(none)"} is current
|
|
19
|
-
`);return}let i=this.activeRuntimeVersion,s=this.setActiveRuntime(t.latestVersion);process.stderr.write(`sootsim runtime updated to ${s.version} (${e})
|
|
20
|
-
`);try{J({from:i,to:s.version,at:Date.now()})}catch{}}catch(t){process.stderr.write(`sootsim runtime update failed (${e}): ${t instanceof Error?t.message:String(t)}
|
|
21
|
-
`)}finally{if(this.runtimeUpdateInFlight=null,e==="startup"&&this.bootstrapping){if(this.bootstrapping=!1,this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}process.stderr.write(`sootsim: ready
|
|
22
|
-
`)}}})(),this.runtimeUpdateInFlight)}setActiveRuntime(e){if(V(e),this.refreshActiveRuntime(),this.shouldWriteLockfile&&this.httpServer)try{this.writeLockfileSnapshot()}catch{}let t=JSON.stringify({type:"runtime:changed",version:e,runtimeDir:this.activeRuntimeDirPath});for(let i of this.sims.values())if(i.ws.readyState===h.OPEN)try{i.ws.send(t)}catch{}return{version:e,runtimeDir:this.activeRuntimeDirPath}}getActiveRuntime(){return{version:this.activeRuntimeVersion,runtimeDir:this.activeRuntimeDirPath}}removeLockfile(){if(this.shouldWriteLockfile)try{U()}catch{}}handleHttpRequest(e,t){if(t.setHeader("Cross-Origin-Opener-Policy","same-origin"),t.setHeader("Cross-Origin-Embedder-Policy",ht),t.setHeader("Cross-Origin-Resource-Policy","cross-origin"),t.setHeader("Document-Policy","js-profiling"),Te(e.url)){Pe(e,t);return}if(Ee(e.url)&&Re(e,t))return;let i=(e.method||"GET").toUpperCase();if(i!=="GET"&&i!=="HEAD"){t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed");return}let s=new URL(e.url||"/","http://localhost");if(s.pathname==="/__bundle-proxy"){let d=s.searchParams.get("url");if(!d){t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: missing url query param");return}let l;try{l=new URL(d)}catch{t.writeHead(400,{"Content-Type":"text/plain"}),t.end("bundle-proxy: invalid url");return}let u=l.hostname;if(!(u==="localhost"||u==="127.0.0.1"||u==="::1"||u.endsWith(".localhost"))){t.writeHead(403,{"Content-Type":"text/plain"}),t.end("bundle-proxy: only loopback targets allowed");return}(async()=>{try{let m=await fetch(l.toString(),{redirect:"follow"}),f={},y=m.headers.get("content-type");if(y&&(f["Content-Type"]=y),f["Cache-Control"]="no-store",t.writeHead(m.status,f),!m.body){t.end();return}let g=m.body.getReader();for(;;){let{done:w,value:A}=await g.read();if(w)break;t.write(Buffer.from(A))}t.end()}catch(m){t.writeHead(502,{"Content-Type":"text/plain"}),t.end(`bundle-proxy: upstream fetch failed: ${m instanceof Error?m.message:String(m)}`)}})();return}if(s.pathname==="/__server-scan"){this.handleServerScan(t);return}if(s.pathname==="/healthz"){t.writeHead(200,{"Content-Type":"application/json","Cache-Control":"no-store"}),t.end(JSON.stringify({ok:!0,pid:process.pid,platform:process.platform,bridgePort:this.effectivePort,runtimePort:this.effectivePort,activeRuntime:this.activeRuntimeVersion,bridgeSource:this.shouldWriteDevLockfile?"vite-dev":this.shouldWriteLockfile?"daemon":"embedded",startedAt:this.startedAt,uptimeMs:this.startedAt>0?Date.now()-this.startedAt:0}));return}if(s.pathname==="/__sootsim/shared-config"){if(t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Cache-Control","no-store"),i==="GET"||i==="HEAD"){let d="{}";try{d=JSON.stringify(M())}catch{}t.writeHead(200,{"Content-Type":"application/json"}),i==="HEAD"?t.end():t.end(d);return}t.writeHead(405,{Allow:"GET, HEAD"}),t.end("method not allowed (use the bridge over WS for writes)");return}this.refreshActiveRuntime();let n=this.activeRuntimeDirPath;if(!n){t.writeHead(503,{"Content-Type":"text/plain; charset=utf-8"}),t.end("sootsim: no active runtime installed. run `sootsim runtime install` to fetch one.");return}let a=s.pathname;if(a==="/runtime"||a==="/runtime/"?a="/":a.startsWith("/runtime/")?a=a.slice(8):a==="/sootsim"||a==="/sootsim/"?a="/":a.startsWith("/sootsim/")&&(a=a.slice(8)),(a===""||a==="/")&&(a="/index.html"),a.includes("\0")){t.writeHead(400),t.end("bad request");return}if(process.platform!=="win32"&&a.includes("\\")){t.writeHead(400),t.end("bad request");return}for(let d of a.split("/"))if(d===".."){t.writeHead(403),t.end("forbidden");return}let r=S.resolve(n,"."+a),c=n.endsWith(S.sep)?n:n+S.sep;if(!r.startsWith(c)&&r!==n){t.writeHead(403),t.end("forbidden");return}I.realpath(r,(d,l)=>{let u=d?r:l,p=u.endsWith(S.sep)?u:u+S.sep;if(!d){let m=(()=>{try{let f=I.realpathSync(n);return f.endsWith(S.sep)?f:f+S.sep}catch{return c}})();if(!p.startsWith(m)&&u+S.sep!==m){t.writeHead(403),t.end("forbidden");return}}I.stat(u,(m,f)=>{if(m||!f?.isFile()){let A=S.extname(a).toLowerCase();if(A&&A!==".html"){t.writeHead(404),t.end("not found");return}if(a.startsWith("/__")||a.startsWith("/api/")||a==="/api"){t.writeHead(404,{"Content-Type":"text/plain; charset=utf-8"}),t.end("not found");return}let N=S.join(n,"index.html");I.readFile(N,(Be,Ne)=>{if(Be){t.writeHead(404),t.end("not found");return}if(t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),i==="HEAD"){t.end();return}t.end(Oe(Ne,this.effectivePort,this.contrastOrigin))});return}let y=S.extname(u).toLowerCase(),g=wt[y]||"application/octet-stream";if(t.writeHead(200,{"Content-Type":g,"Cache-Control":"no-store"}),i==="HEAD"){t.end();return}if(y===".html"){I.readFile(u,(A,N)=>{if(A){try{t.end()}catch{}return}t.end(Oe(N,this.effectivePort,this.contrastOrigin))});return}let w=I.createReadStream(u);w.pipe(t),w.on("error",()=>{try{t.end()}catch{}})})})}sweepIdleCliClients(){let e=Date.now(),t=!1;for(let[i,s]of this.cliSimBySocket){let n=this.cliLastCommandAt.get(i)??0;if(e-n<o.CLI_IDLE_TIMEOUT_MS)continue;let a=!1;for(let r of this.cliBySentId.values())if(r.ws===i){a=!0;break}if(!a){this.cliSimBySocket.delete(i),this.cliLastCommandAt.delete(i);for(let[r,c]of this.cliBySentId)c.ws===i&&this.cliBySentId.delete(r);try{i.close(1e3,"idle timeout")}catch{}t=!0}}t&&this.broadcastSimClientStates(),this.sweepRestorableSims(e),this.reapIdleSims(e)}isAutomationSim(e){return e.meta?.sootsimHostDriver==="playwright"}automationSimOwnerAlive(e){let t=Number(e.meta?.sootsimHostPid);if(!Number.isInteger(t)||t<=1||t===process.pid)return!1;try{return process.kill(t,0),!0}catch(i){return i.code==="EPERM"}}reapIdleSims(e=Date.now()){let t=new Set(this.cliSimBySocket.values()),i=[];for(let n of this.sims.values()){if(n.id===this.primarySimId||t.has(n.id)||this.getActiveLease(n))continue;let a=Math.max(n.lastActiveAt,n.connectedAt),r=e-a,c=this.isAutomationSim(n);if(c&&this.automationSimOwnerAlive(n))continue;let d=c?this.automationSimIdleReapTtlMs:this.simIdleReapTtlMs;if(r>=d){this.closeSimSocketFromHost(n.ws);continue}c&&i.push({sim:n,idleMs:r})}let s=this.maxConcurrentAutomationSims;if(i.length>s){i.sort((n,a)=>a.idleMs-n.idleMs);for(let{sim:n,idleMs:a}of i.slice(0,i.length-s))a<this.automationSimActiveGraceMs||this.closeSimSocketFromHost(n.ws)}}sweepDeadWebSockets(){if(this.wss)for(let e of this.wss.clients){if(e.readyState!==h.OPEN)continue;if(this.wsIsAlive.get(e)===!1){try{e.terminate()}catch{}continue}this.wsIsAlive.set(e,!1);try{e.ping()}catch{try{e.terminate()}catch{}}}}closeSimSocketFromHost(e){if(e.readyState!==h.OPEN)return;try{e.close(re,ne)}catch{try{e.terminate()}catch{}return}let t=setTimeout(()=>{if(e.readyState!==h.CLOSED)try{e.terminate()}catch{}},St);Le(t)}listSims(){return Array.from(this.sims.values()).sort((e,t)=>e.id===this.primarySimId?-1:t.id===this.primarySimId?1:e.connectedAt-t.connectedAt).map(e=>this.describeSim(e))}async sendCommand(e){let t=await this.waitForSim(e.simId),i=this.nextCommandId++;return new Promise((s,n)=>{let a=setTimeout(()=>{this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(new Error("command timed out after 30s"))},3e4);this.pendingCommands.set(i,{simId:t.id,resolve:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),s(d)},reject:d=>{clearTimeout(a),this.pendingCommands.delete(i),this.broadcastSimClientStates(),n(d)}}),this.broadcastSimClientStates();let{simId:r,...c}=e;t.ws.send(JSON.stringify({...c,id:i}))})}async evaluate(e,t){return this.sendCommand({type:"evaluate",code:e,simId:t})}async focusSim(e){return this.sendCommand({type:"focus",simId:e})}async closeSim(e){return this.sendCommand({type:"close",simId:e})}async openPathInEditor(e,t,i){let s=t!=null?`:${t}${i!=null?`:${i}`:""}`:"",n=`${e}${s}`,a=(c,d)=>new Promise(l=>{try{let u=ut(c,d,{detached:!0,stdio:"ignore"}),p=!1;u.on("error",()=>{p||(p=!0,l(!1))}),u.on("spawn",()=>{p||(p=!0,u.unref(),l(!0))})}catch{l(!1)}}),r=process.env.REACT_EDITOR||process.env.EDITOR;if(r){let c=r.split(" ").filter(Boolean);if(c.length&&await a(c[0],[...c.slice(1),"-g",n]))return}await a("cursor",["-g",n])||await a("code",["-g",n])||await this.openUrl(e)}async openUrl(e,t={}){if(this.openUrlHandler){await this.openUrlHandler(e,t);return}await oe(e,t)}async close(){if(this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null),this.devHeartbeatTimer&&(clearInterval(this.devHeartbeatTimer),this.devHeartbeatTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null),this.shouldWriteLockfile)try{U()}catch{}if(this.shouldWriteDevLockfile)try{Q()}catch{}this.effectivePort=0,this.startedAt=0,this.agentHost.close();for(let[i,s]of this.pendingCommands)s.reject(new Error("server closing")),this.pendingCommands.delete(i);for(let i of this.sims.values())i.ws.close();this.sims.clear(),this.primarySimId=null;let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}describeSim(e){let t;try{t=e.ws.readyState}catch{t=h.CLOSED}let i=this.getActiveLease(e);return{id:e.id,origin:e.origin,url:e.url,title:e.title,userAgent:e.userAgent,connectedAt:e.connectedAt,lastSeenAt:e.lastSeenAt,lastActiveAt:e.lastActiveAt||void 0,isPrimary:e.id===this.primarySimId,readyState:t===h.OPEN?"open":t===h.CLOSING?"closing":"closed",attachedCliCount:this.getAttachedCliCount(e.id),lockedBy:i?i.cliLabel||i.cliIdentityKey:void 0,lockedByKind:i?i.kind:void 0,lockExpiresAt:i?i.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused,kind:e.kind,meta:e.meta}}getActiveLease(e){let t=e.cliLease;return t?Date.now()>=t.expiresAt?(e.cliLease=void 0,null):t:null}tryAcquireLease(e,t,i={}){let s=this.cliIdentityKeyBySocket.get(e)??(()=>{let u=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,u),u})(),n=this.cliLabelBySocket.get(e),a=Date.now(),r=this.getActiveLease(t),c=r&&r.cliIdentityKey===s,d=0;if(r&&!c&&!i.force)return{granted:!1,lease:r,lock:{by:r.cliLabel||r.cliIdentityKey,expiresInMs:Math.max(0,r.expiresAt-a)},bootedCount:0};if(r&&!c&&i.force)for(let[u,p]of this.cliSimBySocket){if(p!==t.id)continue;let m=this.cliIdentityKeyBySocket.get(u);if(m&&m!==s){this.cliSimBySocket.delete(u);try{u.close(1e3,"lease claimed by another cli")}catch{}d++}}let l={kind:"cli",cliIdentityKey:s,cliLabel:n,expiresAt:a+o.CLI_LEASE_TTL_MS};return t.cliLease=l,{granted:!0,lease:l,bootedCount:d}}updateUserFocusLease(e,t){let i=t.focused===!0,s=typeof t.visible=="boolean"?t.visible:void 0,n=typeof t.visibilityState=="string"?t.visibilityState:void 0,a=typeof t.documentFocused=="boolean"?t.documentFocused:void 0;e.userFocused===i&&e.userVisible===s&&e.visibilityState===n&&e.documentFocused===a||(e.userFocused=i,e.userVisible=s,e.visibilityState=n,e.documentFocused=a,this.broadcastSimClientStates())}updateUserActivity(e){let t=this.getActiveLease(e);if(t&&t.kind==="cli")return;let s=Date.now()+o.USER_ACTIVE_LEASE_TTL_MS,n=t&&t.kind==="user-active"?Math.max(t.expiresAt,s):s;e.cliLease={kind:"user-active",cliIdentityKey:"__user-active__",cliLabel:"active user",expiresAt:n},this.broadcastSimClientStates()}ensureCliIdentityKey(e){let t=this.cliIdentityKeyBySocket.get(e);if(t)return t;let i=`ws-${this.nextCliFallbackId++}`;return this.cliIdentityKeyBySocket.set(e,i),i}getOpenSim(e){if(e){let s=this.sims.get(e);return s?.ws.readyState===h.OPEN?s:null}let t=this.primarySimId!=null?this.sims.get(this.primarySimId):null;if(t?.ws.readyState===h.OPEN&&t.url)return t;let i=null;for(let s of this.sims.values())if(s.ws.readyState===h.OPEN){if(s.url)return s;i??=s}return t?.ws.readyState===h.OPEN?t:i}async waitForSim(e,t={}){let i=t.attempts??10,s=t.intervalMs??200;for(let n=0;n<i;n++){let a=this.getOpenSim(e);if(a)return a;await new Promise(r=>setTimeout(r,s))}throw new Error(e?`no sim connected with id ${e}`:"no sim connected")}shouldPromoteSim(e){let t=this.primarySimId?this.sims.get(this.primarySimId):null;if(!e.url)return!t;let i=t?.ws.readyState===h.OPEN;if(!t||!i||!t.url)return!0;let s=e.origin?.includes(":5173"),n=t.origin?.includes(":5173");return!!s||!n}broadcastSimAssignments(){for(let e of this.sims.values())e.ws.readyState===h.OPEN&&e.ws.send(JSON.stringify({type:"bridge:welcome",simId:e.id,isPrimary:e.id===this.primarySimId}))}broadcastSimClientStates(){for(let e of this.sims.values()){if(e.ws.readyState!==h.OPEN)continue;let t=this.getActiveLease(e),i={type:"bridge:client-state",attachedCliCount:this.getAttachedCliCount(e.id),activeAgentCommandCount:this.getActiveAgentCommandCount(e.id),recentActions:e.recentActions,lockedBy:t?t.cliLabel||t.cliIdentityKey:void 0,lockedByKind:t?t.kind:void 0,lockExpiresAt:t?t.expiresAt:void 0,userFocused:e.userFocused||void 0,userVisible:e.userVisible,visibilityState:e.visibilityState,documentFocused:e.documentFocused};e.ws.send(JSON.stringify(i))}}setCliSimTarget(e,t){let i=this.cliSimBySocket.get(e);i!==t&&(this.cliSimBySocket.set(e,t),this.recordSimAction(t,i?"cli switched sims":"cli connected",!1),this.broadcastSimClientStates())}recordSimAction(e,t,i=!0){let s=t?.trim();if(!s)return;let n=this.sims.get(e);if(!n)return;let a=Date.now();n.lastActiveAt=a,n.recentActions=[{label:s,at:a},...n.recentActions.filter(r=>r.label!==s)].slice(0,4),i&&this.broadcastSimClientStates()}describeForwardedCommand(e){switch(e?.type){case"evaluate":return"evaluated page state";case"screenshot":return"captured screenshot";case"tap":return"sent tap event";case"keyboard":return e?.action==="type"?"typed text":"used keyboard";case"tree":return"dumped tree";case"focus":return"focused sim";case"close":return"requested close";default:return typeof e?.type=="string"?e.type:null}}getAttachedCliCount(e){let t=new Set;for(let[i,s]of this.cliSimBySocket){if(s!==e||i.readyState!==h.OPEN)continue;let n=this.cliIdentityKeyBySocket.get(i);t.add(n??`ws-unknown-${t.size}`)}return t.size}getOtherCliIdentityCount(e,t){let i=this.cliIdentityKeyBySocket.get(e),s=new Set;for(let[n,a]of this.cliSimBySocket){if(a!==t||n.readyState!==h.OPEN)continue;let r=this.cliIdentityKeyBySocket.get(n);r&&r===i||s.add(r??`ws-unknown-${s.size}`)}return s.size}getActiveAgentCommandCount(e){let t=0;for(let i of this.pendingCommands.values())i.simId===e&&t++;return t}allocateSimId(){for(;;){let e=this.nextSimNumber.toString(16);if(this.nextSimNumber++,!this.sims.has(e)&&!this.restorableSims.has(e))return e}}tryRestoreSimId(e,t){let i=t?.trim();if(!i||i===e.id)return!1;let s=this.sims.get(i);if(s&&s!==e&&s.ws.readyState===h.OPEN)return!1;let n=this.getRestorableSimState(i),a=e.id;this.sims.delete(a),e.id=i,n&&(e.recentActions=n.recentActions.map(r=>({...r})),e.lastActiveAt=n.lastActiveAt,e.cliLease=n.cliLease?{...n.cliLease}:void 0,this.restorableSims.delete(i)),this.sims.set(e.id,e),this.primarySimId===a&&(this.primarySimId=e.id);for(let[r,c]of this.cliSimBySocket)c===a&&this.cliSimBySocket.set(r,e.id);return!0}rememberDisconnectedSim(e){let t=this.getActiveLease(e);this.restorableSims.set(e.id,{recentActions:e.recentActions.map(i=>({...i})),lastActiveAt:e.lastActiveAt,cliLease:t&&t.kind==="cli"?{...t}:void 0,expiresAt:Date.now()+o.SIM_RECONNECT_TTL_MS}),this.sims.delete(e.id)}getRestorableSimState(e){let t=this.restorableSims.get(e);return t?t.expiresAt<=Date.now()?(this.restorableSims.delete(e),null):(t.cliLease&&t.cliLease.expiresAt<=Date.now()&&(t.cliLease=void 0),t):null}sweepRestorableSims(e=Date.now()){for(let[t,i]of this.restorableSims)if(!(i.expiresAt>e)){this.restorableSims.delete(t);for(let[s,n]of this.cliSimBySocket)n===t&&this.cliSimBySocket.delete(s)}}resetServerState(){this.cliIdleTimer&&(clearInterval(this.cliIdleTimer),this.cliIdleTimer=null),this.wsHeartbeatTimer&&(clearInterval(this.wsHeartbeatTimer),this.wsHeartbeatTimer=null),this.runtimeUpdateTimer&&(clearInterval(this.runtimeUpdateTimer),this.runtimeUpdateTimer=null);let e=this.wss,t=this.httpServer;if(this.wss=null,this.httpServer=null,e)try{e.close()}catch{}if(t)try{t.close()}catch{}}};function At(){return!!((process.env.XPC_SERVICE_NAME||"").includes("dev.sootsim.daemon")||process.env.INVOCATION_ID)}async function mi(o,e={}){(o.includes("--help")||o.includes("-h"))&&(console.log(`
|
|
23
|
-
sootsim serve \u2014 run the sootsim bridge in the foreground
|
|
24
|
-
|
|
25
|
-
hosts the WS bridge that CLI commands talk to. once running, any sootsim
|
|
26
|
-
renderer (browser, electron, headless playwright) that connects to port 7668
|
|
27
|
-
becomes drivable from 'sootsim describe', 'sootsim do tap', etc.
|
|
28
|
-
|
|
29
|
-
usage:
|
|
30
|
-
sootsim serve [options]
|
|
31
|
-
|
|
32
|
-
options:
|
|
33
|
-
--port <n> bridge port (defaults to ${7668})
|
|
34
|
-
--quiet suppress per-connection logging
|
|
35
|
-
|
|
36
|
-
examples:
|
|
37
|
-
sootsim serve
|
|
38
|
-
sootsim serve --port 7668 --quiet
|
|
39
|
-
`),process.exit(0));let t=o.indexOf("--port"),i=t>=0&&o[t+1]?Number(o[t+1]):e.port??7668;Number.isNaN(i)&&(console.error(` invalid --port value: ${o[t+1]}`),process.exit(1));let s=o.includes("--quiet")||o.includes("-q"),n=q();n&&z(n)&&(console.error(` a sootsim bridge is already running (pid ${n.pid}, port ${n.bridgePort})`),console.error(" stop it with 'sootsim daemon stop' first"),process.exit(1)),E();let a=await ce(),r=new L({port:i,writeLockfile:!0,contrastOrigin:a}),c=await r.startAsync({silent:s}),d=Date.now(),l=f=>{s||process.stdout.write(`${f}
|
|
40
|
-
`)},u=new Set,p=setInterval(()=>{let f=r.listSims(),y=new Set(f.map(g=>g.id));for(let g of f)if(!u.has(g.id)){let w=g.title||g.url||g.origin||"(unknown)";l(` + ${g.id} ${w}`)}for(let g of u)y.has(g)||l(` - ${g}`);u.clear();for(let g of y)u.add(g)},500);ee({event:"daemon_heartbeat",properties:{bridge_port:c,under_daemon:At(),platform:process.platform,subsource:"daemon"}}),te(),l(`sootsim bridge listening on ws://localhost:${c} (runtime http on same port)`),c!==i&&l(` (preferred port ${i} was taken \u2014 fell back to ${c})`),l(" ready for browser, electron, or headless playwright sims to connect"),l(" (ctrl-c to stop)");let m=async f=>{clearInterval(p),l(`
|
|
41
|
-
${f} received \u2014 shutting down after ${Math.round((Date.now()-d)/1e3)}s`);try{await r.close()}catch{}process.exit(0)};process.on("SIGINT",()=>m("SIGINT")),process.on("SIGTERM",()=>m("SIGTERM")),process.on("SIGHUP",()=>m("SIGHUP")),process.on("exit",()=>{try{r.removeLockfile()}catch{}}),await new Promise(()=>{})}export{mi as runServe};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! sootsim v0.1.239 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
|
-
import{e as a,f as b,g as c}from"./chunk-D4YH5KNQ.js";import"./chunk-JPNTLGLA.js";import"./chunk-SRMYUHBI.js";import"./chunk-6XF2EHL2.js";import"./chunk-ZL2KSYJP.js";import"./chunk-544G2PCM.js";import"./chunk-UZRZGXQ4.js";import"./chunk-JOSDTQZ3.js";import"./chunk-HV2ZRFGP.js";import"./chunk-SLIYVKRX.js";import"./chunk-FOTAUF7Q.js";import"./chunk-BWKVAEAJ.js";export{a as resolveDefaultUploadOrigin,b as resolvePublicPreviewOrigin,c as runUpload};
|