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
package/dist-lib/skills.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;
|
|
@@ -6221,10 +6221,10 @@ var init_registry = __esm({
|
|
|
6221
6221
|
versions: [
|
|
6222
6222
|
{
|
|
6223
6223
|
range: ">=15.0.0",
|
|
6224
|
-
coverage: 0.
|
|
6225
|
-
note: "
|
|
6226
|
-
working: "
|
|
6227
|
-
missing: "in
|
|
6224
|
+
coverage: 0.98,
|
|
6225
|
+
note: "upstream package JS runs against the ExpoFileSystem and ExponentFileSystem native-module seams over one shared VFS. both modules follow the installed Swift sources: member shapes, sync and async twins, error codes and messages including the legacy module's own codes, and events. transfers use fetch and the browser XMLHttpRequest, so download progress, pause and resume, cancellation, and upload progress are real. paired native and Peach runtime conformance covers the class API, write and copy semantics, file handles, digests, directory watching, and the legacy API.",
|
|
6226
|
+
working: "class API over the native FileSystemFile, FileSystemDirectory, and FileSystemFileHandle: write and writeSync (text, bytes, base64, append), text, base64, bytes and their Sync twins, info, md5 and digest (MD5, SHA-1, SHA-256, SHA-384, SHA-512), type from the extension UTType, lastModified, create with its native options, copy, move, and their Sync twins with native overwrite and existence errors, rename, delete, file handles in every FileMode with readBytes, writeBytes, offset, and size, Directory create, createFile, createDirectory, list, listAsRecords, size, copy, move; Paths (document, cache, bundle, disk space); downloadFileAsync with uuid progress events and cancelDownloadAsync; FileSystemDownloadTask and FileSystemUploadTask with start, pause, resume, cancel, and progress events; FileSystemWatcher change events for modify, delete, and rename; pickFileAsync through the document picker into the tmp Inbox. legacy API through ExponentFileSystem: read with position and length, write with append, delete, info, makeDirectory, readDirectory, recursive copy and move, downloadAsync, createDownloadResumable with pause, resume, savable resume data, and cancellation, uploadAsync and createUploadTask (binary and multipart) with progress events, disk capacity reads.",
|
|
6227
|
+
missing: "pickDirectoryAsync always reports a cancelled pick (native opens the chosen folder in place); background URLSession transfers do not continue while the app is suspended; Quick Look canPreview and preview are absent; legacy copyAsync cannot read ph:// photo library assets; Directory.size omits the directory entries' own sizes"
|
|
6228
6228
|
}
|
|
6229
6229
|
]
|
|
6230
6230
|
},
|
|
@@ -6262,9 +6262,9 @@ var init_registry = __esm({
|
|
|
6262
6262
|
{
|
|
6263
6263
|
range: ">=12.0.0",
|
|
6264
6264
|
coverage: 0.8,
|
|
6265
|
-
note: "the published package runs unchanged;
|
|
6266
|
-
working: "openBrowserAsync
|
|
6267
|
-
missing: "embedded SFSafariViewController or Chrome Custom Tab, native styling and cookie isolation,
|
|
6265
|
+
note: "the published package runs unchanged; host-owned browser sessions settle on user cancellation or programmatic dismissal, and auth sessions deliver successful callback URLs, explicit user cancellation, programmatic dismissal, and replacement. the 80% implementation estimate follows the mounted published-package test under cross-origin isolation and popup blocking; native browser presentation and unrestricted redirect schemes remain unsupported.",
|
|
6266
|
+
working: "openBrowserAsync pending result, user cancel and programmatic dismiss, locked result for a second browser, warmUpAsync, coolDownAsync, mayInitWithUrlAsync, published iOS getCustomTabsSupportingBrowsersAsync UnavailabilityError, openAuthSessionAsync success with callback URL, explicit host Cancel Sign-In, dismissAuthSession and replacement dismissal, identity-matched callback and control cleanup, preservation of guest alerts during sign-in, and upstream enums and option processing",
|
|
6267
|
+
missing: "embedded SFSafariViewController or Chrome Custom Tab, native styling and cookie isolation, custom-scheme or foreign-origin auth callbacks, and observing abandonment after browser isolation severs the popup proxy. auth requires a same-origin HTTP(S) callback and user activation allowed by popup policy; an abandoned isolated provider requires the visible host close control"
|
|
6268
6268
|
}
|
|
6269
6269
|
]
|
|
6270
6270
|
},
|
|
@@ -7977,7 +7977,7 @@ var init_registry = __esm({
|
|
|
7977
7977
|
{
|
|
7978
7978
|
range: ">=14.0.0",
|
|
7979
7979
|
coverage: 0.8,
|
|
7980
|
-
note: "printAsync routes through real window.print() (browser print dialog). printToFileAsync now produces a REAL, structurally-valid PDF (verified by `file`/macOS as com.adobe.pdf) carrying the html's text content + a real page count, written to the same in-memory cache the expo-file-system stub serves \u2014 so the returned
|
|
7980
|
+
note: "printAsync routes through real window.print() (browser print dialog). printToFileAsync now produces a REAL, structurally-valid PDF (verified by `file`/macOS as com.adobe.pdf) carrying the html's text content + a real page count, written to the same in-memory cache the expo-file-system stub serves \u2014 so the returned `<cacheDirectory>Print/*.pdf` URI resolves to genuine PDF bytes (readAsStringAsync / FormData upload / Sharing / Print preview all work), and base64 (when requested) decodes to those bytes. This replaces the old `mock://print.pdf` dangling URI that broke every consumer. Fidelity caveat: the worker has no WebView render engine, so the PDF reproduces the document's TEXT (paginated, escaped) but NOT CSS/image layout \u2014 a degraded-but-real simulation of iOS's WKWebView\u2192UIPrintPageRenderer output.",
|
|
7981
7981
|
working: "upstream validation and concurrency guard, printAsync (real window.print), printToFileAsync (real PDF bytes: %PDF header, catalog/pages tree, xref, paginated text content, real numberOfPages, real file:// uri + base64), selectPrinterAsync, Orientation enum",
|
|
7982
7982
|
missing: "CSS/image/font layout fidelity in the generated PDF (text-only render \u2014 needs a worker WebView engine to match WKWebView pixel output), useMarkupFormatter (same text path), printerUrl/AirPrint physical printing, native printer selection sheet (selectPrinterAsync returns undefined)"
|
|
7983
7983
|
}
|
|
@@ -18767,6 +18767,7 @@ var init_sleep = __esm({
|
|
|
18767
18767
|
// src/bridge-constants.ts
|
|
18768
18768
|
var bridge_constants_exports = {};
|
|
18769
18769
|
__export(bridge_constants_exports, {
|
|
18770
|
+
AUTOMATION_SIM_IDLE_REAP_TTL_MS: () => AUTOMATION_SIM_IDLE_REAP_TTL_MS,
|
|
18770
18771
|
DEFAULT_SOOTSIM_BRIDGE_PORT: () => DEFAULT_SOOTSIM_BRIDGE_PORT,
|
|
18771
18772
|
DEFAULT_SOOTSIM_BRIDGE_URL: () => DEFAULT_SOOTSIM_BRIDGE_URL,
|
|
18772
18773
|
SOOTSIM_BRIDGE_SIM_CLOSE_CODE: () => SOOTSIM_BRIDGE_SIM_CLOSE_CODE,
|
|
@@ -18877,7 +18878,7 @@ function resolveSootsimBridgeWebSocketUrl(input) {
|
|
|
18877
18878
|
function isSootsimBridgeHealth(value, expectedPort) {
|
|
18878
18879
|
return typeof value === "object" && value !== null && Reflect.get(value, "ok") === true && Reflect.get(value, "bridgePort") === expectedPort;
|
|
18879
18880
|
}
|
|
18880
|
-
var DEFAULT_SOOTSIM_BRIDGE_PORT, DEFAULT_SOOTSIM_BRIDGE_URL, CONTRAST_DEV_HTTP_BASE_PORT, SOOTSIM_SITE_DEV_HTTP_BASE_PORT, SOOTSIM_SHELL_DEV_HTTP_BASE_PORT, LOCAL_DEV_HTTP_BASE_PORTS, MAX_LOCAL_DEV_PORT_OFFSET, SOOTSIM_BRIDGE_SIM_CLOSE_CODE, SOOTSIM_BRIDGE_SIM_CLOSE_REASON;
|
|
18881
|
+
var DEFAULT_SOOTSIM_BRIDGE_PORT, DEFAULT_SOOTSIM_BRIDGE_URL, CONTRAST_DEV_HTTP_BASE_PORT, SOOTSIM_SITE_DEV_HTTP_BASE_PORT, SOOTSIM_SHELL_DEV_HTTP_BASE_PORT, LOCAL_DEV_HTTP_BASE_PORTS, MAX_LOCAL_DEV_PORT_OFFSET, SOOTSIM_BRIDGE_SIM_CLOSE_CODE, SOOTSIM_BRIDGE_SIM_CLOSE_REASON, AUTOMATION_SIM_IDLE_REAP_TTL_MS;
|
|
18881
18882
|
var init_bridge_constants = __esm({
|
|
18882
18883
|
"src/bridge-constants.ts"() {
|
|
18883
18884
|
"use strict";
|
|
@@ -18893,6 +18894,170 @@ var init_bridge_constants = __esm({
|
|
|
18893
18894
|
MAX_LOCAL_DEV_PORT_OFFSET = 2e3;
|
|
18894
18895
|
SOOTSIM_BRIDGE_SIM_CLOSE_CODE = 4001;
|
|
18895
18896
|
SOOTSIM_BRIDGE_SIM_CLOSE_REASON = "sootsim close";
|
|
18897
|
+
AUTOMATION_SIM_IDLE_REAP_TTL_MS = 5 * 6e4;
|
|
18898
|
+
}
|
|
18899
|
+
});
|
|
18900
|
+
|
|
18901
|
+
// ../contrast/src/sleep.ts
|
|
18902
|
+
function sleep2(ms) {
|
|
18903
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
18904
|
+
}
|
|
18905
|
+
var init_sleep2 = __esm({
|
|
18906
|
+
"../contrast/src/sleep.ts"() {
|
|
18907
|
+
"use strict";
|
|
18908
|
+
}
|
|
18909
|
+
});
|
|
18910
|
+
|
|
18911
|
+
// ../contrast/src/runtime/process-group.ts
|
|
18912
|
+
function signalProcessGroup(child, signal) {
|
|
18913
|
+
if (!child.pid) return;
|
|
18914
|
+
try {
|
|
18915
|
+
process.kill(-child.pid, signal);
|
|
18916
|
+
} catch {
|
|
18917
|
+
try {
|
|
18918
|
+
process.kill(child.pid, signal);
|
|
18919
|
+
} catch {
|
|
18920
|
+
}
|
|
18921
|
+
}
|
|
18922
|
+
}
|
|
18923
|
+
function runningPids(pids) {
|
|
18924
|
+
return pids.filter((pid) => {
|
|
18925
|
+
try {
|
|
18926
|
+
process.kill(pid, 0);
|
|
18927
|
+
return true;
|
|
18928
|
+
} catch (error) {
|
|
18929
|
+
return error instanceof Error && "code" in error && error.code === "EPERM";
|
|
18930
|
+
}
|
|
18931
|
+
});
|
|
18932
|
+
}
|
|
18933
|
+
function groupIsEmpty(pgid) {
|
|
18934
|
+
try {
|
|
18935
|
+
process.kill(-pgid, 0);
|
|
18936
|
+
} catch (error) {
|
|
18937
|
+
if (!(error instanceof Error && "code" in error && error.code === "EPERM"))
|
|
18938
|
+
return true;
|
|
18939
|
+
}
|
|
18940
|
+
const result = (0, import_node_child_process2.spawnSync)("ps", ["-A", "-o", "pgid=,stat="], {
|
|
18941
|
+
encoding: "utf8",
|
|
18942
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
18943
|
+
});
|
|
18944
|
+
if (result.error || result.status !== 0) return false;
|
|
18945
|
+
return !result.stdout.split("\n").some((line) => {
|
|
18946
|
+
const [group, state] = line.trim().split(/\s+/);
|
|
18947
|
+
return Number(group) === pgid && state !== void 0 && !state.startsWith("Z");
|
|
18948
|
+
});
|
|
18949
|
+
}
|
|
18950
|
+
async function waitForExit(pids, pgid, timeoutMs) {
|
|
18951
|
+
const deadline = Date.now() + timeoutMs;
|
|
18952
|
+
const gone = () => runningPids(pids).length === 0 && groupIsEmpty(pgid);
|
|
18953
|
+
while (Date.now() < deadline) {
|
|
18954
|
+
if (gone()) return true;
|
|
18955
|
+
await sleep2(50);
|
|
18956
|
+
}
|
|
18957
|
+
return gone();
|
|
18958
|
+
}
|
|
18959
|
+
async function terminateProcessGroup(child, signal = "SIGTERM", gracefulTimeoutMs = GRACEFUL_TIMEOUT_MS) {
|
|
18960
|
+
if (!child.pid) {
|
|
18961
|
+
try {
|
|
18962
|
+
child.kill(signal);
|
|
18963
|
+
} catch {
|
|
18964
|
+
}
|
|
18965
|
+
return;
|
|
18966
|
+
}
|
|
18967
|
+
signalProcessGroup(child, "SIGSTOP");
|
|
18968
|
+
const descendants = /* @__PURE__ */ new Set();
|
|
18969
|
+
let parents = [child.pid];
|
|
18970
|
+
let inspectionError = null;
|
|
18971
|
+
while (parents.length > 0) {
|
|
18972
|
+
const result = (0, import_node_child_process2.spawnSync)("pgrep", ["-P", parents.join(",")], {
|
|
18973
|
+
encoding: "utf8",
|
|
18974
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
18975
|
+
});
|
|
18976
|
+
if (result.error || result.status !== 0 && result.status !== 1) {
|
|
18977
|
+
inspectionError = new Error(
|
|
18978
|
+
`could not inspect descendants of processes ${parents.join(",")}: ${result.error?.message || result.stderr.trim() || `pgrep exited ${result.status}`}`
|
|
18979
|
+
);
|
|
18980
|
+
break;
|
|
18981
|
+
}
|
|
18982
|
+
const next = [];
|
|
18983
|
+
for (const line of result.stdout.split("\n")) {
|
|
18984
|
+
const descendantPid = Number(line.trim());
|
|
18985
|
+
if (Number.isInteger(descendantPid) && descendantPid > 1 && !descendants.has(descendantPid)) {
|
|
18986
|
+
descendants.add(descendantPid);
|
|
18987
|
+
next.push(descendantPid);
|
|
18988
|
+
try {
|
|
18989
|
+
process.kill(descendantPid, "SIGSTOP");
|
|
18990
|
+
} catch {
|
|
18991
|
+
}
|
|
18992
|
+
}
|
|
18993
|
+
}
|
|
18994
|
+
parents = next;
|
|
18995
|
+
}
|
|
18996
|
+
const pids = [child.pid, ...descendants];
|
|
18997
|
+
const gracefulDeadline = Date.now() + gracefulTimeoutMs;
|
|
18998
|
+
try {
|
|
18999
|
+
process.kill(child.pid, signal);
|
|
19000
|
+
} catch {
|
|
19001
|
+
}
|
|
19002
|
+
signalProcessGroup(child, "SIGCONT");
|
|
19003
|
+
for (const pid of descendants) {
|
|
19004
|
+
try {
|
|
19005
|
+
process.kill(pid, "SIGCONT");
|
|
19006
|
+
} catch {
|
|
19007
|
+
}
|
|
19008
|
+
}
|
|
19009
|
+
let rootExited = child.exitCode !== null || child.signalCode !== null;
|
|
19010
|
+
if (!rootExited) {
|
|
19011
|
+
rootExited = await new Promise((resolveExit) => {
|
|
19012
|
+
const onExit = () => {
|
|
19013
|
+
clearTimeout(deadlineTimer);
|
|
19014
|
+
resolveExit(true);
|
|
19015
|
+
};
|
|
19016
|
+
const deadlineTimer = setTimeout(
|
|
19017
|
+
() => {
|
|
19018
|
+
child.removeListener("exit", onExit);
|
|
19019
|
+
resolveExit(false);
|
|
19020
|
+
},
|
|
19021
|
+
Math.max(0, gracefulDeadline - Date.now())
|
|
19022
|
+
);
|
|
19023
|
+
child.once("exit", onExit);
|
|
19024
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
19025
|
+
child.removeListener("exit", onExit);
|
|
19026
|
+
onExit();
|
|
19027
|
+
}
|
|
19028
|
+
});
|
|
19029
|
+
}
|
|
19030
|
+
if (rootExited) {
|
|
19031
|
+
signalProcessGroup(child, signal);
|
|
19032
|
+
for (const pid of descendants) {
|
|
19033
|
+
try {
|
|
19034
|
+
process.kill(pid, signal);
|
|
19035
|
+
} catch {
|
|
19036
|
+
}
|
|
19037
|
+
}
|
|
19038
|
+
}
|
|
19039
|
+
if (await waitForExit(pids, child.pid, Math.max(0, gracefulDeadline - Date.now()))) {
|
|
19040
|
+
if (inspectionError) throw inspectionError;
|
|
19041
|
+
return;
|
|
19042
|
+
}
|
|
19043
|
+
for (const pid of pids) {
|
|
19044
|
+
try {
|
|
19045
|
+
process.kill(pid, "SIGKILL");
|
|
19046
|
+
} catch {
|
|
19047
|
+
}
|
|
19048
|
+
}
|
|
19049
|
+
signalProcessGroup(child, "SIGKILL");
|
|
19050
|
+
await waitForExit(pids, child.pid, FORCED_EXIT_TIMEOUT_MS);
|
|
19051
|
+
if (inspectionError) throw inspectionError;
|
|
19052
|
+
}
|
|
19053
|
+
var import_node_child_process2, GRACEFUL_TIMEOUT_MS, FORCED_EXIT_TIMEOUT_MS;
|
|
19054
|
+
var init_process_group = __esm({
|
|
19055
|
+
"../contrast/src/runtime/process-group.ts"() {
|
|
19056
|
+
"use strict";
|
|
19057
|
+
import_node_child_process2 = require("node:child_process");
|
|
19058
|
+
init_sleep2();
|
|
19059
|
+
GRACEFUL_TIMEOUT_MS = 3e3;
|
|
19060
|
+
FORCED_EXIT_TIMEOUT_MS = 1e3;
|
|
18896
19061
|
}
|
|
18897
19062
|
});
|
|
18898
19063
|
|
|
@@ -19456,28 +19621,51 @@ var init_optional_demo_registry = __esm({
|
|
|
19456
19621
|
});
|
|
19457
19622
|
|
|
19458
19623
|
// scripts/dev-server-scanner.ts
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19462
|
-
child = (0, import_child_process.
|
|
19624
|
+
function execGuarded(command, timeout, extra = {}) {
|
|
19625
|
+
const maxBuffer = extra.maxBuffer ?? 1024 * 1024;
|
|
19626
|
+
return new Promise((resolve9, reject) => {
|
|
19627
|
+
const child = (0, import_child_process.spawn)("/bin/sh", ["-c", command], {
|
|
19628
|
+
detached: true,
|
|
19629
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
19630
|
+
});
|
|
19631
|
+
let stdout = "";
|
|
19632
|
+
let settled = false;
|
|
19633
|
+
let killing = false;
|
|
19634
|
+
const settle = (err) => {
|
|
19635
|
+
if (settled) return;
|
|
19636
|
+
settled = true;
|
|
19637
|
+
clearTimeout(deadline);
|
|
19463
19638
|
if (err) reject(err);
|
|
19464
19639
|
else resolve9({ stdout });
|
|
19640
|
+
};
|
|
19641
|
+
const killThenSettle = (err) => {
|
|
19642
|
+
if (killing) return;
|
|
19643
|
+
killing = true;
|
|
19644
|
+
clearTimeout(deadline);
|
|
19645
|
+
terminateProcessGroup(child, "SIGKILL", 0).finally(() => settle(err));
|
|
19646
|
+
};
|
|
19647
|
+
const deadline = setTimeout(() => {
|
|
19648
|
+
killThenSettle(
|
|
19649
|
+
Object.assign(new Error(`\`${command}\` did not exit within ${timeout}ms`), {
|
|
19650
|
+
killed: true
|
|
19651
|
+
})
|
|
19652
|
+
);
|
|
19653
|
+
}, timeout);
|
|
19654
|
+
child.stdout.setEncoding("utf8");
|
|
19655
|
+
child.stdout.on("data", (chunk) => {
|
|
19656
|
+
stdout += chunk;
|
|
19657
|
+
if (stdout.length > maxBuffer) {
|
|
19658
|
+
killThenSettle(new Error(`\`${command}\` exceeded maxBuffer ${maxBuffer}`));
|
|
19659
|
+
}
|
|
19660
|
+
});
|
|
19661
|
+
child.on("error", (err) => {
|
|
19662
|
+
if (!killing) settle(err);
|
|
19663
|
+
});
|
|
19664
|
+
child.on("close", (code) => {
|
|
19665
|
+
if (killing) return;
|
|
19666
|
+
settle(code === 0 ? null : new Error(`\`${command}\` exited with ${code}`));
|
|
19465
19667
|
});
|
|
19466
19668
|
});
|
|
19467
|
-
let deadlineTimer;
|
|
19468
|
-
const deadline = new Promise((_resolve, reject) => {
|
|
19469
|
-
deadlineTimer = setTimeout(() => {
|
|
19470
|
-
child?.kill("SIGKILL");
|
|
19471
|
-
const err = new Error(`\`${command}\` did not exit within ${timeout}ms`);
|
|
19472
|
-
Object.assign(err, { killed: true });
|
|
19473
|
-
reject(err);
|
|
19474
|
-
}, timeout + EXEC_EXIT_GRACE_MS);
|
|
19475
|
-
});
|
|
19476
|
-
try {
|
|
19477
|
-
return await Promise.race([ran, deadline]);
|
|
19478
|
-
} finally {
|
|
19479
|
-
clearTimeout(deadlineTimer);
|
|
19480
|
-
}
|
|
19481
19669
|
}
|
|
19482
19670
|
async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
19483
19671
|
try {
|
|
@@ -19508,6 +19696,7 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
|
19508
19696
|
function httpGet(hostname, port, path21, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
19509
19697
|
return new Promise((resolve9) => {
|
|
19510
19698
|
let settled = false;
|
|
19699
|
+
let killing = false;
|
|
19511
19700
|
const settle = (value) => {
|
|
19512
19701
|
if (settled) return;
|
|
19513
19702
|
settled = true;
|
|
@@ -19562,6 +19751,20 @@ function wasKilledByTimeout(err) {
|
|
|
19562
19751
|
}
|
|
19563
19752
|
async function scanListeningProcesses(excludePorts = []) {
|
|
19564
19753
|
const excluded = new Set(excludePorts);
|
|
19754
|
+
const listing = await listListenersShared();
|
|
19755
|
+
if (listing.state === "could-not-look") return listing;
|
|
19756
|
+
return {
|
|
19757
|
+
state: "looked",
|
|
19758
|
+
processes: listing.processes.filter((p) => acceptPort(p.port, excluded))
|
|
19759
|
+
};
|
|
19760
|
+
}
|
|
19761
|
+
function listListenersShared() {
|
|
19762
|
+
inflightListing ??= listListeners().finally(() => {
|
|
19763
|
+
inflightListing = null;
|
|
19764
|
+
});
|
|
19765
|
+
return inflightListing;
|
|
19766
|
+
}
|
|
19767
|
+
async function listListeners() {
|
|
19565
19768
|
let timedOut = false;
|
|
19566
19769
|
try {
|
|
19567
19770
|
const { stdout } = await execGuarded(
|
|
@@ -19573,11 +19776,9 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
19573
19776
|
const parts = line.trim().split(/\s+/);
|
|
19574
19777
|
if (parts.length < 9) continue;
|
|
19575
19778
|
const pid = Number(parts[1]);
|
|
19576
|
-
const
|
|
19577
|
-
const m = addr.match(/:(\d+)$/);
|
|
19779
|
+
const m = parts[8].match(/:(\d+)$/);
|
|
19578
19780
|
if (!m) continue;
|
|
19579
19781
|
const port = Number(m[1]);
|
|
19580
|
-
if (!acceptPort(port, excluded)) continue;
|
|
19581
19782
|
if (!seen.has(port)) seen.set(port, pid);
|
|
19582
19783
|
}
|
|
19583
19784
|
return {
|
|
@@ -19599,7 +19800,6 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
19599
19800
|
if (!portMatch) continue;
|
|
19600
19801
|
const port = Number(portMatch[1]);
|
|
19601
19802
|
const pid = pidMatch ? Number(pidMatch[1]) : 0;
|
|
19602
|
-
if (!acceptPort(port, excluded)) continue;
|
|
19603
19803
|
if (!seen.has(port)) seen.set(port, pid);
|
|
19604
19804
|
}
|
|
19605
19805
|
return {
|
|
@@ -19610,10 +19810,7 @@ async function scanListeningProcesses(excludePorts = []) {
|
|
|
19610
19810
|
if (wasKilledByTimeout(err)) timedOut = true;
|
|
19611
19811
|
}
|
|
19612
19812
|
if (timedOut) return { state: "could-not-look" };
|
|
19613
|
-
return {
|
|
19614
|
-
state: "looked",
|
|
19615
|
-
processes: FALLBACK_PORTS.filter((p) => acceptPort(p.port, excluded))
|
|
19616
|
-
};
|
|
19813
|
+
return { state: "looked", processes: FALLBACK_PORTS };
|
|
19617
19814
|
}
|
|
19618
19815
|
function pidFromNetstat(stdout, port) {
|
|
19619
19816
|
for (const line of stdout.split("\n")) {
|
|
@@ -20097,11 +20294,12 @@ async function scanDevServers(opts = {}) {
|
|
|
20097
20294
|
}
|
|
20098
20295
|
return results.filter((r) => !isSootSimSelfServer(r));
|
|
20099
20296
|
}
|
|
20100
|
-
var import_child_process, import_promises2, import_http, import_net, import_node_fs2, import_node_path3,
|
|
20297
|
+
var import_child_process, import_promises2, import_http, import_net, import_node_fs2, import_node_path3, TIMEOUT_MS, MANIFEST_TIMEOUT_MS, TCP_GATE_MS, BODY_TIMEOUT_MS, FALLBACK_PORTS, SELF_PORT_RANGE_START, SELF_PORT_RANGE_END, DevServerScanUnavailableError, LISTING_TIMEOUT_MS, inflightListing, cwdByPid, localIconPathCache, localIconProbeInFlight, ENRICH_TIMEOUT_MS, enrichmentCache, enrichmentInFlight, knownNonPatched, knownNonExpo, knownOne, portCache, portCacheInvalidatedAt, NEGATIVE_CACHE_TTL_MS, WEAK_RESULT_CACHE_TTL_MS;
|
|
20101
20298
|
var init_dev_server_scanner = __esm({
|
|
20102
20299
|
"scripts/dev-server-scanner.ts"() {
|
|
20103
20300
|
"use strict";
|
|
20104
20301
|
import_child_process = require("child_process");
|
|
20302
|
+
init_process_group();
|
|
20105
20303
|
import_promises2 = require("fs/promises");
|
|
20106
20304
|
import_http = __toESM(require("http"), 1);
|
|
20107
20305
|
import_net = __toESM(require("net"), 1);
|
|
@@ -20112,7 +20310,6 @@ var init_dev_server_scanner = __esm({
|
|
|
20112
20310
|
init_native_dev_bundle_url();
|
|
20113
20311
|
init_settings_bundle();
|
|
20114
20312
|
init_optional_demo_registry();
|
|
20115
|
-
EXEC_EXIT_GRACE_MS = 2e3;
|
|
20116
20313
|
TIMEOUT_MS = 250;
|
|
20117
20314
|
MANIFEST_TIMEOUT_MS = 1500;
|
|
20118
20315
|
TCP_GATE_MS = 120;
|
|
@@ -20137,6 +20334,7 @@ var init_dev_server_scanner = __esm({
|
|
|
20137
20334
|
}
|
|
20138
20335
|
};
|
|
20139
20336
|
LISTING_TIMEOUT_MS = 1e4;
|
|
20337
|
+
inflightListing = null;
|
|
20140
20338
|
cwdByPid = /* @__PURE__ */ new Map();
|
|
20141
20339
|
localIconPathCache = /* @__PURE__ */ new Map();
|
|
20142
20340
|
localIconProbeInFlight = /* @__PURE__ */ new Set();
|
|
@@ -21157,7 +21355,7 @@ function sha256File(filePath) {
|
|
|
21157
21355
|
}
|
|
21158
21356
|
function extractTarball(tarPath, destDir) {
|
|
21159
21357
|
return new Promise((resolve9, reject) => {
|
|
21160
|
-
const child = (0,
|
|
21358
|
+
const child = (0, import_node_child_process3.spawn)("tar", ["-xzf", tarPath, "-C", destDir], {
|
|
21161
21359
|
stdio: ["ignore", "inherit", "inherit"]
|
|
21162
21360
|
});
|
|
21163
21361
|
child.on("error", reject);
|
|
@@ -21167,11 +21365,11 @@ function extractTarball(tarPath, destDir) {
|
|
|
21167
21365
|
});
|
|
21168
21366
|
});
|
|
21169
21367
|
}
|
|
21170
|
-
var
|
|
21368
|
+
var import_node_child_process3, import_node_crypto2, import_node_fs6, import_node_os2, import_node_path6, import_node_stream, import_promises3, DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT;
|
|
21171
21369
|
var init_src = __esm({
|
|
21172
21370
|
"../contrast-runtime-delivery/src/index.ts"() {
|
|
21173
21371
|
"use strict";
|
|
21174
|
-
|
|
21372
|
+
import_node_child_process3 = require("node:child_process");
|
|
21175
21373
|
import_node_crypto2 = __toESM(require("node:crypto"), 1);
|
|
21176
21374
|
import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
21177
21375
|
import_node_os2 = __toESM(require("node:os"), 1);
|
|
@@ -21879,7 +22077,7 @@ function mkfifoSync(p) {
|
|
|
21879
22077
|
import_node_fs9.default.unlinkSync(p);
|
|
21880
22078
|
}
|
|
21881
22079
|
}
|
|
21882
|
-
const result = (0,
|
|
22080
|
+
const result = (0, import_node_child_process4.spawnSync)("mkfifo", ["-m", "600", p]);
|
|
21883
22081
|
if (result.status !== 0) {
|
|
21884
22082
|
throw new Error(
|
|
21885
22083
|
`mkfifo(${p}) failed: ${result.stderr?.toString().trim() || "unknown error"}`
|
|
@@ -21947,7 +22145,7 @@ async function startSession(opts) {
|
|
|
21947
22145
|
if (claudeSessionUuid) {
|
|
21948
22146
|
wrapperArgs.push("--claude-session-uuid", claudeSessionUuid);
|
|
21949
22147
|
}
|
|
21950
|
-
const child = (0,
|
|
22148
|
+
const child = (0, import_node_child_process4.spawn)(executable, wrapperArgs, {
|
|
21951
22149
|
detached: true,
|
|
21952
22150
|
stdio: "ignore",
|
|
21953
22151
|
env: {
|
|
@@ -22099,11 +22297,11 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
|
|
|
22099
22297
|
import_node_fs9.default.closeSync(fd);
|
|
22100
22298
|
}
|
|
22101
22299
|
}
|
|
22102
|
-
var
|
|
22300
|
+
var import_node_child_process4, import_node_crypto4, import_node_fs9, import_node_path9, import_node_readline, AgentSessionError;
|
|
22103
22301
|
var init_agent_sessions = __esm({
|
|
22104
22302
|
"src/agent-sessions.ts"() {
|
|
22105
22303
|
"use strict";
|
|
22106
|
-
|
|
22304
|
+
import_node_child_process4 = require("node:child_process");
|
|
22107
22305
|
import_node_crypto4 = require("node:crypto");
|
|
22108
22306
|
import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
22109
22307
|
import_node_path9 = __toESM(require("node:path"), 1);
|
|
@@ -23271,11 +23469,11 @@ function looksBinary(filePath, size) {
|
|
|
23271
23469
|
if (fd !== void 0) import_node_fs11.default.closeSync(fd);
|
|
23272
23470
|
}
|
|
23273
23471
|
}
|
|
23274
|
-
var
|
|
23472
|
+
var import_node_child_process5, import_node_fs11, import_node_path11, CheckoutRequiresGitError, BINARY_SNIFF_BYTES, LIST_FILES_TIMEOUT_MS, LIST_FILES_ATTEMPTS, LIST_FILES_RETRY_MS, CheckoutFilePlane;
|
|
23275
23473
|
var init_checkout_plane = __esm({
|
|
23276
23474
|
"cli/commands/box/checkout-plane.ts"() {
|
|
23277
23475
|
"use strict";
|
|
23278
|
-
|
|
23476
|
+
import_node_child_process5 = require("node:child_process");
|
|
23279
23477
|
import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
23280
23478
|
import_node_path11 = __toESM(require("node:path"), 1);
|
|
23281
23479
|
CheckoutRequiresGitError = class extends Error {
|
|
@@ -23303,7 +23501,7 @@ var init_checkout_plane = __esm({
|
|
|
23303
23501
|
}
|
|
23304
23502
|
listFiles() {
|
|
23305
23503
|
const args = this.trackedOnly ? ["ls-files", "-z"] : ["ls-files", "-co", "--exclude-standard", "-z"];
|
|
23306
|
-
const stdout = (0,
|
|
23504
|
+
const stdout = (0, import_node_child_process5.execFileSync)("git", args, {
|
|
23307
23505
|
cwd: this.root,
|
|
23308
23506
|
encoding: "utf8",
|
|
23309
23507
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -24365,8 +24563,8 @@ var init_shared_session = __esm({
|
|
|
24365
24563
|
function rethrowIfExit(error) {
|
|
24366
24564
|
if (error instanceof PeachExit) throw error;
|
|
24367
24565
|
}
|
|
24368
|
-
function peachExit(code) {
|
|
24369
|
-
throw new PeachExit(code);
|
|
24566
|
+
function peachExit(code, reason) {
|
|
24567
|
+
throw new PeachExit(code, reason);
|
|
24370
24568
|
}
|
|
24371
24569
|
var import_node_async_hooks, PeachExit, sinks, rnxExit;
|
|
24372
24570
|
var init_run_rnx = __esm({
|
|
@@ -24375,10 +24573,12 @@ var init_run_rnx = __esm({
|
|
|
24375
24573
|
import_node_async_hooks = require("node:async_hooks");
|
|
24376
24574
|
PeachExit = class extends Error {
|
|
24377
24575
|
code;
|
|
24378
|
-
|
|
24576
|
+
reason;
|
|
24577
|
+
constructor(code, reason = null) {
|
|
24379
24578
|
super(`peach exited with code ${code}`);
|
|
24380
24579
|
this.name = "PeachExit";
|
|
24381
24580
|
this.code = code;
|
|
24581
|
+
this.reason = reason;
|
|
24382
24582
|
}
|
|
24383
24583
|
};
|
|
24384
24584
|
sinks = new import_node_async_hooks.AsyncLocalStorage();
|
|
@@ -27031,6 +27231,8 @@ var init_metro_asset_path = __esm({
|
|
|
27031
27231
|
function matchesModuleEntry(modulePath, pattern) {
|
|
27032
27232
|
if (!modulePath || !pattern) return false;
|
|
27033
27233
|
if (modulePath === pattern) return true;
|
|
27234
|
+
if (!modulePath.includes(pattern)) return false;
|
|
27235
|
+
if (!modulePath.includes(`node_modules/${pattern}`)) return false;
|
|
27034
27236
|
if (modulePath === `node_modules/${pattern}`) return true;
|
|
27035
27237
|
if (modulePath === `node_modules/${pattern}.js`) return true;
|
|
27036
27238
|
if (modulePath === `node_modules/${pattern}.ts`) return true;
|
|
@@ -28850,24 +29052,8 @@ var init_bridge_host = __esm({
|
|
|
28850
29052
|
// terminal 4001 code, so the client closes the abandoned window instead
|
|
28851
29053
|
// of reconnecting the zombie straight back in.
|
|
28852
29054
|
static SIM_IDLE_REAP_TTL_MS = 30 * 6e4;
|
|
28853
|
-
// automation sims (spawned by the playwright driver: `peach open --driver
|
|
28854
|
-
// playwright`, the factory/screenshot capture path — `meta.sootsimHostDriver
|
|
28855
|
-
// === 'playwright'`) are unattended one-shot browsers, never a human's tab. a
|
|
28856
|
-
// capture run opens one per slide/app/retry and the 30-min human/dev TTL lets
|
|
28857
|
-
// hundreds pile up inside the window — orphaned ms-playwright chromiums that
|
|
28858
|
-
// drove the box to swap-thrash (load hit 157 in one incident). give them a far
|
|
28859
|
-
// shorter idle TTL, and cap how many can sit concurrently: reap the most-idle
|
|
28860
|
-
// overflow, but never a sim active within ACTIVE_GRACE (an agent composing
|
|
28861
|
-
// between captures), nor primary / cli-attached / leased sims.
|
|
28862
|
-
static AUTOMATION_SIM_IDLE_REAP_TTL_MS = 10 * 6e4;
|
|
28863
|
-
static MAX_CONCURRENT_AUTOMATION_SIMS = 6;
|
|
28864
|
-
static AUTOMATION_SIM_ACTIVE_GRACE_MS = 6e4;
|
|
28865
29055
|
preferredPort;
|
|
28866
29056
|
portFallbackCount;
|
|
28867
|
-
simIdleReapTtlMs;
|
|
28868
|
-
automationSimIdleReapTtlMs;
|
|
28869
|
-
maxConcurrentAutomationSims;
|
|
28870
|
-
automationSimActiveGraceMs;
|
|
28871
29057
|
shouldWriteLockfile;
|
|
28872
29058
|
shouldWriteDevLockfile;
|
|
28873
29059
|
getShellPort;
|
|
@@ -28910,23 +29096,12 @@ var init_bridge_host = __esm({
|
|
|
28910
29096
|
getExcludePorts: opts.agentScanExcludes
|
|
28911
29097
|
});
|
|
28912
29098
|
this.contrastOrigin = opts.contrastOrigin?.replace(/\/$/, "") || null;
|
|
28913
|
-
this.simIdleReapTtlMs = opts.simIdleReapTtlMs ?? _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
|
|
28914
|
-
this.automationSimIdleReapTtlMs = opts.automationSimIdleReapTtlMs ?? _SootSimBridgeHost.AUTOMATION_SIM_IDLE_REAP_TTL_MS;
|
|
28915
|
-
this.maxConcurrentAutomationSims = opts.maxConcurrentAutomationSims ?? _SootSimBridgeHost.MAX_CONCURRENT_AUTOMATION_SIMS;
|
|
28916
|
-
this.automationSimActiveGraceMs = opts.automationSimActiveGraceMs ?? _SootSimBridgeHost.AUTOMATION_SIM_ACTIVE_GRACE_MS;
|
|
28917
29099
|
}
|
|
28918
29100
|
/** expose the agent host so tests and embedders can inspect state or
|
|
28919
29101
|
* inject behavior. not part of the public WS protocol. */
|
|
28920
29102
|
getAgentHost() {
|
|
28921
29103
|
return this.agentHost;
|
|
28922
29104
|
}
|
|
28923
|
-
/** run the abandoned-sim GC pass on demand. the reaper normally fires off
|
|
28924
|
-
* the 30s idle-sweep timer; this lets the F21-3 integration test drive
|
|
28925
|
-
* the real path without waiting for the timer. not part of the public
|
|
28926
|
-
* WS protocol. */
|
|
28927
|
-
reapIdleSimsForTest(now = Date.now()) {
|
|
28928
|
-
this.reapIdleSims(now);
|
|
28929
|
-
}
|
|
28930
29105
|
/** synchronous wrapper around startAsync for callers that don't care
|
|
28931
29106
|
* about port fallback outcomes. returns immediately; actual binding
|
|
28932
29107
|
* happens on the event loop. callers that need to know the bound port
|
|
@@ -29172,6 +29347,10 @@ var init_bridge_host = __esm({
|
|
|
29172
29347
|
this.updateUserActivity(sim);
|
|
29173
29348
|
return;
|
|
29174
29349
|
}
|
|
29350
|
+
if (msg.type === "bridge:capture-active" && sim) {
|
|
29351
|
+
sim.lastActiveAt = Date.now();
|
|
29352
|
+
return;
|
|
29353
|
+
}
|
|
29175
29354
|
if (msg.type === "bridge:write-shared-config") {
|
|
29176
29355
|
if (!msg.patch || typeof msg.patch !== "object" || Array.isArray(msg.patch)) {
|
|
29177
29356
|
return;
|
|
@@ -30172,53 +30351,21 @@ var init_bridge_host = __esm({
|
|
|
30172
30351
|
// automation sims are spawned by the playwright driver (`peach open
|
|
30173
30352
|
// --driver playwright`, the factory/screenshot capture path), which tags them
|
|
30174
30353
|
// with `meta.sootsimHostDriver === 'playwright'` via the host's addInitScript.
|
|
30175
|
-
// they are unattended one-shot browsers, never a human's tab, so they get a
|
|
30176
|
-
// shorter idle TTL and a concurrent cap.
|
|
30177
30354
|
isAutomationSim(sim) {
|
|
30178
30355
|
return sim.meta?.sootsimHostDriver === "playwright";
|
|
30179
30356
|
}
|
|
30180
|
-
// an automation sim whose spawning playwright host process is still alive is
|
|
30181
|
-
// an ACTIVE run, not an abandoned tab. mirrors the cli's playwrightHostPidForSim
|
|
30182
|
-
// (control.ts): extract the host pid from meta, then check liveness so the
|
|
30183
|
-
// host-side idle GC never kills a live capture/factory sim mid-run.
|
|
30184
|
-
automationSimOwnerAlive(sim) {
|
|
30185
|
-
const pid = Number(sim.meta?.sootsimHostPid);
|
|
30186
|
-
if (!Number.isInteger(pid) || pid <= 1 || pid === process.pid) return false;
|
|
30187
|
-
try {
|
|
30188
|
-
process.kill(pid, 0);
|
|
30189
|
-
return true;
|
|
30190
|
-
} catch (err) {
|
|
30191
|
-
return err.code === "EPERM";
|
|
30192
|
-
}
|
|
30193
|
-
}
|
|
30194
30357
|
reapIdleSims(now = Date.now()) {
|
|
30195
30358
|
const attachedSimIds = new Set(this.cliSimBySocket.values());
|
|
30196
|
-
const automationLive = [];
|
|
30197
30359
|
for (const sim of this.sims.values()) {
|
|
30198
|
-
if (sim.id === this.primarySimId) continue;
|
|
30199
30360
|
if (attachedSimIds.has(sim.id)) continue;
|
|
30200
|
-
if (this.getActiveLease(sim)) continue;
|
|
30201
|
-
const lastTouched = Math.max(sim.lastActiveAt, sim.connectedAt);
|
|
30202
|
-
const idleMs = now - lastTouched;
|
|
30203
30361
|
const automation = this.isAutomationSim(sim);
|
|
30204
|
-
|
|
30205
|
-
|
|
30206
|
-
if (idleMs >= ttl) {
|
|
30207
|
-
this.closeSimSocketFromHost(sim.ws);
|
|
30362
|
+
const lease = this.getActiveLease(sim);
|
|
30363
|
+
if (automation ? lease?.kind === "user-active" : sim.id === this.primarySimId || lease) {
|
|
30208
30364
|
continue;
|
|
30209
30365
|
}
|
|
30210
|
-
|
|
30211
|
-
|
|
30212
|
-
|
|
30213
|
-
if (automationLive.length > cap) {
|
|
30214
|
-
automationLive.sort((a, b) => b.idleMs - a.idleMs);
|
|
30215
|
-
for (const { sim, idleMs } of automationLive.slice(
|
|
30216
|
-
0,
|
|
30217
|
-
automationLive.length - cap
|
|
30218
|
-
)) {
|
|
30219
|
-
if (idleMs < this.automationSimActiveGraceMs) continue;
|
|
30220
|
-
this.closeSimSocketFromHost(sim.ws);
|
|
30221
|
-
}
|
|
30366
|
+
const idleMs = now - Math.max(sim.lastActiveAt, sim.connectedAt);
|
|
30367
|
+
const ttl = automation ? AUTOMATION_SIM_IDLE_REAP_TTL_MS : _SootSimBridgeHost.SIM_IDLE_REAP_TTL_MS;
|
|
30368
|
+
if (idleMs >= ttl) this.closeSimSocketFromHost(sim.ws);
|
|
30222
30369
|
}
|
|
30223
30370
|
}
|
|
30224
30371
|
// ping every connected ws; if the previous round's ping went unanswered,
|
|
@@ -33791,7 +33938,7 @@ function resolvePlaywright() {
|
|
|
33791
33938
|
}
|
|
33792
33939
|
function probeBrowser(resolved, env) {
|
|
33793
33940
|
const self = rnxSelfInvocation();
|
|
33794
|
-
const probe3 = (0,
|
|
33941
|
+
const probe3 = (0, import_node_child_process6.spawnSync)(
|
|
33795
33942
|
self.executable,
|
|
33796
33943
|
[...self.prefixArgs, RNX_INTERNAL_COMMAND, RNX_INTERNAL_CHILDREN.playwrightProbe],
|
|
33797
33944
|
{
|
|
@@ -33834,7 +33981,7 @@ function ensurePlaywrightBrowser(resolved, env = process.env) {
|
|
|
33834
33981
|
return { ok: true, executablePath: before.executablePath, installed: false };
|
|
33835
33982
|
}
|
|
33836
33983
|
const installer = rnxSelfInvocation();
|
|
33837
|
-
const install = (0,
|
|
33984
|
+
const install = (0, import_node_child_process6.spawnSync)(
|
|
33838
33985
|
installer.executable,
|
|
33839
33986
|
[
|
|
33840
33987
|
...installer.prefixArgs,
|
|
@@ -33869,11 +34016,11 @@ ${detail}` : ""}`
|
|
|
33869
34016
|
}
|
|
33870
34017
|
return { ok: true, executablePath: after.executablePath, installed: true };
|
|
33871
34018
|
}
|
|
33872
|
-
var
|
|
34019
|
+
var import_node_child_process6, import_node_fs20, import_node_module4, import_node_path22;
|
|
33873
34020
|
var init_playwright_provisioning = __esm({
|
|
33874
34021
|
"cli/drivers/playwright-provisioning.ts"() {
|
|
33875
34022
|
"use strict";
|
|
33876
|
-
|
|
34023
|
+
import_node_child_process6 = require("node:child_process");
|
|
33877
34024
|
import_node_fs20 = require("node:fs");
|
|
33878
34025
|
import_node_module4 = require("node:module");
|
|
33879
34026
|
import_node_path22 = require("node:path");
|
|
@@ -33990,7 +34137,8 @@ ${hint}` : ""}`
|
|
|
33990
34137
|
};
|
|
33991
34138
|
}
|
|
33992
34139
|
const ownerComm = getProcessComm(ownerPid);
|
|
33993
|
-
const
|
|
34140
|
+
const idleMinutes = AUTOMATION_SIM_IDLE_REAP_TTL_MS / 6e4;
|
|
34141
|
+
const ownerNote = ` \u2014 browser closes after ${idleMinutes} min with no peach command, or when pid ${ownerPid}${ownerComm ? ` (${ownerComm})` : ""} exits`;
|
|
33994
34142
|
return {
|
|
33995
34143
|
launched: true,
|
|
33996
34144
|
message: `playwright chrome launched \u2192 ${opts.url}${ownerNote}`,
|
|
@@ -34017,6 +34165,7 @@ var init_playwright = __esm({
|
|
|
34017
34165
|
import_fs8 = require("fs");
|
|
34018
34166
|
import_os2 = require("os");
|
|
34019
34167
|
import_path7 = require("path");
|
|
34168
|
+
init_bridge_constants();
|
|
34020
34169
|
init_playwright_host_log();
|
|
34021
34170
|
init_profiles();
|
|
34022
34171
|
init_internal_child();
|
|
@@ -34550,7 +34699,7 @@ async function ensureRuntimeForOpen() {
|
|
|
34550
34699
|
}
|
|
34551
34700
|
function spawnSootsim(args) {
|
|
34552
34701
|
const { executable, prefixArgs } = rnxSelfInvocation();
|
|
34553
|
-
return (0,
|
|
34702
|
+
return (0, import_node_child_process7.spawn)(executable, [...prefixArgs, ...args], {
|
|
34554
34703
|
detached: true,
|
|
34555
34704
|
stdio: "ignore",
|
|
34556
34705
|
env: process.env
|
|
@@ -34906,12 +35055,14 @@ async function buildShellUrl(target, baseUrl = resolveDefaultShellBaseUrl(), opt
|
|
|
34906
35055
|
await stampAppSplash(await stampAppFonts(resolved, project), project),
|
|
34907
35056
|
project
|
|
34908
35057
|
);
|
|
34909
|
-
if (!opts.device && !opts.proof && !opts.posture && !opts.osVersion
|
|
35058
|
+
if (!opts.device && !opts.proof && !opts.posture && !opts.osVersion && !opts.env?.length)
|
|
35059
|
+
return stamped;
|
|
34910
35060
|
const url = new URL(stamped);
|
|
34911
35061
|
if (opts.device) url.searchParams.set("device", opts.device);
|
|
34912
35062
|
if (opts.posture) url.searchParams.set("posture", opts.posture);
|
|
34913
35063
|
if (opts.osVersion) url.searchParams.set("osVersion", opts.osVersion);
|
|
34914
35064
|
if (opts.proof) url.searchParams.set("proof", "1");
|
|
35065
|
+
for (const entry of opts.env ?? []) url.searchParams.append("env", entry);
|
|
34915
35066
|
return url.toString();
|
|
34916
35067
|
}
|
|
34917
35068
|
function deriveCurrentSimBaseUrl(sim, fallback) {
|
|
@@ -35089,11 +35240,11 @@ async function waitForProcessExit(pid, timeoutMs = 2500) {
|
|
|
35089
35240
|
return !isProcessAlive2(pid);
|
|
35090
35241
|
}
|
|
35091
35242
|
function isPlaywrightHostProcess(pid) {
|
|
35092
|
-
const plain = (0,
|
|
35243
|
+
const plain = (0, import_node_child_process7.spawnSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
35093
35244
|
encoding: "utf8",
|
|
35094
35245
|
stdio: ["ignore", "pipe", "pipe"]
|
|
35095
35246
|
});
|
|
35096
|
-
const withEnv = (0,
|
|
35247
|
+
const withEnv = (0, import_node_child_process7.spawnSync)("ps", ["eww", "-o", "command=", "-p", String(pid)], {
|
|
35097
35248
|
encoding: "utf8",
|
|
35098
35249
|
stdio: ["ignore", "pipe", "pipe"]
|
|
35099
35250
|
});
|
|
@@ -35319,7 +35470,8 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
35319
35470
|
"--device",
|
|
35320
35471
|
"--posture",
|
|
35321
35472
|
"--os-version",
|
|
35322
|
-
"--viewport"
|
|
35473
|
+
"--viewport",
|
|
35474
|
+
"--env"
|
|
35323
35475
|
]
|
|
35324
35476
|
});
|
|
35325
35477
|
const requestedProfileId = args.find((_, i) => args[i - 1] === "--profile");
|
|
@@ -35464,6 +35616,17 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
35464
35616
|
);
|
|
35465
35617
|
rnxExit(1);
|
|
35466
35618
|
}
|
|
35619
|
+
const envArgs = [];
|
|
35620
|
+
for (let i = 0; i < args.length; i++) {
|
|
35621
|
+
if (args[i] !== "--env") continue;
|
|
35622
|
+
const raw = args[i + 1];
|
|
35623
|
+
const eqIndex = raw ? raw.indexOf("=") : -1;
|
|
35624
|
+
if (!raw || eqIndex <= 0) {
|
|
35625
|
+
console.error(` peach open: --env expects KEY=VALUE, got "${raw ?? ""}"`);
|
|
35626
|
+
rnxExit(1);
|
|
35627
|
+
}
|
|
35628
|
+
envArgs.push(raw);
|
|
35629
|
+
}
|
|
35467
35630
|
const viewportArg = args.find((_, i) => args[i - 1] === "--viewport");
|
|
35468
35631
|
const viewportMatch = viewportArg ? /^(\d+)x(\d+)$/.exec(viewportArg) : null;
|
|
35469
35632
|
if (viewportArg && !viewportMatch) {
|
|
@@ -35480,7 +35643,8 @@ async function runOpenCommand(args, opts = {}) {
|
|
|
35480
35643
|
osVersion: osVersionArg,
|
|
35481
35644
|
resolvedBundle,
|
|
35482
35645
|
project,
|
|
35483
|
-
proof: args.includes("--proof")
|
|
35646
|
+
proof: args.includes("--proof"),
|
|
35647
|
+
env: envArgs.length ? envArgs : void 0
|
|
35484
35648
|
};
|
|
35485
35649
|
const selectedShellBaseUrl = configuredRuntimeVersion ? `http://localhost:${parsed.wsPort}/` : explicitBaseUrl || resolveShellBaseUrlForBridgePort(parsed.wsPort);
|
|
35486
35650
|
const baseUrl = applyRuntimeGenerationOrigin(
|
|
@@ -35986,11 +36150,11 @@ async function runCloseCommand(args, opts = {}) {
|
|
|
35986
36150
|
bridge.close();
|
|
35987
36151
|
}
|
|
35988
36152
|
}
|
|
35989
|
-
var
|
|
36153
|
+
var import_node_child_process7, import_node_fs21, import_node_os3, import_node_path23, import_app_catalog_wire, import_settings, import_ws4, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEV_BUNDLE_RESOLVE_ATTEMPTS, DEV_BUNDLE_RESOLVE_INTERVAL_MS;
|
|
35990
36154
|
var init_control = __esm({
|
|
35991
36155
|
"cli/commands/control.ts"() {
|
|
35992
36156
|
"use strict";
|
|
35993
|
-
|
|
36157
|
+
import_node_child_process7 = require("node:child_process");
|
|
35994
36158
|
import_node_fs21 = __toESM(require("node:fs"), 1);
|
|
35995
36159
|
import_node_os3 = __toESM(require("node:os"), 1);
|
|
35996
36160
|
import_node_path23 = __toESM(require("node:path"), 1);
|