sootsim 0.1.251 → 0.1.253
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/README.md +8 -5
- package/dist-cli/bin.js +4 -4
- package/dist-cli/chunks/{agent-OS5AFMNY.js → agent-VULBDRQX.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-JXCJFH4J.js → agent-wrapper-NIKM5YH7.js} +2 -2
- package/dist-cli/chunks/{app-fonts-KM5VGTPQ.js → app-fonts-H6Q7KUPX.js} +2 -2
- package/dist-cli/chunks/{assert-IWDBWZA3.js → assert-KG4DXXXU.js} +2 -2
- package/dist-cli/chunks/{auth-GGWN2KHL.js → auth-YFAM5XCG.js} +2 -2
- package/dist-cli/chunks/beta-X7YVGAZ7.js +2 -0
- package/dist-cli/chunks/{camera-W5JQ5P6L.js → camera-LDDRWGWU.js} +2 -2
- package/dist-cli/chunks/chunk-36BZF4FN.js +29 -0
- package/dist-cli/chunks/{chunk-CQKALFGJ.js → chunk-3UCSOXI3.js} +1 -1
- package/dist-cli/chunks/{chunk-XJYAJ5C3.js → chunk-45WNNP6S.js} +2 -2
- package/dist-cli/chunks/{chunk-UTNAJIRM.js → chunk-46TTKKZH.js} +2 -2
- package/dist-cli/chunks/chunk-57Y54BSR.js +1 -0
- package/dist-cli/chunks/{chunk-LJKL5JQ7.js → chunk-5FUEGJVZ.js} +2 -2
- package/dist-cli/chunks/{chunk-CDZTB6JX.js → chunk-5KIOJ7EY.js} +2 -2
- package/dist-cli/chunks/{chunk-IC4GREHT.js → chunk-5LRIUIDH.js} +1 -1
- package/dist-cli/chunks/{chunk-KEBLYJBJ.js → chunk-7X342NBJ.js} +2 -2
- package/dist-cli/chunks/chunk-AVDM5PJT.js +7 -0
- package/dist-cli/chunks/{chunk-7HCKUJ5R.js → chunk-BMDLK4TN.js} +1 -1
- package/dist-cli/chunks/{chunk-VO5UXLRE.js → chunk-C5WLLPSP.js} +2 -2
- package/dist-cli/chunks/chunk-DCSZ4W7L.js +4 -0
- package/dist-cli/chunks/{chunk-55GPRX3M.js → chunk-DEPT2HN2.js} +2 -2
- package/dist-cli/chunks/{chunk-KD347J3Y.js → chunk-DVL3QEUF.js} +2 -2
- package/dist-cli/chunks/{chunk-LETXRLKY.js → chunk-GQEV66R5.js} +1 -1
- package/dist-cli/chunks/{chunk-Z7IG2OVW.js → chunk-HWJY7OMU.js} +1 -1
- package/dist-cli/chunks/chunk-HWUTV647.js +1 -0
- package/dist-cli/chunks/{chunk-MK5FIMS5.js → chunk-I2SPWGIX.js} +2 -2
- package/dist-cli/chunks/{chunk-7MEV3VTL.js → chunk-IRKSPKGN.js} +1 -1
- package/dist-cli/chunks/{chunk-PM3MMXYH.js → chunk-L2MLV2CS.js} +2 -2
- package/dist-cli/chunks/{chunk-FBAFTRKJ.js → chunk-L6CZJTQL.js} +2 -2
- package/dist-cli/chunks/{chunk-KEJB5OS5.js → chunk-LQGKEJEY.js} +2 -2
- package/dist-cli/chunks/{chunk-WD4B3KV6.js → chunk-MJVYTFNP.js} +3 -3
- package/dist-cli/chunks/{chunk-YJEU2B3D.js → chunk-MWMCDY2F.js} +1 -1
- package/dist-cli/chunks/{chunk-RBHEKEEX.js → chunk-NGPLOHLX.js} +2 -2
- package/dist-cli/chunks/{chunk-63FDEQKS.js → chunk-NKBPE462.js} +1 -1
- package/dist-cli/chunks/{chunk-OOLWKYWS.js → chunk-NTITLMC6.js} +1 -1
- package/dist-cli/chunks/{chunk-TQJZ2AP4.js → chunk-NUEXSE26.js} +2 -2
- package/dist-cli/chunks/{chunk-DVLNBQO6.js → chunk-NUPOCIXQ.js} +2 -2
- package/dist-cli/chunks/{chunk-GMJ3ROI3.js → chunk-PDGZJCKZ.js} +2 -2
- package/dist-cli/chunks/{chunk-ULYIJUKO.js → chunk-PPEVHLXX.js} +2 -2
- package/dist-cli/chunks/{chunk-EY5V6OC5.js → chunk-Q5HUMK3X.js} +2 -2
- package/dist-cli/chunks/{chunk-NQCAEFUQ.js → chunk-QLD2JSAY.js} +1 -1
- package/dist-cli/chunks/{chunk-H3YZXLYR.js → chunk-RKLOJJIQ.js} +1 -1
- package/dist-cli/chunks/{chunk-IYPXOVE4.js → chunk-ROP4FQW2.js} +1 -1
- package/dist-cli/chunks/{chunk-ZL3QAP5O.js → chunk-SM36BLYO.js} +3 -3
- package/dist-cli/chunks/{chunk-37PWKV2H.js → chunk-UTHHCEOE.js} +1 -1
- package/dist-cli/chunks/{chunk-X4HNMVAY.js → chunk-VUUVN4CA.js} +2 -2
- package/dist-cli/chunks/{chunk-PZZPL7XB.js → chunk-WLTTYQFC.js} +1 -1
- package/dist-cli/chunks/{chunk-5T62AM5W.js → chunk-WXXCER5Y.js} +3 -3
- package/dist-cli/chunks/{chunk-7JTW5KO4.js → chunk-XRDM6KN6.js} +1 -1
- package/dist-cli/chunks/{chunk-HLD3JMUC.js → chunk-Y66ZEDLD.js} +2 -2
- package/dist-cli/chunks/{chunk-Z6ZYU2VN.js → chunk-YQDI7PAU.js} +1 -1
- package/dist-cli/chunks/cli-version-YK3KEAWE.js +2 -0
- package/dist-cli/chunks/{compat-Q7NF5FGR.js → compat-5MLHRLL7.js} +3 -3
- package/dist-cli/chunks/{config-CHFGC57H.js → config-XQU7NIBN.js} +2 -2
- package/dist-cli/chunks/{control-GMXYQHOC.js → control-CP27GWY2.js} +2 -2
- package/dist-cli/chunks/daemon-SZ5235QJ.js +2 -0
- package/dist-cli/chunks/{debug-JVFKA6ZJ.js → debug-XAS5RRTR.js} +3 -3
- package/dist-cli/chunks/{desktop-DT6WBVHN.js → desktop-DMRDH54D.js} +3 -3
- package/dist-cli/chunks/{detox-OQ3DVIZB.js → detox-5RWKQ4FY.js} +2 -2
- package/dist-cli/chunks/{device-XBBNWO67.js → device-K4QUDQJW.js} +2 -2
- package/dist-cli/chunks/{diagnose-JFWKSZI6.js → diagnose-XQ3UCGAC.js} +2 -2
- package/dist-cli/chunks/drivers-4XIRJTRV.js +2 -0
- package/dist-cli/chunks/{film-3BI63O2P.js → film-NBO7R7YE.js} +3 -3
- package/dist-cli/chunks/flow-IPFJBZ2T.js +2 -0
- package/dist-cli/chunks/help-OVFNRXKE.js +2 -0
- package/dist-cli/chunks/{hidden-runtime-alias-JGY2SN3U.js → hidden-runtime-alias-HMRDTRPL.js} +2 -2
- package/dist-cli/chunks/home-paths-IHLLHTH3.js +2 -0
- package/dist-cli/chunks/inspect-OLDRJZFR.js +2 -0
- package/dist-cli/chunks/install-desktop-4LN5U3GV.js +2 -0
- package/dist-cli/chunks/{login-QT6OUDLD.js → login-JJ26E3ZL.js} +4 -4
- package/dist-cli/chunks/{logout-QM7I6EYI.js → logout-Z4T2ZUMV.js} +2 -2
- package/dist-cli/chunks/{maestro-YU5YDZ44.js → maestro-27CX2MYE.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-YQ5GE6LW.js → maestro-generate-S2HMOTKV.js} +3 -3
- package/dist-cli/chunks/{mode-MHOIKOWG.js → mode-MUI6VEX5.js} +2 -2
- package/dist-cli/chunks/optional-demo-registry-B5KGRDC7.js +2 -0
- package/dist-cli/chunks/{perf-UDWM5CLN.js → perf-XLL4NAW4.js} +2 -2
- package/dist-cli/chunks/{record-EEYIMPNW.js → record-CO6ZZXOF.js} +3 -3
- package/dist-cli/chunks/runtime-3BT5LEI2.js +2 -0
- package/dist-cli/chunks/{screenshot-command-MDOO4W2M.js → screenshot-command-7TLIPP6M.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-MYFBKRYI.js → screenshots-capture-W47CLDWK.js} +2 -2
- package/dist-cli/chunks/{serve-TFGKULND.js → serve-JFWQW3PY.js} +15 -15
- package/dist-cli/chunks/{setup-WOB5DERX.js → setup-64WP25N3.js} +3 -3
- package/dist-cli/chunks/{skills-MFFPTR5A.js → skills-FEOY5MFR.js} +2 -2
- package/dist-cli/chunks/{storage-6IZXGU2O.js → storage-DVJEOSE5.js} +2 -2
- package/dist-cli/chunks/store-VWZLLKMA.js +2 -0
- package/dist-cli/chunks/telemetry-RRR64APJ.js +2 -0
- package/dist-cli/chunks/{timeline-BRXK7M5J.js → timeline-BN4FOIE5.js} +2 -2
- package/dist-cli/chunks/{upgrade-K6A4PITT.js → upgrade-R6FMWF53.js} +4 -4
- package/dist-cli/chunks/upload-VV6ASI6M.js +2 -0
- package/dist-cli/chunks/version-5GYDQEIP.js +4 -0
- package/dist-cli/chunks/{web-P3ANEMOL.js → web-SZQMAIF5.js} +2 -2
- package/dist-cli/chunks/{what-happened-OFMSOZZB.js → what-happened-2KMAVPKZ.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 -33
- package/dist-lib/host/bridge-host.cjs +404 -329
- 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/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 +523 -435
- package/dist-lib/vite.cjs +1 -1
- package/package.json +2 -1
- package/src/home-paths.ts +5 -40
- package/src/host/bridge-host.ts +4 -5
- package/src/runtime-delivery.ts +36 -377
- package/dist-cli/chunks/beta-LVHWRJCU.js +0 -2
- package/dist-cli/chunks/chunk-2273TU3I.js +0 -1
- package/dist-cli/chunks/chunk-6ACR2P3U.js +0 -1
- package/dist-cli/chunks/chunk-HMOZ6UBM.js +0 -29
- package/dist-cli/chunks/chunk-JFXVQVXW.js +0 -4
- package/dist-cli/chunks/chunk-OLCSJXAQ.js +0 -7
- package/dist-cli/chunks/cli-version-Z2MVFJOA.js +0 -2
- package/dist-cli/chunks/daemon-NM537LET.js +0 -2
- package/dist-cli/chunks/drivers-NOJ7CRI4.js +0 -2
- package/dist-cli/chunks/flow-7ETXJJ6C.js +0 -2
- package/dist-cli/chunks/help-FE5IIJIM.js +0 -2
- package/dist-cli/chunks/home-paths-BLOAGTA2.js +0 -2
- package/dist-cli/chunks/inspect-UA376AF4.js +0 -2
- package/dist-cli/chunks/install-desktop-KBXAATJW.js +0 -2
- package/dist-cli/chunks/optional-demo-registry-RF4SZYRO.js +0 -2
- package/dist-cli/chunks/runtime-UJOIMMBS.js +0 -2
- package/dist-cli/chunks/store-JG2JCUFN.js +0 -2
- package/dist-cli/chunks/telemetry-HI4GNTOS.js +0 -2
- package/dist-cli/chunks/upload-ZNSE6XIN.js +0 -2
- package/dist-cli/chunks/version-4HZWAXW3.js +0 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! sootsim v0.1.
|
|
1
|
+
/*! sootsim v0.1.253 | (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;
|
|
@@ -70,10 +70,10 @@ __export(bridge_host_exports, {
|
|
|
70
70
|
injectSharedConfigIntoHtml: () => injectSharedConfigIntoHtml
|
|
71
71
|
});
|
|
72
72
|
module.exports = __toCommonJS(bridge_host_exports);
|
|
73
|
-
var
|
|
74
|
-
var
|
|
73
|
+
var import_child_process3 = require("child_process");
|
|
74
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
75
75
|
var import_http3 = require("http");
|
|
76
|
-
var
|
|
76
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
77
77
|
var import_ws2 = require("ws");
|
|
78
78
|
|
|
79
79
|
// scripts/dev-server-scanner.ts
|
|
@@ -156,10 +156,10 @@ function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
|
156
156
|
sock.connect(port, "localhost");
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
|
-
function httpGet(port,
|
|
159
|
+
function httpGet(port, path10, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
160
160
|
return new Promise((resolve) => {
|
|
161
161
|
const req = import_http.default.request(
|
|
162
|
-
{ hostname: "localhost", port, path:
|
|
162
|
+
{ hostname: "localhost", port, path: path10, method, timeout, headers },
|
|
163
163
|
(res) => {
|
|
164
164
|
let body = "";
|
|
165
165
|
res.on("data", (c) => body += c.toString());
|
|
@@ -706,34 +706,6 @@ function writeActiveRuntime(version) {
|
|
|
706
706
|
import_node_fs2.default.writeFileSync(activeRuntimeFile(), `${version}
|
|
707
707
|
`, "utf8");
|
|
708
708
|
}
|
|
709
|
-
function listInstalledRuntimes() {
|
|
710
|
-
try {
|
|
711
|
-
return import_node_fs2.default.readdirSync(runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
|
|
712
|
-
} catch {
|
|
713
|
-
return [];
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
function compareSemver(a, b) {
|
|
717
|
-
const parse = (v) => {
|
|
718
|
-
const hyphen = v.indexOf("-");
|
|
719
|
-
const core = hyphen >= 0 ? v.slice(0, hyphen) : v;
|
|
720
|
-
const pre = hyphen >= 0 ? v.slice(hyphen + 1) : "";
|
|
721
|
-
const parts = core.split(".").map((n) => Number.parseInt(n, 10));
|
|
722
|
-
if (parts.some((n) => !Number.isFinite(n))) return [[Number.POSITIVE_INFINITY], v];
|
|
723
|
-
return [parts, pre];
|
|
724
|
-
};
|
|
725
|
-
const [an, ap] = parse(a);
|
|
726
|
-
const [bn, bp] = parse(b);
|
|
727
|
-
for (let i = 0; i < Math.max(an.length, bn.length); i++) {
|
|
728
|
-
const av = an[i] ?? 0;
|
|
729
|
-
const bv = bn[i] ?? 0;
|
|
730
|
-
if (av !== bv) return av - bv;
|
|
731
|
-
}
|
|
732
|
-
if (ap === bp) return 0;
|
|
733
|
-
if (!ap) return 1;
|
|
734
|
-
if (!bp) return -1;
|
|
735
|
-
return ap < bp ? -1 : 1;
|
|
736
|
-
}
|
|
737
709
|
function activeRuntimeDir() {
|
|
738
710
|
const version = readActiveRuntime();
|
|
739
711
|
if (!version) return null;
|
|
@@ -839,149 +811,243 @@ function resolveDevCheckoutRuntimeRoot() {
|
|
|
839
811
|
return null;
|
|
840
812
|
}
|
|
841
813
|
|
|
842
|
-
//
|
|
843
|
-
var
|
|
844
|
-
var
|
|
845
|
-
var
|
|
846
|
-
var
|
|
847
|
-
var
|
|
848
|
-
var import_promises = require("stream/promises");
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
var
|
|
852
|
-
var
|
|
853
|
-
function
|
|
814
|
+
// ../contrast-runtime-delivery/src/index.ts
|
|
815
|
+
var import_node_child_process = require("node:child_process");
|
|
816
|
+
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
817
|
+
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
818
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
819
|
+
var import_node_stream = require("node:stream");
|
|
820
|
+
var import_promises = require("node:stream/promises");
|
|
821
|
+
|
|
822
|
+
// ../contrast-runtime-delivery/src/product.ts
|
|
823
|
+
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
824
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
825
|
+
function listInstalledRuntimes(product) {
|
|
854
826
|
try {
|
|
855
|
-
|
|
856
|
-
return parsed && typeof parsed === "object" ? parsed : {};
|
|
827
|
+
return import_node_fs3.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
|
|
857
828
|
} catch {
|
|
858
|
-
return
|
|
829
|
+
return [];
|
|
859
830
|
}
|
|
860
831
|
}
|
|
861
|
-
function
|
|
862
|
-
|
|
863
|
-
const value = input || process.env[RUNTIME_CDN_ORIGIN_ENV] || config.cdnOrigin || DEFAULT_RUNTIME_CDN_ORIGIN;
|
|
864
|
-
return value.replace(/\/+$/, "");
|
|
865
|
-
}
|
|
866
|
-
function resolveRuntimeChannel(input) {
|
|
867
|
-
const config = readConfig();
|
|
868
|
-
return input || process.env[RUNTIME_CHANNEL_ENV] || config.runtimeChannel || "stable";
|
|
832
|
+
function runtimeTarballCacheName(product, version) {
|
|
833
|
+
return import_node_path2.default.posix.basename(product.tarballPath(version));
|
|
869
834
|
}
|
|
870
|
-
function
|
|
871
|
-
const
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
const url = runtimeManifestUrl(cdnOrigin);
|
|
886
|
-
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
887
|
-
if (!res.ok) {
|
|
888
|
-
throw new Error(`manifest fetch failed: ${res.status} ${res.statusText} (${url})`);
|
|
835
|
+
function compareSemver(a, b) {
|
|
836
|
+
const parse = (v) => {
|
|
837
|
+
const hyphen = v.indexOf("-");
|
|
838
|
+
const core = hyphen >= 0 ? v.slice(0, hyphen) : v;
|
|
839
|
+
const pre = hyphen >= 0 ? v.slice(hyphen + 1) : "";
|
|
840
|
+
const parts = core.split(".").map((n) => Number.parseInt(n, 10));
|
|
841
|
+
if (parts.some((n) => !Number.isFinite(n))) return [[Number.POSITIVE_INFINITY], v];
|
|
842
|
+
return [parts, pre];
|
|
843
|
+
};
|
|
844
|
+
const [an, ap] = parse(a);
|
|
845
|
+
const [bn, bp] = parse(b);
|
|
846
|
+
for (let i = 0; i < Math.max(an.length, bn.length); i++) {
|
|
847
|
+
const av = an[i] ?? 0;
|
|
848
|
+
const bv = bn[i] ?? 0;
|
|
849
|
+
if (av !== bv) return av - bv;
|
|
889
850
|
}
|
|
890
|
-
|
|
851
|
+
if (ap === bp) return 0;
|
|
852
|
+
if (!ap) return 1;
|
|
853
|
+
if (!bp) return -1;
|
|
854
|
+
return ap < bp ? -1 : 1;
|
|
891
855
|
}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
856
|
+
|
|
857
|
+
// ../contrast-runtime-delivery/src/index.ts
|
|
858
|
+
function createRuntimeDelivery(product) {
|
|
859
|
+
function readConfig() {
|
|
860
|
+
try {
|
|
861
|
+
const parsed = JSON.parse(
|
|
862
|
+
import_node_fs4.default.readFileSync(product.configFile(), "utf8")
|
|
863
|
+
);
|
|
864
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
865
|
+
} catch {
|
|
866
|
+
return {};
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
function resolveCdnOrigin(input) {
|
|
870
|
+
const config = readConfig();
|
|
871
|
+
const value = input || process.env[product.env.cdnOrigin] || config.cdnOrigin || product.defaultCdnOrigin;
|
|
872
|
+
return value.replace(/\/+$/, "");
|
|
873
|
+
}
|
|
874
|
+
function resolveChannel(input) {
|
|
875
|
+
const config = readConfig();
|
|
876
|
+
return input || process.env[product.env.channel] || config.runtimeChannel || "stable";
|
|
877
|
+
}
|
|
878
|
+
function resolvePin() {
|
|
879
|
+
const env = process.env[product.env.pin];
|
|
880
|
+
if (env && env.trim()) return env.trim();
|
|
881
|
+
const config = readConfig();
|
|
882
|
+
return typeof config.runtimeVersion === "string" && config.runtimeVersion.trim() ? config.runtimeVersion.trim() : null;
|
|
883
|
+
}
|
|
884
|
+
function manifestUrl(cdnOrigin) {
|
|
885
|
+
const url = new URL(`${resolveCdnOrigin(cdnOrigin)}${product.manifestPath}`);
|
|
886
|
+
url.searchParams.set("t", String(Date.now()));
|
|
887
|
+
return url.toString();
|
|
888
|
+
}
|
|
889
|
+
function tarballUrl(version, cdnOrigin) {
|
|
890
|
+
return `${resolveCdnOrigin(cdnOrigin)}${product.tarballPath(version)}`;
|
|
891
|
+
}
|
|
892
|
+
async function fetchManifest(cdnOrigin) {
|
|
893
|
+
const url = manifestUrl(cdnOrigin);
|
|
894
|
+
const res = await fetch(url, { headers: { Accept: "application/json" } });
|
|
895
|
+
if (!res.ok) {
|
|
896
|
+
throw new Error(`manifest fetch failed: ${res.status} ${res.statusText} (${url})`);
|
|
897
|
+
}
|
|
898
|
+
return await res.json();
|
|
899
|
+
}
|
|
900
|
+
function resolveVersion(manifest, opts = {}) {
|
|
901
|
+
const channel = resolveChannel(opts.channel);
|
|
902
|
+
const version = opts.version || resolvePin() || manifest.channels[channel]?.latest;
|
|
903
|
+
if (!version) {
|
|
904
|
+
throw new Error(
|
|
905
|
+
`no version specified and channel '${channel}' has no latest entry in the manifest`
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
const entry = manifest.versions[version];
|
|
909
|
+
if (!entry) {
|
|
910
|
+
throw new Error(
|
|
911
|
+
`version ${version} not found in manifest; available: ${Object.keys(manifest.versions).slice(-10).join(", ") || "(none)"}`
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
return { version, channel, entry };
|
|
915
|
+
}
|
|
916
|
+
async function install(opts = {}) {
|
|
917
|
+
product.ensureHome();
|
|
918
|
+
const cdnOrigin = resolveCdnOrigin(opts.cdnOrigin);
|
|
919
|
+
const manifest = await fetchManifest(cdnOrigin);
|
|
920
|
+
const { version, channel, entry } = resolveVersion(manifest, opts);
|
|
921
|
+
const destDir = product.runtimeDir(version);
|
|
922
|
+
const setActive = opts.setActive !== false;
|
|
923
|
+
if (!opts.force && import_node_fs4.default.existsSync(import_node_path3.default.join(destDir, product.installedMarker))) {
|
|
924
|
+
if (setActive) product.writeActiveRuntime(version);
|
|
925
|
+
return {
|
|
926
|
+
version,
|
|
927
|
+
channel,
|
|
928
|
+
cdnOrigin,
|
|
929
|
+
runtimeDir: destDir,
|
|
930
|
+
installed: false,
|
|
931
|
+
activated: setActive,
|
|
932
|
+
manifest
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
|
|
936
|
+
const tarCachePath = import_node_path3.default.join(
|
|
937
|
+
product.cacheDir(),
|
|
938
|
+
runtimeTarballCacheName(product, version)
|
|
898
939
|
);
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
940
|
+
process.stderr.write(`${product.id}: downloading runtime ${version}\u2026
|
|
941
|
+
`);
|
|
942
|
+
await downloadToFile(tarUrl, tarCachePath);
|
|
943
|
+
process.stderr.write(`${product.id}: extracting runtime ${version}\u2026
|
|
944
|
+
`);
|
|
945
|
+
const actualSha = await sha256File(tarCachePath);
|
|
946
|
+
if (actualSha !== entry.sha256) {
|
|
947
|
+
import_node_fs4.default.rmSync(tarCachePath, { force: true });
|
|
948
|
+
throw new Error(
|
|
949
|
+
`sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
const tmpDir = import_node_path3.default.join(
|
|
953
|
+
import_node_path3.default.dirname(destDir),
|
|
954
|
+
`.installing-${version}-${process.pid}`
|
|
904
955
|
);
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
956
|
+
import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
957
|
+
import_node_fs4.default.mkdirSync(tmpDir, { recursive: true });
|
|
958
|
+
try {
|
|
959
|
+
await extractTarball(tarCachePath, tmpDir);
|
|
960
|
+
if (!import_node_fs4.default.existsSync(import_node_path3.default.join(tmpDir, product.installedMarker))) {
|
|
961
|
+
throw new Error(
|
|
962
|
+
`extracted tarball for runtime ${version} is missing ${product.installedMarker}`
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
import_node_fs4.default.rmSync(destDir, { recursive: true, force: true });
|
|
966
|
+
import_node_fs4.default.renameSync(tmpDir, destDir);
|
|
967
|
+
} catch (err) {
|
|
968
|
+
import_node_fs4.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
969
|
+
throw err;
|
|
970
|
+
}
|
|
971
|
+
if (setActive) product.writeActiveRuntime(version);
|
|
917
972
|
return {
|
|
918
973
|
version,
|
|
919
974
|
channel,
|
|
920
975
|
cdnOrigin,
|
|
921
976
|
runtimeDir: destDir,
|
|
922
|
-
installed:
|
|
977
|
+
installed: true,
|
|
923
978
|
activated: setActive,
|
|
924
979
|
manifest
|
|
925
980
|
};
|
|
926
981
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
982
|
+
async function updateToLatest(opts = {}) {
|
|
983
|
+
product.ensureHome();
|
|
984
|
+
const cdnOrigin = resolveCdnOrigin(opts.cdnOrigin);
|
|
985
|
+
const channel = resolveChannel(opts.channel);
|
|
986
|
+
const pin = resolvePin();
|
|
987
|
+
if (pin) {
|
|
988
|
+
const activeVersion2 = product.readActiveRuntime();
|
|
989
|
+
const pinInstalled = import_node_fs4.default.existsSync(
|
|
990
|
+
import_node_path3.default.join(product.runtimeDir(pin), product.installedMarker)
|
|
991
|
+
);
|
|
992
|
+
if (activeVersion2 === pin && pinInstalled) {
|
|
993
|
+
return {
|
|
994
|
+
checked: true,
|
|
995
|
+
updated: false,
|
|
996
|
+
reason: `runtime is pinned to ${pin}`,
|
|
997
|
+
activeVersion: activeVersion2,
|
|
998
|
+
latestVersion: pin
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
const installed2 = await install({
|
|
1002
|
+
version: pin,
|
|
1003
|
+
channel,
|
|
1004
|
+
cdnOrigin,
|
|
1005
|
+
setActive: false
|
|
1006
|
+
});
|
|
1007
|
+
return {
|
|
1008
|
+
checked: true,
|
|
1009
|
+
updated: true,
|
|
1010
|
+
reason: `runtime is pinned to ${pin}`,
|
|
1011
|
+
activeVersion: pin,
|
|
1012
|
+
latestVersion: pin,
|
|
1013
|
+
install: installed2
|
|
1014
|
+
};
|
|
948
1015
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
import_fs2.default.rmSync(tmpDir, { recursive: true, force: true });
|
|
953
|
-
throw err;
|
|
954
|
-
}
|
|
955
|
-
if (setActive) writeActiveRuntime(version);
|
|
956
|
-
return {
|
|
957
|
-
version,
|
|
958
|
-
channel,
|
|
959
|
-
cdnOrigin,
|
|
960
|
-
runtimeDir: destDir,
|
|
961
|
-
installed: true,
|
|
962
|
-
activated: setActive,
|
|
963
|
-
manifest
|
|
964
|
-
};
|
|
965
|
-
}
|
|
966
|
-
async function updateRuntimeToLatest(opts = {}) {
|
|
967
|
-
ensureSootsimHome();
|
|
968
|
-
const cdnOrigin = resolveRuntimeCdnOrigin(opts.cdnOrigin);
|
|
969
|
-
const channel = resolveRuntimeChannel(opts.channel);
|
|
970
|
-
const pin = resolveRuntimePin();
|
|
971
|
-
if (pin) {
|
|
972
|
-
const activeVersion2 = readActiveRuntime();
|
|
973
|
-
const pinInstalled = import_fs2.default.existsSync(import_path2.default.join(runtimeDir(pin), "index.html"));
|
|
974
|
-
if (activeVersion2 === pin && pinInstalled) {
|
|
1016
|
+
const manifest = await fetchManifest(cdnOrigin);
|
|
1017
|
+
const latestVersion = manifest.channels[channel]?.latest;
|
|
1018
|
+
if (!latestVersion) {
|
|
975
1019
|
return {
|
|
976
1020
|
checked: true,
|
|
977
1021
|
updated: false,
|
|
978
|
-
reason: `
|
|
979
|
-
activeVersion:
|
|
980
|
-
|
|
1022
|
+
reason: `channel '${channel}' has no latest runtime`,
|
|
1023
|
+
activeVersion: product.readActiveRuntime()
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
const entry = manifest.versions[latestVersion];
|
|
1027
|
+
if (!entry) {
|
|
1028
|
+
return {
|
|
1029
|
+
checked: true,
|
|
1030
|
+
updated: false,
|
|
1031
|
+
reason: `manifest is missing version ${latestVersion}`,
|
|
1032
|
+
activeVersion: product.readActiveRuntime(),
|
|
1033
|
+
latestVersion
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
const activeVersion = product.readActiveRuntime();
|
|
1037
|
+
const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
|
|
1038
|
+
const activeInstalled = activeDir ? import_node_fs4.default.existsSync(import_node_path3.default.join(activeDir, product.installedMarker)) : false;
|
|
1039
|
+
const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
|
|
1040
|
+
if (!shouldInstall) {
|
|
1041
|
+
return {
|
|
1042
|
+
checked: true,
|
|
1043
|
+
updated: false,
|
|
1044
|
+
reason: "active runtime is current",
|
|
1045
|
+
activeVersion,
|
|
1046
|
+
latestVersion
|
|
981
1047
|
};
|
|
982
1048
|
}
|
|
983
|
-
const
|
|
984
|
-
version:
|
|
1049
|
+
const installed = await install({
|
|
1050
|
+
version: latestVersion,
|
|
985
1051
|
channel,
|
|
986
1052
|
cdnOrigin,
|
|
987
1053
|
setActive: false
|
|
@@ -989,57 +1055,40 @@ async function updateRuntimeToLatest(opts = {}) {
|
|
|
989
1055
|
return {
|
|
990
1056
|
checked: true,
|
|
991
1057
|
updated: true,
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
install: install2
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
const manifest = await fetchRuntimeManifest(cdnOrigin);
|
|
999
|
-
const latestVersion = manifest.channels[channel]?.latest;
|
|
1000
|
-
if (!latestVersion) {
|
|
1001
|
-
return {
|
|
1002
|
-
checked: true,
|
|
1003
|
-
updated: false,
|
|
1004
|
-
reason: `channel '${channel}' has no latest runtime`,
|
|
1005
|
-
activeVersion: readActiveRuntime()
|
|
1058
|
+
activeVersion: latestVersion,
|
|
1059
|
+
latestVersion,
|
|
1060
|
+
install: installed
|
|
1006
1061
|
};
|
|
1007
1062
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
return {
|
|
1024
|
-
checked: true,
|
|
1025
|
-
updated: false,
|
|
1026
|
-
reason: "active runtime is current",
|
|
1027
|
-
activeVersion,
|
|
1028
|
-
latestVersion
|
|
1029
|
-
};
|
|
1063
|
+
async function checkUpToDate(opts = {}) {
|
|
1064
|
+
const active = product.readActiveRuntime();
|
|
1065
|
+
const pinned = resolvePin();
|
|
1066
|
+
if (pinned) {
|
|
1067
|
+
return { active, latest: pinned, pinned, outdated: active !== pinned };
|
|
1068
|
+
}
|
|
1069
|
+
try {
|
|
1070
|
+
const manifest = await fetchManifest(resolveCdnOrigin(opts.cdnOrigin));
|
|
1071
|
+
const channel = resolveChannel(opts.channel);
|
|
1072
|
+
const latest = manifest.channels[channel]?.latest ?? null;
|
|
1073
|
+
const outdated = !!(latest && (!active || compareSemver(latest, active) > 0));
|
|
1074
|
+
return { active, latest, pinned: null, outdated };
|
|
1075
|
+
} catch {
|
|
1076
|
+
return { active, latest: null, pinned: null, outdated: false };
|
|
1077
|
+
}
|
|
1030
1078
|
}
|
|
1031
|
-
const install = await installRuntime({
|
|
1032
|
-
version: latestVersion,
|
|
1033
|
-
channel,
|
|
1034
|
-
cdnOrigin,
|
|
1035
|
-
setActive: false
|
|
1036
|
-
});
|
|
1037
1079
|
return {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1080
|
+
product,
|
|
1081
|
+
resolveCdnOrigin,
|
|
1082
|
+
resolveChannel,
|
|
1083
|
+
resolvePin,
|
|
1084
|
+
manifestUrl,
|
|
1085
|
+
tarballUrl,
|
|
1086
|
+
fetchManifest,
|
|
1087
|
+
resolveVersion,
|
|
1088
|
+
install,
|
|
1089
|
+
updateToLatest,
|
|
1090
|
+
checkUpToDate,
|
|
1091
|
+
listInstalled: () => listInstalledRuntimes(product)
|
|
1043
1092
|
};
|
|
1044
1093
|
}
|
|
1045
1094
|
async function downloadToFile(url, destPath) {
|
|
@@ -1047,17 +1096,17 @@ async function downloadToFile(url, destPath) {
|
|
|
1047
1096
|
if (!res.ok || !res.body) {
|
|
1048
1097
|
throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
|
|
1049
1098
|
}
|
|
1050
|
-
|
|
1099
|
+
import_node_fs4.default.mkdirSync(import_node_path3.default.dirname(destPath), { recursive: true });
|
|
1051
1100
|
const tmp = `${destPath}.partial`;
|
|
1052
1101
|
try {
|
|
1053
1102
|
await (0, import_promises.pipeline)(
|
|
1054
|
-
|
|
1055
|
-
|
|
1103
|
+
import_node_stream.Readable.fromWeb(res.body),
|
|
1104
|
+
import_node_fs4.default.createWriteStream(tmp)
|
|
1056
1105
|
);
|
|
1057
|
-
|
|
1106
|
+
import_node_fs4.default.renameSync(tmp, destPath);
|
|
1058
1107
|
} catch (err) {
|
|
1059
1108
|
try {
|
|
1060
|
-
|
|
1109
|
+
import_node_fs4.default.unlinkSync(tmp);
|
|
1061
1110
|
} catch {
|
|
1062
1111
|
}
|
|
1063
1112
|
throw err;
|
|
@@ -1065,8 +1114,8 @@ async function downloadToFile(url, destPath) {
|
|
|
1065
1114
|
}
|
|
1066
1115
|
function sha256File(filePath) {
|
|
1067
1116
|
return new Promise((resolve, reject) => {
|
|
1068
|
-
const hash =
|
|
1069
|
-
const stream =
|
|
1117
|
+
const hash = import_node_crypto.default.createHash("sha256");
|
|
1118
|
+
const stream = import_node_fs4.default.createReadStream(filePath);
|
|
1070
1119
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
1071
1120
|
stream.on("error", reject);
|
|
1072
1121
|
stream.on("end", () => resolve(hash.digest("hex")));
|
|
@@ -1074,7 +1123,7 @@ function sha256File(filePath) {
|
|
|
1074
1123
|
}
|
|
1075
1124
|
function extractTarball(tarPath, destDir) {
|
|
1076
1125
|
return new Promise((resolve, reject) => {
|
|
1077
|
-
const child = (0,
|
|
1126
|
+
const child = (0, import_node_child_process.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
|
|
1078
1127
|
stdio: ["ignore", "inherit", "inherit"]
|
|
1079
1128
|
});
|
|
1080
1129
|
child.on("error", reject);
|
|
@@ -1085,15 +1134,41 @@ function extractTarball(tarPath, destDir) {
|
|
|
1085
1134
|
});
|
|
1086
1135
|
}
|
|
1087
1136
|
|
|
1137
|
+
// src/runtime-delivery.ts
|
|
1138
|
+
var DEFAULT_RUNTIME_CDN_ORIGIN = "https://contrast.dev";
|
|
1139
|
+
var SOOTSIM_RUNTIME_PRODUCT = {
|
|
1140
|
+
id: "sootsim",
|
|
1141
|
+
defaultCdnOrigin: DEFAULT_RUNTIME_CDN_ORIGIN,
|
|
1142
|
+
manifestPath: "/runtimes/manifest.json",
|
|
1143
|
+
tarballPath: (version) => `/runtimes/sootsim-runtime-${version}.tar.gz`,
|
|
1144
|
+
// the engine runtime is a static SPA: shell at the root, engine/ and
|
|
1145
|
+
// engine-tenant/ beneath it. index.html is what the daemon and the
|
|
1146
|
+
// vite/metro plugins serve, so its absence means the tarball is not one.
|
|
1147
|
+
installedMarker: "index.html",
|
|
1148
|
+
env: {
|
|
1149
|
+
cdnOrigin: "SOOTSIM_CDN_ORIGIN",
|
|
1150
|
+
channel: "SOOTSIM_RUNTIME_CHANNEL",
|
|
1151
|
+
pin: "SOOTSIM_RUNTIME_VERSION"
|
|
1152
|
+
},
|
|
1153
|
+
ensureHome: ensureSootsimHome,
|
|
1154
|
+
configFile: configFilePath,
|
|
1155
|
+
runtimesDir,
|
|
1156
|
+
runtimeDir,
|
|
1157
|
+
cacheDir,
|
|
1158
|
+
readActiveRuntime,
|
|
1159
|
+
writeActiveRuntime
|
|
1160
|
+
};
|
|
1161
|
+
var sootsimRuntime = createRuntimeDelivery(SOOTSIM_RUNTIME_PRODUCT);
|
|
1162
|
+
|
|
1088
1163
|
// src/host/agent-host.ts
|
|
1089
|
-
var
|
|
1090
|
-
var
|
|
1164
|
+
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
1165
|
+
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
1091
1166
|
|
|
1092
1167
|
// src/agent-sessions.ts
|
|
1093
|
-
var
|
|
1094
|
-
var
|
|
1095
|
-
var
|
|
1096
|
-
var
|
|
1168
|
+
var import_node_child_process2 = require("node:child_process");
|
|
1169
|
+
var import_node_crypto3 = require("node:crypto");
|
|
1170
|
+
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
1171
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
1097
1172
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
1098
1173
|
|
|
1099
1174
|
// src/agent-events.ts
|
|
@@ -1136,9 +1211,9 @@ function encodeAgentPromptEnvelope(input) {
|
|
|
1136
1211
|
}
|
|
1137
1212
|
|
|
1138
1213
|
// src/attached-projects.ts
|
|
1139
|
-
var
|
|
1140
|
-
var
|
|
1141
|
-
var
|
|
1214
|
+
var import_node_crypto2 = require("node:crypto");
|
|
1215
|
+
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
1216
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
1142
1217
|
var overrideDir = null;
|
|
1143
1218
|
function userDataDir() {
|
|
1144
1219
|
if (overrideDir) return overrideDir;
|
|
@@ -1150,7 +1225,7 @@ function getUserDataDir() {
|
|
|
1150
1225
|
return userDataDir();
|
|
1151
1226
|
}
|
|
1152
1227
|
function storeFile() {
|
|
1153
|
-
return
|
|
1228
|
+
return import_node_path4.default.join(userDataDir(), "attached-projects.json");
|
|
1154
1229
|
}
|
|
1155
1230
|
function cloneEmpty() {
|
|
1156
1231
|
return {
|
|
@@ -1164,7 +1239,7 @@ function loadStore() {
|
|
|
1164
1239
|
const file = storeFile();
|
|
1165
1240
|
let raw;
|
|
1166
1241
|
try {
|
|
1167
|
-
raw =
|
|
1242
|
+
raw = import_node_fs5.default.readFileSync(file, "utf8");
|
|
1168
1243
|
} catch (err) {
|
|
1169
1244
|
if (err.code === "ENOENT") return cloneEmpty();
|
|
1170
1245
|
throw err;
|
|
@@ -1181,7 +1256,7 @@ function loadStore() {
|
|
|
1181
1256
|
} catch (err) {
|
|
1182
1257
|
const quarantine = `${file}.corrupt-${Date.now()}`;
|
|
1183
1258
|
try {
|
|
1184
|
-
|
|
1259
|
+
import_node_fs5.default.renameSync(file, quarantine);
|
|
1185
1260
|
console.warn(
|
|
1186
1261
|
`[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
|
|
1187
1262
|
);
|
|
@@ -1192,16 +1267,16 @@ function loadStore() {
|
|
|
1192
1267
|
}
|
|
1193
1268
|
function writeStore(store) {
|
|
1194
1269
|
const file = storeFile();
|
|
1195
|
-
|
|
1270
|
+
import_node_fs5.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
|
|
1196
1271
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
1197
|
-
const fd =
|
|
1272
|
+
const fd = import_node_fs5.default.openSync(tmp, "w", 384);
|
|
1198
1273
|
try {
|
|
1199
|
-
|
|
1200
|
-
|
|
1274
|
+
import_node_fs5.default.writeFileSync(fd, JSON.stringify(store, null, 2));
|
|
1275
|
+
import_node_fs5.default.fsyncSync(fd);
|
|
1201
1276
|
} finally {
|
|
1202
|
-
|
|
1277
|
+
import_node_fs5.default.closeSync(fd);
|
|
1203
1278
|
}
|
|
1204
|
-
|
|
1279
|
+
import_node_fs5.default.renameSync(tmp, file);
|
|
1205
1280
|
}
|
|
1206
1281
|
function mutateStore(fn) {
|
|
1207
1282
|
const store = loadStore();
|
|
@@ -1210,13 +1285,13 @@ function mutateStore(fn) {
|
|
|
1210
1285
|
return store;
|
|
1211
1286
|
}
|
|
1212
1287
|
function projectIdForCwd(cwd) {
|
|
1213
|
-
return (0,
|
|
1288
|
+
return (0, import_node_crypto2.createHash)("sha256").update(import_node_path4.default.resolve(cwd)).digest("hex").slice(0, 16);
|
|
1214
1289
|
}
|
|
1215
1290
|
function newSessionId() {
|
|
1216
|
-
return `s_${(0,
|
|
1291
|
+
return `s_${(0, import_node_crypto2.randomBytes)(10).toString("hex")}`;
|
|
1217
1292
|
}
|
|
1218
1293
|
function upsertProject(input) {
|
|
1219
|
-
const cwd =
|
|
1294
|
+
const cwd = import_node_path4.default.resolve(input.cwd);
|
|
1220
1295
|
const id = projectIdForCwd(cwd);
|
|
1221
1296
|
let result;
|
|
1222
1297
|
mutateStore((store) => {
|
|
@@ -1242,7 +1317,7 @@ function upsertProject(input) {
|
|
|
1242
1317
|
const now = Date.now();
|
|
1243
1318
|
const created = {
|
|
1244
1319
|
id,
|
|
1245
|
-
name: input.name ??
|
|
1320
|
+
name: input.name ?? import_node_path4.default.basename(cwd),
|
|
1246
1321
|
cwd,
|
|
1247
1322
|
repoRoot: input.repoRoot,
|
|
1248
1323
|
sourceRoots: input.sourceRoots ?? [cwd],
|
|
@@ -1372,8 +1447,8 @@ async function seedFromDemoAppRegistry() {
|
|
|
1372
1447
|
if (apps.length === 0) return;
|
|
1373
1448
|
mutateStore((store) => {
|
|
1374
1449
|
for (const app of apps) {
|
|
1375
|
-
if (!
|
|
1376
|
-
const cwd =
|
|
1450
|
+
if (!import_node_fs5.default.existsSync(app.dir)) continue;
|
|
1451
|
+
const cwd = import_node_path4.default.resolve(app.dir);
|
|
1377
1452
|
const id = projectIdForCwd(cwd);
|
|
1378
1453
|
if (store.attachedProjects.some((p) => p.id === id)) continue;
|
|
1379
1454
|
const now = Date.now();
|
|
@@ -1397,16 +1472,16 @@ async function seedFromDemoAppRegistry() {
|
|
|
1397
1472
|
|
|
1398
1473
|
// src/agent-sessions.ts
|
|
1399
1474
|
function sessionDir(sessionId) {
|
|
1400
|
-
return
|
|
1475
|
+
return import_node_path5.default.join(getUserDataDir(), "sessions", sessionId);
|
|
1401
1476
|
}
|
|
1402
1477
|
function promptFifoPath(sessionId) {
|
|
1403
|
-
return
|
|
1478
|
+
return import_node_path5.default.join(sessionDir(sessionId), "prompt.in");
|
|
1404
1479
|
}
|
|
1405
1480
|
function eventsFifoPath(sessionId) {
|
|
1406
|
-
return
|
|
1481
|
+
return import_node_path5.default.join(sessionDir(sessionId), "events.out");
|
|
1407
1482
|
}
|
|
1408
1483
|
function transcriptPath(sessionId) {
|
|
1409
|
-
return
|
|
1484
|
+
return import_node_path5.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
|
|
1410
1485
|
}
|
|
1411
1486
|
function pidIsAlive(pid, sessionId) {
|
|
1412
1487
|
if (!pid) return false;
|
|
@@ -1416,7 +1491,7 @@ function pidIsAlive(pid, sessionId) {
|
|
|
1416
1491
|
return false;
|
|
1417
1492
|
}
|
|
1418
1493
|
if (sessionId) {
|
|
1419
|
-
if (!
|
|
1494
|
+
if (!import_node_fs6.default.existsSync(sessionDir(sessionId))) return false;
|
|
1420
1495
|
}
|
|
1421
1496
|
return true;
|
|
1422
1497
|
}
|
|
@@ -1428,11 +1503,11 @@ function resolveSootsimInvocation() {
|
|
|
1428
1503
|
const resourcesPath = process.resourcesPath;
|
|
1429
1504
|
if (resourcesPath) {
|
|
1430
1505
|
const candidates = [
|
|
1431
|
-
|
|
1432
|
-
|
|
1506
|
+
import_node_path5.default.join(resourcesPath, "bin", "sootsim"),
|
|
1507
|
+
import_node_path5.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
|
|
1433
1508
|
];
|
|
1434
1509
|
for (const c of candidates) {
|
|
1435
|
-
if (
|
|
1510
|
+
if (import_node_fs6.default.existsSync(c)) return { cmd: c, prefixArgs: [] };
|
|
1436
1511
|
}
|
|
1437
1512
|
}
|
|
1438
1513
|
}
|
|
@@ -1455,15 +1530,15 @@ function tryWorkspaceSootsim() {
|
|
|
1455
1530
|
const sootsimDir = resolveSootsimPackageDir();
|
|
1456
1531
|
if (!sootsimDir) return null;
|
|
1457
1532
|
const binaryName = `sootsim-${process.platform}-${process.arch}`;
|
|
1458
|
-
const distBinary =
|
|
1459
|
-
if (
|
|
1460
|
-
const distBin =
|
|
1461
|
-
if (
|
|
1533
|
+
const distBinary = import_node_path5.default.join(sootsimDir, "dist-bin", binaryName);
|
|
1534
|
+
if (import_node_fs6.default.existsSync(distBinary)) return { cmd: distBinary, prefixArgs: [] };
|
|
1535
|
+
const distBin = import_node_path5.default.join(sootsimDir, "dist-cli", "bin.js");
|
|
1536
|
+
if (import_node_fs6.default.existsSync(distBin)) {
|
|
1462
1537
|
try {
|
|
1463
|
-
const src =
|
|
1464
|
-
if (
|
|
1465
|
-
const srcMtime =
|
|
1466
|
-
const buildMtime =
|
|
1538
|
+
const src = import_node_path5.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
|
|
1539
|
+
if (import_node_fs6.default.existsSync(src)) {
|
|
1540
|
+
const srcMtime = import_node_fs6.default.statSync(src).mtimeMs;
|
|
1541
|
+
const buildMtime = import_node_fs6.default.statSync(distBin).mtimeMs;
|
|
1467
1542
|
if (buildMtime < srcMtime) {
|
|
1468
1543
|
console.warn(
|
|
1469
1544
|
`[sootsim] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/sootsim build:cli\`.`
|
|
@@ -1482,22 +1557,22 @@ function tryWorkspaceSootsim() {
|
|
|
1482
1557
|
function resolveSootsimPackageDir() {
|
|
1483
1558
|
try {
|
|
1484
1559
|
const resolved = require.resolve("sootsim/package.json");
|
|
1485
|
-
return
|
|
1560
|
+
return import_node_path5.default.dirname(resolved);
|
|
1486
1561
|
} catch {
|
|
1487
1562
|
}
|
|
1488
1563
|
const here = fileFromImportMeta();
|
|
1489
1564
|
if (!here) return null;
|
|
1490
|
-
let cur =
|
|
1565
|
+
let cur = import_node_path5.default.dirname(here);
|
|
1491
1566
|
for (let i = 0; i < 8; i++) {
|
|
1492
|
-
const pkg =
|
|
1567
|
+
const pkg = import_node_path5.default.join(cur, "package.json");
|
|
1493
1568
|
try {
|
|
1494
|
-
if (
|
|
1495
|
-
const parsed = JSON.parse(
|
|
1569
|
+
if (import_node_fs6.default.existsSync(pkg)) {
|
|
1570
|
+
const parsed = JSON.parse(import_node_fs6.default.readFileSync(pkg, "utf8"));
|
|
1496
1571
|
if (parsed.name === "sootsim") return cur;
|
|
1497
1572
|
}
|
|
1498
1573
|
} catch {
|
|
1499
1574
|
}
|
|
1500
|
-
const parent =
|
|
1575
|
+
const parent = import_node_path5.default.dirname(cur);
|
|
1501
1576
|
if (parent === cur) break;
|
|
1502
1577
|
cur = parent;
|
|
1503
1578
|
}
|
|
@@ -1513,28 +1588,28 @@ function fileFromImportMeta() {
|
|
|
1513
1588
|
}
|
|
1514
1589
|
}
|
|
1515
1590
|
async function withStartLock(projectId, provider, fn) {
|
|
1516
|
-
const lockDir =
|
|
1517
|
-
|
|
1591
|
+
const lockDir = import_node_path5.default.join(getUserDataDir(), "locks");
|
|
1592
|
+
import_node_fs6.default.mkdirSync(lockDir, { recursive: true });
|
|
1518
1593
|
try {
|
|
1519
|
-
|
|
1594
|
+
import_node_fs6.default.chmodSync(lockDir, 448);
|
|
1520
1595
|
} catch {
|
|
1521
1596
|
}
|
|
1522
|
-
const lockPath =
|
|
1597
|
+
const lockPath = import_node_path5.default.join(lockDir, `start-${projectId}-${provider}.lock`);
|
|
1523
1598
|
const deadline = Date.now() + 4e3;
|
|
1524
1599
|
let fd = null;
|
|
1525
1600
|
while (fd === null) {
|
|
1526
1601
|
try {
|
|
1527
|
-
fd =
|
|
1602
|
+
fd = import_node_fs6.default.openSync(
|
|
1528
1603
|
lockPath,
|
|
1529
|
-
|
|
1604
|
+
import_node_fs6.constants.O_WRONLY | import_node_fs6.constants.O_CREAT | import_node_fs6.constants.O_EXCL,
|
|
1530
1605
|
384
|
|
1531
1606
|
);
|
|
1532
1607
|
} catch (err) {
|
|
1533
1608
|
if (err.code !== "EEXIST") throw err;
|
|
1534
1609
|
try {
|
|
1535
|
-
const stale = Number(
|
|
1610
|
+
const stale = Number(import_node_fs6.default.readFileSync(lockPath, "utf8").trim());
|
|
1536
1611
|
if (stale && !isProcessAlive(stale)) {
|
|
1537
|
-
|
|
1612
|
+
import_node_fs6.default.unlinkSync(lockPath);
|
|
1538
1613
|
continue;
|
|
1539
1614
|
}
|
|
1540
1615
|
} catch {
|
|
@@ -1548,15 +1623,15 @@ async function withStartLock(projectId, provider, fn) {
|
|
|
1548
1623
|
}
|
|
1549
1624
|
}
|
|
1550
1625
|
try {
|
|
1551
|
-
|
|
1626
|
+
import_node_fs6.default.writeFileSync(fd, String(process.pid));
|
|
1552
1627
|
return await fn();
|
|
1553
1628
|
} finally {
|
|
1554
1629
|
try {
|
|
1555
|
-
|
|
1630
|
+
import_node_fs6.default.closeSync(fd);
|
|
1556
1631
|
} catch {
|
|
1557
1632
|
}
|
|
1558
1633
|
try {
|
|
1559
|
-
|
|
1634
|
+
import_node_fs6.default.unlinkSync(lockPath);
|
|
1560
1635
|
} catch {
|
|
1561
1636
|
}
|
|
1562
1637
|
}
|
|
@@ -1570,28 +1645,28 @@ function isProcessAlive(pid) {
|
|
|
1570
1645
|
}
|
|
1571
1646
|
}
|
|
1572
1647
|
function mkfifoSync(p) {
|
|
1573
|
-
const parent =
|
|
1574
|
-
|
|
1648
|
+
const parent = import_node_path5.default.dirname(p);
|
|
1649
|
+
import_node_fs6.default.mkdirSync(parent, { recursive: true });
|
|
1575
1650
|
try {
|
|
1576
|
-
|
|
1651
|
+
import_node_fs6.default.chmodSync(parent, 448);
|
|
1577
1652
|
} catch {
|
|
1578
1653
|
}
|
|
1579
|
-
if (
|
|
1654
|
+
if (import_node_fs6.default.existsSync(p)) {
|
|
1580
1655
|
try {
|
|
1581
|
-
const stat =
|
|
1656
|
+
const stat = import_node_fs6.default.statSync(p);
|
|
1582
1657
|
if (stat.isFIFO()) {
|
|
1583
1658
|
try {
|
|
1584
|
-
|
|
1659
|
+
import_node_fs6.default.chmodSync(p, 384);
|
|
1585
1660
|
} catch {
|
|
1586
1661
|
}
|
|
1587
1662
|
return;
|
|
1588
1663
|
}
|
|
1589
|
-
|
|
1664
|
+
import_node_fs6.default.unlinkSync(p);
|
|
1590
1665
|
} catch {
|
|
1591
|
-
|
|
1666
|
+
import_node_fs6.default.unlinkSync(p);
|
|
1592
1667
|
}
|
|
1593
1668
|
}
|
|
1594
|
-
const result = (0,
|
|
1669
|
+
const result = (0, import_node_child_process2.spawnSync)("mkfifo", ["-m", "600", p]);
|
|
1595
1670
|
if (result.status !== 0) {
|
|
1596
1671
|
throw new Error(
|
|
1597
1672
|
`mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
|
|
@@ -1621,7 +1696,7 @@ async function startSession(opts) {
|
|
|
1621
1696
|
`session already running for project=${project.id} provider=${provider} (session ${existingLive.id}, pid ${existingLive.wrapperPid}). end it first with \`sootsim agent end <sessionId>\`.`
|
|
1622
1697
|
);
|
|
1623
1698
|
}
|
|
1624
|
-
const claudeSessionUuid = provider === "claude" ? (0,
|
|
1699
|
+
const claudeSessionUuid = provider === "claude" ? (0, import_node_crypto3.randomUUID)() : void 0;
|
|
1625
1700
|
const session = upsertSession({
|
|
1626
1701
|
projectId: project.id,
|
|
1627
1702
|
provider,
|
|
@@ -1635,10 +1710,10 @@ async function startSession(opts) {
|
|
|
1635
1710
|
const transcript = transcriptPath(session.id);
|
|
1636
1711
|
mkfifoSync(promptIn);
|
|
1637
1712
|
mkfifoSync(eventsOut);
|
|
1638
|
-
const transcriptDir =
|
|
1639
|
-
|
|
1713
|
+
const transcriptDir = import_node_path5.default.dirname(transcript);
|
|
1714
|
+
import_node_fs6.default.mkdirSync(transcriptDir, { recursive: true });
|
|
1640
1715
|
try {
|
|
1641
|
-
|
|
1716
|
+
import_node_fs6.default.chmodSync(transcriptDir, 448);
|
|
1642
1717
|
} catch {
|
|
1643
1718
|
}
|
|
1644
1719
|
const { cmd, prefixArgs } = resolveSootsimInvocation();
|
|
@@ -1666,7 +1741,7 @@ async function startSession(opts) {
|
|
|
1666
1741
|
if (claudeSessionUuid) {
|
|
1667
1742
|
wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
|
|
1668
1743
|
}
|
|
1669
|
-
const child = (0,
|
|
1744
|
+
const child = (0, import_node_child_process2.spawn)(cmd, wrapperArgs, {
|
|
1670
1745
|
detached: true,
|
|
1671
1746
|
stdio: "ignore",
|
|
1672
1747
|
env: {
|
|
@@ -1689,7 +1764,7 @@ async function startSession(opts) {
|
|
|
1689
1764
|
}
|
|
1690
1765
|
}
|
|
1691
1766
|
try {
|
|
1692
|
-
|
|
1767
|
+
import_node_fs6.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
|
|
1693
1768
|
} catch {
|
|
1694
1769
|
}
|
|
1695
1770
|
updateSessionStatus(session.id, { status: "ended" });
|
|
@@ -1717,18 +1792,18 @@ async function sendPrompt(sessionId, prompt) {
|
|
|
1717
1792
|
);
|
|
1718
1793
|
}
|
|
1719
1794
|
const fifo = promptFifoPath(sessionId);
|
|
1720
|
-
if (!
|
|
1795
|
+
if (!import_node_fs6.default.existsSync(fifo)) {
|
|
1721
1796
|
throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
|
|
1722
1797
|
}
|
|
1723
|
-
const fd =
|
|
1798
|
+
const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_WRONLY);
|
|
1724
1799
|
try {
|
|
1725
1800
|
const wireText = encodeAgentPromptEnvelope(prompt);
|
|
1726
1801
|
if (!wireText) {
|
|
1727
1802
|
throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
|
|
1728
1803
|
}
|
|
1729
|
-
|
|
1804
|
+
import_node_fs6.default.writeSync(fd, wireText + "\n");
|
|
1730
1805
|
} finally {
|
|
1731
|
-
|
|
1806
|
+
import_node_fs6.default.closeSync(fd);
|
|
1732
1807
|
}
|
|
1733
1808
|
updateSessionStatus(sessionId, {
|
|
1734
1809
|
lastPrompt: prompt.displayText ?? prompt.text,
|
|
@@ -1750,7 +1825,7 @@ async function endSession(sessionId) {
|
|
|
1750
1825
|
const base = getUserDataDir();
|
|
1751
1826
|
if (dir.startsWith(base)) {
|
|
1752
1827
|
try {
|
|
1753
|
-
|
|
1828
|
+
import_node_fs6.default.rmSync(dir, { recursive: true, force: true });
|
|
1754
1829
|
} catch {
|
|
1755
1830
|
}
|
|
1756
1831
|
}
|
|
@@ -1758,11 +1833,11 @@ async function endSession(sessionId) {
|
|
|
1758
1833
|
}
|
|
1759
1834
|
function subscribeEvents(sessionId, onEvent) {
|
|
1760
1835
|
const fifo = eventsFifoPath(sessionId);
|
|
1761
|
-
if (!
|
|
1836
|
+
if (!import_node_fs6.default.existsSync(fifo)) {
|
|
1762
1837
|
throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
|
|
1763
1838
|
}
|
|
1764
|
-
const fd =
|
|
1765
|
-
const stream =
|
|
1839
|
+
const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR);
|
|
1840
|
+
const stream = import_node_fs6.default.createReadStream("", { fd, autoClose: true });
|
|
1766
1841
|
const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1767
1842
|
rl.on("line", (line) => {
|
|
1768
1843
|
const event = parseAgentEventLine(line);
|
|
@@ -1783,7 +1858,7 @@ function subscribeEvents(sessionId, onEvent) {
|
|
|
1783
1858
|
};
|
|
1784
1859
|
}
|
|
1785
1860
|
async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
1786
|
-
const fd =
|
|
1861
|
+
const fd = import_node_fs6.default.openSync(fifo, import_node_fs6.constants.O_RDWR | import_node_fs6.constants.O_NONBLOCK);
|
|
1787
1862
|
const buf = Buffer.alloc(8192);
|
|
1788
1863
|
let leftover = "";
|
|
1789
1864
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -1791,7 +1866,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
|
1791
1866
|
while (Date.now() < deadline) {
|
|
1792
1867
|
let n = 0;
|
|
1793
1868
|
try {
|
|
1794
|
-
n =
|
|
1869
|
+
n = import_node_fs6.default.readSync(fd, buf, 0, buf.length, null);
|
|
1795
1870
|
} catch (err) {
|
|
1796
1871
|
if (err.code !== "EAGAIN") throw err;
|
|
1797
1872
|
n = 0;
|
|
@@ -1811,15 +1886,15 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
|
1811
1886
|
}
|
|
1812
1887
|
return null;
|
|
1813
1888
|
} finally {
|
|
1814
|
-
|
|
1889
|
+
import_node_fs6.default.closeSync(fd);
|
|
1815
1890
|
}
|
|
1816
1891
|
}
|
|
1817
1892
|
|
|
1818
1893
|
// src/agentbus-prompt.ts
|
|
1819
|
-
var
|
|
1820
|
-
var
|
|
1894
|
+
var import_node_child_process3 = require("node:child_process");
|
|
1895
|
+
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
1821
1896
|
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
1822
|
-
var
|
|
1897
|
+
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
1823
1898
|
|
|
1824
1899
|
// src/agent-identity.ts
|
|
1825
1900
|
var AGENTBUS_SESSION_RE = /^[A-Za-z0-9._:-]{1,160}$/;
|
|
@@ -1842,8 +1917,8 @@ function resolveAgentbusCommand(explicit) {
|
|
|
1842
1917
|
if (fromArg) return fromArg;
|
|
1843
1918
|
const fromEnv = process.env.AGENTBUS_COMMAND?.trim();
|
|
1844
1919
|
if (fromEnv) return fromEnv;
|
|
1845
|
-
const localBin =
|
|
1846
|
-
if (
|
|
1920
|
+
const localBin = import_node_path6.default.join(import_node_os2.default.homedir(), ".local", "bin", "agentbus");
|
|
1921
|
+
if (import_node_fs7.default.existsSync(localBin)) return localBin;
|
|
1847
1922
|
return "agentbus";
|
|
1848
1923
|
}
|
|
1849
1924
|
async function sendPromptToAgentbusSession(input) {
|
|
@@ -1858,7 +1933,7 @@ async function sendPromptToAgentbusSession(input) {
|
|
|
1858
1933
|
const command = resolveAgentbusCommand(input.command);
|
|
1859
1934
|
const timeoutMs = input.timeoutMs ?? 15e3;
|
|
1860
1935
|
await new Promise((resolve, reject) => {
|
|
1861
|
-
const child = (0,
|
|
1936
|
+
const child = (0, import_node_child_process3.spawn)(command, ["send", sessionId, text], {
|
|
1862
1937
|
stdio: ["ignore", "ignore", "pipe"],
|
|
1863
1938
|
env: process.env
|
|
1864
1939
|
});
|
|
@@ -2084,7 +2159,7 @@ var AgentHost = class {
|
|
|
2084
2159
|
);
|
|
2085
2160
|
const project = upsertProject({
|
|
2086
2161
|
cwd: match.cwd,
|
|
2087
|
-
name: match.projectName ??
|
|
2162
|
+
name: match.projectName ?? import_node_path7.default.basename(match.cwd),
|
|
2088
2163
|
preferredProvider: input.provider ?? existing?.preferredProvider,
|
|
2089
2164
|
sourceRoots: existing?.sourceRoots ?? [match.cwd],
|
|
2090
2165
|
knownBundleUrls,
|
|
@@ -2095,18 +2170,18 @@ var AgentHost = class {
|
|
|
2095
2170
|
}
|
|
2096
2171
|
getTranscript(sessionId) {
|
|
2097
2172
|
const p = transcriptPath(sessionId);
|
|
2098
|
-
if (!
|
|
2173
|
+
if (!import_node_fs8.default.existsSync(p)) {
|
|
2099
2174
|
return { error: "transcript not found", code: "NO_TRANSCRIPT" };
|
|
2100
2175
|
}
|
|
2101
|
-
return
|
|
2176
|
+
return import_node_fs8.default.readFileSync(p, "utf8");
|
|
2102
2177
|
}
|
|
2103
2178
|
getPaths() {
|
|
2104
2179
|
const dir = getUserDataDir();
|
|
2105
2180
|
return {
|
|
2106
2181
|
userDataDir: dir,
|
|
2107
|
-
storeFile:
|
|
2108
|
-
sessionsDir:
|
|
2109
|
-
transcriptsDir:
|
|
2182
|
+
storeFile: import_node_path7.default.join(dir, "attached-projects.json"),
|
|
2183
|
+
sessionsDir: import_node_path7.default.join(dir, "sessions"),
|
|
2184
|
+
transcriptsDir: import_node_path7.default.join(dir, "transcripts")
|
|
2110
2185
|
};
|
|
2111
2186
|
}
|
|
2112
2187
|
// --- subscription management ---
|
|
@@ -2691,10 +2766,10 @@ function handleAppApiRequest(req, res) {
|
|
|
2691
2766
|
}
|
|
2692
2767
|
|
|
2693
2768
|
// src/host/open-url.ts
|
|
2694
|
-
var
|
|
2695
|
-
var
|
|
2769
|
+
var import_child_process2 = require("child_process");
|
|
2770
|
+
var import_fs2 = require("fs");
|
|
2696
2771
|
var import_os = require("os");
|
|
2697
|
-
var
|
|
2772
|
+
var import_path2 = require("path");
|
|
2698
2773
|
var MAC_CHROMIUM_CANDIDATES = [
|
|
2699
2774
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
2700
2775
|
"~/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
@@ -2732,19 +2807,19 @@ var UNIX_CHROMIUM_COMMANDS = [
|
|
|
2732
2807
|
];
|
|
2733
2808
|
var WINDOWS_CHROMIUM_COMMANDS = ["chrome", "msedge", "brave"];
|
|
2734
2809
|
function expandHome(candidate) {
|
|
2735
|
-
return candidate.startsWith("~/") ? (0,
|
|
2810
|
+
return candidate.startsWith("~/") ? (0, import_path2.join)((0, import_os.homedir)(), candidate.slice(2)) : candidate;
|
|
2736
2811
|
}
|
|
2737
2812
|
function firstExisting(candidates) {
|
|
2738
2813
|
for (const candidate of candidates) {
|
|
2739
2814
|
const expanded = expandHome(candidate);
|
|
2740
|
-
if ((0,
|
|
2815
|
+
if ((0, import_fs2.existsSync)(expanded)) return expanded;
|
|
2741
2816
|
}
|
|
2742
2817
|
return null;
|
|
2743
2818
|
}
|
|
2744
2819
|
function lookupExecutable(command, platform) {
|
|
2745
2820
|
try {
|
|
2746
2821
|
const tool = platform === "win32" ? "where" : "which";
|
|
2747
|
-
const out = (0,
|
|
2822
|
+
const out = (0, import_child_process2.execFileSync)(tool, [command], {
|
|
2748
2823
|
encoding: "utf8",
|
|
2749
2824
|
timeout: 1500,
|
|
2750
2825
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -2756,7 +2831,7 @@ function lookupExecutable(command, platform) {
|
|
|
2756
2831
|
}
|
|
2757
2832
|
function resolveChromiumBinary(platform = process.platform) {
|
|
2758
2833
|
const envCandidate = process.env.CHROME_PATH || process.env.CHROMIUM_PATH;
|
|
2759
|
-
if (envCandidate && (0,
|
|
2834
|
+
if (envCandidate && (0, import_fs2.existsSync)(envCandidate)) return envCandidate;
|
|
2760
2835
|
const direct = platform === "darwin" ? firstExisting(MAC_CHROMIUM_CANDIDATES) : platform === "win32" ? firstExisting(WINDOWS_CHROMIUM_CANDIDATES) : firstExisting(LINUX_CHROMIUM_CANDIDATES);
|
|
2761
2836
|
if (direct) return direct;
|
|
2762
2837
|
const commands = platform === "win32" ? WINDOWS_CHROMIUM_COMMANDS : UNIX_CHROMIUM_COMMANDS;
|
|
@@ -2813,7 +2888,7 @@ function buildChromiumUrlCommand(url, options = {}) {
|
|
|
2813
2888
|
}
|
|
2814
2889
|
async function spawnLaunch(command, args, detached) {
|
|
2815
2890
|
return new Promise((resolve, reject) => {
|
|
2816
|
-
const child = (0,
|
|
2891
|
+
const child = (0, import_child_process2.spawn)(command, args, {
|
|
2817
2892
|
detached,
|
|
2818
2893
|
stdio: "ignore"
|
|
2819
2894
|
});
|
|
@@ -3328,7 +3403,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
3328
3403
|
return;
|
|
3329
3404
|
}
|
|
3330
3405
|
if (msg.type === "runtime:list") {
|
|
3331
|
-
const versions =
|
|
3406
|
+
const versions = sootsimRuntime.listInstalled();
|
|
3332
3407
|
const active = this.getActiveRuntime();
|
|
3333
3408
|
const reply = {
|
|
3334
3409
|
type: "runtime:list:ok",
|
|
@@ -3345,7 +3420,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
3345
3420
|
}
|
|
3346
3421
|
if (msg.type === "runtime:use") {
|
|
3347
3422
|
const version = typeof msg.version === "string" ? msg.version : "";
|
|
3348
|
-
const installed =
|
|
3423
|
+
const installed = sootsimRuntime.listInstalled();
|
|
3349
3424
|
if (!installed.includes(version)) {
|
|
3350
3425
|
try {
|
|
3351
3426
|
ws.send(
|
|
@@ -3874,7 +3949,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
3874
3949
|
if (reason === "startup") {
|
|
3875
3950
|
process.stderr.write("sootsim: checking for runtime updates\u2026\n");
|
|
3876
3951
|
}
|
|
3877
|
-
const result = await
|
|
3952
|
+
const result = await sootsimRuntime.updateToLatest();
|
|
3878
3953
|
if (!result.updated || !result.latestVersion) {
|
|
3879
3954
|
if (reason === "startup") {
|
|
3880
3955
|
process.stderr.write(
|
|
@@ -4110,34 +4185,34 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4110
4185
|
return;
|
|
4111
4186
|
}
|
|
4112
4187
|
}
|
|
4113
|
-
const resolved =
|
|
4114
|
-
const baseWithSep = baseDir.endsWith(
|
|
4188
|
+
const resolved = import_path3.default.resolve(baseDir, "." + rel);
|
|
4189
|
+
const baseWithSep = baseDir.endsWith(import_path3.default.sep) ? baseDir : baseDir + import_path3.default.sep;
|
|
4115
4190
|
if (!resolved.startsWith(baseWithSep) && resolved !== baseDir) {
|
|
4116
4191
|
res.writeHead(403);
|
|
4117
4192
|
res.end("forbidden");
|
|
4118
4193
|
return;
|
|
4119
4194
|
}
|
|
4120
|
-
|
|
4195
|
+
import_fs3.default.realpath(resolved, (realErr, realResolved) => {
|
|
4121
4196
|
const servePath = realErr ? resolved : realResolved;
|
|
4122
|
-
const servePathWithSep = servePath.endsWith(
|
|
4197
|
+
const servePathWithSep = servePath.endsWith(import_path3.default.sep) ? servePath : servePath + import_path3.default.sep;
|
|
4123
4198
|
if (!realErr) {
|
|
4124
4199
|
const realBaseWithSep = (() => {
|
|
4125
4200
|
try {
|
|
4126
|
-
const rb =
|
|
4127
|
-
return rb.endsWith(
|
|
4201
|
+
const rb = import_fs3.default.realpathSync(baseDir);
|
|
4202
|
+
return rb.endsWith(import_path3.default.sep) ? rb : rb + import_path3.default.sep;
|
|
4128
4203
|
} catch {
|
|
4129
4204
|
return baseWithSep;
|
|
4130
4205
|
}
|
|
4131
4206
|
})();
|
|
4132
|
-
if (!servePathWithSep.startsWith(realBaseWithSep) && servePath +
|
|
4207
|
+
if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path3.default.sep !== realBaseWithSep) {
|
|
4133
4208
|
res.writeHead(403);
|
|
4134
4209
|
res.end("forbidden");
|
|
4135
4210
|
return;
|
|
4136
4211
|
}
|
|
4137
4212
|
}
|
|
4138
|
-
|
|
4213
|
+
import_fs3.default.stat(servePath, (err, stats) => {
|
|
4139
4214
|
if (err || !stats?.isFile()) {
|
|
4140
|
-
const ext2 =
|
|
4215
|
+
const ext2 = import_path3.default.extname(rel).toLowerCase();
|
|
4141
4216
|
if (ext2 && ext2 !== ".html") {
|
|
4142
4217
|
res.writeHead(404);
|
|
4143
4218
|
res.end("not found");
|
|
@@ -4148,8 +4223,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4148
4223
|
res.end("not found");
|
|
4149
4224
|
return;
|
|
4150
4225
|
}
|
|
4151
|
-
const indexPath =
|
|
4152
|
-
|
|
4226
|
+
const indexPath = import_path3.default.join(baseDir, "index.html");
|
|
4227
|
+
import_fs3.default.readFile(indexPath, (err2, data) => {
|
|
4153
4228
|
if (err2) {
|
|
4154
4229
|
res.writeHead(404);
|
|
4155
4230
|
res.end("not found");
|
|
@@ -4169,7 +4244,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4169
4244
|
});
|
|
4170
4245
|
return;
|
|
4171
4246
|
}
|
|
4172
|
-
const ext =
|
|
4247
|
+
const ext = import_path3.default.extname(servePath).toLowerCase();
|
|
4173
4248
|
const contentType = HTTP_MIME_TYPES[ext] || "application/octet-stream";
|
|
4174
4249
|
res.writeHead(200, {
|
|
4175
4250
|
"Content-Type": contentType,
|
|
@@ -4180,7 +4255,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4180
4255
|
return;
|
|
4181
4256
|
}
|
|
4182
4257
|
if (ext === ".html") {
|
|
4183
|
-
|
|
4258
|
+
import_fs3.default.readFile(servePath, (readErr, data) => {
|
|
4184
4259
|
if (readErr) {
|
|
4185
4260
|
try {
|
|
4186
4261
|
res.end();
|
|
@@ -4194,7 +4269,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4194
4269
|
});
|
|
4195
4270
|
return;
|
|
4196
4271
|
}
|
|
4197
|
-
const stream =
|
|
4272
|
+
const stream = import_fs3.default.createReadStream(servePath);
|
|
4198
4273
|
stream.pipe(res);
|
|
4199
4274
|
stream.on("error", () => {
|
|
4200
4275
|
try {
|
|
@@ -4400,7 +4475,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
4400
4475
|
const target = `${filePath}${loc}`;
|
|
4401
4476
|
const trySpawn = (cmd, args) => new Promise((resolve) => {
|
|
4402
4477
|
try {
|
|
4403
|
-
const child = (0,
|
|
4478
|
+
const child = (0, import_child_process3.spawn)(cmd, args, { detached: true, stdio: "ignore" });
|
|
4404
4479
|
let settled = false;
|
|
4405
4480
|
child.on("error", () => {
|
|
4406
4481
|
if (settled) return;
|