rnxsim 0.1.370 → 0.1.372
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/cli/bin.ts +2 -2
- package/cli/commands/box/checkout-plane.ts +65 -14
- package/cli/commands/box/cloud-box.ts +294 -0
- package/cli/commands/box/plane-share.ts +208 -0
- package/cli/commands/box/rnx-command.ts +2 -2
- package/cli/commands/box/search-command.ts +157 -0
- package/cli/commands/box.ts +269 -13
- package/cli/commands/control.ts +6 -1
- package/cli/outbound-endpoints.ts +37 -1
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-3R4424LW.js → agent-RTAKJ5UM.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-4PPWZWSY.js → agent-wrapper-JWRDI26D.js} +2 -2
- package/dist-cli/chunks/{app-fonts-KYXB6CXQ.js → app-fonts-RKO3N4PB.js} +2 -2
- package/dist-cli/chunks/{assert-7EZOWGYQ.js → assert-Y5LXPWC6.js} +2 -2
- package/dist-cli/chunks/{auth-L7M36H6C.js → auth-4SPTRWTM.js} +2 -2
- package/dist-cli/chunks/{beta-FKAF6YWJ.js → beta-KYS22QPY.js} +2 -2
- package/dist-cli/chunks/{box-5Y5VBMHV.js → box-7CK72ZPF.js} +617 -596
- package/dist-cli/chunks/{camera-XHF2RPFG.js → camera-RUL426MQ.js} +2 -2
- package/dist-cli/chunks/{chunk-EQ3OE2AV.js → chunk-2MA3Q44D.js} +1 -1
- package/dist-cli/chunks/{chunk-DHYTRCIP.js → chunk-2OA2WE7G.js} +2 -2
- package/dist-cli/chunks/{chunk-DMHSD6YJ.js → chunk-3C6LTIDV.js} +2 -2
- package/dist-cli/chunks/{chunk-NR2V2ONN.js → chunk-4UMODU6C.js} +2 -2
- package/dist-cli/chunks/{chunk-Z2VBSNFI.js → chunk-5Q6ZEZFF.js} +1 -1
- package/dist-cli/chunks/{chunk-LUOHRBJG.js → chunk-7FYOZQBM.js} +1 -1
- package/dist-cli/chunks/{chunk-Q4MRJ6PO.js → chunk-BRRWRBW7.js} +2 -2
- package/dist-cli/chunks/chunk-CEQXZ3GA.js +11 -0
- package/dist-cli/chunks/{chunk-DUXHYPBP.js → chunk-CZ2FOZVC.js} +2 -2
- package/dist-cli/chunks/{chunk-CMVRTZ5G.js → chunk-D5AT7UT5.js} +2 -2
- package/dist-cli/chunks/{chunk-D2GZASRV.js → chunk-DQOQQFMP.js} +1 -1
- package/dist-cli/chunks/{chunk-3UXXYJVD.js → chunk-EKSSAC4L.js} +1 -1
- package/dist-cli/chunks/{chunk-5BR33NAZ.js → chunk-EY5OHL2M.js} +1 -1
- package/dist-cli/chunks/{chunk-FK4JSTZ3.js → chunk-FOW2LPM7.js} +2 -2
- package/dist-cli/chunks/{chunk-WFQHT4QD.js → chunk-G5G7PQKO.js} +2 -2
- package/dist-cli/chunks/{chunk-WPV4H5S4.js → chunk-GPYG2L7R.js} +2 -2
- package/dist-cli/chunks/{chunk-3SOPYG7S.js → chunk-H2SKPUSI.js} +2 -2
- package/dist-cli/chunks/{chunk-6A6L3VJR.js → chunk-H567W7JT.js} +2 -2
- package/dist-cli/chunks/{chunk-PAUEZO6F.js → chunk-HDGZAVH3.js} +2 -2
- package/dist-cli/chunks/{chunk-AALKIAUZ.js → chunk-I37LRPZ3.js} +1 -1
- package/dist-cli/chunks/{chunk-JZLDHPB7.js → chunk-I7LRVN5M.js} +2 -2
- package/dist-cli/chunks/{chunk-3BG6UCQY.js → chunk-IX25FFF3.js} +11 -11
- package/dist-cli/chunks/{chunk-72S5FCBY.js → chunk-J2TJRPDB.js} +2 -2
- package/dist-cli/chunks/{chunk-RRX52O37.js → chunk-JPRHJMUJ.js} +1 -1
- package/dist-cli/chunks/{chunk-BMIJZNKD.js → chunk-K4TGUDY4.js} +2 -2
- package/dist-cli/chunks/{chunk-7C7TJYZ3.js → chunk-KSE5XGYU.js} +2 -2
- package/dist-cli/chunks/{chunk-OJZHECGH.js → chunk-KVVNCIJA.js} +1 -1
- package/dist-cli/chunks/{chunk-LXPHL6FO.js → chunk-KWLUOLYQ.js} +2 -2
- package/dist-cli/chunks/{chunk-C7BA5CCM.js → chunk-KXAE64HF.js} +2 -2
- package/dist-cli/chunks/{chunk-EWSWOWXK.js → chunk-L5BEWXQZ.js} +2 -2
- package/dist-cli/chunks/{chunk-D24EOJ4C.js → chunk-LAQKTHRM.js} +2 -2
- package/dist-cli/chunks/{chunk-IDLFVRPN.js → chunk-LWLHVF6Y.js} +1 -1
- package/dist-cli/chunks/{chunk-EOIBLKZO.js → chunk-MKHW3JNL.js} +2 -2
- package/dist-cli/chunks/{chunk-64JAEJ6N.js → chunk-MSM2E74F.js} +1 -1
- package/dist-cli/chunks/{chunk-DXV37CJN.js → chunk-NBEOA72C.js} +1 -1
- package/dist-cli/chunks/{chunk-H5X5FJ63.js → chunk-NLMDMNO6.js} +2 -2
- package/dist-cli/chunks/{chunk-6W4HIWC7.js → chunk-NT43X5LI.js} +2 -2
- package/dist-cli/chunks/{chunk-PNOENVMJ.js → chunk-NWPYM54M.js} +1 -1
- package/dist-cli/chunks/{chunk-O6QLKSAM.js → chunk-OLHHB6LD.js} +2 -2
- package/dist-cli/chunks/{chunk-MDCY532E.js → chunk-P6K6XFWE.js} +2 -2
- package/dist-cli/chunks/{chunk-LIMWG54N.js → chunk-PETP6LVI.js} +1 -1
- package/dist-cli/chunks/{chunk-YIZGNT7A.js → chunk-PKY76S57.js} +1 -1
- package/dist-cli/chunks/chunk-POR7R3TP.js +4 -0
- package/dist-cli/chunks/chunk-PUH6RQBJ.js +7 -0
- package/dist-cli/chunks/{chunk-NJMU5BN6.js → chunk-Q5WPPOFV.js} +1 -1
- package/dist-cli/chunks/{chunk-HQQTS2CB.js → chunk-Q7JSU5DI.js} +3 -3
- package/dist-cli/chunks/{chunk-U63T6LIQ.js → chunk-QA2PTSOC.js} +1 -1
- package/dist-cli/chunks/{chunk-2FOGXVOK.js → chunk-R7HMFLXI.js} +2 -2
- package/dist-cli/chunks/{chunk-FA75F34Z.js → chunk-RXKZJAGY.js} +1 -1
- package/dist-cli/chunks/{chunk-5RKRVS5A.js → chunk-SC7PGULZ.js} +2 -2
- package/dist-cli/chunks/{chunk-UFVAAWGZ.js → chunk-SLTEYNAE.js} +1 -1
- package/dist-cli/chunks/{chunk-6GPS7U4X.js → chunk-SSQCKJQZ.js} +2 -2
- package/dist-cli/chunks/{chunk-ARMXC3C3.js → chunk-SZX6ARJX.js} +3 -3
- package/dist-cli/chunks/{chunk-6S5LJV2O.js → chunk-U3XYGLXG.js} +2 -2
- package/dist-cli/chunks/chunk-UA5WQCBU.js +7 -0
- package/dist-cli/chunks/{chunk-VVQCZ42C.js → chunk-UVKX6FQ4.js} +1 -1
- package/dist-cli/chunks/{chunk-Z3DENGXW.js → chunk-VQQXUXXF.js} +2 -2
- package/dist-cli/chunks/{chunk-I52NT6VG.js → chunk-WR7LRCYW.js} +1 -1
- package/dist-cli/chunks/{chunk-HEKHLQ3B.js → chunk-XA4YU3A4.js} +3 -3
- package/dist-cli/chunks/{chunk-GRO74J2X.js → chunk-YEGWC2OY.js} +1 -1
- package/dist-cli/chunks/{chunk-AVJBT5LF.js → chunk-YWTBN7SD.js} +1 -1
- package/dist-cli/chunks/{chunk-PIZXOXBL.js → chunk-ZRQKEKHX.js} +2 -2
- package/dist-cli/chunks/{chunk-X6WQ4YWE.js → chunk-ZTZTRD5R.js} +1 -1
- package/dist-cli/chunks/{cleanup-MXMMJ7JW.js → cleanup-7ATBNZHC.js} +2 -2
- package/dist-cli/chunks/cli-version-D2IDQO7X.js +4 -0
- package/dist-cli/chunks/{compat-E6KE5KDI.js → compat-4ZC6ZMMA.js} +2 -2
- package/dist-cli/chunks/{config-QSLLVZDS.js → config-EOBODQ32.js} +2 -2
- package/dist-cli/chunks/{connect-QE4VU6GB.js → connect-ZQ72CZ7O.js} +2 -2
- package/dist-cli/chunks/control-FKPKLOE2.js +4 -0
- package/dist-cli/chunks/daemon-WFHWS3JU.js +4 -0
- package/dist-cli/chunks/{debug-5FG3MBJS.js → debug-7Z325GNU.js} +3 -3
- package/dist-cli/chunks/{desktop-5EZX7NX5.js → desktop-CR7ALX7H.js} +3 -3
- package/dist-cli/chunks/{detox-WJGQP5TM.js → detox-RZ37736M.js} +2 -2
- package/dist-cli/chunks/{device-D7LKCAMS.js → device-TA3SQP6K.js} +2 -2
- package/dist-cli/chunks/{diagnose-A3W6ZTGA.js → diagnose-JFKFKR3S.js} +2 -2
- package/dist-cli/chunks/disk-cleanup-HZM7VM4S.js +4 -0
- package/dist-cli/chunks/{do-chain-RUJNRPPF.js → do-chain-MTT65YNX.js} +2 -2
- package/dist-cli/chunks/drivers-BXEXWRVJ.js +4 -0
- package/dist-cli/chunks/{env-U67SQVTV.js → env-SFI24PLS.js} +2 -2
- package/dist-cli/chunks/{film-XC6UAQ3V.js → film-GPHSJLIH.js} +3 -3
- package/dist-cli/chunks/flow-FBCU3TZN.js +4 -0
- package/dist-cli/chunks/help-6MLROWYO.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-7S2TNZXG.js → hidden-runtime-alias-7Z6PYH53.js} +2 -2
- package/dist-cli/chunks/{home-paths-LMO5LB4F.js → home-paths-MEGVA6ET.js} +2 -2
- package/dist-cli/chunks/inspect-EWT5SXBD.js +4 -0
- package/dist-cli/chunks/install-desktop-IFBUH7MH.js +4 -0
- package/dist-cli/chunks/{login-JIU42S4C.js → login-EHUZYRAM.js} +2 -2
- package/dist-cli/chunks/{logout-JTAWQXZO.js → logout-WPGT62N6.js} +2 -2
- package/dist-cli/chunks/{maestro-TYBQYOGB.js → maestro-4HVDLCTI.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-YLAGWVKE.js → maestro-generate-VBS2EZMM.js} +3 -3
- package/dist-cli/chunks/{mode-DV24ZRZ6.js → mode-MGTS4QTF.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-JZH66VIM.js → optional-demo-registry-F3FQT5WT.js} +2 -2
- package/dist-cli/chunks/{perf-LXXJ4EAX.js → perf-47R3OEI7.js} +2 -2
- package/dist-cli/chunks/{permissions-KAOVZUPW.js → permissions-ZOLFZWR2.js} +2 -2
- package/dist-cli/chunks/{platform-KW35446W.js → platform-C4E26ZBZ.js} +3 -3
- package/dist-cli/chunks/privacy-WXGGG4ZI.js +4 -0
- package/dist-cli/chunks/{record-EK3ETFHZ.js → record-OUXWCWUF.js} +3 -3
- package/dist-cli/chunks/{report-issue-NW5PCAZF.js → report-issue-LJJXONXQ.js} +2 -2
- package/dist-cli/chunks/reset-ZZYLPETS.js +4 -0
- package/dist-cli/chunks/resolve-target-MVZZR2JW.js +4 -0
- package/dist-cli/chunks/runtime-DEC5AF3M.js +4 -0
- package/dist-cli/chunks/{screenshot-command-TQSPTFT2.js → screenshot-command-CUHDOS5D.js} +3 -3
- package/dist-cli/chunks/{screenshot-layers-IZP3L3AQ.js → screenshot-layers-DVWQVKT6.js} +2 -2
- package/dist-cli/chunks/{screenshots-capture-K7LJOVAE.js → screenshots-capture-GWIUJ3A6.js} +2 -2
- package/dist-cli/chunks/{serve-MMX4WXXG.js → serve-TX5OKGJM.js} +19 -19
- package/dist-cli/chunks/setup-X7LLGW67.js +4 -0
- package/dist-cli/chunks/{sim-client-KLAYIFOC.js → sim-client-W4WZOZ3P.js} +2 -2
- package/dist-cli/chunks/{skills-N4D3POIS.js → skills-TDFQAZ6A.js} +2 -2
- package/dist-cli/chunks/{state-ES6TFQZF.js → state-P2Z25OLQ.js} +2 -2
- package/dist-cli/chunks/{storage-52DR5V2C.js → storage-DWEOFXEB.js} +2 -2
- package/dist-cli/chunks/store-TKBLMYCV.js +4 -0
- package/dist-cli/chunks/telemetry-E3CBKJMD.js +4 -0
- package/dist-cli/chunks/{timeline-NRVNB5JR.js → timeline-55XNA4GX.js} +2 -2
- package/dist-cli/chunks/{upgrade-LNED5YQ2.js → upgrade-3XRCVDVC.js} +2 -2
- package/dist-cli/chunks/upload-QB77GSMQ.js +4 -0
- package/dist-cli/chunks/{version-VEF2DYGG.js → version-WTYGLXBJ.js} +2 -2
- package/dist-cli/chunks/{web-CGDE6S73.js → web-ZWRY3VHM.js} +2 -2
- package/dist-cli/chunks/welcome-7ATM5EGX.js +5 -0
- package/dist-cli/chunks/{what-happened-FSIDWL32.js → what-happened-Q3IGIH4K.js} +2 -2
- package/dist-cli/chunks/{ws-bridge-QXFQLRE7.js → ws-bridge-KCPZSBBX.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/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/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 +69 -34
- package/dist-lib/home-paths.cjs +1 -1
- package/dist-lib/host/bridge-host.cjs +430 -106
- 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 +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-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 +149 -93
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +679 -307
- package/dist-lib/vite.cjs +1 -1
- package/package.json +1 -1
- package/scripts/dev-server-scanner.ts +275 -92
- package/src/dev-bundle-resolution.ts +123 -40
- package/src/disk-cleanup.ts +44 -0
- package/src/host/bridge-host.ts +11 -0
- package/src/host/plane-host.ts +203 -0
- package/dist-cli/chunks/chunk-GJRLPJQL.js +0 -6
- package/dist-cli/chunks/chunk-NTC46LSA.js +0 -4
- package/dist-cli/chunks/chunk-OTFTMGAL.js +0 -7
- package/dist-cli/chunks/cli-version-MLS55UTY.js +0 -4
- package/dist-cli/chunks/control-XD5F6K5T.js +0 -4
- package/dist-cli/chunks/daemon-UN5SE2JO.js +0 -4
- package/dist-cli/chunks/disk-cleanup-BDRHX5ZG.js +0 -4
- package/dist-cli/chunks/drivers-3NJ5RL6X.js +0 -4
- package/dist-cli/chunks/flow-FHZZD3P6.js +0 -4
- package/dist-cli/chunks/help-BYYDUSXF.js +0 -4
- package/dist-cli/chunks/inspect-RQCTWDCC.js +0 -4
- package/dist-cli/chunks/install-desktop-GOWXCQUE.js +0 -4
- package/dist-cli/chunks/privacy-MIFE72CG.js +0 -4
- package/dist-cli/chunks/reset-RZ4O5AFJ.js +0 -4
- package/dist-cli/chunks/resolve-target-7R5BNYMM.js +0 -4
- package/dist-cli/chunks/runtime-MZHLSRS6.js +0 -4
- package/dist-cli/chunks/setup-YFP3KEQZ.js +0 -4
- package/dist-cli/chunks/store-HOL45WCI.js +0 -4
- package/dist-cli/chunks/telemetry-BV6OTYPF.js +0 -4
- package/dist-cli/chunks/upload-RXKHFIBU.js +0 -4
- package/dist-cli/chunks/welcome-FT2AMUWW.js +0 -5
package/dist-lib/skills.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! rnx v0.1.
|
|
1
|
+
/*! rnx v0.1.372 | (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;
|
|
@@ -14659,9 +14659,9 @@ function safeChildPlistName(value) {
|
|
|
14659
14659
|
name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
|
|
14660
14660
|
};
|
|
14661
14661
|
}
|
|
14662
|
-
async function readableSettingsBundle(
|
|
14662
|
+
async function readableSettingsBundle(path20) {
|
|
14663
14663
|
try {
|
|
14664
|
-
const root = await (0, import_promises.stat)((0, import_node_path.join)(
|
|
14664
|
+
const root = await (0, import_promises.stat)((0, import_node_path.join)(path20, "Root.plist"));
|
|
14665
14665
|
return root.isFile() && root.size <= MAX_PLIST_BYTES;
|
|
14666
14666
|
} catch {
|
|
14667
14667
|
return false;
|
|
@@ -14706,11 +14706,11 @@ async function settingsBundleFingerprint(bundlePath) {
|
|
|
14706
14706
|
return null;
|
|
14707
14707
|
}
|
|
14708
14708
|
}
|
|
14709
|
-
async function parsePlistRecord(
|
|
14709
|
+
async function parsePlistRecord(path20) {
|
|
14710
14710
|
try {
|
|
14711
|
-
const metadata = await (0, import_promises.stat)(
|
|
14711
|
+
const metadata = await (0, import_promises.stat)(path20);
|
|
14712
14712
|
if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
|
|
14713
|
-
const source = await (0, import_promises.readFile)(
|
|
14713
|
+
const source = await (0, import_promises.readFile)(path20, "utf8");
|
|
14714
14714
|
const parsed = parsePlistSource(source);
|
|
14715
14715
|
return isRecord2(parsed) ? parsed : null;
|
|
14716
14716
|
} catch {
|
|
@@ -14972,6 +14972,25 @@ var init_optional_demo_registry = __esm({
|
|
|
14972
14972
|
});
|
|
14973
14973
|
|
|
14974
14974
|
// scripts/dev-server-scanner.ts
|
|
14975
|
+
function execGuarded(command, timeout, extra = {}) {
|
|
14976
|
+
let child;
|
|
14977
|
+
const ran = new Promise((resolve7, reject) => {
|
|
14978
|
+
child = (0, import_child_process.exec)(command, { encoding: "utf8", timeout, ...extra }, (err, stdout) => {
|
|
14979
|
+
if (err) reject(err);
|
|
14980
|
+
else resolve7({ stdout });
|
|
14981
|
+
});
|
|
14982
|
+
});
|
|
14983
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
14984
|
+
const timer = setTimeout(() => {
|
|
14985
|
+
child?.kill("SIGKILL");
|
|
14986
|
+
const err = new Error(`\`${command}\` did not exit within ${timeout}ms`);
|
|
14987
|
+
Object.assign(err, { killed: true });
|
|
14988
|
+
reject(err);
|
|
14989
|
+
}, timeout + EXEC_EXIT_GRACE_MS);
|
|
14990
|
+
timer.unref?.();
|
|
14991
|
+
});
|
|
14992
|
+
return Promise.race([ran, deadline]);
|
|
14993
|
+
}
|
|
14975
14994
|
async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
14976
14995
|
try {
|
|
14977
14996
|
return await Promise.any(
|
|
@@ -14998,93 +15017,116 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
|
|
|
14998
15017
|
return null;
|
|
14999
15018
|
}
|
|
15000
15019
|
}
|
|
15001
|
-
function httpGet(hostname, port,
|
|
15020
|
+
function httpGet(hostname, port, path20, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
|
|
15002
15021
|
return new Promise((resolve7) => {
|
|
15003
|
-
|
|
15004
|
-
|
|
15005
|
-
(
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15015
|
-
|
|
15016
|
-
|
|
15017
|
-
|
|
15018
|
-
|
|
15019
|
-
|
|
15020
|
-
|
|
15021
|
-
|
|
15022
|
-
|
|
15023
|
-
|
|
15024
|
-
|
|
15025
|
-
|
|
15026
|
-
|
|
15027
|
-
req.destroy();
|
|
15028
|
-
resolve7(null);
|
|
15022
|
+
let settled = false;
|
|
15023
|
+
const settle = (value) => {
|
|
15024
|
+
if (settled) return;
|
|
15025
|
+
settled = true;
|
|
15026
|
+
resolve7(value);
|
|
15027
|
+
};
|
|
15028
|
+
const req = import_http.default.request({ hostname, port, path: path20, method, headers }, (res) => {
|
|
15029
|
+
let body = "";
|
|
15030
|
+
res.on("data", (c) => body += c.toString());
|
|
15031
|
+
const contentType = (() => {
|
|
15032
|
+
const raw = res.headers["content-type"];
|
|
15033
|
+
if (typeof raw === "string") return raw;
|
|
15034
|
+
if (Array.isArray(raw)) return raw[0];
|
|
15035
|
+
return void 0;
|
|
15036
|
+
})();
|
|
15037
|
+
res.on(
|
|
15038
|
+
"end",
|
|
15039
|
+
() => settle({
|
|
15040
|
+
statusCode: res.statusCode || 0,
|
|
15041
|
+
body,
|
|
15042
|
+
contentType,
|
|
15043
|
+
hostname
|
|
15044
|
+
})
|
|
15045
|
+
);
|
|
15029
15046
|
});
|
|
15047
|
+
req.on("error", () => settle(null));
|
|
15030
15048
|
req.end();
|
|
15049
|
+
const giveUp = setTimeout(() => {
|
|
15050
|
+
settle(null);
|
|
15051
|
+
req.socket?.unref();
|
|
15052
|
+
}, timeout);
|
|
15053
|
+
const abandon = setTimeout(() => req.destroy(), BODY_TIMEOUT_MS);
|
|
15054
|
+
abandon.unref?.();
|
|
15055
|
+
req.on("close", () => {
|
|
15056
|
+
clearTimeout(giveUp);
|
|
15057
|
+
clearTimeout(abandon);
|
|
15058
|
+
setImmediate(() => settle(null));
|
|
15059
|
+
});
|
|
15031
15060
|
});
|
|
15032
15061
|
}
|
|
15062
|
+
function isOwnShellPort(port) {
|
|
15063
|
+
const offset = Number(process.env.PORT_OFFSET) || 0;
|
|
15064
|
+
if (port >= SELF_PORT_RANGE_START && port <= SELF_PORT_RANGE_END) return true;
|
|
15065
|
+
return offset > 0 && port >= SELF_PORT_RANGE_START + offset && port <= SELF_PORT_RANGE_END + offset;
|
|
15066
|
+
}
|
|
15033
15067
|
function acceptPort(port, excluded) {
|
|
15034
15068
|
if (port <= 0 || port >= 2e4) return false;
|
|
15035
15069
|
if (excluded.has(port)) return false;
|
|
15036
|
-
if (port
|
|
15070
|
+
if (isOwnShellPort(port)) return false;
|
|
15037
15071
|
return true;
|
|
15038
15072
|
}
|
|
15039
|
-
|
|
15073
|
+
function wasKilledByTimeout(err) {
|
|
15074
|
+
return !!(err && typeof err === "object" && err.killed);
|
|
15075
|
+
}
|
|
15076
|
+
async function scanListeningProcesses(excludePorts = []) {
|
|
15040
15077
|
const excluded = new Set(excludePorts);
|
|
15078
|
+
let timedOut = false;
|
|
15041
15079
|
try {
|
|
15042
|
-
const { stdout } = await
|
|
15080
|
+
const { stdout } = await execGuarded(
|
|
15043
15081
|
`lsof -iTCP -sTCP:LISTEN -P -n 2>/dev/null | grep -E '^(node|bun)'`,
|
|
15044
|
-
|
|
15082
|
+
LISTING_TIMEOUT_MS
|
|
15045
15083
|
);
|
|
15046
|
-
|
|
15047
|
-
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
if (!seen.has(port)) seen.set(port, pid);
|
|
15058
|
-
}
|
|
15059
|
-
if (seen.size > 0) {
|
|
15060
|
-
return [...seen.entries()].map(([port, pid]) => ({ port, pid }));
|
|
15061
|
-
}
|
|
15084
|
+
const seen = /* @__PURE__ */ new Map();
|
|
15085
|
+
for (const line of stdout.trim() ? stdout.trim().split("\n") : []) {
|
|
15086
|
+
const parts = line.trim().split(/\s+/);
|
|
15087
|
+
if (parts.length < 9) continue;
|
|
15088
|
+
const pid = Number(parts[1]);
|
|
15089
|
+
const addr = parts[8];
|
|
15090
|
+
const m = addr.match(/:(\d+)$/);
|
|
15091
|
+
if (!m) continue;
|
|
15092
|
+
const port = Number(m[1]);
|
|
15093
|
+
if (!acceptPort(port, excluded)) continue;
|
|
15094
|
+
if (!seen.has(port)) seen.set(port, pid);
|
|
15062
15095
|
}
|
|
15063
|
-
|
|
15096
|
+
return {
|
|
15097
|
+
state: "looked",
|
|
15098
|
+
processes: [...seen.entries()].map(([port, pid]) => ({ port, pid }))
|
|
15099
|
+
};
|
|
15100
|
+
} catch (err) {
|
|
15101
|
+
if (wasKilledByTimeout(err)) timedOut = true;
|
|
15064
15102
|
}
|
|
15065
15103
|
try {
|
|
15066
|
-
const { stdout } = await
|
|
15067
|
-
|
|
15068
|
-
|
|
15069
|
-
|
|
15070
|
-
|
|
15071
|
-
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
|
|
15075
|
-
|
|
15076
|
-
|
|
15077
|
-
|
|
15078
|
-
|
|
15079
|
-
if (!seen.has(port)) seen.set(port, pid);
|
|
15080
|
-
}
|
|
15081
|
-
if (seen.size > 0) {
|
|
15082
|
-
return [...seen.entries()].map(([port, pid]) => ({ port, pid }));
|
|
15083
|
-
}
|
|
15104
|
+
const { stdout } = await execGuarded(
|
|
15105
|
+
`ss -tlnp 2>/dev/null | grep -E '"(node|bun)"'`,
|
|
15106
|
+
LISTING_TIMEOUT_MS
|
|
15107
|
+
);
|
|
15108
|
+
const seen = /* @__PURE__ */ new Map();
|
|
15109
|
+
for (const line of stdout.trim() ? stdout.trim().split("\n") : []) {
|
|
15110
|
+
const portMatch = line.match(/:(\d+)\s/);
|
|
15111
|
+
const pidMatch = line.match(/pid=(\d+)/);
|
|
15112
|
+
if (!portMatch) continue;
|
|
15113
|
+
const port = Number(portMatch[1]);
|
|
15114
|
+
const pid = pidMatch ? Number(pidMatch[1]) : 0;
|
|
15115
|
+
if (!acceptPort(port, excluded)) continue;
|
|
15116
|
+
if (!seen.has(port)) seen.set(port, pid);
|
|
15084
15117
|
}
|
|
15085
|
-
|
|
15118
|
+
return {
|
|
15119
|
+
state: "looked",
|
|
15120
|
+
processes: [...seen.entries()].map(([port, pid]) => ({ port, pid }))
|
|
15121
|
+
};
|
|
15122
|
+
} catch (err) {
|
|
15123
|
+
if (wasKilledByTimeout(err)) timedOut = true;
|
|
15086
15124
|
}
|
|
15087
|
-
|
|
15125
|
+
if (timedOut) return { state: "could-not-look" };
|
|
15126
|
+
return {
|
|
15127
|
+
state: "looked",
|
|
15128
|
+
processes: FALLBACK_PORTS.filter((p) => acceptPort(p.port, excluded))
|
|
15129
|
+
};
|
|
15088
15130
|
}
|
|
15089
15131
|
function pidFromNetstat(stdout, port) {
|
|
15090
15132
|
for (const line of stdout.split("\n")) {
|
|
@@ -15104,9 +15146,7 @@ function pidFromNetstat(stdout, port) {
|
|
|
15104
15146
|
async function resolveListeningPid(port) {
|
|
15105
15147
|
if (!Number.isInteger(port) || port <= 0) return null;
|
|
15106
15148
|
try {
|
|
15107
|
-
const { stdout } = await
|
|
15108
|
-
encoding: "utf8",
|
|
15109
|
-
timeout: 8e3,
|
|
15149
|
+
const { stdout } = await execGuarded("netstat -anv -p tcp 2>/dev/null", 8e3, {
|
|
15110
15150
|
maxBuffer: 16 * 1024 * 1024
|
|
15111
15151
|
});
|
|
15112
15152
|
const pid = pidFromNetstat(stdout, port);
|
|
@@ -15114,9 +15154,7 @@ async function resolveListeningPid(port) {
|
|
|
15114
15154
|
} catch {
|
|
15115
15155
|
}
|
|
15116
15156
|
try {
|
|
15117
|
-
const { stdout } = await
|
|
15118
|
-
encoding: "utf8",
|
|
15119
|
-
timeout: 8e3,
|
|
15157
|
+
const { stdout } = await execGuarded(`ss -tlnp 2>/dev/null`, 8e3, {
|
|
15120
15158
|
maxBuffer: 16 * 1024 * 1024
|
|
15121
15159
|
});
|
|
15122
15160
|
for (const line of stdout.split("\n")) {
|
|
@@ -15141,10 +15179,10 @@ async function resolveProcessCwd(pid) {
|
|
|
15141
15179
|
} catch {
|
|
15142
15180
|
}
|
|
15143
15181
|
try {
|
|
15144
|
-
const { stdout } = await
|
|
15145
|
-
|
|
15146
|
-
|
|
15147
|
-
|
|
15182
|
+
const { stdout } = await execGuarded(
|
|
15183
|
+
`lsof -b -w -p ${pid} -a -d cwd -Fn 2>/dev/null`,
|
|
15184
|
+
8e3
|
|
15185
|
+
);
|
|
15148
15186
|
for (const line of stdout.split("\n")) {
|
|
15149
15187
|
if (line.startsWith("n") && line.length > 1) {
|
|
15150
15188
|
const cwd = line.slice(1).trim();
|
|
@@ -15306,7 +15344,8 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
15306
15344
|
const manifestParsed = manifestRes ? safeParseManifest(manifestRes.body) : null;
|
|
15307
15345
|
const manifestLaunchUrl = typeof manifestParsed?.launchAsset?.url === "string" ? manifestParsed.launchAsset.url : null;
|
|
15308
15346
|
const manifestClient = manifestParsed?.extra?.expoClient || manifestParsed?.extra || {};
|
|
15309
|
-
|
|
15347
|
+
const manifestState = !manifestRes ? "no-answer" : manifestParsed && (manifestLaunchUrl || typeof manifestClient.name === "string") ? "resolved" : "no-manifest";
|
|
15348
|
+
if (manifestState === "resolved") {
|
|
15310
15349
|
knownNonPatched.add(port);
|
|
15311
15350
|
const launchUrl2 = manifestLaunchUrl || `${buildLoopbackProbeBaseUrl("http:", probeHostname, port)}/index.bundle?platform=ios&dev=true&hot=true&minify=false`;
|
|
15312
15351
|
const framework = launchUrl2.includes(
|
|
@@ -15327,17 +15366,15 @@ async function probePort(port, buildIconProxyUrl, listeningProcess) {
|
|
|
15327
15366
|
}
|
|
15328
15367
|
if (statusRes && statusRes.body.includes("packager-status:running")) {
|
|
15329
15368
|
knownNonPatched.add(port);
|
|
15369
|
+
const result = makeResult(
|
|
15370
|
+
probeHostname,
|
|
15371
|
+
port,
|
|
15372
|
+
expoRes && expoRes.statusCode === 200 ? "expo" : "metro",
|
|
15373
|
+
owner
|
|
15374
|
+
);
|
|
15375
|
+
if (manifestState === "no-answer") result.bundleUrlProvisional = true;
|
|
15330
15376
|
return enrichWithManifest(
|
|
15331
|
-
applyManifest(
|
|
15332
|
-
makeResult(
|
|
15333
|
-
probeHostname,
|
|
15334
|
-
port,
|
|
15335
|
-
expoRes && expoRes.statusCode === 200 ? "expo" : "metro",
|
|
15336
|
-
owner
|
|
15337
|
-
),
|
|
15338
|
-
manifestRes,
|
|
15339
|
-
buildIconProxyUrl
|
|
15340
|
-
),
|
|
15377
|
+
applyManifest(result, manifestRes, buildIconProxyUrl),
|
|
15341
15378
|
buildIconProxyUrl
|
|
15342
15379
|
);
|
|
15343
15380
|
}
|
|
@@ -15430,7 +15467,9 @@ async function attachAppSettingsBundle(result, projectRoot) {
|
|
|
15430
15467
|
}
|
|
15431
15468
|
async function scanDevServers(opts = {}) {
|
|
15432
15469
|
await loadOptionalDemoApps();
|
|
15433
|
-
const
|
|
15470
|
+
const scan = await scanListeningProcesses(opts.excludePorts);
|
|
15471
|
+
if (scan.state === "could-not-look") throw new DevServerScanUnavailableError();
|
|
15472
|
+
const processes = scan.processes;
|
|
15434
15473
|
const currentPorts = new Set(processes.map((p) => p.port));
|
|
15435
15474
|
for (const p of [...portCache.keys()]) {
|
|
15436
15475
|
if (!currentPorts.has(p)) portCache.delete(p);
|
|
@@ -15494,7 +15533,7 @@ async function scanDevServers(opts = {}) {
|
|
|
15494
15533
|
}
|
|
15495
15534
|
return results.filter((r) => !isSootSimSelfServer(r));
|
|
15496
15535
|
}
|
|
15497
|
-
var import_child_process, import_promises2, import_http, import_net, import_node_path3,
|
|
15536
|
+
var import_child_process, import_promises2, import_http, import_net, import_node_path3, EXEC_EXIT_GRACE_MS, 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, cwdByPid, ENRICH_TIMEOUT_MS, enrichmentCache, enrichmentInFlight, knownNonPatched, knownNonExpo, knownOne, portCache, NEGATIVE_CACHE_TTL_MS, WEAK_RESULT_CACHE_TTL_MS;
|
|
15498
15537
|
var init_dev_server_scanner = __esm({
|
|
15499
15538
|
"scripts/dev-server-scanner.ts"() {
|
|
15500
15539
|
"use strict";
|
|
@@ -15503,16 +15542,16 @@ var init_dev_server_scanner = __esm({
|
|
|
15503
15542
|
import_http = __toESM(require("http"), 1);
|
|
15504
15543
|
import_net = __toESM(require("net"), 1);
|
|
15505
15544
|
import_node_path3 = require("node:path");
|
|
15506
|
-
import_util = require("util");
|
|
15507
15545
|
init_backend_origin();
|
|
15508
15546
|
init_config();
|
|
15509
15547
|
init_native_dev_bundle_url();
|
|
15510
15548
|
init_settings_bundle();
|
|
15511
15549
|
init_optional_demo_registry();
|
|
15512
|
-
|
|
15550
|
+
EXEC_EXIT_GRACE_MS = 2e3;
|
|
15513
15551
|
TIMEOUT_MS = 250;
|
|
15514
15552
|
MANIFEST_TIMEOUT_MS = 1500;
|
|
15515
15553
|
TCP_GATE_MS = 120;
|
|
15554
|
+
BODY_TIMEOUT_MS = 3e4;
|
|
15516
15555
|
FALLBACK_PORTS = [
|
|
15517
15556
|
8081,
|
|
15518
15557
|
8082,
|
|
@@ -15524,6 +15563,15 @@ var init_dev_server_scanner = __esm({
|
|
|
15524
15563
|
3001,
|
|
15525
15564
|
19e3
|
|
15526
15565
|
].map((port) => ({ port, pid: 0 }));
|
|
15566
|
+
SELF_PORT_RANGE_START = 5170;
|
|
15567
|
+
SELF_PORT_RANGE_END = 5200;
|
|
15568
|
+
DevServerScanUnavailableError = class extends Error {
|
|
15569
|
+
constructor() {
|
|
15570
|
+
super("could not enumerate listening processes (lsof/ss unavailable or timed out)");
|
|
15571
|
+
this.name = "DevServerScanUnavailableError";
|
|
15572
|
+
}
|
|
15573
|
+
};
|
|
15574
|
+
LISTING_TIMEOUT_MS = 1e4;
|
|
15527
15575
|
cwdByPid = /* @__PURE__ */ new Map();
|
|
15528
15576
|
ENRICH_TIMEOUT_MS = 2e4;
|
|
15529
15577
|
enrichmentCache = /* @__PURE__ */ new Map();
|
|
@@ -18451,9 +18499,290 @@ var init_open_url = __esm({
|
|
|
18451
18499
|
}
|
|
18452
18500
|
});
|
|
18453
18501
|
|
|
18502
|
+
// cli/commands/box/checkout-plane.ts
|
|
18503
|
+
function looksBinary(filePath, size) {
|
|
18504
|
+
if (size === 0) return false;
|
|
18505
|
+
let fd;
|
|
18506
|
+
try {
|
|
18507
|
+
fd = import_node_fs9.default.openSync(filePath, "r");
|
|
18508
|
+
const buffer = Buffer.alloc(Math.min(BINARY_SNIFF_BYTES, size));
|
|
18509
|
+
const read = import_node_fs9.default.readSync(fd, buffer, 0, buffer.length, 0);
|
|
18510
|
+
return buffer.subarray(0, read).includes(0);
|
|
18511
|
+
} catch {
|
|
18512
|
+
return false;
|
|
18513
|
+
} finally {
|
|
18514
|
+
if (fd !== void 0) import_node_fs9.default.closeSync(fd);
|
|
18515
|
+
}
|
|
18516
|
+
}
|
|
18517
|
+
var import_node_child_process5, import_node_fs9, import_node_path10, CheckoutRequiresGitError, BINARY_SNIFF_BYTES, LIST_FILES_TIMEOUT_MS, CheckoutFilePlane;
|
|
18518
|
+
var init_checkout_plane = __esm({
|
|
18519
|
+
"cli/commands/box/checkout-plane.ts"() {
|
|
18520
|
+
"use strict";
|
|
18521
|
+
import_node_child_process5 = require("node:child_process");
|
|
18522
|
+
import_node_fs9 = __toESM(require("node:fs"), 1);
|
|
18523
|
+
import_node_path10 = __toESM(require("node:path"), 1);
|
|
18524
|
+
CheckoutRequiresGitError = class extends Error {
|
|
18525
|
+
};
|
|
18526
|
+
BINARY_SNIFF_BYTES = 8192;
|
|
18527
|
+
LIST_FILES_TIMEOUT_MS = 1e4;
|
|
18528
|
+
CheckoutFilePlane = class {
|
|
18529
|
+
root;
|
|
18530
|
+
entries = /* @__PURE__ */ new Map();
|
|
18531
|
+
sniffed = /* @__PURE__ */ new Map();
|
|
18532
|
+
// the deadline above, as a number a caller can set. what it changes is how
|
|
18533
|
+
// long a wedged git is waited on, never whether it is waited on, so proving
|
|
18534
|
+
// the kill does not have to cost the production deadline.
|
|
18535
|
+
listTimeoutMs;
|
|
18536
|
+
constructor(root, options = {}) {
|
|
18537
|
+
this.root = import_node_path10.default.resolve(root);
|
|
18538
|
+
this.listTimeoutMs = options.listTimeoutMs ?? LIST_FILES_TIMEOUT_MS;
|
|
18539
|
+
}
|
|
18540
|
+
index() {
|
|
18541
|
+
return this.entries;
|
|
18542
|
+
}
|
|
18543
|
+
async refresh() {
|
|
18544
|
+
let stdout;
|
|
18545
|
+
try {
|
|
18546
|
+
stdout = (0, import_node_child_process5.execFileSync)("git", ["ls-files", "-co", "--exclude-standard", "-z"], {
|
|
18547
|
+
cwd: this.root,
|
|
18548
|
+
encoding: "utf8",
|
|
18549
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
18550
|
+
timeout: this.listTimeoutMs,
|
|
18551
|
+
// stating the environment is not redundant here. bun 1.3.14 resolves
|
|
18552
|
+
// the binary for the synchronous form against the PATH it captured at
|
|
18553
|
+
// startup and ignores a later change to `process.env.PATH`, so without
|
|
18554
|
+
// this it runs a different git than every other call in the process.
|
|
18555
|
+
env: process.env
|
|
18556
|
+
});
|
|
18557
|
+
} catch (error) {
|
|
18558
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18559
|
+
const killed = error instanceof Error && "signal" in error && error.signal === "SIGTERM";
|
|
18560
|
+
throw new CheckoutRequiresGitError(
|
|
18561
|
+
killed ? `git did not list the project's files in ${this.root} within ${this.listTimeoutMs / 1e3}s, so the box has no file set to serve. the checkout may be on a stalled filesystem, or this machine may be too loaded to start a subprocess.` : `could not list the project's files with git in ${this.root}: ${message}`
|
|
18562
|
+
);
|
|
18563
|
+
}
|
|
18564
|
+
if (stdout.length === 0) {
|
|
18565
|
+
throw new CheckoutRequiresGitError(
|
|
18566
|
+
`git listed no files in ${this.root}. either git tracks nothing there and nothing untracked is visible to it, or this machine could not read the child process's output.`
|
|
18567
|
+
);
|
|
18568
|
+
}
|
|
18569
|
+
const next = /* @__PURE__ */ new Map();
|
|
18570
|
+
const nextSniffed = /* @__PURE__ */ new Map();
|
|
18571
|
+
for (const relative of stdout.split("\0")) {
|
|
18572
|
+
if (!relative) continue;
|
|
18573
|
+
let stat2;
|
|
18574
|
+
try {
|
|
18575
|
+
stat2 = import_node_fs9.default.statSync(import_node_path10.default.join(this.root, relative));
|
|
18576
|
+
} catch {
|
|
18577
|
+
continue;
|
|
18578
|
+
}
|
|
18579
|
+
if (!stat2.isFile()) continue;
|
|
18580
|
+
const seen = this.sniffed.get(relative);
|
|
18581
|
+
const binary = seen && seen.size === stat2.size && seen.mtimeMs === stat2.mtimeMs ? seen.binary : looksBinary(import_node_path10.default.join(this.root, relative), stat2.size);
|
|
18582
|
+
nextSniffed.set(relative, { size: stat2.size, mtimeMs: stat2.mtimeMs, binary });
|
|
18583
|
+
next.set(relative, {
|
|
18584
|
+
size: stat2.size,
|
|
18585
|
+
// a checkout carries no write policy of its own; if the user can write
|
|
18586
|
+
// the file, so can the shell
|
|
18587
|
+
readOnly: false,
|
|
18588
|
+
binary
|
|
18589
|
+
});
|
|
18590
|
+
}
|
|
18591
|
+
this.entries = next;
|
|
18592
|
+
this.sniffed = nextSniffed;
|
|
18593
|
+
}
|
|
18594
|
+
absolute(planePath) {
|
|
18595
|
+
const resolved = import_node_path10.default.resolve(this.root, planePath);
|
|
18596
|
+
if (resolved !== this.root && !resolved.startsWith(`${this.root}${import_node_path10.default.sep}`)) {
|
|
18597
|
+
throw new Error(`path escapes the project: ${planePath}`);
|
|
18598
|
+
}
|
|
18599
|
+
return resolved;
|
|
18600
|
+
}
|
|
18601
|
+
async read(planePath) {
|
|
18602
|
+
return import_node_fs9.default.promises.readFile(this.absolute(planePath), "utf8");
|
|
18603
|
+
}
|
|
18604
|
+
async readBytes(planePath) {
|
|
18605
|
+
return import_node_fs9.default.promises.readFile(this.absolute(planePath));
|
|
18606
|
+
}
|
|
18607
|
+
async write(planePath, content) {
|
|
18608
|
+
const absolute = this.absolute(planePath);
|
|
18609
|
+
await import_node_fs9.default.promises.mkdir(import_node_path10.default.dirname(absolute), { recursive: true });
|
|
18610
|
+
await import_node_fs9.default.promises.writeFile(absolute, content);
|
|
18611
|
+
this.entries.set(planePath, {
|
|
18612
|
+
size: content.byteLength,
|
|
18613
|
+
readOnly: false,
|
|
18614
|
+
// the bytes are in hand, so the same NUL test costs nothing here
|
|
18615
|
+
binary: content.subarray(0, BINARY_SNIFF_BYTES).includes(0)
|
|
18616
|
+
});
|
|
18617
|
+
}
|
|
18618
|
+
async delete(planePath) {
|
|
18619
|
+
await import_node_fs9.default.promises.rm(this.absolute(planePath), { force: true });
|
|
18620
|
+
this.entries.delete(planePath);
|
|
18621
|
+
}
|
|
18622
|
+
};
|
|
18623
|
+
}
|
|
18624
|
+
});
|
|
18625
|
+
|
|
18626
|
+
// src/host/plane-host.ts
|
|
18627
|
+
var import_node_fs10, import_node_path11, import_plane, WS_OPEN2, PlaneNotRegisteredError, PlaneHost;
|
|
18628
|
+
var init_plane_host = __esm({
|
|
18629
|
+
"src/host/plane-host.ts"() {
|
|
18630
|
+
"use strict";
|
|
18631
|
+
import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
18632
|
+
import_node_path11 = __toESM(require("node:path"), 1);
|
|
18633
|
+
import_plane = require("@contrast/harness/plane");
|
|
18634
|
+
init_checkout_plane();
|
|
18635
|
+
WS_OPEN2 = 1;
|
|
18636
|
+
PlaneNotRegisteredError = class extends Error {
|
|
18637
|
+
};
|
|
18638
|
+
PlaneHost = class {
|
|
18639
|
+
// roots a box authorized, each tied to the socket that authorized it
|
|
18640
|
+
registered = /* @__PURE__ */ new Map();
|
|
18641
|
+
open = /* @__PURE__ */ new Map();
|
|
18642
|
+
byRoot = /* @__PURE__ */ new Map();
|
|
18643
|
+
nextPlaneId = 1;
|
|
18644
|
+
/** handle a plane:* message. returns true iff it was one. */
|
|
18645
|
+
async handleMessage(ws, msg) {
|
|
18646
|
+
if (typeof msg !== "object" || msg === null) return false;
|
|
18647
|
+
const record = { ...msg };
|
|
18648
|
+
const type = record.type;
|
|
18649
|
+
if (typeof type !== "string" || !type.startsWith("plane:")) return false;
|
|
18650
|
+
const id = record.id;
|
|
18651
|
+
try {
|
|
18652
|
+
this.respond(ws, id, await this.dispatch(ws, type, record));
|
|
18653
|
+
} catch (err) {
|
|
18654
|
+
const code = err instanceof PlaneNotRegisteredError ? "plane-not-registered" : void 0;
|
|
18655
|
+
this.respondError(ws, id, err instanceof Error ? err.message : String(err), code);
|
|
18656
|
+
}
|
|
18657
|
+
return true;
|
|
18658
|
+
}
|
|
18659
|
+
unregisterSocket(ws) {
|
|
18660
|
+
for (const [root, sockets] of [...this.registered]) {
|
|
18661
|
+
if (!sockets.delete(ws)) continue;
|
|
18662
|
+
if (sockets.size > 0) continue;
|
|
18663
|
+
this.registered.delete(root);
|
|
18664
|
+
const planeId = this.byRoot.get(root);
|
|
18665
|
+
if (planeId) {
|
|
18666
|
+
this.open.delete(planeId);
|
|
18667
|
+
this.byRoot.delete(root);
|
|
18668
|
+
}
|
|
18669
|
+
}
|
|
18670
|
+
for (const [planeId, entry] of [...this.open]) {
|
|
18671
|
+
entry.sockets.delete(ws);
|
|
18672
|
+
if (entry.sockets.size === 0 && !this.registered.has(entry.root)) {
|
|
18673
|
+
this.open.delete(planeId);
|
|
18674
|
+
this.byRoot.delete(entry.root);
|
|
18675
|
+
}
|
|
18676
|
+
}
|
|
18677
|
+
}
|
|
18678
|
+
/** roots currently reachable, for the daemon's status output. */
|
|
18679
|
+
registeredRoots() {
|
|
18680
|
+
return [...this.registered.keys()];
|
|
18681
|
+
}
|
|
18682
|
+
async dispatch(ws, type, msg) {
|
|
18683
|
+
switch (type) {
|
|
18684
|
+
case "plane:register": {
|
|
18685
|
+
const root = this.realRoot(String(msg.root ?? ""));
|
|
18686
|
+
const sockets = this.registered.get(root) ?? /* @__PURE__ */ new Set();
|
|
18687
|
+
sockets.add(ws);
|
|
18688
|
+
this.registered.set(root, sockets);
|
|
18689
|
+
return { root, holders: sockets.size };
|
|
18690
|
+
}
|
|
18691
|
+
// READ ONLY, and that is the whole point of it existing beside the
|
|
18692
|
+
// `holders` field on plane:register.
|
|
18693
|
+
//
|
|
18694
|
+
// registration is the AUTHORIZATION step: it is what permits any page on
|
|
18695
|
+
// this machine to open that root over a loopback socket that CORS does
|
|
18696
|
+
// not protect. so a caller asking "is anyone else in this checkout"
|
|
18697
|
+
// cannot be made to authorize the root in order to find out, even
|
|
18698
|
+
// briefly. it also means the count is the honest one: no box reads 0 and
|
|
18699
|
+
// a single box reads 1, where asking through register would have made
|
|
18700
|
+
// every answer one higher and forced a threshold that counts the asker.
|
|
18701
|
+
case "plane:status": {
|
|
18702
|
+
const root = this.realRoot(String(msg.root ?? ""));
|
|
18703
|
+
const sockets = this.registered.get(root);
|
|
18704
|
+
return { root, holders: sockets?.size ?? 0, registered: Boolean(sockets) };
|
|
18705
|
+
}
|
|
18706
|
+
case "plane:open": {
|
|
18707
|
+
const root = this.realRoot(String(msg.root ?? ""));
|
|
18708
|
+
if (!this.registered.has(root)) {
|
|
18709
|
+
throw new PlaneNotRegisteredError(
|
|
18710
|
+
`no box has registered ${root}; start one with \`rnx box\` there`
|
|
18711
|
+
);
|
|
18712
|
+
}
|
|
18713
|
+
const existingId = this.byRoot.get(root);
|
|
18714
|
+
const existing = existingId ? this.open.get(existingId) : void 0;
|
|
18715
|
+
if (existingId && existing) {
|
|
18716
|
+
existing.sockets.add(ws);
|
|
18717
|
+
return { planeId: existingId, version: existing.version };
|
|
18718
|
+
}
|
|
18719
|
+
const plane = new CheckoutFilePlane(root);
|
|
18720
|
+
await plane.refresh();
|
|
18721
|
+
const planeId = `plane-${this.nextPlaneId++}`;
|
|
18722
|
+
const entry = {
|
|
18723
|
+
root,
|
|
18724
|
+
plane,
|
|
18725
|
+
version: (0, import_plane.indexVersion)(plane.index()),
|
|
18726
|
+
sockets: /* @__PURE__ */ new Set([ws])
|
|
18727
|
+
};
|
|
18728
|
+
this.open.set(planeId, entry);
|
|
18729
|
+
this.byRoot.set(root, planeId);
|
|
18730
|
+
return { planeId, version: entry.version };
|
|
18731
|
+
}
|
|
18732
|
+
case "plane:close": {
|
|
18733
|
+
const entry = this.open.get(String(msg.planeId ?? ""));
|
|
18734
|
+
if (entry) entry.sockets.delete(ws);
|
|
18735
|
+
return { ok: true };
|
|
18736
|
+
}
|
|
18737
|
+
default: {
|
|
18738
|
+
const entry = this.entry(msg);
|
|
18739
|
+
const handled = await (0, import_plane.dispatchPlaneCommand)(entry.plane, type, msg);
|
|
18740
|
+
if (!handled) throw new Error(`unknown plane command: ${type}`);
|
|
18741
|
+
if (handled.version) entry.version = handled.version;
|
|
18742
|
+
return handled.result;
|
|
18743
|
+
}
|
|
18744
|
+
}
|
|
18745
|
+
}
|
|
18746
|
+
entry(msg) {
|
|
18747
|
+
const entry = this.open.get(String(msg.planeId ?? ""));
|
|
18748
|
+
if (!entry) throw new Error(`unknown planeId: ${String(msg.planeId)}`);
|
|
18749
|
+
return entry;
|
|
18750
|
+
}
|
|
18751
|
+
// resolve symlinks and relative segments before comparing, so a registered
|
|
18752
|
+
// root and an opened one cannot disagree about the same directory.
|
|
18753
|
+
realRoot(root) {
|
|
18754
|
+
if (!root) throw new Error("root is required");
|
|
18755
|
+
const resolved = import_node_path11.default.resolve(root);
|
|
18756
|
+
let real;
|
|
18757
|
+
try {
|
|
18758
|
+
real = import_node_fs10.default.realpathSync(resolved);
|
|
18759
|
+
} catch {
|
|
18760
|
+
throw new Error(`no such directory: ${resolved}`);
|
|
18761
|
+
}
|
|
18762
|
+
if (!import_node_fs10.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
|
|
18763
|
+
return real;
|
|
18764
|
+
}
|
|
18765
|
+
respond(ws, id, result) {
|
|
18766
|
+
if (ws.readyState !== WS_OPEN2) return;
|
|
18767
|
+
try {
|
|
18768
|
+
ws.send(JSON.stringify({ id, result }));
|
|
18769
|
+
} catch {
|
|
18770
|
+
}
|
|
18771
|
+
}
|
|
18772
|
+
respondError(ws, id, error, code) {
|
|
18773
|
+
if (ws.readyState !== WS_OPEN2) return;
|
|
18774
|
+
try {
|
|
18775
|
+
ws.send(JSON.stringify({ id, error, ...code ? { code } : {} }));
|
|
18776
|
+
} catch {
|
|
18777
|
+
}
|
|
18778
|
+
}
|
|
18779
|
+
};
|
|
18780
|
+
}
|
|
18781
|
+
});
|
|
18782
|
+
|
|
18454
18783
|
// src/host/replacement-module-handler.ts
|
|
18455
18784
|
function getReplacementLoader(filePath) {
|
|
18456
|
-
const ext =
|
|
18785
|
+
const ext = import_node_path12.default.extname(filePath).toLowerCase();
|
|
18457
18786
|
switch (ext) {
|
|
18458
18787
|
case ".js":
|
|
18459
18788
|
return "js";
|
|
@@ -18535,7 +18864,7 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
18535
18864
|
res.end("replacement files must be .js, .jsx, .ts, or .tsx");
|
|
18536
18865
|
return true;
|
|
18537
18866
|
}
|
|
18538
|
-
if (!
|
|
18867
|
+
if (!import_node_path12.default.isAbsolute(targetPath)) {
|
|
18539
18868
|
res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
|
|
18540
18869
|
res.end("replacement file path must be absolute");
|
|
18541
18870
|
return true;
|
|
@@ -18543,10 +18872,10 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
18543
18872
|
const runtimePackages = new Set(url.searchParams.getAll("runtimePackage"));
|
|
18544
18873
|
let resolvedProjectRoot;
|
|
18545
18874
|
if (options.projectRoot) {
|
|
18546
|
-
const lexicalProjectRoot =
|
|
18875
|
+
const lexicalProjectRoot = import_node_path12.default.resolve(options.projectRoot);
|
|
18547
18876
|
resolvedProjectRoot = await import_promises5.default.realpath(options.projectRoot);
|
|
18548
|
-
const lexicalTarget =
|
|
18549
|
-
if (lexicalTarget.startsWith("..") ||
|
|
18877
|
+
const lexicalTarget = import_node_path12.default.relative(lexicalProjectRoot, targetPath);
|
|
18878
|
+
if (lexicalTarget.startsWith("..") || import_node_path12.default.isAbsolute(lexicalTarget)) {
|
|
18550
18879
|
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
18551
18880
|
res.end("replacement file must be inside the project root");
|
|
18552
18881
|
return true;
|
|
@@ -18562,8 +18891,8 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
|
|
|
18562
18891
|
return true;
|
|
18563
18892
|
}
|
|
18564
18893
|
if (resolvedProjectRoot) {
|
|
18565
|
-
const relativeTarget =
|
|
18566
|
-
if (relativeTarget.startsWith("..") ||
|
|
18894
|
+
const relativeTarget = import_node_path12.default.relative(resolvedProjectRoot, resolvedTargetPath);
|
|
18895
|
+
if (relativeTarget.startsWith("..") || import_node_path12.default.isAbsolute(relativeTarget)) {
|
|
18567
18896
|
res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
|
|
18568
18897
|
res.end("replacement file must be inside the project root");
|
|
18569
18898
|
return true;
|
|
@@ -18648,12 +18977,12 @@ exports.jsxDEV = exports.jsx`,
|
|
|
18648
18977
|
}
|
|
18649
18978
|
return true;
|
|
18650
18979
|
}
|
|
18651
|
-
var import_promises5,
|
|
18980
|
+
var import_promises5, import_node_path12, import_esbuild, REPLACEMENT_MODULE_ROUTE;
|
|
18652
18981
|
var init_replacement_module_handler = __esm({
|
|
18653
18982
|
"src/host/replacement-module-handler.ts"() {
|
|
18654
18983
|
"use strict";
|
|
18655
18984
|
import_promises5 = __toESM(require("node:fs/promises"), 1);
|
|
18656
|
-
|
|
18985
|
+
import_node_path12 = __toESM(require("node:path"), 1);
|
|
18657
18986
|
import_esbuild = require("esbuild");
|
|
18658
18987
|
init_backend_origin();
|
|
18659
18988
|
REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
|
|
@@ -18900,6 +19229,7 @@ var init_bridge_host = __esm({
|
|
|
18900
19229
|
init_agent_host();
|
|
18901
19230
|
init_fetch_proxy_handler();
|
|
18902
19231
|
init_open_url();
|
|
19232
|
+
init_plane_host();
|
|
18903
19233
|
init_replacement_module_handler();
|
|
18904
19234
|
init_websocket_proxy();
|
|
18905
19235
|
SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY = "require-corp";
|
|
@@ -18964,6 +19294,7 @@ var init_bridge_host = __esm({
|
|
|
18964
19294
|
nextCliFallbackId = 1;
|
|
18965
19295
|
cliIdleTimer = null;
|
|
18966
19296
|
agentHost;
|
|
19297
|
+
planeHost = new PlaneHost();
|
|
18967
19298
|
static CLI_IDLE_TIMEOUT_MS = 6e4;
|
|
18968
19299
|
static CLI_LEASE_TTL_MS = 6e5;
|
|
18969
19300
|
static USER_ACTIVE_LEASE_TTL_MS = 8e3;
|
|
@@ -19195,6 +19526,10 @@ var init_bridge_host = __esm({
|
|
|
19195
19526
|
void this.agentHost.handleMessage(ws, msg);
|
|
19196
19527
|
return;
|
|
19197
19528
|
}
|
|
19529
|
+
if (typeof msg.type === "string" && msg.type.startsWith("plane:")) {
|
|
19530
|
+
void this.planeHost.handleMessage(ws, msg);
|
|
19531
|
+
return;
|
|
19532
|
+
}
|
|
19198
19533
|
if (msg.type === "runtime:list") {
|
|
19199
19534
|
const versions = sootsimRuntime.listInstalled();
|
|
19200
19535
|
const active = this.getActiveRuntime();
|
|
@@ -19517,6 +19852,7 @@ var init_bridge_host = __esm({
|
|
|
19517
19852
|
});
|
|
19518
19853
|
ws.on("close", () => {
|
|
19519
19854
|
this.agentHost.unregisterSocket(ws);
|
|
19855
|
+
this.planeHost.unregisterSocket(ws);
|
|
19520
19856
|
if (role === "sim" && sim) {
|
|
19521
19857
|
this.rememberDisconnectedSim(sim);
|
|
19522
19858
|
if (this.primarySimId === sim.id) {
|
|
@@ -21214,17 +21550,17 @@ function liveDevBridgeLockfiles() {
|
|
|
21214
21550
|
return readDevBridgeLockfiles().filter((lockfile) => isDevBridgeLockfileFresh(lockfile));
|
|
21215
21551
|
}
|
|
21216
21552
|
function checkoutRoot(cwd) {
|
|
21217
|
-
let current =
|
|
21553
|
+
let current = import_node_path13.default.resolve(cwd);
|
|
21218
21554
|
while (true) {
|
|
21219
|
-
if (
|
|
21220
|
-
const parent =
|
|
21555
|
+
if (import_node_fs11.default.existsSync(import_node_path13.default.join(current, ".git"))) return current;
|
|
21556
|
+
const parent = import_node_path13.default.dirname(current);
|
|
21221
21557
|
if (parent === current) return null;
|
|
21222
21558
|
current = parent;
|
|
21223
21559
|
}
|
|
21224
21560
|
}
|
|
21225
21561
|
function pathContains(parent, child) {
|
|
21226
|
-
const relative =
|
|
21227
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
21562
|
+
const relative = import_node_path13.default.relative(parent, child);
|
|
21563
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${import_node_path13.default.sep}`) && !import_node_path13.default.isAbsolute(relative);
|
|
21228
21564
|
}
|
|
21229
21565
|
function resolveDefaultDevBridgeLockfile() {
|
|
21230
21566
|
const lockfiles = liveDevBridgeLockfiles();
|
|
@@ -21647,18 +21983,18 @@ async function evalInBridge(bridge, code, opts = {}) {
|
|
|
21647
21983
|
if (opts.acquireLock) payload.acquireLock = true;
|
|
21648
21984
|
return bridge.send(payload);
|
|
21649
21985
|
}
|
|
21650
|
-
async function callInBridge(bridge,
|
|
21651
|
-
return bridge.send({ type: "call", path:
|
|
21986
|
+
async function callInBridge(bridge, path20, ...args) {
|
|
21987
|
+
return bridge.send({ type: "call", path: path20, args });
|
|
21652
21988
|
}
|
|
21653
|
-
async function callInBridgeWrite(bridge,
|
|
21654
|
-
return bridge.send({ type: "call", path:
|
|
21989
|
+
async function callInBridgeWrite(bridge, path20, ...args) {
|
|
21990
|
+
return bridge.send({ type: "call", path: path20, args, acquireLock: true });
|
|
21655
21991
|
}
|
|
21656
|
-
var
|
|
21992
|
+
var import_node_fs11, import_node_path13, import_ws3, RNX_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError;
|
|
21657
21993
|
var init_ws_bridge = __esm({
|
|
21658
21994
|
"cli/ws-bridge.ts"() {
|
|
21659
21995
|
"use strict";
|
|
21660
|
-
|
|
21661
|
-
|
|
21996
|
+
import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
21997
|
+
import_node_path13 = __toESM(require("node:path"), 1);
|
|
21662
21998
|
import_ws3 = require("ws");
|
|
21663
21999
|
init_bridge_constants();
|
|
21664
22000
|
init_cli_constants();
|
|
@@ -21753,8 +22089,8 @@ function getDefaultPortForProtocol(protocol) {
|
|
|
21753
22089
|
return protocol === "https:" ? 443 : 80;
|
|
21754
22090
|
}
|
|
21755
22091
|
function isBaseServerUrl(url) {
|
|
21756
|
-
const
|
|
21757
|
-
return (
|
|
22092
|
+
const path20 = url.pathname || "/";
|
|
22093
|
+
return (path20 === "/" || path20 === "") && !url.search && !url.hash;
|
|
21758
22094
|
}
|
|
21759
22095
|
async function resolvePortViaServerScan(port) {
|
|
21760
22096
|
try {
|
|
@@ -21768,6 +22104,7 @@ async function resolvePortViaServerScan(port) {
|
|
|
21768
22104
|
(s) => !!s && typeof s === "object" && s.port === port && typeof s.bundleUrl === "string"
|
|
21769
22105
|
);
|
|
21770
22106
|
if (!match) return null;
|
|
22107
|
+
if (match.bundleUrlProvisional) return null;
|
|
21771
22108
|
return {
|
|
21772
22109
|
// normalize exactly like the manifest-probe branch below — the scan
|
|
21773
22110
|
// returns metro's manifest launchAsset url (lazy=true for code-split
|
|
@@ -21783,45 +22120,76 @@ async function resolvePortViaServerScan(port) {
|
|
|
21783
22120
|
return null;
|
|
21784
22121
|
}
|
|
21785
22122
|
}
|
|
21786
|
-
async function
|
|
21787
|
-
|
|
22123
|
+
async function probeExpoManifest(normalizedBaseUrl, port) {
|
|
22124
|
+
let body;
|
|
22125
|
+
const pending = fetchDevProbe(`${normalizedBaseUrl}/`, {
|
|
22126
|
+
headers: { "expo-platform": "ios" }
|
|
22127
|
+
}).then(
|
|
22128
|
+
async (res) => res.ok ? { ok: true, body: await res.text() } : null,
|
|
22129
|
+
() => void 0
|
|
22130
|
+
);
|
|
22131
|
+
const answered = await Promise.race([
|
|
22132
|
+
pending,
|
|
22133
|
+
new Promise(
|
|
22134
|
+
(resolve7) => setTimeout(() => resolve7("timeout"), MANIFEST_PROBE_TIMEOUT_MS).unref?.()
|
|
22135
|
+
)
|
|
22136
|
+
]);
|
|
22137
|
+
if (answered === "timeout" || answered === void 0) return { state: "no-answer" };
|
|
22138
|
+
if (answered === null) return { state: "no-manifest" };
|
|
22139
|
+
body = answered.body;
|
|
22140
|
+
if (!body.trim()) return { state: "no-answer" };
|
|
22141
|
+
let manifest;
|
|
21788
22142
|
try {
|
|
21789
|
-
|
|
21790
|
-
headers: { "expo-platform": "ios" }
|
|
21791
|
-
});
|
|
21792
|
-
if (manifestRes.ok) {
|
|
21793
|
-
const manifest = await manifestRes.json();
|
|
21794
|
-
const client = manifest?.extra?.expoClient || manifest?.extra || {};
|
|
21795
|
-
const rawLaunchUrl = typeof manifest?.launchAsset?.url === "string" ? manifest.launchAsset.url : void 0;
|
|
21796
|
-
const launchUrl2 = rawLaunchUrl ? alignLoopbackBundleUrlWithProbe(rawLaunchUrl, normalizedBaseUrl) : void 0;
|
|
21797
|
-
if (launchUrl2 || client.name) {
|
|
21798
|
-
return {
|
|
21799
|
-
bundleUrl: normalizeNativeDevBundleUrl(
|
|
21800
|
-
launchUrl2 || `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`
|
|
21801
|
-
),
|
|
21802
|
-
port,
|
|
21803
|
-
framework: inferManifestFramework(launchUrl2, client.sdkVersion),
|
|
21804
|
-
projectName: client.name
|
|
21805
|
-
};
|
|
21806
|
-
}
|
|
21807
|
-
}
|
|
22143
|
+
manifest = JSON.parse(body);
|
|
21808
22144
|
} catch {
|
|
22145
|
+
return { state: "no-manifest" };
|
|
21809
22146
|
}
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
22147
|
+
const client = manifest?.extra?.expoClient || manifest?.extra || {};
|
|
22148
|
+
const rawLaunchUrl = typeof manifest?.launchAsset?.url === "string" ? manifest.launchAsset.url : void 0;
|
|
22149
|
+
const launchUrl2 = rawLaunchUrl ? alignLoopbackBundleUrlWithProbe(rawLaunchUrl, normalizedBaseUrl) : void 0;
|
|
22150
|
+
if (!launchUrl2 && !client.name) return { state: "no-manifest" };
|
|
22151
|
+
return {
|
|
22152
|
+
state: "resolved",
|
|
22153
|
+
bundle: {
|
|
22154
|
+
bundleUrl: normalizeNativeDevBundleUrl(
|
|
22155
|
+
launchUrl2 || `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`
|
|
22156
|
+
),
|
|
22157
|
+
port,
|
|
22158
|
+
framework: inferManifestFramework(launchUrl2, client.sdkVersion),
|
|
22159
|
+
projectName: client.name
|
|
21821
22160
|
}
|
|
22161
|
+
};
|
|
22162
|
+
}
|
|
22163
|
+
async function isPackagerRunning(normalizedBaseUrl) {
|
|
22164
|
+
try {
|
|
22165
|
+
const res = await fetchDevProbe(`${normalizedBaseUrl}/status`);
|
|
22166
|
+
if (!res.ok) return false;
|
|
22167
|
+
return (await res.text()).includes("packager-status:running");
|
|
21822
22168
|
} catch {
|
|
22169
|
+
return false;
|
|
21823
22170
|
}
|
|
21824
|
-
|
|
22171
|
+
}
|
|
22172
|
+
async function probeBaseUrlBundleDirect(baseUrl, port) {
|
|
22173
|
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
22174
|
+
let manifest = await probeExpoManifest(normalizedBaseUrl, port);
|
|
22175
|
+
let packagerConfirmed = false;
|
|
22176
|
+
if (manifest.state === "no-answer") {
|
|
22177
|
+
packagerConfirmed = await isPackagerRunning(normalizedBaseUrl);
|
|
22178
|
+
if (!packagerConfirmed) return null;
|
|
22179
|
+
const deadline = Date.now() + MANIFEST_BOOT_BUDGET_MS;
|
|
22180
|
+
while (manifest.state === "no-answer" && Date.now() < deadline) {
|
|
22181
|
+
await new Promise((resolve7) => setTimeout(resolve7, MANIFEST_BOOT_RETRY_MS));
|
|
22182
|
+
manifest = await probeExpoManifest(normalizedBaseUrl, port);
|
|
22183
|
+
}
|
|
22184
|
+
}
|
|
22185
|
+
if (manifest.state === "resolved") return manifest.bundle;
|
|
22186
|
+
if (manifest.state === "no-answer") return null;
|
|
22187
|
+
if (!packagerConfirmed && !await isPackagerRunning(normalizedBaseUrl)) return null;
|
|
22188
|
+
return {
|
|
22189
|
+
bundleUrl: `${normalizedBaseUrl}${METRO_BUNDLE_PATH}`,
|
|
22190
|
+
port,
|
|
22191
|
+
framework: "metro"
|
|
22192
|
+
};
|
|
21825
22193
|
}
|
|
21826
22194
|
async function probeBaseUrlBundle(baseUrl, port) {
|
|
21827
22195
|
try {
|
|
@@ -21870,11 +22238,15 @@ async function resolveConnectionInput(input) {
|
|
|
21870
22238
|
}
|
|
21871
22239
|
return { bundleUrl: parsed.toString(), port, framework: "unknown" };
|
|
21872
22240
|
}
|
|
22241
|
+
var MANIFEST_PROBE_TIMEOUT_MS, MANIFEST_BOOT_BUDGET_MS, MANIFEST_BOOT_RETRY_MS;
|
|
21873
22242
|
var init_dev_bundle_resolution = __esm({
|
|
21874
22243
|
"src/dev-bundle-resolution.ts"() {
|
|
21875
22244
|
"use strict";
|
|
21876
22245
|
init_backend_origin();
|
|
21877
22246
|
init_native_dev_bundle_url();
|
|
22247
|
+
MANIFEST_PROBE_TIMEOUT_MS = 5e3;
|
|
22248
|
+
MANIFEST_BOOT_BUDGET_MS = 3e4;
|
|
22249
|
+
MANIFEST_BOOT_RETRY_MS = 1e3;
|
|
21878
22250
|
}
|
|
21879
22251
|
});
|
|
21880
22252
|
|
|
@@ -21985,9 +22357,9 @@ var init_profiles = __esm({
|
|
|
21985
22357
|
// cli/app-project.ts
|
|
21986
22358
|
function firstNamedFile(dir, names) {
|
|
21987
22359
|
for (const name2 of names) {
|
|
21988
|
-
const candidate =
|
|
22360
|
+
const candidate = import_node_path14.default.join(dir, name2);
|
|
21989
22361
|
try {
|
|
21990
|
-
if (
|
|
22362
|
+
if (import_node_fs12.default.statSync(candidate).isFile()) return candidate;
|
|
21991
22363
|
} catch {
|
|
21992
22364
|
}
|
|
21993
22365
|
}
|
|
@@ -22000,24 +22372,24 @@ function findSootSimAppConfig(dir) {
|
|
|
22000
22372
|
return firstNamedFile(dir, SOOTSIM_APP_CONFIG_NAMES);
|
|
22001
22373
|
}
|
|
22002
22374
|
function resolveAppProject(projectRoot) {
|
|
22003
|
-
const appDir =
|
|
22375
|
+
const appDir = import_node_path14.default.resolve(projectRoot);
|
|
22004
22376
|
try {
|
|
22005
|
-
if (!
|
|
22377
|
+
if (!import_node_fs12.default.statSync(appDir).isDirectory()) return null;
|
|
22006
22378
|
} catch {
|
|
22007
22379
|
return null;
|
|
22008
22380
|
}
|
|
22009
22381
|
const configPath = findSootSimAppConfig(appDir);
|
|
22010
|
-
if (!configPath && !findExpoAppConfig(appDir) && !
|
|
22382
|
+
if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs12.default.existsSync(import_node_path14.default.join(appDir, "package.json"))) {
|
|
22011
22383
|
return null;
|
|
22012
22384
|
}
|
|
22013
22385
|
return { appDir, configPath };
|
|
22014
22386
|
}
|
|
22015
|
-
var
|
|
22387
|
+
var import_node_fs12, import_node_path14, EXPO_APP_CONFIG_NAMES, SOOTSIM_APP_CONFIG_NAMES;
|
|
22016
22388
|
var init_app_project = __esm({
|
|
22017
22389
|
"cli/app-project.ts"() {
|
|
22018
22390
|
"use strict";
|
|
22019
|
-
|
|
22020
|
-
|
|
22391
|
+
import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
22392
|
+
import_node_path14 = __toESM(require("node:path"), 1);
|
|
22021
22393
|
EXPO_APP_CONFIG_NAMES = [
|
|
22022
22394
|
"app.config.js",
|
|
22023
22395
|
"app.config.ts",
|
|
@@ -22046,13 +22418,13 @@ function isSootSimConfig(value) {
|
|
|
22046
22418
|
}
|
|
22047
22419
|
function resolveConfigReplacementFiles(config, configPath) {
|
|
22048
22420
|
if (!config.modules) return config;
|
|
22049
|
-
const configDir =
|
|
22421
|
+
const configDir = import_node_path15.default.dirname(configPath);
|
|
22050
22422
|
return {
|
|
22051
22423
|
...config,
|
|
22052
22424
|
modules: Object.fromEntries(
|
|
22053
22425
|
Object.entries(config.modules).map(([name2, resolution]) => [
|
|
22054
22426
|
name2,
|
|
22055
|
-
resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file:
|
|
22427
|
+
resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file: import_node_path15.default.resolve(configDir, resolution.file) } : resolution
|
|
22056
22428
|
])
|
|
22057
22429
|
)
|
|
22058
22430
|
};
|
|
@@ -22082,12 +22454,12 @@ async function resolveSootSimAppConfig(startDir = process.cwd()) {
|
|
|
22082
22454
|
const project = resolveAppProject(startDir);
|
|
22083
22455
|
return { project, config: await loadSootSimAppConfig(project) };
|
|
22084
22456
|
}
|
|
22085
|
-
var import_node_module,
|
|
22457
|
+
var import_node_module, import_node_path15, import_jiti, require2;
|
|
22086
22458
|
var init_app_config = __esm({
|
|
22087
22459
|
"cli/app-config.ts"() {
|
|
22088
22460
|
"use strict";
|
|
22089
22461
|
import_node_module = require("node:module");
|
|
22090
|
-
|
|
22462
|
+
import_node_path15 = __toESM(require("node:path"), 1);
|
|
22091
22463
|
init_src();
|
|
22092
22464
|
import_jiti = require("jiti");
|
|
22093
22465
|
init_public_brand();
|
|
@@ -22155,13 +22527,13 @@ function discoverNativeLinkedAppFonts(opts) {
|
|
|
22155
22527
|
scannedFontDirectories++;
|
|
22156
22528
|
let entries;
|
|
22157
22529
|
try {
|
|
22158
|
-
entries =
|
|
22530
|
+
entries = import_node_fs13.default.readdirSync(current.dir, { withFileTypes: true });
|
|
22159
22531
|
} catch {
|
|
22160
22532
|
continue;
|
|
22161
22533
|
}
|
|
22162
22534
|
for (const entry of entries) {
|
|
22163
22535
|
if (entry.isSymbolicLink()) continue;
|
|
22164
|
-
const fullPath =
|
|
22536
|
+
const fullPath = import_node_path16.default.join(current.dir, entry.name);
|
|
22165
22537
|
if (entry.isDirectory()) {
|
|
22166
22538
|
if (current.depth < 4 && pending.length < 64 && !entry.name.startsWith(".")) {
|
|
22167
22539
|
pending.push({ dir: fullPath, depth: current.depth + 1 });
|
|
@@ -22169,15 +22541,15 @@ function discoverNativeLinkedAppFonts(opts) {
|
|
|
22169
22541
|
continue;
|
|
22170
22542
|
}
|
|
22171
22543
|
if (!entry.isFile() || !/\.(ttf|otf|woff|woff2)$/i.test(entry.name)) continue;
|
|
22172
|
-
const relative =
|
|
22173
|
-
fontPaths.push(
|
|
22544
|
+
const relative = import_node_path16.default.relative(root, fullPath).split(import_node_path16.default.sep).join("/");
|
|
22545
|
+
fontPaths.push(import_node_path16.default.posix.join(metroPathPrefix, relative));
|
|
22174
22546
|
if (fontPaths.length >= 256) break;
|
|
22175
22547
|
}
|
|
22176
22548
|
}
|
|
22177
22549
|
};
|
|
22178
22550
|
try {
|
|
22179
22551
|
const packageJson = JSON.parse(
|
|
22180
|
-
|
|
22552
|
+
import_node_fs13.default.readFileSync(import_node_path16.default.join(selectedAppDir, "package.json"), "utf8")
|
|
22181
22553
|
);
|
|
22182
22554
|
const dependencyNames = /* @__PURE__ */ new Set();
|
|
22183
22555
|
for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
|
|
@@ -22192,24 +22564,24 @@ function discoverNativeLinkedAppFonts(opts) {
|
|
|
22192
22564
|
const config = Reflect.get(packageJson, "reactNativeVectorIcons");
|
|
22193
22565
|
const configuredFontDir = config && typeof config === "object" ? Reflect.get(config, "fontDir") : null;
|
|
22194
22566
|
const configuredDir = typeof configuredFontDir === "string" ? configuredFontDir : "rnvi-fonts";
|
|
22195
|
-
const root =
|
|
22196
|
-
const relativeRoot =
|
|
22197
|
-
if (!relativeRoot.startsWith("..") && !
|
|
22198
|
-
collectFontFiles(root, relativeRoot.split(
|
|
22567
|
+
const root = import_node_path16.default.resolve(selectedAppDir, configuredDir);
|
|
22568
|
+
const relativeRoot = import_node_path16.default.relative(selectedAppDir, root);
|
|
22569
|
+
if (!relativeRoot.startsWith("..") && !import_node_path16.default.isAbsolute(relativeRoot)) {
|
|
22570
|
+
collectFontFiles(root, relativeRoot.split(import_node_path16.default.sep).join("/"));
|
|
22199
22571
|
}
|
|
22200
|
-
const vectorIconRequire = (0, import_node_module2.createRequire)(
|
|
22572
|
+
const vectorIconRequire = (0, import_node_module2.createRequire)(import_node_path16.default.join(selectedAppDir, "package.json"));
|
|
22201
22573
|
for (const dependencyName of vectorIconDependencies) {
|
|
22202
22574
|
try {
|
|
22203
22575
|
const entryPath = vectorIconRequire.resolve(dependencyName);
|
|
22204
|
-
const dependencyPath = dependencyName.split("/").join(
|
|
22205
|
-
const marker = `${
|
|
22576
|
+
const dependencyPath = dependencyName.split("/").join(import_node_path16.default.sep);
|
|
22577
|
+
const marker = `${import_node_path16.default.sep}node_modules${import_node_path16.default.sep}${dependencyPath}${import_node_path16.default.sep}`;
|
|
22206
22578
|
const markerIndex = entryPath.lastIndexOf(marker);
|
|
22207
22579
|
if (markerIndex === -1) continue;
|
|
22208
22580
|
const packageRoot = entryPath.slice(0, markerIndex + marker.length - 1);
|
|
22209
22581
|
const fontsDir = dependencyName === "react-native-vector-icons" ? "Fonts" : "fonts";
|
|
22210
22582
|
collectFontFiles(
|
|
22211
|
-
|
|
22212
|
-
|
|
22583
|
+
import_node_path16.default.join(packageRoot, fontsDir),
|
|
22584
|
+
import_node_path16.default.posix.join("node_modules", dependencyName, fontsDir)
|
|
22213
22585
|
);
|
|
22214
22586
|
} catch {
|
|
22215
22587
|
}
|
|
@@ -22218,37 +22590,37 @@ function discoverNativeLinkedAppFonts(opts) {
|
|
|
22218
22590
|
} catch {
|
|
22219
22591
|
}
|
|
22220
22592
|
try {
|
|
22221
|
-
const configPath =
|
|
22222
|
-
if (
|
|
22223
|
-
const appConfigRequire = (0, import_node_module2.createRequire)(
|
|
22593
|
+
const configPath = import_node_path16.default.join(selectedAppDir, "react-native.config.js");
|
|
22594
|
+
if (import_node_fs13.default.statSync(configPath).isFile()) {
|
|
22595
|
+
const appConfigRequire = (0, import_node_module2.createRequire)(import_node_path16.default.join(selectedAppDir, "package.json"));
|
|
22224
22596
|
const rnConfig = appConfigRequire(configPath);
|
|
22225
22597
|
const assets = rnConfig && typeof rnConfig === "object" ? Reflect.get(rnConfig, "assets") : null;
|
|
22226
22598
|
if (Array.isArray(assets)) {
|
|
22227
22599
|
for (const assetDir of assets) {
|
|
22228
22600
|
if (typeof assetDir !== "string") continue;
|
|
22229
|
-
const root =
|
|
22230
|
-
const relativeRoot =
|
|
22231
|
-
if (relativeRoot.startsWith("..") ||
|
|
22232
|
-
collectFontFiles(root, relativeRoot.split(
|
|
22601
|
+
const root = import_node_path16.default.resolve(selectedAppDir, assetDir);
|
|
22602
|
+
const relativeRoot = import_node_path16.default.relative(selectedAppDir, root);
|
|
22603
|
+
if (relativeRoot.startsWith("..") || import_node_path16.default.isAbsolute(relativeRoot)) continue;
|
|
22604
|
+
collectFontFiles(root, relativeRoot.split(import_node_path16.default.sep).join("/"));
|
|
22233
22605
|
}
|
|
22234
22606
|
}
|
|
22235
22607
|
}
|
|
22236
22608
|
} catch {
|
|
22237
22609
|
}
|
|
22238
22610
|
if (platform === "ios") {
|
|
22239
|
-
const iosDir =
|
|
22611
|
+
const iosDir = import_node_path16.default.join(selectedAppDir, "ios");
|
|
22240
22612
|
try {
|
|
22241
|
-
const targetDirs =
|
|
22613
|
+
const targetDirs = import_node_fs13.default.readdirSync(iosDir, { withFileTypes: true }).filter(
|
|
22242
22614
|
(entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
|
|
22243
22615
|
).slice(0, 64);
|
|
22244
|
-
const plistPaths = [
|
|
22616
|
+
const plistPaths = [import_node_path16.default.join(iosDir, "Info.plist")];
|
|
22245
22617
|
for (const entry of targetDirs) {
|
|
22246
|
-
plistPaths.push(
|
|
22618
|
+
plistPaths.push(import_node_path16.default.join(iosDir, entry.name, "Info.plist"));
|
|
22247
22619
|
}
|
|
22248
22620
|
for (const plistPath of plistPaths) {
|
|
22249
22621
|
let parsed;
|
|
22250
22622
|
try {
|
|
22251
|
-
parsed = parsePlistSource(
|
|
22623
|
+
parsed = parsePlistSource(import_node_fs13.default.readFileSync(plistPath, "utf8"));
|
|
22252
22624
|
} catch {
|
|
22253
22625
|
continue;
|
|
22254
22626
|
}
|
|
@@ -22258,21 +22630,21 @@ function discoverNativeLinkedAppFonts(opts) {
|
|
|
22258
22630
|
for (const declaredFont of declaredFonts) {
|
|
22259
22631
|
if (typeof declaredFont !== "string") continue;
|
|
22260
22632
|
const candidates = [
|
|
22261
|
-
|
|
22262
|
-
|
|
22633
|
+
import_node_path16.default.resolve(import_node_path16.default.dirname(plistPath), declaredFont),
|
|
22634
|
+
import_node_path16.default.resolve(iosDir, declaredFont)
|
|
22263
22635
|
];
|
|
22264
22636
|
const fontPath = candidates.find((candidate) => {
|
|
22265
|
-
const relative =
|
|
22266
|
-
if (relative.startsWith("..") ||
|
|
22637
|
+
const relative = import_node_path16.default.relative(selectedAppDir, candidate);
|
|
22638
|
+
if (relative.startsWith("..") || import_node_path16.default.isAbsolute(relative)) return false;
|
|
22267
22639
|
try {
|
|
22268
|
-
return
|
|
22640
|
+
return import_node_fs13.default.statSync(candidate).isFile();
|
|
22269
22641
|
} catch {
|
|
22270
22642
|
return false;
|
|
22271
22643
|
}
|
|
22272
22644
|
});
|
|
22273
22645
|
if (!fontPath) continue;
|
|
22274
22646
|
fontPaths.push(
|
|
22275
|
-
|
|
22647
|
+
import_node_path16.default.relative(selectedAppDir, fontPath).split(import_node_path16.default.sep).join("/")
|
|
22276
22648
|
);
|
|
22277
22649
|
}
|
|
22278
22650
|
}
|
|
@@ -22311,13 +22683,13 @@ async function resolveMetroProjectRoot(bundleUrl, opts) {
|
|
|
22311
22683
|
function encodeAppFontsWire(specs) {
|
|
22312
22684
|
return specs.map((spec) => `${encodeURIComponent(spec.url)}::${encodeURIComponent(spec.family)}`).join(",");
|
|
22313
22685
|
}
|
|
22314
|
-
var
|
|
22686
|
+
var import_node_fs13, import_node_module2, import_node_path16, import_config_plugin_fonts, require3;
|
|
22315
22687
|
var init_app_fonts = __esm({
|
|
22316
22688
|
"cli/app-fonts.ts"() {
|
|
22317
22689
|
"use strict";
|
|
22318
|
-
|
|
22690
|
+
import_node_fs13 = __toESM(require("node:fs"), 1);
|
|
22319
22691
|
import_node_module2 = require("node:module");
|
|
22320
|
-
|
|
22692
|
+
import_node_path16 = __toESM(require("node:path"), 1);
|
|
22321
22693
|
import_config_plugin_fonts = require("sootsim-engine/engine/config-plugin-fonts");
|
|
22322
22694
|
init_dev_server_scanner();
|
|
22323
22695
|
init_plist();
|
|
@@ -23408,7 +23780,7 @@ function resolvePlaywright() {
|
|
|
23408
23780
|
try {
|
|
23409
23781
|
const modulePath = requireFromRoot.resolve(spec);
|
|
23410
23782
|
const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
|
|
23411
|
-
const parsed = JSON.parse((0,
|
|
23783
|
+
const parsed = JSON.parse((0, import_node_fs14.readFileSync)(packageJsonPath, "utf8"));
|
|
23412
23784
|
if (!isRecord3(parsed) || typeof parsed.version !== "string") continue;
|
|
23413
23785
|
const bin = parsed.bin;
|
|
23414
23786
|
let binPath = null;
|
|
@@ -23420,8 +23792,8 @@ function resolvePlaywright() {
|
|
|
23420
23792
|
binPath = typeof named === "string" ? named : typeof first === "string" ? first : null;
|
|
23421
23793
|
}
|
|
23422
23794
|
if (!binPath) continue;
|
|
23423
|
-
const cliPath = (0,
|
|
23424
|
-
if (!(0,
|
|
23795
|
+
const cliPath = (0, import_node_path17.join)((0, import_node_path17.dirname)(packageJsonPath), binPath);
|
|
23796
|
+
if (!(0, import_node_fs14.existsSync)(cliPath)) continue;
|
|
23425
23797
|
return {
|
|
23426
23798
|
spec,
|
|
23427
23799
|
modulePath,
|
|
@@ -23437,7 +23809,7 @@ function resolvePlaywright() {
|
|
|
23437
23809
|
return null;
|
|
23438
23810
|
}
|
|
23439
23811
|
function probeBrowser(resolved, env) {
|
|
23440
|
-
const probe3 = (0,
|
|
23812
|
+
const probe3 = (0, import_node_child_process6.spawnSync)(process.execPath, ["-e", PLAYWRIGHT_BROWSER_PROBE], {
|
|
23441
23813
|
env: {
|
|
23442
23814
|
...env,
|
|
23443
23815
|
SOOTSIM_PW_MODULE: resolved.modulePath
|
|
@@ -23460,7 +23832,7 @@ function probeBrowser(resolved, env) {
|
|
|
23460
23832
|
return {
|
|
23461
23833
|
ok: true,
|
|
23462
23834
|
executablePath: parsed.executablePath,
|
|
23463
|
-
exists: parsed.exists && (0,
|
|
23835
|
+
exists: parsed.exists && (0, import_node_fs14.existsSync)(parsed.executablePath)
|
|
23464
23836
|
};
|
|
23465
23837
|
} catch (error) {
|
|
23466
23838
|
return {
|
|
@@ -23475,7 +23847,7 @@ function ensurePlaywrightBrowser(resolved, env = process.env) {
|
|
|
23475
23847
|
if (before.exists) {
|
|
23476
23848
|
return { ok: true, executablePath: before.executablePath, installed: false };
|
|
23477
23849
|
}
|
|
23478
|
-
const install = (0,
|
|
23850
|
+
const install = (0, import_node_child_process6.spawnSync)(process.execPath, [resolved.cliPath, "install", "chromium"], {
|
|
23479
23851
|
env,
|
|
23480
23852
|
encoding: "utf8",
|
|
23481
23853
|
timeout: 10 * 6e4
|
|
@@ -23499,14 +23871,14 @@ ${detail}` : ""}`
|
|
|
23499
23871
|
}
|
|
23500
23872
|
return { ok: true, executablePath: after.executablePath, installed: true };
|
|
23501
23873
|
}
|
|
23502
|
-
var
|
|
23874
|
+
var import_node_child_process6, import_node_fs14, import_node_module4, import_node_path17, PLAYWRIGHT_BROWSER_PROBE;
|
|
23503
23875
|
var init_playwright_provisioning = __esm({
|
|
23504
23876
|
"cli/drivers/playwright-provisioning.ts"() {
|
|
23505
23877
|
"use strict";
|
|
23506
|
-
|
|
23507
|
-
|
|
23878
|
+
import_node_child_process6 = require("node:child_process");
|
|
23879
|
+
import_node_fs14 = require("node:fs");
|
|
23508
23880
|
import_node_module4 = require("node:module");
|
|
23509
|
-
|
|
23881
|
+
import_node_path17 = require("node:path");
|
|
23510
23882
|
PLAYWRIGHT_BROWSER_PROBE = `
|
|
23511
23883
|
const { existsSync } = require('node:fs');
|
|
23512
23884
|
const modulePath = process.env.SOOTSIM_PW_MODULE;
|
|
@@ -24681,21 +25053,21 @@ function assertExplicitBridgeLock(preferredPort, explicitPort, lock) {
|
|
|
24681
25053
|
}
|
|
24682
25054
|
async function ensureRuntimeForOpen() {
|
|
24683
25055
|
const active = readActiveRuntime();
|
|
24684
|
-
if (active &&
|
|
25056
|
+
if (active && import_node_fs15.default.existsSync(runtimeDir(active))) return;
|
|
24685
25057
|
console.error(" installing rnx engine runtime...");
|
|
24686
25058
|
const { runRuntime: runRuntime2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
24687
25059
|
await runRuntime2(["install"], {});
|
|
24688
25060
|
}
|
|
24689
25061
|
function spawnSootsim(args) {
|
|
24690
25062
|
const entry = process.argv[1];
|
|
24691
|
-
if (entry &&
|
|
24692
|
-
return (0,
|
|
25063
|
+
if (entry && import_node_fs15.default.existsSync(entry)) {
|
|
25064
|
+
return (0, import_node_child_process7.spawn)(process.execPath, [entry, ...args], {
|
|
24693
25065
|
detached: true,
|
|
24694
25066
|
stdio: "ignore",
|
|
24695
25067
|
env: process.env
|
|
24696
25068
|
});
|
|
24697
25069
|
}
|
|
24698
|
-
return (0,
|
|
25070
|
+
return (0, import_node_child_process7.spawn)(rnxPublicBrand.commandName, args, {
|
|
24699
25071
|
detached: true,
|
|
24700
25072
|
stdio: "ignore",
|
|
24701
25073
|
env: process.env
|
|
@@ -24776,7 +25148,7 @@ async function resolveConnectionInputForCli(target) {
|
|
|
24776
25148
|
const registeredPort = /^\d+$/.test(normalized) ? Number(normalized) : localBasePort(normalized);
|
|
24777
25149
|
if (registeredPort && registeredPort > 0) {
|
|
24778
25150
|
const discovered = await probePort(registeredPort);
|
|
24779
|
-
if (discovered) {
|
|
25151
|
+
if (discovered && !discovered.bundleUrlProvisional) {
|
|
24780
25152
|
return {
|
|
24781
25153
|
bundleUrl: discovered.bundleUrl,
|
|
24782
25154
|
port: discovered.port,
|
|
@@ -24835,10 +25207,10 @@ async function buildResolvedBundleOpenUrl(target, baseUrl, opts = {}) {
|
|
|
24835
25207
|
}
|
|
24836
25208
|
function normalizeReplacementPath(filePath) {
|
|
24837
25209
|
if (filePath.startsWith("~/")) {
|
|
24838
|
-
return
|
|
25210
|
+
return import_node_path18.default.join(import_node_os3.default.homedir(), filePath.slice(2));
|
|
24839
25211
|
}
|
|
24840
|
-
if (
|
|
24841
|
-
return
|
|
25212
|
+
if (import_node_path18.default.isAbsolute(filePath)) return filePath;
|
|
25213
|
+
return import_node_path18.default.resolve(process.cwd(), filePath);
|
|
24842
25214
|
}
|
|
24843
25215
|
function parseOpenRuntimeConfig(args) {
|
|
24844
25216
|
const modules = {};
|
|
@@ -24857,7 +25229,7 @@ function parseOpenRuntimeConfig(args) {
|
|
|
24857
25229
|
}
|
|
24858
25230
|
const moduleName = raw.slice(0, eqIndex).trim();
|
|
24859
25231
|
const filePath = normalizeReplacementPath(raw.slice(eqIndex + 1).trim());
|
|
24860
|
-
if (!
|
|
25232
|
+
if (!import_node_fs15.default.existsSync(filePath)) {
|
|
24861
25233
|
console.error(` rnx open: replacement file not found: ${filePath}`);
|
|
24862
25234
|
rnxExit(1);
|
|
24863
25235
|
}
|
|
@@ -24888,7 +25260,7 @@ async function resolveOpenAppProject(resolvedBundle) {
|
|
|
24888
25260
|
return advertisedRoot ? resolveAppProject(advertisedRoot) : null;
|
|
24889
25261
|
}
|
|
24890
25262
|
async function ensureConfiguredRuntime(version) {
|
|
24891
|
-
if (
|
|
25263
|
+
if (import_node_fs15.default.existsSync(import_node_path18.default.join(runtimeDir(version), "index.html"))) return;
|
|
24892
25264
|
console.error(` installing configured engine runtime ${version}...`);
|
|
24893
25265
|
const result = await sootsimRuntime.install({
|
|
24894
25266
|
version,
|
|
@@ -25248,7 +25620,7 @@ function playwrightHostPidForSim(sim) {
|
|
|
25248
25620
|
function signalDriverLaunchConnected(result) {
|
|
25249
25621
|
if (!result.connectAckFile) return false;
|
|
25250
25622
|
try {
|
|
25251
|
-
|
|
25623
|
+
import_node_fs15.default.writeFileSync(
|
|
25252
25624
|
result.connectAckFile,
|
|
25253
25625
|
`${JSON.stringify({ connectedAt: Date.now(), pid: result.pid ?? null })}
|
|
25254
25626
|
`,
|
|
@@ -25262,19 +25634,19 @@ function signalDriverLaunchConnected(result) {
|
|
|
25262
25634
|
function printDriverDiagnosticLogTail(result) {
|
|
25263
25635
|
if (!result.diagnosticLogPath) return;
|
|
25264
25636
|
try {
|
|
25265
|
-
const detail =
|
|
25637
|
+
const detail = import_node_fs15.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
|
|
25266
25638
|
if (!detail) {
|
|
25267
|
-
console.error(` ${
|
|
25639
|
+
console.error(` ${import_node_path18.default.basename(result.diagnosticLogPath)} was empty`);
|
|
25268
25640
|
return;
|
|
25269
25641
|
}
|
|
25270
25642
|
const shown = detail.length > 4e3 ? `\u2026
|
|
25271
25643
|
${detail.slice(-4e3)}` : detail;
|
|
25272
|
-
console.error(` ${
|
|
25644
|
+
console.error(` ${import_node_path18.default.basename(result.diagnosticLogPath)}:`);
|
|
25273
25645
|
console.error(shown);
|
|
25274
25646
|
} catch (err) {
|
|
25275
25647
|
const message = err instanceof Error ? err.message : String(err);
|
|
25276
25648
|
console.error(
|
|
25277
|
-
` failed to read ${
|
|
25649
|
+
` failed to read ${import_node_path18.default.basename(result.diagnosticLogPath)}: ${message}`
|
|
25278
25650
|
);
|
|
25279
25651
|
}
|
|
25280
25652
|
}
|
|
@@ -25295,11 +25667,11 @@ async function waitForProcessExit(pid, timeoutMs = 2500) {
|
|
|
25295
25667
|
return !isProcessAlive2(pid);
|
|
25296
25668
|
}
|
|
25297
25669
|
function isPlaywrightHostProcess(pid) {
|
|
25298
|
-
const plain = (0,
|
|
25670
|
+
const plain = (0, import_node_child_process7.spawnSync)("ps", ["-o", "command=", "-p", String(pid)], {
|
|
25299
25671
|
encoding: "utf8",
|
|
25300
25672
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25301
25673
|
});
|
|
25302
|
-
const withEnv = (0,
|
|
25674
|
+
const withEnv = (0, import_node_child_process7.spawnSync)("ps", ["eww", "-o", "command=", "-p", String(pid)], {
|
|
25303
25675
|
encoding: "utf8",
|
|
25304
25676
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25305
25677
|
});
|
|
@@ -26071,14 +26443,14 @@ async function runCloseCommand(args, opts = {}) {
|
|
|
26071
26443
|
bridge.close();
|
|
26072
26444
|
}
|
|
26073
26445
|
}
|
|
26074
|
-
var
|
|
26446
|
+
var import_node_child_process7, import_node_fs15, import_node_os3, import_node_path18, import_settings, import_ws5, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS;
|
|
26075
26447
|
var init_control = __esm({
|
|
26076
26448
|
"cli/commands/control.ts"() {
|
|
26077
26449
|
"use strict";
|
|
26078
|
-
|
|
26079
|
-
|
|
26450
|
+
import_node_child_process7 = require("node:child_process");
|
|
26451
|
+
import_node_fs15 = __toESM(require("node:fs"), 1);
|
|
26080
26452
|
import_node_os3 = __toESM(require("node:os"), 1);
|
|
26081
|
-
|
|
26453
|
+
import_node_path18 = __toESM(require("node:path"), 1);
|
|
26082
26454
|
import_settings = require("sootsim-engine/settings");
|
|
26083
26455
|
import_ws5 = require("ws");
|
|
26084
26456
|
init_dev_server_scanner();
|
|
@@ -26942,14 +27314,14 @@ process.stdin.on('end', async () => {
|
|
|
26942
27314
|
function getBaseDir() {
|
|
26943
27315
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
26944
27316
|
if (explicit?.trim()) {
|
|
26945
|
-
return (0,
|
|
27317
|
+
return (0, import_node_path19.dirname)((0, import_node_path19.resolve)(explicit));
|
|
26946
27318
|
}
|
|
26947
27319
|
return electronUserDataDir();
|
|
26948
27320
|
}
|
|
26949
27321
|
function getSharedDesktopAuthFilePath() {
|
|
26950
27322
|
const explicit = process.env[SESSION_FILE_ENV];
|
|
26951
|
-
if (explicit?.trim()) return (0,
|
|
26952
|
-
return (0,
|
|
27323
|
+
if (explicit?.trim()) return (0, import_node_path19.resolve)(explicit);
|
|
27324
|
+
return (0, import_node_path19.join)(getBaseDir(), "desktop-auth.json");
|
|
26953
27325
|
}
|
|
26954
27326
|
function normalizeUser(input) {
|
|
26955
27327
|
if (!input || typeof input !== "object") return null;
|
|
@@ -26996,26 +27368,26 @@ function normalizeSession(input) {
|
|
|
26996
27368
|
}
|
|
26997
27369
|
function readSharedDesktopAuthSession() {
|
|
26998
27370
|
const filepath = getSharedDesktopAuthFilePath();
|
|
26999
|
-
if (!(0,
|
|
27371
|
+
if (!(0, import_node_fs16.existsSync)(filepath)) return null;
|
|
27000
27372
|
try {
|
|
27001
|
-
const parsed = JSON.parse((0,
|
|
27373
|
+
const parsed = JSON.parse((0, import_node_fs16.readFileSync)(filepath, "utf8"));
|
|
27002
27374
|
const normalized = normalizeSession(parsed);
|
|
27003
27375
|
if (!normalized) {
|
|
27004
|
-
(0,
|
|
27376
|
+
(0, import_node_fs16.rmSync)(filepath, { force: true });
|
|
27005
27377
|
return null;
|
|
27006
27378
|
}
|
|
27007
27379
|
return normalized;
|
|
27008
27380
|
} catch {
|
|
27009
|
-
(0,
|
|
27381
|
+
(0, import_node_fs16.rmSync)(filepath, { force: true });
|
|
27010
27382
|
return null;
|
|
27011
27383
|
}
|
|
27012
27384
|
}
|
|
27013
|
-
var
|
|
27385
|
+
var import_node_fs16, import_node_path19, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
|
|
27014
27386
|
var init_shared_session = __esm({
|
|
27015
27387
|
"src/auth/shared-session.ts"() {
|
|
27016
27388
|
"use strict";
|
|
27017
|
-
|
|
27018
|
-
|
|
27389
|
+
import_node_fs16 = require("node:fs");
|
|
27390
|
+
import_node_path19 = require("node:path");
|
|
27019
27391
|
init_home_paths();
|
|
27020
27392
|
SESSION_VERSION = 1;
|
|
27021
27393
|
SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
|
|
@@ -27257,16 +27629,16 @@ function resolveFlowScreenshotPath(screenshotDir, name2) {
|
|
|
27257
27629
|
}
|
|
27258
27630
|
function resolveProjectRelativeFlowBase(flowDir) {
|
|
27259
27631
|
if (!flowDir) return process.cwd();
|
|
27260
|
-
return
|
|
27632
|
+
return path18.basename(flowDir) === ".maestro" ? path18.dirname(flowDir) : flowDir;
|
|
27261
27633
|
}
|
|
27262
27634
|
function resolveFlowScreenshotPathWithMode(screenshotDir, name2, opts) {
|
|
27263
27635
|
const normalizedName = name2.endsWith(".png") ? name2 : `${name2}.png`;
|
|
27264
|
-
if (
|
|
27636
|
+
if (path18.isAbsolute(normalizedName)) return normalizedName;
|
|
27265
27637
|
if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
|
|
27266
27638
|
const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
|
|
27267
|
-
return
|
|
27639
|
+
return path18.resolve(baseDir, normalizedName);
|
|
27268
27640
|
}
|
|
27269
|
-
return
|
|
27641
|
+
return path18.join(screenshotDir, normalizedName);
|
|
27270
27642
|
}
|
|
27271
27643
|
function normalizeFlowScreenshotSpec(step) {
|
|
27272
27644
|
if (typeof step === "string") {
|
|
@@ -27323,12 +27695,12 @@ function parseFlowSteps(content) {
|
|
|
27323
27695
|
const parsed = import_yaml.default.parse(candidate);
|
|
27324
27696
|
return Array.isArray(parsed) ? parsed : [];
|
|
27325
27697
|
}
|
|
27326
|
-
var
|
|
27698
|
+
var fs18, path18, import_settings3, import_yaml, import_proof_frame, DEFAULT_TIMEOUT, FLOW_TIMEOUT_SCALE, scaledTimeout, SCREEN_W, SCREEN_H, SootSimBridgeFlowRunner;
|
|
27327
27699
|
var init_bridge_flow_runner = __esm({
|
|
27328
27700
|
"cli/bridge-flow-runner.ts"() {
|
|
27329
27701
|
"use strict";
|
|
27330
|
-
|
|
27331
|
-
|
|
27702
|
+
fs18 = __toESM(require("fs"), 1);
|
|
27703
|
+
path18 = __toESM(require("path"), 1);
|
|
27332
27704
|
import_settings3 = require("sootsim-engine/settings");
|
|
27333
27705
|
import_yaml = __toESM(require("yaml"), 1);
|
|
27334
27706
|
import_proof_frame = __toESM(require_proof_frame(), 1);
|
|
@@ -27535,14 +27907,14 @@ var init_bridge_flow_runner = __esm({
|
|
|
27535
27907
|
if (chunks.length === 0) {
|
|
27536
27908
|
throw new Error("recording requested but no video buffer was produced");
|
|
27537
27909
|
}
|
|
27538
|
-
|
|
27910
|
+
fs18.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
|
|
27539
27911
|
const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
|
|
27540
27912
|
const extension = videoMime.includes("mp4") ? "mp4" : "webm";
|
|
27541
|
-
const outputPath =
|
|
27913
|
+
const outputPath = path18.join(
|
|
27542
27914
|
this.opts.recordingOutputDir,
|
|
27543
27915
|
`sootsim-${Date.now()}.${extension}`
|
|
27544
27916
|
);
|
|
27545
|
-
|
|
27917
|
+
fs18.writeFileSync(outputPath, Buffer.concat(chunks));
|
|
27546
27918
|
return outputPath;
|
|
27547
27919
|
}
|
|
27548
27920
|
async waitForRecordingTail(opts) {
|
|
@@ -28038,7 +28410,7 @@ var init_bridge_flow_runner = __esm({
|
|
|
28038
28410
|
flowDir: this.opts.flowDir
|
|
28039
28411
|
}
|
|
28040
28412
|
);
|
|
28041
|
-
|
|
28413
|
+
fs18.mkdirSync(path18.dirname(outputPath), { recursive: true });
|
|
28042
28414
|
const layers = spec.layers ?? this.opts.screenshotLayers;
|
|
28043
28415
|
const screenshotRequest = {
|
|
28044
28416
|
type: "screenshot",
|
|
@@ -28077,11 +28449,11 @@ var init_bridge_flow_runner = __esm({
|
|
|
28077
28449
|
throw new Error("could not read current device model for framed screenshot");
|
|
28078
28450
|
}
|
|
28079
28451
|
const framed = await composeFramedScreenshot(rawBuffer, model);
|
|
28080
|
-
|
|
28452
|
+
fs18.writeFileSync(outputPath, framed);
|
|
28081
28453
|
console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
|
|
28082
28454
|
return outputPath;
|
|
28083
28455
|
}
|
|
28084
|
-
|
|
28456
|
+
fs18.writeFileSync(outputPath, rawBuffer);
|
|
28085
28457
|
console.log(`[flow] screenshot: ${outputPath}`);
|
|
28086
28458
|
return outputPath;
|
|
28087
28459
|
}
|
|
@@ -28103,10 +28475,10 @@ var init_bridge_flow_runner = __esm({
|
|
|
28103
28475
|
// + a11y tree + console errors/warnings + failed network requests +
|
|
28104
28476
|
// shell state, all under one directory so post-mortem is one grep away.
|
|
28105
28477
|
async captureFailureBundle(outputDir, context) {
|
|
28106
|
-
|
|
28478
|
+
fs18.mkdirSync(outputDir, { recursive: true });
|
|
28107
28479
|
const write = (name2, content) => {
|
|
28108
28480
|
try {
|
|
28109
|
-
|
|
28481
|
+
fs18.writeFileSync(path18.join(outputDir, name2), content);
|
|
28110
28482
|
} catch {
|
|
28111
28483
|
}
|
|
28112
28484
|
};
|
|
@@ -28644,8 +29016,8 @@ var init_bridge_flow_runner = __esm({
|
|
|
28644
29016
|
runScript(target) {
|
|
28645
29017
|
const spec = typeof target === "string" ? { file: target } : target;
|
|
28646
29018
|
if (!spec.file) throw new Error("runScript requires a file");
|
|
28647
|
-
const scriptPath =
|
|
28648
|
-
const source =
|
|
29019
|
+
const scriptPath = path18.resolve(this.opts.flowDir, spec.file);
|
|
29020
|
+
const source = fs18.readFileSync(scriptPath, "utf8");
|
|
28649
29021
|
this.js.evaluate(source, { env: spec.env });
|
|
28650
29022
|
console.log(`[flow] runScript: ${spec.file} done`);
|
|
28651
29023
|
}
|
|
@@ -28942,10 +29314,10 @@ var init_bridge_flow_runner = __esm({
|
|
|
28942
29314
|
for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
|
|
28943
29315
|
}
|
|
28944
29316
|
if (file) {
|
|
28945
|
-
const flowPath =
|
|
28946
|
-
const flowContent =
|
|
29317
|
+
const flowPath = path18.resolve(this.opts.flowDir, file);
|
|
29318
|
+
const flowContent = fs18.readFileSync(flowPath, "utf8");
|
|
28947
29319
|
const previousDir = this.opts.flowDir;
|
|
28948
|
-
this.opts.flowDir =
|
|
29320
|
+
this.opts.flowDir = path18.dirname(flowPath);
|
|
28949
29321
|
try {
|
|
28950
29322
|
await this.runFlow(parseFlowSteps(flowContent));
|
|
28951
29323
|
} finally {
|
|
@@ -29100,8 +29472,8 @@ __export(registry_exports, {
|
|
|
29100
29472
|
skillRegistry: () => skillRegistry
|
|
29101
29473
|
});
|
|
29102
29474
|
module.exports = __toCommonJS(registry_exports);
|
|
29103
|
-
var
|
|
29104
|
-
var
|
|
29475
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
29476
|
+
var path19 = __toESM(require("path"), 1);
|
|
29105
29477
|
|
|
29106
29478
|
// src/skills/builtin/a11y-review.ts
|
|
29107
29479
|
init_reap_browser();
|
|
@@ -29120,8 +29492,8 @@ var skill = {
|
|
|
29120
29492
|
},
|
|
29121
29493
|
async execute(params, context) {
|
|
29122
29494
|
const { chromium } = await import("playwright");
|
|
29123
|
-
const
|
|
29124
|
-
const
|
|
29495
|
+
const path20 = await import("path");
|
|
29496
|
+
const fs20 = await import("fs");
|
|
29125
29497
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
29126
29498
|
headless: true
|
|
29127
29499
|
});
|
|
@@ -29176,9 +29548,9 @@ var skill = {
|
|
|
29176
29548
|
warnings: issues.filter((i) => i.severity === "warning").length,
|
|
29177
29549
|
tree: typeof tree === "string" ? tree : JSON.stringify(tree)
|
|
29178
29550
|
};
|
|
29179
|
-
const reportPath =
|
|
29180
|
-
|
|
29181
|
-
|
|
29551
|
+
const reportPath = path20.join(context.outputDir, "a11y-report.json");
|
|
29552
|
+
fs20.mkdirSync(path20.dirname(reportPath), { recursive: true });
|
|
29553
|
+
fs20.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
29182
29554
|
return {
|
|
29183
29555
|
success: issues.filter((i) => i.severity === "error").length === 0,
|
|
29184
29556
|
message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
|
|
@@ -29211,14 +29583,14 @@ var skill2 = {
|
|
|
29211
29583
|
}
|
|
29212
29584
|
},
|
|
29213
29585
|
async execute(params, context) {
|
|
29214
|
-
const
|
|
29215
|
-
const
|
|
29586
|
+
const fs20 = await import("node:fs");
|
|
29587
|
+
const path20 = await import("node:path");
|
|
29216
29588
|
const { COMPAT_RESULT_CAVEAT: COMPAT_RESULT_CAVEAT2, formatPackageStatus: formatPackageStatus2, formatScanCounts: formatScanCounts2, scanDeps: scanDeps2 } = await Promise.resolve().then(() => (init_web(), web_exports));
|
|
29217
|
-
const packagePath =
|
|
29218
|
-
if (!
|
|
29589
|
+
const packagePath = path20.join(context.projectDir, "package.json");
|
|
29590
|
+
if (!fs20.existsSync(packagePath)) {
|
|
29219
29591
|
return { success: false, message: "No package.json found" };
|
|
29220
29592
|
}
|
|
29221
|
-
const parsed = JSON.parse(
|
|
29593
|
+
const parsed = JSON.parse(fs20.readFileSync(packagePath, "utf8"));
|
|
29222
29594
|
if (!parsed || typeof parsed !== "object") {
|
|
29223
29595
|
return { success: false, message: "package.json is not an object" };
|
|
29224
29596
|
}
|
|
@@ -29230,9 +29602,9 @@ var skill2 = {
|
|
|
29230
29602
|
}) : scanDeps2(parsed);
|
|
29231
29603
|
const packageResult = params.packageName ? scan.packages[0] : void 0;
|
|
29232
29604
|
const message = packageResult ? `${params.packageName}: ${formatPackageStatus2(packageResult)}. ${COMPAT_RESULT_CAVEAT2}` : `${formatScanCounts2(scan)}. ${COMPAT_RESULT_CAVEAT2}`;
|
|
29233
|
-
const reportPath =
|
|
29234
|
-
|
|
29235
|
-
|
|
29605
|
+
const reportPath = path20.join(context.outputDir, "compat-report.json");
|
|
29606
|
+
fs20.mkdirSync(path20.dirname(reportPath), { recursive: true });
|
|
29607
|
+
fs20.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
|
|
29236
29608
|
`);
|
|
29237
29609
|
return {
|
|
29238
29610
|
success: true,
|
|
@@ -29276,8 +29648,8 @@ var skill3 = {
|
|
|
29276
29648
|
record: { type: "boolean", description: "Record video of the flow" }
|
|
29277
29649
|
},
|
|
29278
29650
|
async execute(params, context) {
|
|
29279
|
-
const
|
|
29280
|
-
const
|
|
29651
|
+
const fs20 = await import("fs");
|
|
29652
|
+
const path20 = await import("path");
|
|
29281
29653
|
const yaml2 = await import("yaml");
|
|
29282
29654
|
const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT2 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
|
|
29283
29655
|
const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
|
|
@@ -29287,7 +29659,7 @@ var skill3 = {
|
|
|
29287
29659
|
const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT2 });
|
|
29288
29660
|
host.start({ silent: true });
|
|
29289
29661
|
try {
|
|
29290
|
-
const flowContent =
|
|
29662
|
+
const flowContent = fs20.readFileSync(params.flowPath, "utf8");
|
|
29291
29663
|
const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
|
|
29292
29664
|
const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
|
|
29293
29665
|
const steps = yaml2.parse(stepsBody);
|
|
@@ -29314,7 +29686,7 @@ var skill3 = {
|
|
|
29314
29686
|
});
|
|
29315
29687
|
const driver = new SootSimBridgeFlowRunner2(bridge, {
|
|
29316
29688
|
screenshotDir: context.outputDir,
|
|
29317
|
-
flowDir:
|
|
29689
|
+
flowDir: path20.dirname(path20.resolve(params.flowPath)),
|
|
29318
29690
|
simId,
|
|
29319
29691
|
recordingOutputDir: params.record ? context.outputDir : void 0
|
|
29320
29692
|
});
|
|
@@ -29336,7 +29708,7 @@ var skill3 = {
|
|
|
29336
29708
|
simId,
|
|
29337
29709
|
videoPath: videoPath || void 0
|
|
29338
29710
|
},
|
|
29339
|
-
artifacts: videoPath ? [{ type: "video", name:
|
|
29711
|
+
artifacts: videoPath ? [{ type: "video", name: path20.basename(videoPath), path: videoPath }] : void 0
|
|
29340
29712
|
};
|
|
29341
29713
|
} finally {
|
|
29342
29714
|
try {
|
|
@@ -29383,8 +29755,8 @@ var skill4 = {
|
|
|
29383
29755
|
},
|
|
29384
29756
|
async execute(params, context) {
|
|
29385
29757
|
const { chromium } = await import("playwright");
|
|
29386
|
-
const
|
|
29387
|
-
const
|
|
29758
|
+
const path20 = await import("path");
|
|
29759
|
+
const fs20 = await import("fs");
|
|
29388
29760
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
29389
29761
|
headless: true
|
|
29390
29762
|
});
|
|
@@ -29410,9 +29782,9 @@ var skill4 = {
|
|
|
29410
29782
|
...profile,
|
|
29411
29783
|
fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
|
|
29412
29784
|
};
|
|
29413
|
-
const reportPath =
|
|
29414
|
-
|
|
29415
|
-
|
|
29785
|
+
const reportPath = path20.join(context.outputDir, "perf-report.json");
|
|
29786
|
+
fs20.mkdirSync(path20.dirname(reportPath), { recursive: true });
|
|
29787
|
+
fs20.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
29416
29788
|
return {
|
|
29417
29789
|
success: true,
|
|
29418
29790
|
message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
|
|
@@ -29445,8 +29817,8 @@ var skill5 = {
|
|
|
29445
29817
|
},
|
|
29446
29818
|
async execute(params, context) {
|
|
29447
29819
|
const { chromium } = await import("playwright");
|
|
29448
|
-
const
|
|
29449
|
-
const
|
|
29820
|
+
const path20 = await import("path");
|
|
29821
|
+
const fs20 = await import("fs");
|
|
29450
29822
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
29451
29823
|
headless: true
|
|
29452
29824
|
});
|
|
@@ -29454,8 +29826,8 @@ var skill5 = {
|
|
|
29454
29826
|
try {
|
|
29455
29827
|
await page.goto(context.url, { waitUntil: "networkidle" });
|
|
29456
29828
|
await page.waitForTimeout(2e3);
|
|
29457
|
-
const outputPath =
|
|
29458
|
-
|
|
29829
|
+
const outputPath = path20.join(context.outputDir, `${params.name}.png`);
|
|
29830
|
+
fs20.mkdirSync(path20.dirname(outputPath), { recursive: true });
|
|
29459
29831
|
await page.screenshot({ path: outputPath });
|
|
29460
29832
|
return {
|
|
29461
29833
|
success: true,
|
|
@@ -29496,8 +29868,8 @@ var skill6 = {
|
|
|
29496
29868
|
},
|
|
29497
29869
|
async execute(params, context) {
|
|
29498
29870
|
const { chromium } = await import("playwright");
|
|
29499
|
-
const
|
|
29500
|
-
const
|
|
29871
|
+
const path20 = await import("path");
|
|
29872
|
+
const fs20 = await import("fs");
|
|
29501
29873
|
const browser = await launchReapedChrome((options) => chromium.launch(options), {
|
|
29502
29874
|
headless: true
|
|
29503
29875
|
});
|
|
@@ -29505,14 +29877,14 @@ var skill6 = {
|
|
|
29505
29877
|
try {
|
|
29506
29878
|
await page.goto(context.url, { waitUntil: "networkidle" });
|
|
29507
29879
|
await page.waitForTimeout(2e3);
|
|
29508
|
-
const currentPath =
|
|
29509
|
-
|
|
29880
|
+
const currentPath = path20.join(context.outputDir, `${params.name}-current.png`);
|
|
29881
|
+
fs20.mkdirSync(path20.dirname(currentPath), { recursive: true });
|
|
29510
29882
|
await page.screenshot({ path: currentPath });
|
|
29511
29883
|
try {
|
|
29512
29884
|
const { PNG } = await import("pngjs");
|
|
29513
29885
|
const pixelmatch = (await import("pixelmatch")).default;
|
|
29514
|
-
const baseline = PNG.sync.read(
|
|
29515
|
-
const current = PNG.sync.read(
|
|
29886
|
+
const baseline = PNG.sync.read(fs20.readFileSync(params.baseline));
|
|
29887
|
+
const current = PNG.sync.read(fs20.readFileSync(currentPath));
|
|
29516
29888
|
const { width, height } = baseline;
|
|
29517
29889
|
const diff = new PNG({ width, height });
|
|
29518
29890
|
const numDiffPixels = pixelmatch(
|
|
@@ -29523,8 +29895,8 @@ var skill6 = {
|
|
|
29523
29895
|
height,
|
|
29524
29896
|
{ threshold: params.threshold || 0.1 }
|
|
29525
29897
|
);
|
|
29526
|
-
const diffPath =
|
|
29527
|
-
|
|
29898
|
+
const diffPath = path20.join(context.outputDir, `${params.name}-diff.png`);
|
|
29899
|
+
fs20.writeFileSync(diffPath, PNG.sync.write(diff));
|
|
29528
29900
|
const totalPixels = width * height;
|
|
29529
29901
|
const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
|
|
29530
29902
|
return {
|
|
@@ -29588,10 +29960,10 @@ var skillRegistry = {
|
|
|
29588
29960
|
},
|
|
29589
29961
|
// load skills from a project manifest (sootsim-skills.json)
|
|
29590
29962
|
async loadFromManifest(projectDir) {
|
|
29591
|
-
const manifestPath =
|
|
29592
|
-
if (!
|
|
29963
|
+
const manifestPath = path19.join(projectDir, "sootsim-skills.json");
|
|
29964
|
+
if (!fs19.existsSync(manifestPath)) return;
|
|
29593
29965
|
try {
|
|
29594
|
-
const manifest = JSON.parse(
|
|
29966
|
+
const manifest = JSON.parse(fs19.readFileSync(manifestPath, "utf8"));
|
|
29595
29967
|
if (Array.isArray(manifest.skills)) {
|
|
29596
29968
|
for (const entry of manifest.skills) {
|
|
29597
29969
|
if (typeof entry === "string") {
|
|
@@ -29602,7 +29974,7 @@ var skillRegistry = {
|
|
|
29602
29974
|
}
|
|
29603
29975
|
} else if (entry.file) {
|
|
29604
29976
|
try {
|
|
29605
|
-
const mod = await import(
|
|
29977
|
+
const mod = await import(path19.resolve(projectDir, entry.file));
|
|
29606
29978
|
if (mod.skill) this.register(mod.skill);
|
|
29607
29979
|
} catch {
|
|
29608
29980
|
}
|
|
@@ -29615,10 +29987,10 @@ var skillRegistry = {
|
|
|
29615
29987
|
// auto-discover skills based on project dependencies
|
|
29616
29988
|
suggestSkills(projectDir) {
|
|
29617
29989
|
const suggestions = [];
|
|
29618
|
-
const pkgPath =
|
|
29619
|
-
if (!
|
|
29990
|
+
const pkgPath = path19.join(projectDir, "package.json");
|
|
29991
|
+
if (!fs19.existsSync(pkgPath)) return suggestions;
|
|
29620
29992
|
try {
|
|
29621
|
-
const pkg = JSON.parse(
|
|
29993
|
+
const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf8"));
|
|
29622
29994
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
29623
29995
|
if (deps["detox"] || deps["maestro"]) {
|
|
29624
29996
|
suggestions.push("maestro-test");
|