peachsim 0.1.626 → 0.1.627
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 +3 -2
- package/cli/commands/box/bundle-plane.ts +7 -2
- package/cli/commands/box.ts +9 -2
- package/cli/commands/control.ts +32 -1
- package/cli/commands/flow.ts +17 -6
- package/cli/commands/maestro-generate.ts +5 -12
- package/cli/commands/maestro.ts +16 -6
- package/cli/commands/platform.ts +1 -0
- package/cli/commands/test.ts +14 -0
- package/cli/commands/upload.ts +18 -8
- package/cli/drivers/playwright-sim-host.ts +10 -3
- package/cli/drivers/playwright.ts +8 -5
- package/cli/run-rnx.ts +8 -4
- package/dist-lib/agent-daemon-client.cjs +2 -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 +4 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +18 -8
- package/dist-lib/capture-contract.mjs +18 -8
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +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 +239 -102
- 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/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +19 -8
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +215 -28
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +292 -128
- package/dist-lib/swift-compile.cjs +1 -1
- package/dist-lib/swift-compile.mjs +1 -1
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +14488 -14349
- package/dist-lib/vite-kotlin.cjs +1 -1
- package/dist-lib/vite-swift.cjs +1 -1
- package/dist-lib/vite.cjs +2 -1
- package/install.mjs +16 -0
- package/install.sh +199 -0
- package/package.json +6 -1
- package/scripts/dev-server-scanner.ts +77 -46
- package/src/bridge-constants.ts +11 -0
- package/src/capture-contract.ts +40 -7
- package/src/host/bridge-host.ts +24 -103
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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;
|
|
@@ -587,8 +587,8 @@ var init_shared_session = __esm({
|
|
|
587
587
|
});
|
|
588
588
|
|
|
589
589
|
// cli/run-rnx.ts
|
|
590
|
-
function peachExit(code) {
|
|
591
|
-
throw new PeachExit(code);
|
|
590
|
+
function peachExit(code, reason) {
|
|
591
|
+
throw new PeachExit(code, reason);
|
|
592
592
|
}
|
|
593
593
|
var import_node_async_hooks, PeachExit, sinks, rnxExit;
|
|
594
594
|
var init_run_rnx = __esm({
|
|
@@ -597,10 +597,12 @@ var init_run_rnx = __esm({
|
|
|
597
597
|
import_node_async_hooks = require("node:async_hooks");
|
|
598
598
|
PeachExit = class extends Error {
|
|
599
599
|
code;
|
|
600
|
-
|
|
600
|
+
reason;
|
|
601
|
+
constructor(code, reason = null) {
|
|
601
602
|
super(`peach exited with code ${code}`);
|
|
602
603
|
this.name = "PeachExit";
|
|
603
604
|
this.code = code;
|
|
605
|
+
this.reason = reason;
|
|
604
606
|
}
|
|
605
607
|
};
|
|
606
608
|
sinks = new import_node_async_hooks.AsyncLocalStorage();
|
|
@@ -3253,6 +3255,8 @@ var init_metro_asset_path = __esm({
|
|
|
3253
3255
|
function matchesModuleEntry(modulePath, pattern) {
|
|
3254
3256
|
if (!modulePath || !pattern) return false;
|
|
3255
3257
|
if (modulePath === pattern) return true;
|
|
3258
|
+
if (!modulePath.includes(pattern)) return false;
|
|
3259
|
+
if (!modulePath.includes(`node_modules/${pattern}`)) return false;
|
|
3256
3260
|
if (modulePath === `node_modules/${pattern}`) return true;
|
|
3257
3261
|
if (modulePath === `node_modules/${pattern}.js`) return true;
|
|
3258
3262
|
if (modulePath === `node_modules/${pattern}.ts`) return true;
|
|
@@ -4675,6 +4679,161 @@ var import_ws = require("ws");
|
|
|
4675
4679
|
|
|
4676
4680
|
// scripts/dev-server-scanner.ts
|
|
4677
4681
|
var import_child_process = require("child_process");
|
|
4682
|
+
|
|
4683
|
+
// ../contrast/src/runtime/process-group.ts
|
|
4684
|
+
var import_node_child_process = require("node:child_process");
|
|
4685
|
+
|
|
4686
|
+
// ../contrast/src/sleep.ts
|
|
4687
|
+
function sleep(ms) {
|
|
4688
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
// ../contrast/src/runtime/process-group.ts
|
|
4692
|
+
var GRACEFUL_TIMEOUT_MS = 3e3;
|
|
4693
|
+
var FORCED_EXIT_TIMEOUT_MS = 1e3;
|
|
4694
|
+
function signalProcessGroup(child, signal) {
|
|
4695
|
+
if (!child.pid) return;
|
|
4696
|
+
try {
|
|
4697
|
+
process.kill(-child.pid, signal);
|
|
4698
|
+
} catch {
|
|
4699
|
+
try {
|
|
4700
|
+
process.kill(child.pid, signal);
|
|
4701
|
+
} catch {
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
function runningPids(pids) {
|
|
4706
|
+
return pids.filter((pid) => {
|
|
4707
|
+
try {
|
|
4708
|
+
process.kill(pid, 0);
|
|
4709
|
+
return true;
|
|
4710
|
+
} catch (error) {
|
|
4711
|
+
return error instanceof Error && "code" in error && error.code === "EPERM";
|
|
4712
|
+
}
|
|
4713
|
+
});
|
|
4714
|
+
}
|
|
4715
|
+
function groupIsEmpty(pgid) {
|
|
4716
|
+
try {
|
|
4717
|
+
process.kill(-pgid, 0);
|
|
4718
|
+
} catch (error) {
|
|
4719
|
+
if (!(error instanceof Error && "code" in error && error.code === "EPERM"))
|
|
4720
|
+
return true;
|
|
4721
|
+
}
|
|
4722
|
+
const result = (0, import_node_child_process.spawnSync)("ps", ["-A", "-o", "pgid=,stat="], {
|
|
4723
|
+
encoding: "utf8",
|
|
4724
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4725
|
+
});
|
|
4726
|
+
if (result.error || result.status !== 0) return false;
|
|
4727
|
+
return !result.stdout.split("\n").some((line) => {
|
|
4728
|
+
const [group, state] = line.trim().split(/\s+/);
|
|
4729
|
+
return Number(group) === pgid && state !== void 0 && !state.startsWith("Z");
|
|
4730
|
+
});
|
|
4731
|
+
}
|
|
4732
|
+
async function waitForExit(pids, pgid, timeoutMs) {
|
|
4733
|
+
const deadline = Date.now() + timeoutMs;
|
|
4734
|
+
const gone = () => runningPids(pids).length === 0 && groupIsEmpty(pgid);
|
|
4735
|
+
while (Date.now() < deadline) {
|
|
4736
|
+
if (gone()) return true;
|
|
4737
|
+
await sleep(50);
|
|
4738
|
+
}
|
|
4739
|
+
return gone();
|
|
4740
|
+
}
|
|
4741
|
+
async function terminateProcessGroup(child, signal = "SIGTERM", gracefulTimeoutMs = GRACEFUL_TIMEOUT_MS) {
|
|
4742
|
+
if (!child.pid) {
|
|
4743
|
+
try {
|
|
4744
|
+
child.kill(signal);
|
|
4745
|
+
} catch {
|
|
4746
|
+
}
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4749
|
+
signalProcessGroup(child, "SIGSTOP");
|
|
4750
|
+
const descendants = /* @__PURE__ */ new Set();
|
|
4751
|
+
let parents = [child.pid];
|
|
4752
|
+
let inspectionError = null;
|
|
4753
|
+
while (parents.length > 0) {
|
|
4754
|
+
const result = (0, import_node_child_process.spawnSync)("pgrep", ["-P", parents.join(",")], {
|
|
4755
|
+
encoding: "utf8",
|
|
4756
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
4757
|
+
});
|
|
4758
|
+
if (result.error || result.status !== 0 && result.status !== 1) {
|
|
4759
|
+
inspectionError = new Error(
|
|
4760
|
+
`could not inspect descendants of processes ${parents.join(",")}: ${result.error?.message || result.stderr.trim() || `pgrep exited ${result.status}`}`
|
|
4761
|
+
);
|
|
4762
|
+
break;
|
|
4763
|
+
}
|
|
4764
|
+
const next = [];
|
|
4765
|
+
for (const line of result.stdout.split("\n")) {
|
|
4766
|
+
const descendantPid = Number(line.trim());
|
|
4767
|
+
if (Number.isInteger(descendantPid) && descendantPid > 1 && !descendants.has(descendantPid)) {
|
|
4768
|
+
descendants.add(descendantPid);
|
|
4769
|
+
next.push(descendantPid);
|
|
4770
|
+
try {
|
|
4771
|
+
process.kill(descendantPid, "SIGSTOP");
|
|
4772
|
+
} catch {
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
parents = next;
|
|
4777
|
+
}
|
|
4778
|
+
const pids = [child.pid, ...descendants];
|
|
4779
|
+
const gracefulDeadline = Date.now() + gracefulTimeoutMs;
|
|
4780
|
+
try {
|
|
4781
|
+
process.kill(child.pid, signal);
|
|
4782
|
+
} catch {
|
|
4783
|
+
}
|
|
4784
|
+
signalProcessGroup(child, "SIGCONT");
|
|
4785
|
+
for (const pid of descendants) {
|
|
4786
|
+
try {
|
|
4787
|
+
process.kill(pid, "SIGCONT");
|
|
4788
|
+
} catch {
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
let rootExited = child.exitCode !== null || child.signalCode !== null;
|
|
4792
|
+
if (!rootExited) {
|
|
4793
|
+
rootExited = await new Promise((resolveExit) => {
|
|
4794
|
+
const onExit = () => {
|
|
4795
|
+
clearTimeout(deadlineTimer);
|
|
4796
|
+
resolveExit(true);
|
|
4797
|
+
};
|
|
4798
|
+
const deadlineTimer = setTimeout(
|
|
4799
|
+
() => {
|
|
4800
|
+
child.removeListener("exit", onExit);
|
|
4801
|
+
resolveExit(false);
|
|
4802
|
+
},
|
|
4803
|
+
Math.max(0, gracefulDeadline - Date.now())
|
|
4804
|
+
);
|
|
4805
|
+
child.once("exit", onExit);
|
|
4806
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
4807
|
+
child.removeListener("exit", onExit);
|
|
4808
|
+
onExit();
|
|
4809
|
+
}
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
if (rootExited) {
|
|
4813
|
+
signalProcessGroup(child, signal);
|
|
4814
|
+
for (const pid of descendants) {
|
|
4815
|
+
try {
|
|
4816
|
+
process.kill(pid, signal);
|
|
4817
|
+
} catch {
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
if (await waitForExit(pids, child.pid, Math.max(0, gracefulDeadline - Date.now()))) {
|
|
4822
|
+
if (inspectionError) throw inspectionError;
|
|
4823
|
+
return;
|
|
4824
|
+
}
|
|
4825
|
+
for (const pid of pids) {
|
|
4826
|
+
try {
|
|
4827
|
+
process.kill(pid, "SIGKILL");
|
|
4828
|
+
} catch {
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4831
|
+
signalProcessGroup(child, "SIGKILL");
|
|
4832
|
+
await waitForExit(pids, child.pid, FORCED_EXIT_TIMEOUT_MS);
|
|
4833
|
+
if (inspectionError) throw inspectionError;
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
// scripts/dev-server-scanner.ts
|
|
4678
4837
|
var import_promises2 = require("fs/promises");
|
|
4679
4838
|
var import_http = __toESM(require("http"), 1);
|
|
4680
4839
|
var import_net = __toESM(require("net"), 1);
|
|
@@ -5088,29 +5247,51 @@ async function readAppSettingsBundle(projectRoot) {
|
|
|
5088
5247
|
|
|
5089
5248
|
// scripts/dev-server-scanner.ts
|
|
5090
5249
|
init_optional_demo_registry();
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5250
|
+
function execGuarded(command, timeout, extra = {}) {
|
|
5251
|
+
const maxBuffer = extra.maxBuffer ?? 1024 * 1024;
|
|
5252
|
+
return new Promise((resolve5, reject) => {
|
|
5253
|
+
const child = (0, import_child_process.spawn)("/bin/sh", ["-c", command], {
|
|
5254
|
+
detached: true,
|
|
5255
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
5256
|
+
});
|
|
5257
|
+
let stdout = "";
|
|
5258
|
+
let settled = false;
|
|
5259
|
+
let killing = false;
|
|
5260
|
+
const settle = (err) => {
|
|
5261
|
+
if (settled) return;
|
|
5262
|
+
settled = true;
|
|
5263
|
+
clearTimeout(deadline);
|
|
5096
5264
|
if (err) reject(err);
|
|
5097
5265
|
else resolve5({ stdout });
|
|
5266
|
+
};
|
|
5267
|
+
const killThenSettle = (err) => {
|
|
5268
|
+
if (killing) return;
|
|
5269
|
+
killing = true;
|
|
5270
|
+
clearTimeout(deadline);
|
|
5271
|
+
terminateProcessGroup(child, "SIGKILL", 0).finally(() => settle(err));
|
|
5272
|
+
};
|
|
5273
|
+
const deadline = setTimeout(() => {
|
|
5274
|
+
killThenSettle(
|
|
5275
|
+
Object.assign(new Error(`\`${command}\` did not exit within ${timeout}ms`), {
|
|
5276
|
+
killed: true
|
|
5277
|
+
})
|
|
5278
|
+
);
|
|
5279
|
+
}, timeout);
|
|
5280
|
+
child.stdout.setEncoding("utf8");
|
|
5281
|
+
child.stdout.on("data", (chunk) => {
|
|
5282
|
+
stdout += chunk;
|
|
5283
|
+
if (stdout.length > maxBuffer) {
|
|
5284
|
+
killThenSettle(new Error(`\`${command}\` exceeded maxBuffer ${maxBuffer}`));
|
|
5285
|
+
}
|
|
5286
|
+
});
|
|
5287
|
+
child.on("error", (err) => {
|
|
5288
|
+
if (!killing) settle(err);
|
|
5289
|
+
});
|
|
5290
|
+
child.on("close", (code) => {
|
|
5291
|
+
if (killing) return;
|
|
5292
|
+
settle(code === 0 ? null : new Error(`\`${command}\` exited with ${code}`));
|
|
5098
5293
|
});
|
|
5099
5294
|
});
|
|
5100
|
-
let deadlineTimer;
|
|
5101
|
-
const deadline = new Promise((_resolve, reject) => {
|
|
5102
|
-
deadlineTimer = setTimeout(() => {
|
|
5103
|
-
child?.kill("SIGKILL");
|
|
5104
|
-
const err = new Error(`\`${command}\` did not exit within ${timeout}ms`);
|
|
5105
|
-
Object.assign(err, { killed: true });
|
|
5106
|
-
reject(err);
|
|
5107
|
-
}, timeout + EXEC_EXIT_GRACE_MS);
|
|
5108
|
-
});
|
|
5109
|
-
try {
|
|
5110
|
-
return await Promise.race([ran, deadline]);
|
|
5111
|
-
} finally {
|
|
5112
|
-
clearTimeout(deadlineTimer);
|
|
5113
|
-
}
|
|
5114
5295
|
}
|
|
5115
5296
|
var TIMEOUT_MS = 250;
|
|
5116
5297
|
var MANIFEST_TIMEOUT_MS = 1500;
|
|
@@ -5145,6 +5326,7 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
|
5145
5326
|
function httpGet(hostname, port, path12, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
5146
5327
|
return new Promise((resolve5) => {
|
|
5147
5328
|
let settled = false;
|
|
5329
|
+
let killing = false;
|
|
5148
5330
|
const settle = (value) => {
|
|
5149
5331
|
if (settled) return;
|
|
5150
5332
|
settled = true;
|
|
@@ -5219,6 +5401,21 @@ function wasKilledByTimeout(err) {
|
|
|
5219
5401
|
}
|
|
5220
5402
|
async function scanListeningProcesses(excludePorts = []) {
|
|
5221
5403
|
const excluded = new Set(excludePorts);
|
|
5404
|
+
const listing = await listListenersShared();
|
|
5405
|
+
if (listing.state === "could-not-look") return listing;
|
|
5406
|
+
return {
|
|
5407
|
+
state: "looked",
|
|
5408
|
+
processes: listing.processes.filter((p) => acceptPort(p.port, excluded))
|
|
5409
|
+
};
|
|
5410
|
+
}
|
|
5411
|
+
var inflightListing = null;
|
|
5412
|
+
function listListenersShared() {
|
|
5413
|
+
inflightListing ??= listListeners().finally(() => {
|
|
5414
|
+
inflightListing = null;
|
|
5415
|
+
});
|
|
5416
|
+
return inflightListing;
|
|
5417
|
+
}
|
|
5418
|
+
async function listListeners() {
|
|
5222
5419
|
let timedOut = false;
|
|
5223
5420
|
try {
|
|
5224
5421
|
const { stdout } = await execGuarded(
|
|
@@ -5230,11 +5427,9 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
5230
5427
|
const parts = line.trim().split(/\s+/);
|
|
5231
5428
|
if (parts.length < 9) continue;
|
|
5232
5429
|
const pid = Number(parts[1]);
|
|
5233
|
-
const
|
|
5234
|
-
const m = addr.match(/:(\d+)$/);
|
|
5430
|
+
const m = parts[8].match(/:(\d+)$/);
|
|
5235
5431
|
if (!m) continue;
|
|
5236
5432
|
const port = Number(m[1]);
|
|
5237
|
-
if (!acceptPort(port, excluded)) continue;
|
|
5238
5433
|
if (!seen.has(port)) seen.set(port, pid);
|
|
5239
5434
|
}
|
|
5240
5435
|
return {
|
|
@@ -5256,7 +5451,6 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
5256
5451
|
if (!portMatch) continue;
|
|
5257
5452
|
const port = Number(portMatch[1]);
|
|
5258
5453
|
const pid = pidMatch ? Number(pidMatch[1]) : 0;
|
|
5259
|
-
if (!acceptPort(port, excluded)) continue;
|
|
5260
5454
|
if (!seen.has(port)) seen.set(port, pid);
|
|
5261
5455
|
}
|
|
5262
5456
|
return {
|
|
@@ -5267,10 +5461,7 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
5267
5461
|
if (wasKilledByTimeout(err)) timedOut = true;
|
|
5268
5462
|
}
|
|
5269
5463
|
if (timedOut) return { state: "could-not-look" };
|
|
5270
|
-
return {
|
|
5271
|
-
state: "looked",
|
|
5272
|
-
processes: FALLBACK_PORTS.filter((p) => acceptPort(p.port, excluded))
|
|
5273
|
-
};
|
|
5464
|
+
return { state: "looked", processes: FALLBACK_PORTS };
|
|
5274
5465
|
}
|
|
5275
5466
|
function pidFromNetstat(stdout, port) {
|
|
5276
5467
|
for (const line of stdout.split("\n")) {
|
|
@@ -5776,6 +5967,7 @@ var DEFAULT_SOOTSIM_BRIDGE_PORT = 7668;
|
|
|
5776
5967
|
var DEFAULT_SOOTSIM_BRIDGE_URL = `http://localhost:${DEFAULT_SOOTSIM_BRIDGE_PORT}/`;
|
|
5777
5968
|
var SOOTSIM_BRIDGE_SIM_CLOSE_CODE = 4001;
|
|
5778
5969
|
var SOOTSIM_BRIDGE_SIM_CLOSE_REASON = "sootsim close";
|
|
5970
|
+
var AUTOMATION_SIM_IDLE_REAP_TTL_MS = 5 * 6e4;
|
|
5779
5971
|
|
|
5780
5972
|
// src/cli-version.ts
|
|
5781
5973
|
var import_node_fs3 = require("node:fs");
|
|
@@ -5817,7 +6009,7 @@ var import_path = __toESM(require("path"), 1);
|
|
|
5817
6009
|
var import_url = require("url");
|
|
5818
6010
|
|
|
5819
6011
|
// ../contrast-runtime-delivery/src/index.ts
|
|
5820
|
-
var
|
|
6012
|
+
var import_node_child_process2 = require("node:child_process");
|
|
5821
6013
|
var import_node_crypto2 = __toESM(require("node:crypto"), 1);
|
|
5822
6014
|
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
5823
6015
|
var import_node_os2 = __toESM(require("node:os"), 1);
|
|
@@ -6216,7 +6408,7 @@ function sha256File(filePath) {
|
|
|
6216
6408
|
}
|
|
6217
6409
|
function extractTarball(tarPath, destDir) {
|
|
6218
6410
|
return new Promise((resolve5, reject) => {
|
|
6219
|
-
const child = (0,
|
|
6411
|
+
const child = (0, import_node_child_process2.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
|
|
6220
6412
|
stdio: ["ignore", "inherit", "inherit"]
|
|
6221
6413
|
});
|
|
6222
6414
|
child.on("error", reject);
|
|
@@ -6326,7 +6518,7 @@ var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
|
6326
6518
|
var import_node_path10 = __toESM(require("node:path"), 1);
|
|
6327
6519
|
|
|
6328
6520
|
// src/agent-sessions.ts
|
|
6329
|
-
var
|
|
6521
|
+
var import_node_child_process3 = require("node:child_process");
|
|
6330
6522
|
var import_node_crypto4 = require("node:crypto");
|
|
6331
6523
|
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
6332
6524
|
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
@@ -6880,7 +7072,7 @@ function mkfifoSync(p) {
|
|
|
6880
7072
|
import_node_fs9.default.unlinkSync(p);
|
|
6881
7073
|
}
|
|
6882
7074
|
}
|
|
6883
|
-
const result = (0,
|
|
7075
|
+
const result = (0, import_node_child_process3.spawnSync)("mkfifo", ["-m", "600", p]);
|
|
6884
7076
|
if (result.status !== 0) {
|
|
6885
7077
|
throw new Error(
|
|
6886
7078
|
`mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
|
|
@@ -6955,7 +7147,7 @@ async function startSession(opts) {
|
|
|
6955
7147
|
if (claudeSessionUuid) {
|
|
6956
7148
|
wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
|
|
6957
7149
|
}
|
|
6958
|
-
const child = (0,
|
|
7150
|
+
const child = (0, import_node_child_process3.spawn)(executable, wrapperArgs, {
|
|
6959
7151
|
detached: true,
|
|
6960
7152
|
stdio: "ignore",
|
|
6961
7153
|
env: {
|
|
@@ -8167,7 +8359,7 @@ async function dispatchPlaneCommand(plane, type, msg, mutationOptions) {
|
|
|
8167
8359
|
}
|
|
8168
8360
|
|
|
8169
8361
|
// cli/commands/box/checkout-plane.ts
|
|
8170
|
-
var
|
|
8362
|
+
var import_node_child_process4 = require("node:child_process");
|
|
8171
8363
|
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
8172
8364
|
var import_node_path11 = __toESM(require("node:path"), 1);
|
|
8173
8365
|
var CheckoutRequiresGitError = class extends Error {
|
|
@@ -8209,7 +8401,7 @@ var CheckoutFilePlane = class {
|
|
|
8209
8401
|
}
|
|
8210
8402
|
listFiles() {
|
|
8211
8403
|
const args = this.trackedOnly ? ["ls-files", "-z"] : ["ls-files", "-co", "--exclude-standard", "-z"];
|
|
8212
|
-
const stdout = (0,
|
|
8404
|
+
const stdout = (0, import_node_child_process4.execFileSync)("git", args, {
|
|
8213
8405
|
cwd: this.root,
|
|
8214
8406
|
encoding: "utf8",
|
|
8215
8407
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -9250,24 +9442,8 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
9250
9442
|
// terminal 4001 code, so the client closes the abandoned window instead
|
|
9251
9443
|
// of reconnecting the zombie straight back in.
|
|
9252
9444
|
static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
|
|
9253
|
-
// automation sims (spawned by the playwright driver: `peach open --driver
|
|
9254
|
-
// playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
|
|
9255
|
-
// === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
|
|
9256
|
-
// capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
|
|
9257
|
-
// hundreds pile up inside the window — orphaned ms-playwright chromiums that
|
|
9258
|
-
// drove the box to swap-thrash (load hit 157 in one incident). give them a far
|
|
9259
|
-
// shorter idle TTL, and cap how many can sit concurrently: reap the most-idle
|
|
9260
|
-
// overflow, but never a sim active within ACTIVE_GRACE (an agent composing
|
|
9261
|
-
// between captures), nor primary / cli-attached / leased sims.
|
|
9262
|
-
static AUTOMATION_SIM_IDLE_REAP_TTL_MS = 10 * 6e4;
|
|
9263
|
-
static MAX_CONCURRENT_AUTOMATION_SIMS = 6;
|
|
9264
|
-
static AUTOMATION_SIM_ACTIVE_GRACE_MS = 6e4;
|
|
9265
9445
|
preferredPort;
|
|
9266
9446
|
portFallbackCount;
|
|
9267
|
-
simIdleReapTtlMs;
|
|
9268
|
-
automationSimIdleReapTtlMs;
|
|
9269
|
-
maxConcurrentAutomationSims;
|
|
9270
|
-
automationSimActiveGraceMs;
|
|
9271
9447
|
shouldWriteLockfile;
|
|
9272
9448
|
shouldWriteDevLockfile;
|
|
9273
9449
|
getShellPort;
|
|
@@ -9310,23 +9486,12 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
9310
9486
|
getExcludePorts: opts.agentScanExcludes
|
|
9311
9487
|
});
|
|
9312
9488
|
this.contrastOrigin = opts.contrastOrigin?.replace(/\/$/, "") || null;
|
|
9313
|
-
this.simIdleReapTtlMs = opts.simIdleReapTtlMs ?? _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
|
|
9314
|
-
this.automationSimIdleReapTtlMs = opts.automationSimIdleReapTtlMs ?? _SootSimBridgeHost.AUTOMATION_SIM_IDLE_REAP_TTL_MS;
|
|
9315
|
-
this.maxConcurrentAutomationSims = opts.maxConcurrentAutomationSims ?? _SootSimBridgeHost.MAX_CONCURRENT_AUTOMATION_SIMS;
|
|
9316
|
-
this.automationSimActiveGraceMs = opts.automationSimActiveGraceMs ?? _SootSimBridgeHost.AUTOMATION_SIM_ACTIVE_GRACE_MS;
|
|
9317
9489
|
}
|
|
9318
9490
|
/** expose the agent host so tests and embedders can inspect state or
|
|
9319
9491
|
* inject behavior. not part of the public WS protocol. */
|
|
9320
9492
|
getAgentHost() {
|
|
9321
9493
|
return this.agentHost;
|
|
9322
9494
|
}
|
|
9323
|
-
/** run the abandoned-sim GC pass on demand. the reaper normally fires off
|
|
9324
|
-
* the 30s idle-sweep timer; this lets the F21-3 integration test drive
|
|
9325
|
-
* the real path without waiting for the timer. not part of the public
|
|
9326
|
-
* WS protocol. */
|
|
9327
|
-
reapIdleSimsForTest(now = Date.now()) {
|
|
9328
|
-
this.reapIdleSims(now);
|
|
9329
|
-
}
|
|
9330
9495
|
/** synchronous wrapper around startAsync for callers that don't care
|
|
9331
9496
|
* about port fallback outcomes. returns immediately; actual binding
|
|
9332
9497
|
* happens on the event loop. callers that need to know the bound port
|
|
@@ -9572,6 +9737,10 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
9572
9737
|
this.updateUserActivity(sim);
|
|
9573
9738
|
return;
|
|
9574
9739
|
}
|
|
9740
|
+
if (msg.type === "bridge:capture-active" && sim) {
|
|
9741
|
+
sim.lastActiveAt = Date.now();
|
|
9742
|
+
return;
|
|
9743
|
+
}
|
|
9575
9744
|
if (msg.type === "bridge:write-shared-config") {
|
|
9576
9745
|
if (!msg.patch || typeof msg.patch !== "object" || Array.isArray(msg.patch)) {
|
|
9577
9746
|
return;
|
|
@@ -10572,53 +10741,21 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
|
|
|
10572
10741
|
// automation sims are spawned by the playwright driver (`peach open
|
|
10573
10742
|
// --driver playwright`, the factory/screenshot capture path), which tags them
|
|
10574
10743
|
// with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
|
|
10575
|
-
// they are unattended one-shot browsers, never a human's tab, so they get a
|
|
10576
|
-
// shorter idle TTL and a concurrent cap.
|
|
10577
10744
|
isAutomationSim(sim) {
|
|
10578
10745
|
return sim.meta?.sootsimHostDriver === "playwright";
|
|
10579
10746
|
}
|
|
10580
|
-
// an automation sim whose spawning playwright host process is still alive is
|
|
10581
|
-
// an ACTIVE run, not an abandoned tab. mirrors the cli's playwrightHostPidForSim
|
|
10582
|
-
// (control.ts): extract the host pid from meta, then check liveness so the
|
|
10583
|
-
// host-side idle GC never kills a live capture/factory sim mid-run.
|
|
10584
|
-
automationSimOwnerAlive(sim) {
|
|
10585
|
-
const pid = Number(sim.meta?.sootsimHostPid);
|
|
10586
|
-
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return false;
|
|
10587
|
-
try {
|
|
10588
|
-
process.kill(pid, 0);
|
|
10589
|
-
return true;
|
|
10590
|
-
} catch (err) {
|
|
10591
|
-
return err.code === "EPERM";
|
|
10592
|
-
}
|
|
10593
|
-
}
|
|
10594
10747
|
reapIdleSims(now = Date.now()) {
|
|
10595
10748
|
const attachedSimIds = new Set(this.cliSimBySocket.values());
|
|
10596
|
-
const automationLive = [];
|
|
10597
10749
|
for (const sim of this.sims.values()) {
|
|
10598
|
-
if (sim.id === this.primarySimId) continue;
|
|
10599
10750
|
if (attachedSimIds.has(sim.id)) continue;
|
|
10600
|
-
if (this.getActiveLease(sim)) continue;
|
|
10601
|
-
const lastTouched = Math.max(sim.lastActiveAt, sim.connectedAt);
|
|
10602
|
-
const idleMs = now - lastTouched;
|
|
10603
10751
|
const automation = this.isAutomationSim(sim);
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
if (idleMs >= ttl) {
|
|
10607
|
-
this.closeSimSocketFromHost(sim.ws);
|
|
10752
|
+
const lease = this.getActiveLease(sim);
|
|
10753
|
+
if (automation ? lease?.kind === "user-active" : sim.id === this.primarySimId || lease) {
|
|
10608
10754
|
continue;
|
|
10609
10755
|
}
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
if (automationLive.length > cap) {
|
|
10614
|
-
automationLive.sort((a, b) => b.idleMs - a.idleMs);
|
|
10615
|
-
for (const { sim, idleMs } of automationLive.slice(
|
|
10616
|
-
0,
|
|
10617
|
-
automationLive.length - cap
|
|
10618
|
-
)) {
|
|
10619
|
-
if (idleMs < this.automationSimActiveGraceMs) continue;
|
|
10620
|
-
this.closeSimSocketFromHost(sim.ws);
|
|
10621
|
-
}
|
|
10756
|
+
const idleMs = now - Math.max(sim.lastActiveAt, sim.connectedAt);
|
|
10757
|
+
const ttl = automation ? AUTOMATION_SIM_IDLE_REAP_TTL_MS : _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
|
|
10758
|
+
if (idleMs >= ttl) this.closeSimSocketFromHost(sim.ws);
|
|
10622
10759
|
}
|
|
10623
10760
|
}
|
|
10624
10761
|
// ping every connected ws; if the previous round's ping went unanswered,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
|
|
2
2
|
|
|
3
3
|
// src/host/fetch-proxy-overrides.ts
|
|
4
4
|
var FETCH_PROXY_BROWSER_USER_AGENT = "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";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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;
|
|
@@ -973,6 +973,7 @@ function resolveSootsimBridgePort(input = {}) {
|
|
|
973
973
|
if (explicitPort !== null) return explicitPort;
|
|
974
974
|
return DEFAULT_SOOTSIM_BRIDGE_PORT + parsePortOffset(input.portOffset);
|
|
975
975
|
}
|
|
976
|
+
var AUTOMATION_SIM_IDLE_REAP_TTL_MS = 5 * 6e4;
|
|
976
977
|
|
|
977
978
|
// src/cli-constants.ts
|
|
978
979
|
var DEFAULT_SOOTSIM_SHELL_URL = "http://localhost:5173/";
|
|
@@ -3155,13 +3156,18 @@ async function connect(options = {}) {
|
|
|
3155
3156
|
|
|
3156
3157
|
// src/capture-contract.ts
|
|
3157
3158
|
var RNX_SCREEN_CAPTURE_VERSION = 1;
|
|
3159
|
+
function isLiveRasterSource(node) {
|
|
3160
|
+
const source = node.props?.source;
|
|
3161
|
+
return node.type === "image" && !!source && typeof source === "object" && "uri" in source && typeof source.uri === "string" && source.uri.startsWith("live:");
|
|
3162
|
+
}
|
|
3158
3163
|
function selectRnxRasterNodeIds(tree) {
|
|
3159
3164
|
const nodesById = new Map(tree.nodes.map((node) => [node.nodeId, node]));
|
|
3160
3165
|
const unsupported = /* @__PURE__ */ new Set();
|
|
3161
3166
|
for (const node of tree.nodes) {
|
|
3162
|
-
const
|
|
3167
|
+
const liveVideo = isLiveRasterSource(node);
|
|
3168
|
+
const visibleFrame = liveVideo && node.visibleFrame && (node.visibleFrame.width <= 0 || node.visibleFrame.height <= 0) ? node.frame : node.visibleFrame ?? node.frame;
|
|
3163
3169
|
if (!visibleFrame || visibleFrame.width <= 0 || visibleFrame.height <= 0) continue;
|
|
3164
|
-
if (node.type === "masked-view" || node.type === "text" && typeof node.text === "string" && (new RegExp("\\p{Emoji_Presentation}", "u").test(node.text) || new RegExp("\\uFE0F|\\u200D|\\u20E3|\\p{Emoji_Modifier}|\\p{Regional_Indicator}", "u").test(
|
|
3170
|
+
if (node.type === "masked-view" || liveVideo || node.type === "text" && typeof node.text === "string" && (new RegExp("\\p{Emoji_Presentation}", "u").test(node.text) || new RegExp("\\uFE0F|\\u200D|\\u20E3|\\p{Emoji_Modifier}|\\p{Regional_Indicator}", "u").test(
|
|
3165
3171
|
node.text
|
|
3166
3172
|
)) || node.style._liquidGlass !== void 0 || node.style._liquidGlassEdge !== void 0 || node.style._liquidGlassMaterialTint !== void 0) {
|
|
3167
3173
|
unsupported.add(node.nodeId);
|
|
@@ -3179,17 +3185,21 @@ function selectRnxRasterNodeIds(tree) {
|
|
|
3179
3185
|
}
|
|
3180
3186
|
const screenArea = tree.width * tree.height;
|
|
3181
3187
|
const maxLayerArea = screenArea * 0.25;
|
|
3182
|
-
const maxAtlasArea = screenArea * 0.5;
|
|
3183
3188
|
const candidates = [...unsupported].map((nodeId) => {
|
|
3184
3189
|
const node = nodesById.get(nodeId);
|
|
3185
|
-
|
|
3186
|
-
|
|
3190
|
+
if (!node) return null;
|
|
3191
|
+
const liveVideo = isLiveRasterSource(node);
|
|
3192
|
+
const frame = liveVideo && node.visibleFrame && (node.visibleFrame.width <= 0 || node.visibleFrame.height <= 0) ? node.frame : node.visibleFrame ?? node.frame;
|
|
3193
|
+
return frame ? { nodeId, area: frame.width * frame.height, liveVideo } : null;
|
|
3187
3194
|
}).filter(
|
|
3188
|
-
(candidate) => candidate !== null && candidate.area <= maxLayerArea
|
|
3189
|
-
).sort(
|
|
3195
|
+
(candidate) => candidate !== null && (candidate.liveVideo || candidate.area <= maxLayerArea)
|
|
3196
|
+
).sort(
|
|
3197
|
+
(left, right) => Number(right.liveVideo) - Number(left.liveVideo) || left.area - right.area || left.nodeId - right.nodeId
|
|
3198
|
+
);
|
|
3190
3199
|
const selected = /* @__PURE__ */ new Set();
|
|
3191
3200
|
let atlasArea = 0;
|
|
3192
3201
|
for (const candidate of candidates) {
|
|
3202
|
+
const maxAtlasArea = screenArea * (candidate.liveVideo ? 1 : 0.5);
|
|
3193
3203
|
if (atlasArea + candidate.area > maxAtlasArea) continue;
|
|
3194
3204
|
selected.add(candidate.nodeId);
|
|
3195
3205
|
atlasArea += candidate.area;
|
|
@@ -3270,6 +3280,7 @@ function rnxCaptureRasterRegions(capture) {
|
|
|
3270
3280
|
nodeId: node.nodeId,
|
|
3271
3281
|
parentNodeId: node.parentNodeId,
|
|
3272
3282
|
type: node.type,
|
|
3283
|
+
props: node.props,
|
|
3273
3284
|
text: node.text,
|
|
3274
3285
|
style: node.style.resolved,
|
|
3275
3286
|
layout: node.layout.local,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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 __defProp = Object.defineProperty;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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/dist-lib/menu.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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 __defProp = Object.defineProperty;
|
package/dist-lib/menu.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.627 | (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 __defProp = Object.defineProperty;
|