peachsim 0.1.657 → 0.1.658

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.
Files changed (105) hide show
  1. package/README.md +21 -2
  2. package/cli/app-config.ts +25 -9
  3. package/cli/bridge-flow-runner.ts +10 -23
  4. package/cli/commands/compat.ts +234 -10
  5. package/cli/commands/do-chain.ts +5 -1
  6. package/cli/commands/inspect/actions.ts +33 -76
  7. package/cli/commands/inspect/resolve-target.ts +67 -2
  8. package/cli/commands/inspect.ts +16 -1
  9. package/cli/drivers/playwright-provisioning.ts +95 -0
  10. package/cli/ws-bridge.ts +7 -7
  11. package/dist-lib/agent-daemon-client.cjs +1 -1
  12. package/dist-lib/agent-events.cjs +1 -1
  13. package/dist-lib/agent-identity.cjs +1 -1
  14. package/dist-lib/agent-sessions.cjs +1 -1
  15. package/dist-lib/attached-projects.cjs +1 -1
  16. package/dist-lib/auth/shared-session.cjs +1 -1
  17. package/dist-lib/backend-origin.cjs +1 -1
  18. package/dist-lib/beta.cjs +1 -1
  19. package/dist-lib/beta.mjs +1 -1
  20. package/dist-lib/bridge-constants.cjs +1 -1
  21. package/dist-lib/bridge-contract-input.cjs +9 -1
  22. package/dist-lib/bridge-contract-input.mjs +9 -1
  23. package/dist-lib/bridge-contract.cjs +1 -1
  24. package/dist-lib/bridge-contract.mjs +1 -1
  25. package/dist-lib/capture-contract.cjs +1 -1
  26. package/dist-lib/capture-contract.mjs +1 -1
  27. package/dist-lib/cli-constants.cjs +1 -1
  28. package/dist-lib/cloud-contract.cjs +1 -1
  29. package/dist-lib/cloud-contract.mjs +1 -1
  30. package/dist-lib/cloud-test-args.cjs +1 -1
  31. package/dist-lib/cloud-test-args.mjs +1 -1
  32. package/dist-lib/cloud.cjs +1 -1
  33. package/dist-lib/cloud.mjs +1 -1
  34. package/dist-lib/config.cjs +3 -2
  35. package/dist-lib/detox/index.cjs +1 -1
  36. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  37. package/dist-lib/home-paths.cjs +1 -1
  38. package/dist-lib/host/bridge-host.cjs +78 -35
  39. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  40. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  41. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  42. package/dist-lib/host/replacement-module-handler.cjs +51 -8
  43. package/dist-lib/host/websocket-proxy.cjs +1 -1
  44. package/dist-lib/index.cjs +317 -70
  45. package/dist-lib/jump-to-source-babel.cjs +1 -1
  46. package/dist-lib/jump-to-source-native.cjs +1 -1
  47. package/dist-lib/kotlin-host.cjs +8 -4
  48. package/dist-lib/menu.cjs +1 -1
  49. package/dist-lib/menu.mjs +1 -1
  50. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  51. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  52. package/dist-lib/metro-production-bundle.cjs +1 -1
  53. package/dist-lib/metro-production-bundle.mjs +1 -1
  54. package/dist-lib/metro.cjs +300 -29
  55. package/dist-lib/native-app-identity.cjs +58 -25
  56. package/dist-lib/native-app-identity.mjs +57 -25
  57. package/dist-lib/plist.cjs +64 -0
  58. package/dist-lib/plist.mjs +29 -0
  59. package/dist-lib/profiles.cjs +1 -1
  60. package/dist-lib/public-brand.cjs +1 -1
  61. package/dist-lib/react-native-host-modules.cjs +1 -1
  62. package/dist-lib/react-native-host-modules.mjs +1 -1
  63. package/dist-lib/render-mode.cjs +1 -1
  64. package/dist-lib/scripts/dev-server-scanner.cjs +2 -2
  65. package/dist-lib/sdk.cjs +36 -49
  66. package/dist-lib/sdk.mjs +36 -49
  67. package/dist-lib/skills.cjs +250 -131
  68. package/dist-lib/swift-compile.cjs +1 -1
  69. package/dist-lib/swift-compile.mjs +1 -1
  70. package/dist-lib/swift-package.cjs +1 -1
  71. package/dist-lib/swift-package.mjs +1 -1
  72. package/dist-lib/swift-submit.cjs +1 -1
  73. package/dist-lib/swift-submit.mjs +1 -1
  74. package/dist-lib/swift.cjs +1 -1
  75. package/dist-lib/vite-swift.cjs +1 -1
  76. package/dist-lib/vite.cjs +51 -8
  77. package/kotlin/AppSources/android/app/UiModeManager.kt +9 -0
  78. package/kotlin/AppSources/android/content/Context.kt +9 -2
  79. package/kotlin/AppSources/android/content/res/Configuration.kt +16 -0
  80. package/kotlin/AppSources/android/content/res/Resources.kt +7 -0
  81. package/kotlin/AppSources/android/graphics/Color.kt +13 -0
  82. package/kotlin/AppSources/android/view/View.kt +2 -0
  83. package/kotlin/AppSources/android/view/Window.kt +99 -8
  84. package/kotlin/AppSources/android/view/WindowInsetsController.kt +12 -0
  85. package/kotlin/AppSources/android/view/WindowManager.kt +16 -0
  86. package/kotlin/AppSources/androidx/activity/EdgeToEdge.kt +71 -0
  87. package/kotlin/AppSources/androidx/core/view/WindowCompat.kt +32 -0
  88. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +16 -11
  89. package/kotlin/AppSources/dev/peach/app/PeachWindowHost.kt +2 -1
  90. package/kotlin/ComposeSources/PeachComposeHost.kt +11 -1
  91. package/package.json +8 -1
  92. package/skills/peach-setup/SKILL.md +27 -0
  93. package/src/android-theme.ts +167 -0
  94. package/src/android-xml.ts +70 -0
  95. package/src/bridge-contract-input.ts +10 -1
  96. package/src/bridge-contract.ts +7 -1
  97. package/src/config.ts +8 -0
  98. package/src/generated/android-framework-themes.json +6303 -0
  99. package/src/host/replacement-module-handler.ts +33 -0
  100. package/src/index.ts +1 -0
  101. package/src/kotlin-app.ts +75 -61
  102. package/src/kotlin-host.ts +7 -3
  103. package/src/metro-plugin.ts +46 -3
  104. package/src/native-app-identity.ts +75 -26
  105. package/src/sim-client.ts +2 -4
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.657 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.658 | (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;
@@ -4511,6 +4511,8 @@ var init_supported_native_packages = __esm({
4511
4511
  // seam+coverage
4512
4512
  "@react-native-firebase/app",
4513
4513
  // seam+coverage
4514
+ "@react-native-firebase/app-check",
4515
+ // seam
4514
4516
  "@react-native-firebase/auth",
4515
4517
  // seam
4516
4518
  "@react-native-firebase/crashlytics",
@@ -5265,6 +5267,8 @@ var init_supported_native_packages = __esm({
5265
5267
  // seam
5266
5268
  "react-native-worklets",
5267
5269
  // preset+coverage
5270
+ "react-native-worklets-core",
5271
+ // seam
5268
5272
  "react-native-xxhash",
5269
5273
  // seam+coverage
5270
5274
  "react-native-youtube",
@@ -7372,11 +7376,11 @@ var init_registry = __esm({
7372
7376
  stubType: "native",
7373
7377
  versions: [
7374
7378
  {
7375
- range: ">=18.0.0",
7376
- coverage: 0,
7377
- note: "the reference iOS simulator performs this package's behavior. Peach currently provides only this unsupported shape: development token noop : App Check API shape resolves with stub tokens. imports and API shape receive no behavior credit",
7378
- working: "default appCheck(), activate, setTokenAutoRefreshEnabled, getToken, onTokenChanged",
7379
- missing: "real attestation provider, token refresh, enforcement with Firebase services"
7379
+ range: ">=23.0.0",
7380
+ coverage: 0.8,
7381
+ note: "native-seam only. the published app-check JS runs over NativeRNFBTurboAppCheck, which mirrors RNFBAppCheckModule and a port of AppCheckCore token caching. the debug provider exchanges its token at firebaseappcheck.googleapis.com, so a debug token registered in the Firebase console yields real tokens, and the firebase js sdk services behind the other RNFB seams attach them. DeviceCheck and App Attest report the unsupported-attestation-provider error a device without DCDevice support reports",
7382
+ working: "initializeAppCheck and activate, configureProvider for debug, deviceCheck, appAttest and appAttestWithDeviceCheckFallback, getToken with caching and forced refresh, getLimitedUseToken, token auto-refresh setting, provider-not-ready and token-error rejections, debug token logging and persistence",
7383
+ missing: "Apple-signed DeviceCheck and App Attest attestation"
7380
7384
  }
7381
7385
  ]
7382
7386
  },
@@ -9900,8 +9904,8 @@ var init_registry = __esm({
9900
9904
  {
9901
9905
  range: ">=125.0.0",
9902
9906
  coverage: 0.85,
9903
- note: "load-safe noop \u2014 registerGlobals/setupReactNativeWebRTC accept calls; on web the global navigator.mediaDevices / RTCPeerConnection are already present so no patching is required",
9904
- missing: "no native iOS/Android WebRTC bindings. apps that need raw camera capture should use the browser getUserMedia API directly"
9907
+ note: "published JS runs over WebRTCModule backed by browser peers, capture, data channels, stats, RTCView frames and encryption. recording aliases share one pending capture; stop and disposal invalidate it. device playout controls existing and incoming audio receivers",
9908
+ missing: "AVAudioSession categories and hardware audio routing have no browser equivalent"
9905
9909
  }
9906
9910
  ]
9907
9911
  },
@@ -10012,9 +10016,9 @@ var init_registry = __esm({
10012
10016
  versions: [
10013
10017
  {
10014
10018
  range: ">=1.0.0",
10015
- coverage: 0.5,
10016
- note: "callbacks run, but every worklet stays on the main JavaScript thread while the reference iOS simulator executes worklets on their dedicated runtime",
10017
- missing: "no off-thread JS execution (matches our react-native-worklets-pkg stub story). complex worklet pipelines that actually need parallelism will see degraded performance, not crashes"
10019
+ coverage: 0.85,
10020
+ note: "published JS over the Worklets TurboModule: contexts run worklets on their own worker runtimes, createRunOnJS and cross-context calls settle promises on the calling thread, and shared values replicate writes and listeners across runtimes",
10021
+ missing: "shared value writes replicate in order instead of under one mutex, so simultaneous writes from two threads can briefly disagree; a worklet a context received and passes to another context loses its captured closure"
10018
10022
  }
10019
10023
  ]
10020
10024
  },
@@ -10023,10 +10027,10 @@ var init_registry = __esm({
10023
10027
  stubType: "native",
10024
10028
  versions: [
10025
10029
  {
10026
- range: ">=125.0.0",
10030
+ range: ">=124.0.0",
10027
10031
  coverage: 0.7,
10028
- note: "load-safe pass-through \u2014 RTCPeerConnection / RTCIceCandidate / RTCSessionDescription / MediaStream / MediaStreamTrack / mediaDevices forwarded from globalThis (browsers have these natively); registerGlobals is a noop; RTCView component renders null since we have no host-side video bridge yet",
10029
- missing: "RTCView visual rendering needs a host bridge that paints a video element into the device frame (deferred). raw audio/video peer connections work via the browser globals"
10032
+ note: "published JS runs over WebRTCModule backed by browser peer connections, capture, native events, data channels, stats and live RTCView frames. audio receivers obey device playout state",
10033
+ missing: "native hardware audio routing has no browser equivalent"
10030
10034
  }
10031
10035
  ]
10032
10036
  },
@@ -19241,7 +19245,7 @@ function hasOwnKeys(value) {
19241
19245
  }
19242
19246
  function hasPeachConfig(config) {
19243
19247
  if (!config) return false;
19244
- return typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
19248
+ return typeof config.runtimeVersion === "string" && config.runtimeVersion.length > 0 || hasOwnKeys(config.modules) || hasOwnKeys(config.turboModules) || hasOwnKeys(config.nativeModules) || hasOwnKeys(config.nativeViews) || hasOwnKeys(config.env) || hasOwnKeys(config.network?.remap) || hasOwnKeys(config.settings) || hasOwnKeys(config.initialState);
19245
19249
  }
19246
19250
  function mergePeachConfig(base, override) {
19247
19251
  if (!hasPeachConfig(base) && !hasPeachConfig(override)) return void 0;
@@ -19255,6 +19259,7 @@ function mergePeachConfig(base, override) {
19255
19259
  ...base.nativeModules || {},
19256
19260
  ...override.nativeModules || {}
19257
19261
  },
19262
+ nativeViews: { ...base.nativeViews || {}, ...override.nativeViews || {} },
19258
19263
  env: { ...base.env || {}, ...override.env || {} },
19259
19264
  network: {
19260
19265
  remap: { ...base.network?.remap || {}, ...override.network?.remap || {} }
@@ -24083,12 +24088,15 @@ function transformsFor(filePath) {
24083
24088
  );
24084
24089
  }
24085
24090
  }
24091
+ function isLocalSpecifier(specifier) {
24092
+ return specifier.startsWith("./") || specifier.startsWith("../");
24093
+ }
24086
24094
  function isContrastKitSpecifier(specifier) {
24087
24095
  return specifier === "contrast-kit" || specifier.startsWith("contrast-kit/");
24088
24096
  }
24089
24097
  function unsupportedSpecifier(specifier) {
24090
24098
  return new Error(
24091
- `replacement modules may only import react, react-native, contrast-kit, and the packages rnx stubs for this app; '${specifier}' is none of those. vendor the code into the replacement file, or add the package to peach.config so the simulator bridges it.`
24099
+ `replacement modules may only import react, react-native, contrast-kit, the packages rnx stubs for this app, and other project files by relative path; '${specifier}' is none of those. vendor the code into a project file, or add the package to peach.config so the simulator bridges it.`
24092
24100
  );
24093
24101
  }
24094
24102
  function bridgeDeclaration(name2, specifier) {
@@ -24111,11 +24119,9 @@ function compileReplacementModule(input) {
24111
24119
  const transformed = (0, import_dist.transform)(input.source, {
24112
24120
  transforms: transformsFor(input.filePath),
24113
24121
  filePath: input.filePath,
24114
- // classic runtime, matching what the app's own Metro build does for a file
24115
- // that has no automatic-runtime pragma: the file imports React itself.
24116
- jsxRuntime: "classic",
24117
- jsxPragma: "React.createElement",
24118
- jsxFragmentPragma: "React.Fragment",
24122
+ // the automatic runtime, as @react-native/babel-preset and babel-preset-expo
24123
+ // compile the app's own files: jsx needs no React import.
24124
+ jsxRuntime: "automatic",
24119
24125
  production: true,
24120
24126
  sourceMapOptions: { compiledFilename: input.filePath }
24121
24127
  });
@@ -24142,6 +24148,13 @@ function compileReplacementModule(input) {
24142
24148
  return name2;
24143
24149
  };
24144
24150
  const edits = [];
24151
+ const pointAtLocalModule = (specifierToken, specifier) => {
24152
+ edits.push({
24153
+ start: specifierToken.start,
24154
+ end: specifierToken.end,
24155
+ text: JSON.stringify(input.localModuleUrl(specifier))
24156
+ });
24157
+ };
24145
24158
  for (let index = 0; index < tokens.length; index++) {
24146
24159
  const token = tokens[index];
24147
24160
  if (token.type === EXPORT_KEYWORD) {
@@ -24161,6 +24174,10 @@ function compileReplacementModule(input) {
24161
24174
  }
24162
24175
  if (fromAt > 0 && tokens[fromAt] && read(tokens[fromAt]) === "from" && tokens[fromAt + 1]?.type === import_types.TokenType.string) {
24163
24176
  const specifier2 = readSpecifier(tokens[fromAt + 1]);
24177
+ if (isLocalSpecifier(specifier2)) {
24178
+ pointAtLocalModule(tokens[fromAt + 1], specifier2);
24179
+ continue;
24180
+ }
24164
24181
  throw new Error(
24165
24182
  `a replacement module cannot re-export from another module, and this one re-exports from '${specifier2}'. import what you need and export the binding.`
24166
24183
  );
@@ -24213,6 +24230,10 @@ function compileReplacementModule(input) {
24213
24230
  const specifierToken = tokens[cursor];
24214
24231
  if (!specifierToken) throw new Error("replacement module import is unterminated");
24215
24232
  const specifier = readSpecifier(specifierToken);
24233
+ if (isLocalSpecifier(specifier)) {
24234
+ pointAtLocalModule(specifierToken, specifier);
24235
+ continue;
24236
+ }
24216
24237
  if (specifier !== "react" && specifier !== "react-native" && !JSX_RUNTIME_SPECIFIERS.has(specifier) && !isContrastKitSpecifier(specifier) && !input.runtimePackages.has(specifier)) {
24217
24238
  throw unsupportedSpecifier(specifier);
24218
24239
  }
@@ -24278,6 +24299,25 @@ function sendJavaScript(req, res, source) {
24278
24299
  });
24279
24300
  res.end(req.method === "HEAD" ? void 0 : source);
24280
24301
  }
24302
+ function resolveLocalImport(fromFile, specifier) {
24303
+ const base = import_node_path14.default.resolve(import_node_path14.default.dirname(fromFile), specifier);
24304
+ const candidates = [
24305
+ ...REPLACEMENT_MODULE_EXTENSIONS.some(
24306
+ (ext) => ext === import_node_path14.default.extname(base).toLowerCase()
24307
+ ) ? [base] : [],
24308
+ ...REPLACEMENT_MODULE_EXTENSIONS.map((ext) => base + ext),
24309
+ ...REPLACEMENT_MODULE_EXTENSIONS.map((ext) => import_node_path14.default.join(base, `index${ext}`))
24310
+ ];
24311
+ const found = candidates.find(
24312
+ (candidate) => (0, import_node_fs14.statSync)(candidate, { throwIfNoEntry: false })?.isFile()
24313
+ );
24314
+ if (!found) {
24315
+ throw new Error(
24316
+ `'${specifier}' imported by ${fromFile} matches no ${REPLACEMENT_MODULE_EXTENSIONS.join(", ")} file`
24317
+ );
24318
+ }
24319
+ return found;
24320
+ }
24281
24321
  function isReplacementModuleRequestUrl(rawUrl) {
24282
24322
  if (!rawUrl) return false;
24283
24323
  try {
@@ -24368,7 +24408,14 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24368
24408
  const compiled = compileReplacementModule({
24369
24409
  filePath: resolvedTargetPath,
24370
24410
  source: await import_promises5.default.readFile(resolvedTargetPath, "utf8"),
24371
- runtimePackages
24411
+ runtimePackages,
24412
+ // the imported file's url is this request's with only its path changed,
24413
+ // so the token, cache key and runtime packages carry over.
24414
+ localModuleUrl: (specifier) => {
24415
+ const local = new URL(url.href);
24416
+ local.searchParams.set("path", resolveLocalImport(targetPath, specifier));
24417
+ return `${local.pathname}${local.search}`;
24418
+ }
24372
24419
  });
24373
24420
  const map = Buffer.from(JSON.stringify(compiled.sourceMap), "utf8").toString("base64");
24374
24421
  sendJavaScript(
@@ -24385,10 +24432,11 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24385
24432
  }
24386
24433
  return true;
24387
24434
  }
24388
- var import_promises5, import_node_path14, REPLACEMENT_MODULE_ROUTE;
24435
+ var import_node_fs14, import_promises5, import_node_path14, REPLACEMENT_MODULE_ROUTE;
24389
24436
  var init_replacement_module_handler = __esm({
24390
24437
  "src/host/replacement-module-handler.ts"() {
24391
24438
  "use strict";
24439
+ import_node_fs14 = require("node:fs");
24392
24440
  import_promises5 = __toESM(require("node:fs/promises"), 1);
24393
24441
  import_node_path14 = __toESM(require("node:path"), 1);
24394
24442
  init_replacementModule();
@@ -24733,25 +24781,25 @@ function normalizeSession(input) {
24733
24781
  }
24734
24782
  function readSharedDesktopAuthSession() {
24735
24783
  const filepath = getSharedDesktopAuthFilePath();
24736
- if (!(0, import_node_fs14.existsSync)(filepath)) return null;
24784
+ if (!(0, import_node_fs15.existsSync)(filepath)) return null;
24737
24785
  try {
24738
- const parsed = JSON.parse((0, import_node_fs14.readFileSync)(filepath, "utf8"));
24786
+ const parsed = JSON.parse((0, import_node_fs15.readFileSync)(filepath, "utf8"));
24739
24787
  const normalized = normalizeSession(parsed);
24740
24788
  if (!normalized) {
24741
- (0, import_node_fs14.rmSync)(filepath, { force: true });
24789
+ (0, import_node_fs15.rmSync)(filepath, { force: true });
24742
24790
  return null;
24743
24791
  }
24744
24792
  return normalized;
24745
24793
  } catch {
24746
- (0, import_node_fs14.rmSync)(filepath, { force: true });
24794
+ (0, import_node_fs15.rmSync)(filepath, { force: true });
24747
24795
  return null;
24748
24796
  }
24749
24797
  }
24750
- var import_node_fs14, import_node_path15, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
24798
+ var import_node_fs15, import_node_path15, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
24751
24799
  var init_shared_session = __esm({
24752
24800
  "src/auth/shared-session.ts"() {
24753
24801
  "use strict";
24754
- import_node_fs14 = require("node:fs");
24802
+ import_node_fs15 = require("node:fs");
24755
24803
  import_node_path15 = require("node:path");
24756
24804
  init_home_paths();
24757
24805
  SESSION_VERSION = 1;
@@ -28222,7 +28270,7 @@ function detectFramework2(deps) {
28222
28270
  }
28223
28271
  function detectProject(dir) {
28224
28272
  const pkgPath = (0, import_node_path16.join)(dir, "package.json");
28225
- if (!(0, import_node_fs15.existsSync)(pkgPath)) return null;
28273
+ if (!(0, import_node_fs16.existsSync)(pkgPath)) return null;
28226
28274
  const pkg = readProjectManifest(dir);
28227
28275
  if (!pkg) return null;
28228
28276
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
@@ -28240,19 +28288,19 @@ function detectProject(dir) {
28240
28288
  // apps write .cjs as often as .js, and missing one reads as "this project
28241
28289
  // has no bundler config" and sends the user to create a second one.
28242
28290
  hasViteConfig: CONFIG_EXTENSIONS.some(
28243
- (ext) => (0, import_node_fs15.existsSync)((0, import_node_path16.join)(dir, `vite.config.${ext}`))
28291
+ (ext) => (0, import_node_fs16.existsSync)((0, import_node_path16.join)(dir, `vite.config.${ext}`))
28244
28292
  ),
28245
28293
  hasMetroConfig: CONFIG_EXTENSIONS.some(
28246
- (ext) => (0, import_node_fs15.existsSync)((0, import_node_path16.join)(dir, `metro.config.${ext}`))
28294
+ (ext) => (0, import_node_fs16.existsSync)((0, import_node_path16.join)(dir, `metro.config.${ext}`))
28247
28295
  ),
28248
28296
  devCommand: typeof devCommand === "string" ? devCommand : null
28249
28297
  };
28250
28298
  }
28251
28299
  function readProjectMetadata(path23) {
28252
28300
  try {
28253
- const info = (0, import_node_fs15.lstatSync)(path23);
28301
+ const info = (0, import_node_fs16.lstatSync)(path23);
28254
28302
  if (!info.isFile() || info.size > 4 * 1024 * 1024) return null;
28255
- return (0, import_node_fs15.readFileSync)(path23, "utf8");
28303
+ return (0, import_node_fs16.readFileSync)(path23, "utf8");
28256
28304
  } catch {
28257
28305
  return null;
28258
28306
  }
@@ -28289,11 +28337,11 @@ function readProjectManifest(dir) {
28289
28337
  devDependencies: record(metadataValue(parsed, "devDependencies"))
28290
28338
  };
28291
28339
  }
28292
- var import_node_fs15, import_node_path16, import_json5, import_yaml, CONFIG_EXTENSIONS;
28340
+ var import_node_fs16, import_node_path16, import_json5, import_yaml, CONFIG_EXTENSIONS;
28293
28341
  var init_detect = __esm({
28294
28342
  "cli/commands/detect.ts"() {
28295
28343
  "use strict";
28296
- import_node_fs15 = require("node:fs");
28344
+ import_node_fs16 = require("node:fs");
28297
28345
  import_node_path16 = require("node:path");
28298
28346
  import_json5 = __toESM(require("json5"), 1);
28299
28347
  import_yaml = require("yaml");
@@ -28335,17 +28383,17 @@ function readImmutableBundleSource(bundlePath) {
28335
28383
  if ((0, import_node_path17.extname)(filepath) !== ".js") {
28336
28384
  throw new Error(`${REMOTE_COMMAND} requires one local Metro .js bundle`);
28337
28385
  }
28338
- const descriptor = (0, import_node_fs16.openSync)(filepath, "r");
28386
+ const descriptor = (0, import_node_fs17.openSync)(filepath, "r");
28339
28387
  try {
28340
- const before = (0, import_node_fs16.fstatSync)(descriptor, { bigint: true });
28388
+ const before = (0, import_node_fs17.fstatSync)(descriptor, { bigint: true });
28341
28389
  if (!before.isFile()) {
28342
28390
  throw new Error(`${REMOTE_COMMAND} bundle must be a regular local file`);
28343
28391
  }
28344
28392
  if (before.size <= 0n) {
28345
28393
  throw new Error(`${REMOTE_COMMAND} bundle is empty`);
28346
28394
  }
28347
- const bytes = (0, import_node_fs16.readFileSync)(descriptor);
28348
- const after = (0, import_node_fs16.fstatSync)(descriptor, { bigint: true });
28395
+ const bytes = (0, import_node_fs17.readFileSync)(descriptor);
28396
+ const after = (0, import_node_fs17.fstatSync)(descriptor, { bigint: true });
28349
28397
  if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || bytes.length !== Number(before.size)) {
28350
28398
  throw new Error(`${REMOTE_COMMAND} bundle changed while it was being read`);
28351
28399
  }
@@ -28360,7 +28408,7 @@ function readImmutableBundleSource(bundlePath) {
28360
28408
  }
28361
28409
  return source;
28362
28410
  } finally {
28363
- (0, import_node_fs16.closeSync)(descriptor);
28411
+ (0, import_node_fs17.closeSync)(descriptor);
28364
28412
  }
28365
28413
  }
28366
28414
  async function fetchBundleSource(bundleUrl) {
@@ -28408,14 +28456,14 @@ async function loadBundleSource(bundleInput) {
28408
28456
  }
28409
28457
  function listMetroAssetDest(assetsPath) {
28410
28458
  const directory = (0, import_node_path17.resolve)(assetsPath);
28411
- if (!(0, import_node_fs16.existsSync)(directory)) return { directory, files: [], truncated: false };
28412
- const skipNested = (0, import_node_fs16.existsSync)((0, import_node_path17.join)(directory, "package.json"));
28459
+ if (!(0, import_node_fs17.existsSync)(directory)) return { directory, files: [], truncated: false };
28460
+ const skipNested = (0, import_node_fs17.existsSync)((0, import_node_path17.join)(directory, "package.json"));
28413
28461
  const files = [];
28414
28462
  let truncated = false;
28415
28463
  const walk = (dir, prefix) => {
28416
28464
  let entries;
28417
28465
  try {
28418
- entries = (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true });
28466
+ entries = (0, import_node_fs17.readdirSync)(dir, { withFileTypes: true });
28419
28467
  } catch {
28420
28468
  return;
28421
28469
  }
@@ -28462,7 +28510,7 @@ function distinctByContent(directory, options) {
28462
28510
  for (const relative2 of options) {
28463
28511
  let bytes;
28464
28512
  try {
28465
- bytes = (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(directory, relative2));
28513
+ bytes = (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(directory, relative2));
28466
28514
  } catch {
28467
28515
  continue;
28468
28516
  }
@@ -28494,7 +28542,7 @@ function placeMetroDescriptor(listing, descriptor) {
28494
28542
  let bytes;
28495
28543
  try {
28496
28544
  bytes = combination.map(
28497
- (relative2) => (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(listing.directory, relative2))
28545
+ (relative2) => (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(listing.directory, relative2))
28498
28546
  );
28499
28547
  } catch {
28500
28548
  continue;
@@ -28665,7 +28713,7 @@ async function embedBundleAssets(bundlePath, command, assetPolicy) {
28665
28713
  );
28666
28714
  }
28667
28715
  const relative2 = placement?.files.get(variant.scale);
28668
- if (relative2 && dest) return (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(dest.directory, relative2));
28716
+ if (relative2 && dest) return (0, import_node_fs17.readFileSync)((0, import_node_path17.join)(dest.directory, relative2));
28669
28717
  if (placement && placement.files.size > 0) return null;
28670
28718
  if (placement && placement.ambiguous.length > 0 && dest) {
28671
28719
  throw new Error(
@@ -28880,12 +28928,12 @@ function createCloudBridgeForParsed(parsed) {
28880
28928
  if (!session) return null;
28881
28929
  return session.service === "box" ? new CloudBoxBridge(session) : new CloudBridge(session);
28882
28930
  }
28883
- var import_node_crypto6, import_node_fs16, import_node_path17, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS, CloudBridge, CloudBoxBridge;
28931
+ var import_node_crypto6, import_node_fs17, import_node_path17, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS, CloudBridge, CloudBoxBridge;
28884
28932
  var init_cloud_client = __esm({
28885
28933
  "cli/cloud-client.ts"() {
28886
28934
  "use strict";
28887
28935
  import_node_crypto6 = require("node:crypto");
28888
- import_node_fs16 = require("node:fs");
28936
+ import_node_fs17 = require("node:fs");
28889
28937
  import_node_path17 = require("node:path");
28890
28938
  init_metroAssetArtifact();
28891
28939
  init_metroCloudArtifact();
@@ -31298,30 +31346,30 @@ var init_parent_pid = __esm({
31298
31346
 
31299
31347
  // cli/secure-file.ts
31300
31348
  function writeSecureJsonAtomic(filepath, value) {
31301
- (0, import_node_fs17.mkdirSync)((0, import_node_path18.dirname)(filepath), { recursive: true });
31349
+ (0, import_node_fs18.mkdirSync)((0, import_node_path18.dirname)(filepath), { recursive: true });
31302
31350
  const temporary = `${filepath}.tmp-${process.pid}-${(0, import_node_crypto7.randomUUID)()}`;
31303
31351
  let descriptor = null;
31304
31352
  try {
31305
- descriptor = (0, import_node_fs17.openSync)(temporary, "wx", 384);
31306
- (0, import_node_fs17.fchmodSync)(descriptor, 384);
31307
- (0, import_node_fs17.writeFileSync)(descriptor, `${JSON.stringify(value, null, 2)}
31353
+ descriptor = (0, import_node_fs18.openSync)(temporary, "wx", 384);
31354
+ (0, import_node_fs18.fchmodSync)(descriptor, 384);
31355
+ (0, import_node_fs18.writeFileSync)(descriptor, `${JSON.stringify(value, null, 2)}
31308
31356
  `);
31309
- (0, import_node_fs17.fsyncSync)(descriptor);
31310
- (0, import_node_fs17.closeSync)(descriptor);
31357
+ (0, import_node_fs18.fsyncSync)(descriptor);
31358
+ (0, import_node_fs18.closeSync)(descriptor);
31311
31359
  descriptor = null;
31312
- (0, import_node_fs17.renameSync)(temporary, filepath);
31360
+ (0, import_node_fs18.renameSync)(temporary, filepath);
31313
31361
  } catch (error) {
31314
- if (descriptor !== null) (0, import_node_fs17.closeSync)(descriptor);
31315
- (0, import_node_fs17.rmSync)(temporary, { force: true });
31362
+ if (descriptor !== null) (0, import_node_fs18.closeSync)(descriptor);
31363
+ (0, import_node_fs18.rmSync)(temporary, { force: true });
31316
31364
  throw error;
31317
31365
  }
31318
31366
  }
31319
- var import_node_crypto7, import_node_fs17, import_node_path18;
31367
+ var import_node_crypto7, import_node_fs18, import_node_path18;
31320
31368
  var init_secure_file = __esm({
31321
31369
  "cli/secure-file.ts"() {
31322
31370
  "use strict";
31323
31371
  import_node_crypto7 = require("node:crypto");
31324
- import_node_fs17 = require("node:fs");
31372
+ import_node_fs18 = require("node:fs");
31325
31373
  import_node_path18 = require("node:path");
31326
31374
  }
31327
31375
  });
@@ -31499,7 +31547,7 @@ function liveDevBridgeLockfiles() {
31499
31547
  function checkoutRoot(cwd) {
31500
31548
  let current = import_node_path19.default.resolve(cwd);
31501
31549
  while (true) {
31502
- if (import_node_fs18.default.existsSync(import_node_path19.default.join(current, ".git"))) return current;
31550
+ if (import_node_fs19.default.existsSync(import_node_path19.default.join(current, ".git"))) return current;
31503
31551
  const parent = import_node_path19.default.dirname(current);
31504
31552
  if (parent === current) return null;
31505
31553
  current = parent;
@@ -31894,9 +31942,8 @@ function createBridge(wsPort, opts = {}) {
31894
31942
  );
31895
31943
  return sendOnce(successor);
31896
31944
  }
31897
- clearCurrentSimId();
31898
31945
  throw new Error(
31899
- `saved sim ${sentSimId} is gone${message.slice(missingSimMessage.length)}; run \`peach list\` and \`peach use <sim>\`, or open a fresh sim`
31946
+ `saved sim ${sentSimId} is not connected${message.slice(missingSimMessage.length)}; commands resume when it reconnects, or run \`peach list\` and \`peach use <sim>\`, or open a fresh sim`
31900
31947
  );
31901
31948
  }
31902
31949
  throw error;
@@ -32010,11 +32057,11 @@ async function callInBridge(bridge, path23, ...args) {
32010
32057
  async function callInBridgeWrite(bridge, path23, ...args) {
32011
32058
  return bridge.send({ type: "call", path: path23, args, acquireLock: true });
32012
32059
  }
32013
- var import_node_fs18, import_node_path19, import_ws2, PEACH_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError, BRIDGE_VALUE_FLAGS_TABLE, BRIDGE_VALUE_FLAGS;
32060
+ var import_node_fs19, import_node_path19, import_ws2, PEACH_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError, BRIDGE_VALUE_FLAGS_TABLE, BRIDGE_VALUE_FLAGS;
32014
32061
  var init_ws_bridge = __esm({
32015
32062
  "cli/ws-bridge.ts"() {
32016
32063
  "use strict";
32017
- import_node_fs18 = __toESM(require("node:fs"), 1);
32064
+ import_node_fs19 = __toESM(require("node:fs"), 1);
32018
32065
  import_node_path19 = __toESM(require("node:path"), 1);
32019
32066
  import_ws2 = require("ws");
32020
32067
  init_bridge_constants();
@@ -32308,8 +32355,8 @@ var init_dev_bundle_resolution = __esm({
32308
32355
 
32309
32356
  // src/dot-env.ts
32310
32357
  function selectEnvFile(env, notices) {
32311
- if (import_node_fs19.default.existsSync("/tmp/envfile")) {
32312
- return { name: import_node_fs19.default.readFileSync("/tmp/envfile", "utf8").trim(), fromEnvfile: false };
32358
+ if (import_node_fs20.default.existsSync("/tmp/envfile")) {
32359
+ return { name: import_node_fs20.default.readFileSync("/tmp/envfile", "utf8").trim(), fromEnvfile: false };
32313
32360
  }
32314
32361
  const requested = env.ENVFILE;
32315
32362
  if (!requested) return { name: DEFAULT_ENV_FILE, fromEnvfile: false };
@@ -32379,9 +32426,9 @@ function readProjectDotEnv(envsRoot, env = process.env) {
32379
32426
  ...requestedPaths,
32380
32427
  import_node_path20.default.resolve(import_node_path20.default.join(envsRoot, DEFAULT_ENV_FILE))
32381
32428
  ];
32382
- if (!import_node_fs19.default.existsSync(candidates[2])) candidates.push(import_node_path20.default.resolve(DEFAULT_ENV_FILE));
32429
+ if (!import_node_fs20.default.existsSync(candidates[2])) candidates.push(import_node_path20.default.resolve(DEFAULT_ENV_FILE));
32383
32430
  const tried = [...new Set(candidates)];
32384
- const resolved = tried.find((candidate) => import_node_fs19.default.existsSync(candidate));
32431
+ const resolved = tried.find((candidate) => import_node_fs20.default.existsSync(candidate));
32385
32432
  if (!resolved) {
32386
32433
  notices.push(
32387
32434
  "*** Missing .env file ****",
@@ -32401,7 +32448,7 @@ function readProjectDotEnv(envsRoot, env = process.env) {
32401
32448
  );
32402
32449
  }
32403
32450
  const config = {};
32404
- for (const line of import_node_fs19.default.readFileSync(resolved, "utf8").split("\n")) {
32451
+ for (const line of import_node_fs20.default.readFileSync(resolved, "utf8").split("\n")) {
32405
32452
  if (!line.trim()) continue;
32406
32453
  if (/^[ \t\n\v\f\r]*#/.test(line)) continue;
32407
32454
  const match = DOTENV_PATTERN.exec(line);
@@ -32411,11 +32458,11 @@ function readProjectDotEnv(envsRoot, env = process.env) {
32411
32458
  }
32412
32459
  return { config, notices };
32413
32460
  }
32414
- var import_node_fs19, import_node_path20, DEFAULT_ENV_FILE, DOTENV_PATTERN, BUILD_SETTING_PATTERN, INVALID_ENTRY;
32461
+ var import_node_fs20, import_node_path20, DEFAULT_ENV_FILE, DOTENV_PATTERN, BUILD_SETTING_PATTERN, INVALID_ENTRY;
32415
32462
  var init_dot_env = __esm({
32416
32463
  "src/dot-env.ts"() {
32417
32464
  "use strict";
32418
- import_node_fs19 = __toESM(require("node:fs"), 1);
32465
+ import_node_fs20 = __toESM(require("node:fs"), 1);
32419
32466
  import_node_path20 = __toESM(require("node:path"), 1);
32420
32467
  DEFAULT_ENV_FILE = ".env";
32421
32468
  DOTENV_PATTERN = /^(?:export[ \t\n\v\f\r]+|)(?<key>[\p{Alphabetic}\p{Nd}_]+)[ \t\n\v\f\r]*=[ \t\n\v\f\r]*((?<quote>["'])?(?<val>[^\n]*?[^\\\n])\k<quote>?|)$/u;
@@ -32445,7 +32492,7 @@ function readNativeFirebaseConfig(projectRoot) {
32445
32492
  "app.config.ts",
32446
32493
  "app.config.cjs",
32447
32494
  "app.config.mjs"
32448
- ].some((name2) => import_node_fs20.default.existsSync(import_node_path21.default.join(projectRoot, name2))))
32495
+ ].some((name2) => import_node_fs21.default.existsSync(import_node_path21.default.join(projectRoot, name2))))
32449
32496
  return result;
32450
32497
  const require5 = (0, import_node_module.createRequire)(import_node_path21.default.join(projectRoot, "package.json"));
32451
32498
  const configModule = require5("@expo/config");
@@ -32461,7 +32508,7 @@ function readNativeFirebaseConfig(projectRoot) {
32461
32508
  const native = config[platform];
32462
32509
  if (!isRecord(native) || typeof native.googleServicesFile !== "string") continue;
32463
32510
  try {
32464
- const source = import_node_fs20.default.readFileSync(
32511
+ const source = import_node_fs21.default.readFileSync(
32465
32512
  import_node_path21.default.resolve(projectRoot, native.googleServicesFile),
32466
32513
  "utf8"
32467
32514
  );
@@ -32514,11 +32561,11 @@ function readNativeFirebaseConfig(projectRoot) {
32514
32561
  }
32515
32562
  return result;
32516
32563
  }
32517
- var import_node_fs20, import_node_module, import_node_path21;
32564
+ var import_node_fs21, import_node_module, import_node_path21;
32518
32565
  var init_native_firebase_config = __esm({
32519
32566
  "src/native-firebase-config.ts"() {
32520
32567
  "use strict";
32521
- import_node_fs20 = __toESM(require("node:fs"), 1);
32568
+ import_node_fs21 = __toESM(require("node:fs"), 1);
32522
32569
  import_node_module = require("node:module");
32523
32570
  import_node_path21 = __toESM(require("node:path"), 1);
32524
32571
  init_is_record();
@@ -32732,14 +32779,14 @@ var init_bundleAssets = __esm({
32732
32779
  // cli/app-catalog.ts
32733
32780
  function listDir(dir) {
32734
32781
  try {
32735
- return import_node_fs21.default.readdirSync(dir, { withFileTypes: true });
32782
+ return import_node_fs22.default.readdirSync(dir, { withFileTypes: true });
32736
32783
  } catch {
32737
32784
  return [];
32738
32785
  }
32739
32786
  }
32740
32787
  function readText(file) {
32741
32788
  try {
32742
- return import_node_fs21.default.readFileSync(file, "utf8");
32789
+ return import_node_fs22.default.readFileSync(file, "utf8");
32743
32790
  } catch {
32744
32791
  return null;
32745
32792
  }
@@ -32779,11 +32826,11 @@ function discoverAppCatalog(appDir) {
32779
32826
  if (accentName === null && Object.keys(colors).length === 0) return null;
32780
32827
  return { colors, accentName };
32781
32828
  }
32782
- var import_node_fs21, import_node_path22, ACCENT_BUILD_SETTING, PLIST_ACCENT;
32829
+ var import_node_fs22, import_node_path22, ACCENT_BUILD_SETTING, PLIST_ACCENT;
32783
32830
  var init_app_catalog = __esm({
32784
32831
  "cli/app-catalog.ts"() {
32785
32832
  "use strict";
32786
- import_node_fs21 = __toESM(require("node:fs"), 1);
32833
+ import_node_fs22 = __toESM(require("node:fs"), 1);
32787
32834
  import_node_path22 = __toESM(require("node:path"), 1);
32788
32835
  init_bundleAssets();
32789
32836
  ACCENT_BUILD_SETTING = /ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "?([^";]+)"?;/;
@@ -32796,7 +32843,7 @@ function firstNamedFile(dir, names) {
32796
32843
  for (const name2 of names) {
32797
32844
  const candidate = import_node_path23.default.join(dir, name2);
32798
32845
  try {
32799
- if (import_node_fs22.default.statSync(candidate).isFile()) return candidate;
32846
+ if (import_node_fs23.default.statSync(candidate).isFile()) return candidate;
32800
32847
  } catch {
32801
32848
  }
32802
32849
  }
@@ -32811,21 +32858,21 @@ function findRNXAppConfig(dir) {
32811
32858
  function resolveAppProject(projectRoot) {
32812
32859
  const appDir = import_node_path23.default.resolve(projectRoot);
32813
32860
  try {
32814
- if (!import_node_fs22.default.statSync(appDir).isDirectory()) return null;
32861
+ if (!import_node_fs23.default.statSync(appDir).isDirectory()) return null;
32815
32862
  } catch {
32816
32863
  return null;
32817
32864
  }
32818
32865
  const configPath = findRNXAppConfig(appDir);
32819
- if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs22.default.existsSync(import_node_path23.default.join(appDir, "package.json"))) {
32866
+ if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs23.default.existsSync(import_node_path23.default.join(appDir, "package.json"))) {
32820
32867
  return null;
32821
32868
  }
32822
32869
  return { appDir, configPath };
32823
32870
  }
32824
- var import_node_fs22, import_node_path23, EXPO_APP_CONFIG_NAMES, PEACH_APP_CONFIG_NAMES;
32871
+ var import_node_fs23, import_node_path23, EXPO_APP_CONFIG_NAMES, PEACH_APP_CONFIG_NAMES;
32825
32872
  var init_app_project = __esm({
32826
32873
  "cli/app-project.ts"() {
32827
32874
  "use strict";
32828
- import_node_fs22 = __toESM(require("node:fs"), 1);
32875
+ import_node_fs23 = __toESM(require("node:fs"), 1);
32829
32876
  import_node_path23 = __toESM(require("node:path"), 1);
32830
32877
  EXPO_APP_CONFIG_NAMES = [
32831
32878
  "app.config.js",
@@ -32851,19 +32898,25 @@ function isPeachConfig(value) {
32851
32898
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
32852
32899
  const runtimeVersion = Reflect.get(value, "runtimeVersion");
32853
32900
  const network = Reflect.get(value, "network");
32854
- return (runtimeVersion === void 0 || typeof runtimeVersion === "string" && runtimeVersion === runtimeVersion.trim() && isValidRuntimeVersion(runtimeVersion)) && isOptionalRecord(Reflect.get(value, "modules")) && isOptionalRecord(Reflect.get(value, "turboModules")) && isOptionalRecord(Reflect.get(value, "nativeModules")) && isOptionalRecord(Reflect.get(value, "env")) && isOptionalRecord(network) && isOptionalRecord(Reflect.get(value, "settings")) && isOptionalRecord(Reflect.get(value, "initialState"));
32901
+ return (runtimeVersion === void 0 || typeof runtimeVersion === "string" && runtimeVersion === runtimeVersion.trim() && isValidRuntimeVersion(runtimeVersion)) && isOptionalRecord(Reflect.get(value, "modules")) && isOptionalRecord(Reflect.get(value, "turboModules")) && isOptionalRecord(Reflect.get(value, "nativeModules")) && isOptionalRecord(Reflect.get(value, "nativeViews")) && isOptionalRecord(Reflect.get(value, "env")) && isOptionalRecord(network) && isOptionalRecord(Reflect.get(value, "settings")) && isOptionalRecord(Reflect.get(value, "initialState"));
32902
+ }
32903
+ function resolveFileEntries(entries, configDir) {
32904
+ if (!entries) return entries;
32905
+ return Object.fromEntries(
32906
+ Object.entries(entries).map(([name2, resolution]) => [
32907
+ name2,
32908
+ resolution && typeof resolution === "object" && "file" in resolution && typeof resolution.file === "string" ? { ...resolution, file: import_node_path24.default.resolve(configDir, resolution.file) } : resolution
32909
+ ])
32910
+ );
32855
32911
  }
32856
32912
  function resolveConfigReplacementFiles(config, configPath) {
32857
- if (!config.modules) return config;
32858
32913
  const configDir = import_node_path24.default.dirname(configPath);
32859
32914
  return {
32860
32915
  ...config,
32861
- modules: Object.fromEntries(
32862
- Object.entries(config.modules).map(([name2, resolution]) => [
32863
- name2,
32864
- resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file: import_node_path24.default.resolve(configDir, resolution.file) } : resolution
32865
- ])
32866
- )
32916
+ modules: resolveFileEntries(config.modules, configDir),
32917
+ turboModules: resolveFileEntries(config.turboModules, configDir),
32918
+ nativeModules: resolveFileEntries(config.nativeModules, configDir),
32919
+ nativeViews: resolveFileEntries(config.nativeViews, configDir)
32867
32920
  };
32868
32921
  }
32869
32922
  async function loadRNXAppConfig(project) {
@@ -32953,7 +33006,7 @@ function discoverNativeLinkedAppFonts(opts) {
32953
33006
  scannedFontDirectories++;
32954
33007
  let entries;
32955
33008
  try {
32956
- entries = import_node_fs23.default.readdirSync(current.dir, { withFileTypes: true });
33009
+ entries = import_node_fs24.default.readdirSync(current.dir, { withFileTypes: true });
32957
33010
  } catch {
32958
33011
  continue;
32959
33012
  }
@@ -32975,7 +33028,7 @@ function discoverNativeLinkedAppFonts(opts) {
32975
33028
  };
32976
33029
  try {
32977
33030
  const packageJson = JSON.parse(
32978
- import_node_fs23.default.readFileSync(import_node_path25.default.join(selectedAppDir, "package.json"), "utf8")
33031
+ import_node_fs24.default.readFileSync(import_node_path25.default.join(selectedAppDir, "package.json"), "utf8")
32979
33032
  );
32980
33033
  const dependencyNames = /* @__PURE__ */ new Set();
32981
33034
  for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
@@ -33026,7 +33079,7 @@ function discoverNativeLinkedAppFonts(opts) {
33026
33079
  }
33027
33080
  try {
33028
33081
  const configPath = import_node_path25.default.join(selectedAppDir, "react-native.config.js");
33029
- if (import_node_fs23.default.statSync(configPath).isFile()) {
33082
+ if (import_node_fs24.default.statSync(configPath).isFile()) {
33030
33083
  const appConfigRequire = (0, import_node_module3.createRequire)(import_node_path25.default.join(selectedAppDir, "package.json"));
33031
33084
  const rnConfig = appConfigRequire(configPath);
33032
33085
  const assets = rnConfig && typeof rnConfig === "object" ? Reflect.get(rnConfig, "assets") : null;
@@ -33045,7 +33098,7 @@ function discoverNativeLinkedAppFonts(opts) {
33045
33098
  if (platform === "ios") {
33046
33099
  const iosDir = import_node_path25.default.join(selectedAppDir, "ios");
33047
33100
  try {
33048
- const targetDirs = import_node_fs23.default.readdirSync(iosDir, { withFileTypes: true }).filter(
33101
+ const targetDirs = import_node_fs24.default.readdirSync(iosDir, { withFileTypes: true }).filter(
33049
33102
  (entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
33050
33103
  ).slice(0, 64);
33051
33104
  const plistPaths = [import_node_path25.default.join(iosDir, "Info.plist")];
@@ -33055,7 +33108,7 @@ function discoverNativeLinkedAppFonts(opts) {
33055
33108
  for (const plistPath of plistPaths) {
33056
33109
  let parsed;
33057
33110
  try {
33058
- parsed = parsePlistSource(import_node_fs23.default.readFileSync(plistPath, "utf8"));
33111
+ parsed = parsePlistSource(import_node_fs24.default.readFileSync(plistPath, "utf8"));
33059
33112
  } catch {
33060
33113
  continue;
33061
33114
  }
@@ -33072,7 +33125,7 @@ function discoverNativeLinkedAppFonts(opts) {
33072
33125
  const relative2 = import_node_path25.default.relative(selectedAppDir, candidate);
33073
33126
  if (relative2.startsWith("..") || import_node_path25.default.isAbsolute(relative2)) return false;
33074
33127
  try {
33075
- return import_node_fs23.default.statSync(candidate).isFile();
33128
+ return import_node_fs24.default.statSync(candidate).isFile();
33076
33129
  } catch {
33077
33130
  return false;
33078
33131
  }
@@ -33118,11 +33171,11 @@ async function resolveMetroProjectRoot(bundleUrl, opts) {
33118
33171
  function encodeAppFontsWire(specs) {
33119
33172
  return specs.map((spec) => `${encodeURIComponent(spec.url)}::${encodeURIComponent(spec.family)}`).join(",");
33120
33173
  }
33121
- var import_node_fs23, import_node_module3, import_node_path25, import_config_plugin_fonts, require3;
33174
+ var import_node_fs24, import_node_module3, import_node_path25, import_config_plugin_fonts, require3;
33122
33175
  var init_app_fonts = __esm({
33123
33176
  "cli/app-fonts.ts"() {
33124
33177
  "use strict";
33125
- import_node_fs23 = __toESM(require("node:fs"), 1);
33178
+ import_node_fs24 = __toESM(require("node:fs"), 1);
33126
33179
  import_node_module3 = require("node:module");
33127
33180
  import_node_path25 = __toESM(require("node:path"), 1);
33128
33181
  import_config_plugin_fonts = require("peach-engine/engine/config-plugin-fonts");
@@ -34392,13 +34445,13 @@ function resolvePlaywright() {
34392
34445
  try {
34393
34446
  const modulePath = requireFromRoot.resolve(spec);
34394
34447
  const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
34395
- const parsed = JSON.parse((0, import_node_fs24.readFileSync)(packageJsonPath, "utf8"));
34448
+ const parsed = JSON.parse((0, import_node_fs25.readFileSync)(packageJsonPath, "utf8"));
34396
34449
  if (!isRecord(parsed) || typeof parsed.version !== "string") continue;
34397
34450
  const corePackagePath = (0, import_node_module5.createRequire)(modulePath).resolve(
34398
34451
  "playwright-core/package.json"
34399
34452
  );
34400
34453
  const cliPath = (0, import_node_path26.join)((0, import_node_path26.dirname)(corePackagePath), "cli.js");
34401
- if (!(0, import_node_fs24.existsSync)(cliPath)) continue;
34454
+ if (!(0, import_node_fs25.existsSync)(cliPath)) continue;
34402
34455
  return {
34403
34456
  spec,
34404
34457
  modulePath,
@@ -34469,7 +34522,7 @@ function probeBrowser(resolved, env) {
34469
34522
  return {
34470
34523
  ok: true,
34471
34524
  executablePath: parsed.executablePath,
34472
- exists: parsed.exists && (0, import_node_fs24.existsSync)(parsed.executablePath)
34525
+ exists: parsed.exists && (0, import_node_fs25.existsSync)(parsed.executablePath)
34473
34526
  };
34474
34527
  } catch (error) {
34475
34528
  return {
@@ -34485,6 +34538,8 @@ function ensurePlaywrightBrowser(resolved, headless, env = process.env) {
34485
34538
  const before = probeBrowser(resolved, probeEnv);
34486
34539
  if (!before.ok) return before;
34487
34540
  if (before.exists) {
34541
+ const missing2 = missingLibrariesMessage(before.executablePath, browser);
34542
+ if (missing2) return { ok: false, message: missing2 };
34488
34543
  return { ok: true, executablePath: before.executablePath, installed: false };
34489
34544
  }
34490
34545
  const installer = rnxSelfInvocation();
@@ -34521,14 +34576,50 @@ ${detail}` : ""}`
34521
34576
  message: `${resolved.spec}@${resolved.version} browser install completed, but its required ${browser} executable is still missing at ${after.executablePath}`
34522
34577
  };
34523
34578
  }
34579
+ const missing = missingLibrariesMessage(after.executablePath, browser);
34580
+ if (missing) return { ok: false, message: missing };
34524
34581
  return { ok: true, executablePath: after.executablePath, installed: true };
34525
34582
  }
34526
- var import_node_child_process6, import_node_fs24, import_node_module5, import_node_path26;
34583
+ function isTime64Distro() {
34584
+ if (!(0, import_node_fs25.existsSync)("/etc/os-release")) return false;
34585
+ const fields = Object.fromEntries(
34586
+ (0, import_node_fs25.readFileSync)("/etc/os-release", "utf8").split("\n").map((line) => line.match(/^(\w+)="?([^"]*)"?$/)).filter((match) => match !== null).map((match) => [match[1], match[2]])
34587
+ );
34588
+ const version = Number.parseFloat(fields.VERSION_ID ?? "");
34589
+ return fields.ID === "ubuntu" && version >= 24.04 || fields.ID === "debian" && version >= 13;
34590
+ }
34591
+ function missingLibrariesMessage(executablePath, browser) {
34592
+ if (process.platform !== "linux") return null;
34593
+ const ldd = (0, import_node_child_process6.spawnSync)("ldd", [executablePath], { encoding: "utf8", timeout: 3e4 });
34594
+ const libraries = [...(ldd.stdout ?? "").matchAll(/^\s*(\S+) => not found$/gm)].map(
34595
+ (match) => match[1]
34596
+ );
34597
+ if (!libraries.length) return null;
34598
+ const time64 = isTime64Distro();
34599
+ const packages = /* @__PURE__ */ new Set();
34600
+ const unknown = [];
34601
+ for (const library of libraries) {
34602
+ const name2 = LIBRARY_PACKAGES[library];
34603
+ if (!name2) unknown.push(library);
34604
+ else packages.add(time64 && TIME64_PACKAGES.has(name2) ? `${name2}t64` : name2);
34605
+ }
34606
+ const sudo = process.getuid?.() === 0 ? "" : "sudo ";
34607
+ return [
34608
+ `${browser} at ${executablePath} cannot start: this system is missing shared libraries it links (${libraries.join(", ")}).`,
34609
+ ...packages.size ? [
34610
+ "On Debian or Ubuntu, install them and run the command again:",
34611
+ "",
34612
+ ` ${sudo}apt-get update && ${sudo}apt-get install -y --no-install-recommends ${[...packages].join(" ")}`
34613
+ ] : [],
34614
+ ...unknown.length ? ["", `No known Debian package provides: ${unknown.join(", ")}`] : []
34615
+ ].join("\n");
34616
+ }
34617
+ var import_node_child_process6, import_node_fs25, import_node_module5, import_node_path26, LIBRARY_PACKAGES, TIME64_PACKAGES;
34527
34618
  var init_playwright_provisioning = __esm({
34528
34619
  "cli/drivers/playwright-provisioning.ts"() {
34529
34620
  "use strict";
34530
34621
  import_node_child_process6 = require("node:child_process");
34531
- import_node_fs24 = require("node:fs");
34622
+ import_node_fs25 = require("node:fs");
34532
34623
  import_node_module5 = require("node:module");
34533
34624
  import_node_path26 = require("node:path");
34534
34625
  init_src();
@@ -34537,6 +34628,42 @@ var init_playwright_provisioning = __esm({
34537
34628
  init_internal_child();
34538
34629
  init_self_invocation();
34539
34630
  init_playwright_core_pin();
34631
+ LIBRARY_PACKAGES = {
34632
+ "libasound.so.2": "libasound2",
34633
+ "libatk-1.0.so.0": "libatk1.0-0",
34634
+ "libatk-bridge-2.0.so.0": "libatk-bridge2.0-0",
34635
+ "libatspi.so.0": "libatspi2.0-0",
34636
+ "libcairo.so.2": "libcairo2",
34637
+ "libcups.so.2": "libcups2",
34638
+ "libdbus-1.so.3": "libdbus-1-3",
34639
+ "libexpat.so.1": "libexpat1",
34640
+ "libgbm.so.1": "libgbm1",
34641
+ "libgio-2.0.so.0": "libglib2.0-0",
34642
+ "libglib-2.0.so.0": "libglib2.0-0",
34643
+ "libgobject-2.0.so.0": "libglib2.0-0",
34644
+ "libnspr4.so": "libnspr4",
34645
+ "libnss3.so": "libnss3",
34646
+ "libnssutil3.so": "libnss3",
34647
+ "libpango-1.0.so.0": "libpango-1.0-0",
34648
+ "libsmime3.so": "libnss3",
34649
+ "libudev.so.1": "libudev1",
34650
+ "libX11.so.6": "libx11-6",
34651
+ "libxcb.so.1": "libxcb1",
34652
+ "libXcomposite.so.1": "libxcomposite1",
34653
+ "libXdamage.so.1": "libxdamage1",
34654
+ "libXext.so.6": "libxext6",
34655
+ "libXfixes.so.3": "libxfixes3",
34656
+ "libxkbcommon.so.0": "libxkbcommon0",
34657
+ "libXrandr.so.2": "libxrandr2"
34658
+ };
34659
+ TIME64_PACKAGES = /* @__PURE__ */ new Set([
34660
+ "libasound2",
34661
+ "libatk1.0-0",
34662
+ "libatk-bridge2.0-0",
34663
+ "libatspi2.0-0",
34664
+ "libcups2",
34665
+ "libglib2.0-0"
34666
+ ]);
34540
34667
  }
34541
34668
  });
34542
34669
 
@@ -35461,7 +35588,7 @@ function assertExplicitBridgeLock(preferredPort, explicitPort, lock) {
35461
35588
  async function ensureRuntimeForOpen() {
35462
35589
  if (resolveDevCheckoutRuntimeRoot()) return;
35463
35590
  const active = readActiveRuntime();
35464
- if (active && import_node_fs25.default.existsSync(runtimeDir(active))) return;
35591
+ if (active && import_node_fs26.default.existsSync(runtimeDir(active))) return;
35465
35592
  console.error(" installing peach engine runtime...");
35466
35593
  const { runRuntime: runRuntime2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
35467
35594
  await runRuntime2(["install"], {});
@@ -35637,7 +35764,7 @@ function parseOpenRuntimeConfig(args) {
35637
35764
  }
35638
35765
  const moduleName = raw.slice(0, eqIndex).trim();
35639
35766
  const filePath = normalizeReplacementPath(raw.slice(eqIndex + 1).trim());
35640
- if (!import_node_fs25.default.existsSync(filePath)) {
35767
+ if (!import_node_fs26.default.existsSync(filePath)) {
35641
35768
  console.error(` peach open: replacement file not found: ${filePath}`);
35642
35769
  rnxExit(1);
35643
35770
  }
@@ -35668,7 +35795,7 @@ async function resolveAppProjectForBundleUrl(bundleUrl) {
35668
35795
  return advertisedRoot ? resolveAppProject(advertisedRoot) : null;
35669
35796
  }
35670
35797
  async function ensureConfiguredRuntime(version) {
35671
- if (import_node_fs25.default.existsSync(import_node_path27.default.join(runtimeDir(version), "index.html"))) return;
35798
+ if (import_node_fs26.default.existsSync(import_node_path27.default.join(runtimeDir(version), "index.html"))) return;
35672
35799
  console.error(` installing configured engine runtime ${version}...`);
35673
35800
  const result = await rnxRuntime.install({
35674
35801
  version,
@@ -35985,7 +36112,7 @@ function playwrightHostPidForSim(sim) {
35985
36112
  function signalDriverLaunchConnected(result) {
35986
36113
  if (!result.connectAckFile) return false;
35987
36114
  try {
35988
- import_node_fs25.default.writeFileSync(
36115
+ import_node_fs26.default.writeFileSync(
35989
36116
  result.connectAckFile,
35990
36117
  `${JSON.stringify({ connectedAt: Date.now(), pid: result.pid ?? null })}
35991
36118
  `,
@@ -35999,7 +36126,7 @@ function signalDriverLaunchConnected(result) {
35999
36126
  function printDriverDiagnosticLogTail(result) {
36000
36127
  if (!result.diagnosticLogPath) return;
36001
36128
  try {
36002
- const detail = import_node_fs25.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
36129
+ const detail = import_node_fs26.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
36003
36130
  if (!detail) {
36004
36131
  console.error(` ${import_node_path27.default.basename(result.diagnosticLogPath)} was empty`);
36005
36132
  return;
@@ -36990,12 +37117,12 @@ async function runCloseCommand(args, opts = {}) {
36990
37117
  bridge.close();
36991
37118
  }
36992
37119
  }
36993
- var import_node_child_process7, import_node_fs25, import_node_os4, import_node_path27, import_app_catalog_wire, import_devices2, import_ws4, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEV_BUNDLE_RESOLVE_ATTEMPTS, DEV_BUNDLE_RESOLVE_INTERVAL_MS;
37120
+ var import_node_child_process7, import_node_fs26, import_node_os4, import_node_path27, import_app_catalog_wire, import_devices2, import_ws4, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEV_BUNDLE_RESOLVE_ATTEMPTS, DEV_BUNDLE_RESOLVE_INTERVAL_MS;
36994
37121
  var init_control = __esm({
36995
37122
  "cli/commands/control.ts"() {
36996
37123
  "use strict";
36997
37124
  import_node_child_process7 = require("node:child_process");
36998
- import_node_fs25 = __toESM(require("node:fs"), 1);
37125
+ import_node_fs26 = __toESM(require("node:fs"), 1);
36999
37126
  import_node_os4 = __toESM(require("node:os"), 1);
37000
37127
  import_node_path27 = __toESM(require("node:path"), 1);
37001
37128
  import_app_catalog_wire = require("peach-engine/engine/app-catalog-wire");
@@ -38529,7 +38656,6 @@ var init_bridge_flow_runner = __esm({
38529
38656
  });
38530
38657
  firstLaunchDone = false;
38531
38658
  appStopped = false;
38532
- launchArgumentsActive = false;
38533
38659
  profilingEnabled = false;
38534
38660
  recordingEnabled = false;
38535
38661
  recordingAccessChecked = false;
@@ -39762,17 +39888,6 @@ var init_bridge_flow_runner = __esm({
39762
39888
  }
39763
39889
  throw new Error("extendedWaitUntil timed out");
39764
39890
  }
39765
- async reloadGuestApp() {
39766
- const reloaded = await this.bridge.send({
39767
- type: "call",
39768
- simId: this.opts.simId,
39769
- path: "SootSim.bridges.hotRemount.reloadExternalApp",
39770
- args: []
39771
- });
39772
- if (reloaded) return;
39773
- await this.evaluate("window.location.reload()").catch(() => {
39774
- });
39775
- }
39776
39891
  async resetGuestAppData(launchOptions) {
39777
39892
  const reset = await this.bridge.send(
39778
39893
  {
@@ -39833,6 +39948,7 @@ var init_bridge_flow_runner = __esm({
39833
39948
  }
39834
39949
  const wantsClear = !!(opts && typeof opts === "object" && opts.clearState);
39835
39950
  const wantsResetRuntime = readBooleanKey(opts, "resetRuntime");
39951
+ const wantsForeground = isObjectRecord(opts) && opts.stopApp === false;
39836
39952
  await this.setLaunchPermissions(isObjectRecord(opts) ? opts.permissions : void 0);
39837
39953
  if (!this.firstLaunchDone) {
39838
39954
  this.firstLaunchDone = true;
@@ -39867,7 +39983,14 @@ var init_bridge_flow_runner = __esm({
39867
39983
  await this.waitForTree(12e4);
39868
39984
  await this.waitForTree(3e4);
39869
39985
  } else {
39870
- await this.launchShellAppFromHomeIfNeeded(opts);
39986
+ const launched = await this.launchShellAppFromHomeIfNeeded(opts);
39987
+ if (!launched && !wantsForeground) {
39988
+ await this.waitForTree(12e4);
39989
+ await this.reloadGuestAppRuntime({
39990
+ launchArguments: null,
39991
+ initialUrl: null
39992
+ });
39993
+ }
39871
39994
  await this.waitForTree(12e4);
39872
39995
  await this.waitForTree(3e4);
39873
39996
  }
@@ -39877,13 +40000,11 @@ var init_bridge_flow_runner = __esm({
39877
40000
  launchArguments: hasLaunchArguments ? launchArguments : null,
39878
40001
  initialUrl: null
39879
40002
  });
39880
- } else if (hasLaunchArguments || this.launchArgumentsActive || this.appStopped) {
40003
+ } else if (hasLaunchArguments || this.appStopped || !wantsForeground) {
39881
40004
  await this.reloadGuestAppRuntime({
39882
40005
  launchArguments: hasLaunchArguments ? launchArguments : null,
39883
40006
  initialUrl: null
39884
40007
  });
39885
- } else {
39886
- await this.reloadGuestApp();
39887
40008
  }
39888
40009
  await this.waitForTree(12e4);
39889
40010
  if (this.opts.onAfterLaunch) {
@@ -39897,7 +40018,6 @@ var init_bridge_flow_runner = __esm({
39897
40018
  }
39898
40019
  }
39899
40020
  this.appStopped = false;
39900
- this.launchArgumentsActive = hasLaunchArguments;
39901
40021
  if (this.profilingEnabled) {
39902
40022
  await this.startProfile();
39903
40023
  }
@@ -40109,7 +40229,6 @@ var init_bridge_flow_runner = __esm({
40109
40229
  throw new Error(`openLink failed: ${result?.error || "no test bridge"}`);
40110
40230
  }
40111
40231
  this.appStopped = false;
40112
- this.launchArgumentsActive = false;
40113
40232
  this.firstLaunchDone = true;
40114
40233
  }
40115
40234
  // evaluate a `when:` predicate. returns true if the step should run.