peachsim 0.1.669 → 0.1.670

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 (115) hide show
  1. package/cli/commands/control.ts +8 -5
  2. package/cli/commands/inspect/core.ts +7 -5
  3. package/cli/commands/inspect/wait-selector.ts +2 -11
  4. package/cli/commands/inspect.ts +6 -59
  5. package/cli/commands/kotlin.ts +6 -4
  6. package/cli/commands/skills.ts +28 -7
  7. package/cli/commands/upgrade.ts +18 -3
  8. package/cli/main.ts +21 -0
  9. package/cli/output-redaction.ts +182 -0
  10. package/cli/parse-args.ts +1 -0
  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 +1 -1
  22. package/dist-lib/bridge-contract-input.mjs +1 -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 +1 -1
  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 +29 -19
  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 +1 -1
  43. package/dist-lib/host/websocket-proxy.cjs +1 -1
  44. package/dist-lib/index.cjs +260 -17
  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 +2 -1
  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 +259 -16
  55. package/dist-lib/native-app-identity.cjs +1 -1
  56. package/dist-lib/native-app-identity.mjs +1 -1
  57. package/dist-lib/native-firebase-metadata.cjs +115 -0
  58. package/dist-lib/native-firebase-metadata.mjs +86 -0
  59. package/dist-lib/plist.cjs +1 -1
  60. package/dist-lib/plist.mjs +1 -1
  61. package/dist-lib/profiles.cjs +1 -1
  62. package/dist-lib/public-brand.cjs +1 -1
  63. package/dist-lib/react-native-host-modules.cjs +1 -1
  64. package/dist-lib/react-native-host-modules.mjs +1 -1
  65. package/dist-lib/render-mode.cjs +1 -1
  66. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  67. package/dist-lib/sdk.cjs +2 -2
  68. package/dist-lib/sdk.mjs +2 -2
  69. package/dist-lib/skills.cjs +479 -203
  70. package/dist-lib/swift-compile.cjs +1 -1
  71. package/dist-lib/swift-compile.mjs +1 -1
  72. package/dist-lib/swift-package.cjs +1 -1
  73. package/dist-lib/swift-package.mjs +1 -1
  74. package/dist-lib/swift-submit.cjs +1 -1
  75. package/dist-lib/swift-submit.mjs +1 -1
  76. package/dist-lib/swift.cjs +1 -1
  77. package/dist-lib/vite-swift.cjs +21 -13
  78. package/dist-lib/vite.cjs +1 -1
  79. package/kotlin/AppSources/androidx/activity/ActivityFlags.kt +9 -0
  80. package/kotlin/AppSources/androidx/activity/BackEventCompat.kt +25 -4
  81. package/kotlin/AppSources/androidx/activity/ComponentActivity.kt +15 -4
  82. package/kotlin/AppSources/androidx/activity/EdgeToEdge.kt +12 -8
  83. package/kotlin/AppSources/androidx/activity/ExperimentalActivityApi.kt +6 -0
  84. package/kotlin/AppSources/androidx/activity/OnBackPressedCallback.kt +50 -9
  85. package/kotlin/AppSources/androidx/activity/OnBackPressedDispatcher.kt +67 -89
  86. package/kotlin/AppSources/androidx/activity/compose/BackHandler.kt +55 -24
  87. package/kotlin/AppSources/androidx/activity/compose/internal/BackHandlerCompat.kt +38 -0
  88. package/kotlin/AppSources/androidx/activity/compose/internal/BackHandlerDispatcherCompat.kt +27 -0
  89. package/kotlin/AppSources/dev/peach/app/PeachApp.kt +5 -5
  90. package/kotlin/ComposeSources/PeachComposeHost.kt +31 -7
  91. package/kotlin/fixtures/kotlin-app/app/build.gradle.kts +1 -1
  92. package/kotlin/fixtures/kotlin-app-variants/Browse.kt +73 -0
  93. package/kotlin/fixtures/kotlin-app-variants/Focus.kt +62 -0
  94. package/kotlin/fixtures/kotlin-app-variants/Lists.kt +57 -0
  95. package/kotlin/fixtures/kotlin-app-variants/Nav.kt +47 -0
  96. package/kotlin/fixtures/kotlin-app-variants/Nested.kt +64 -0
  97. package/kotlin/fixtures/kotlin-app-variants/Pan.kt +38 -0
  98. package/kotlin/fixtures/kotlin-app-variants/Pickers.kt +44 -0
  99. package/kotlin/fixtures/kotlin-app-variants/Press.kt +43 -0
  100. package/kotlin/fixtures/kotlin-app-variants/Transition.kt +69 -0
  101. package/kotlin/fixtures/kotlin-app-variants/ViewConfig.kt +22 -0
  102. package/kotlin/toolchain.json +30 -2
  103. package/package.json +8 -1
  104. package/skills/contrast/SKILL.md +2 -1
  105. package/skills/peach-debug/SKILL.md +2 -2
  106. package/skills/peach-test/SKILL.md +3 -3
  107. package/src/expo-swift-host.ts +13 -4
  108. package/src/kotlin-app.ts +35 -16
  109. package/src/kotlin-host.ts +1 -0
  110. package/src/metro-plugin.ts +24 -0
  111. package/src/native-firebase-config.ts +202 -21
  112. package/src/native-firebase-metadata.ts +114 -0
  113. package/src/swift-host.ts +30 -15
  114. package/src/vite-plugin.ts +46 -2
  115. package/kotlin/AppSources/androidx/activity/Cancellable.kt +0 -5
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.669 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.670 | (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;
@@ -18900,7 +18900,7 @@ var init_web = __esm({
18900
18900
 
18901
18901
  // src/sleep.ts
18902
18902
  function sleep(ms) {
18903
- return new Promise((resolve9) => setTimeout(resolve9, ms));
18903
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
18904
18904
  }
18905
18905
  var init_sleep = __esm({
18906
18906
  "src/sleep.ts"() {
@@ -19044,7 +19044,7 @@ var init_bridge_constants = __esm({
19044
19044
 
19045
19045
  // ../contrast/src/sleep.ts
19046
19046
  function sleep2(ms) {
19047
- return new Promise((resolve9) => setTimeout(resolve9, ms));
19047
+ return new Promise((resolve10) => setTimeout(resolve10, ms));
19048
19048
  }
19049
19049
  var init_sleep2 = __esm({
19050
19050
  "../contrast/src/sleep.ts"() {
@@ -19480,9 +19480,9 @@ function safeChildPlistName(value) {
19480
19480
  name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
19481
19481
  };
19482
19482
  }
19483
- async function readableSettingsBundle(path27) {
19483
+ async function readableSettingsBundle(path28) {
19484
19484
  try {
19485
- const root = await (0, import_promises.stat)((0, import_node_path.join)(path27, "Root.plist"));
19485
+ const root = await (0, import_promises.stat)((0, import_node_path.join)(path28, "Root.plist"));
19486
19486
  return root.isFile() && root.size <= MAX_PLIST_BYTES;
19487
19487
  } catch {
19488
19488
  return false;
@@ -19527,11 +19527,11 @@ async function settingsBundleFingerprint(bundlePath) {
19527
19527
  return null;
19528
19528
  }
19529
19529
  }
19530
- async function parsePlistRecord(path27) {
19530
+ async function parsePlistRecord(path28) {
19531
19531
  try {
19532
- const metadata = await (0, import_promises.stat)(path27);
19532
+ const metadata = await (0, import_promises.stat)(path28);
19533
19533
  if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
19534
- const source = await (0, import_promises.readFile)(path27, "utf8");
19534
+ const source = await (0, import_promises.readFile)(path28, "utf8");
19535
19535
  const parsed = parsePlistSource(source);
19536
19536
  return isRecord2(parsed) ? parsed : null;
19537
19537
  } catch {
@@ -19785,7 +19785,7 @@ var init_optional_demo_registry = __esm({
19785
19785
  // scripts/dev-server-scanner.ts
19786
19786
  function execGuarded(command, timeout, extra = {}) {
19787
19787
  const maxBuffer = extra.maxBuffer ?? 1024 * 1024;
19788
- return new Promise((resolve9, reject) => {
19788
+ return new Promise((resolve10, reject) => {
19789
19789
  const child = (0, import_child_process.spawn)("/bin/sh", ["-c", command], {
19790
19790
  detached: true,
19791
19791
  stdio: ["ignore", "pipe", "ignore"]
@@ -19798,7 +19798,7 @@ function execGuarded(command, timeout, extra = {}) {
19798
19798
  settled = true;
19799
19799
  clearTimeout(deadline);
19800
19800
  if (err) reject(err);
19801
- else resolve9({ stdout });
19801
+ else resolve10({ stdout });
19802
19802
  };
19803
19803
  const killThenSettle = (err) => {
19804
19804
  if (killing) return;
@@ -19833,14 +19833,14 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
19833
19833
  try {
19834
19834
  return await Promise.any(
19835
19835
  LOOPBACK_PROBE_HOSTNAMES.map(
19836
- (hostname) => new Promise((resolve9, reject) => {
19836
+ (hostname) => new Promise((resolve10, reject) => {
19837
19837
  const sock = new import_net.default.Socket();
19838
19838
  let settled = false;
19839
19839
  const done = (reachable) => {
19840
19840
  if (settled) return;
19841
19841
  settled = true;
19842
19842
  sock.destroy();
19843
- if (reachable) resolve9(hostname);
19843
+ if (reachable) resolve10(hostname);
19844
19844
  else reject(new Error(`unreachable loopback host ${hostname}`));
19845
19845
  };
19846
19846
  sock.setTimeout(timeout);
@@ -19855,16 +19855,16 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
19855
19855
  return null;
19856
19856
  }
19857
19857
  }
19858
- function httpGet(hostname, port, path27, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
19859
- return new Promise((resolve9) => {
19858
+ function httpGet(hostname, port, path28, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
19859
+ return new Promise((resolve10) => {
19860
19860
  let settled = false;
19861
19861
  let killing = false;
19862
19862
  const settle = (value) => {
19863
19863
  if (settled) return;
19864
19864
  settled = true;
19865
- resolve9(value);
19865
+ resolve10(value);
19866
19866
  };
19867
- const req = import_http.default.request({ hostname, port, path: path27, method, headers }, (res) => {
19867
+ const req = import_http.default.request({ hostname, port, path: path28, method, headers }, (res) => {
19868
19868
  let body = "";
19869
19869
  res.on("data", (c) => body += c.toString());
19870
19870
  const contentType = (() => {
@@ -21118,9 +21118,9 @@ function getCliVersion() {
21118
21118
  () => (0, import_node_url2.fileURLToPath)(import_meta.resolve(`${rnxPublicBrand.packageName}/package.json`)),
21119
21119
  () => (0, import_node_url2.fileURLToPath)(new URL("../package.json", __sootsim_import_meta_url))
21120
21120
  ];
21121
- for (const resolve9 of candidates) {
21121
+ for (const resolve10 of candidates) {
21122
21122
  try {
21123
- const version = JSON.parse((0, import_node_fs5.readFileSync)(resolve9(), "utf8")).version;
21123
+ const version = JSON.parse((0, import_node_fs5.readFileSync)(resolve10(), "utf8")).version;
21124
21124
  if (typeof version === "string" && version) {
21125
21125
  cached2 = version;
21126
21126
  return cached2;
@@ -21180,8 +21180,8 @@ function pickImagesetFile(images) {
21180
21180
  scale: pick.scale === "2x" ? 2 : pick.scale === "3x" ? 3 : 1
21181
21181
  };
21182
21182
  }
21183
- function flatScale(path27) {
21184
- const match = /@([23])x\.[^./]+$/.exec(path27);
21183
+ function flatScale(path28) {
21184
+ const match = /@([23])x\.[^./]+$/.exec(path28);
21185
21185
  return match ? Number(match[1]) : 1;
21186
21186
  }
21187
21187
  function providesNamespace(text) {
@@ -21208,13 +21208,13 @@ function catalogEntryName(contentsPath, kind, readText2) {
21208
21208
  }
21209
21209
  return segments.join("/");
21210
21210
  }
21211
- function isFlatResourceImage(path27) {
21212
- return path27.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path27));
21211
+ function isFlatResourceImage(path28) {
21212
+ return path28.split("/").includes("Resources") && RASTER_EXTENSIONS.has(extOf(path28));
21213
21213
  }
21214
21214
  function enumerateBundleImages(paths, readText2) {
21215
21215
  const table = [];
21216
21216
  const seen = /* @__PURE__ */ new Set();
21217
- const catalogs = paths.filter((path27) => baseOf(path27) === "Contents.json");
21217
+ const catalogs = paths.filter((path28) => baseOf(path28) === "Contents.json");
21218
21218
  for (const contentsPath of catalogs) {
21219
21219
  const name2 = catalogEntryName(contentsPath, ".imageset", readText2);
21220
21220
  if (name2 === null || seen.has(name2)) continue;
@@ -21235,12 +21235,12 @@ function enumerateBundleImages(paths, readText2) {
21235
21235
  seen.add(name2);
21236
21236
  table.push({ name: name2, file: `${dir}/${pick.filename}`, scale: pick.scale });
21237
21237
  }
21238
- for (const path27 of paths) {
21239
- if (!isFlatResourceImage(path27)) continue;
21240
- const name2 = baseOf(path27).slice(0, -extOf(path27).length);
21238
+ for (const path28 of paths) {
21239
+ if (!isFlatResourceImage(path28)) continue;
21240
+ const name2 = baseOf(path28).slice(0, -extOf(path28).length);
21241
21241
  if (name2 === "" || seen.has(name2)) continue;
21242
21242
  seen.add(name2);
21243
- table.push({ name: name2, file: path27, scale: flatScale(path27) });
21243
+ table.push({ name: name2, file: path28, scale: flatScale(path28) });
21244
21244
  }
21245
21245
  return table;
21246
21246
  }
@@ -21269,7 +21269,7 @@ function colorsetValue(color) {
21269
21269
  }
21270
21270
  function enumerateBundleColors(paths, readText2) {
21271
21271
  const table = {};
21272
- for (const contentsPath of paths.filter((path27) => baseOf(path27) === "Contents.json")) {
21272
+ for (const contentsPath of paths.filter((path28) => baseOf(path28) === "Contents.json")) {
21273
21273
  const name2 = catalogEntryName(contentsPath, ".colorset", readText2);
21274
21274
  if (name2 === null || name2 in table) continue;
21275
21275
  let colors;
@@ -21333,8 +21333,8 @@ function axisExtremes(points) {
21333
21333
  function pathBounds(d) {
21334
21334
  const xs = [];
21335
21335
  const ys = [];
21336
- for (const path27 of d)
21337
- (0, import_svgpath.default)(path27).abs().unshort().unarc().iterate((segment, _index, x, y) => {
21336
+ for (const path28 of d)
21337
+ (0, import_svgpath.default)(path28).abs().unshort().unarc().iterate((segment, _index, x, y) => {
21338
21338
  const [command, ...args] = segment;
21339
21339
  if (command === "M" || command === "L") {
21340
21340
  xs.push(Number(args[0]));
@@ -21361,7 +21361,7 @@ function guide(svg, id, axis) {
21361
21361
  }
21362
21362
  function enumerateBundleSymbols(paths, readText2) {
21363
21363
  const table = {};
21364
- for (const contentsPath of paths.filter((path27) => baseOf(path27) === "Contents.json")) {
21364
+ for (const contentsPath of paths.filter((path28) => baseOf(path28) === "Contents.json")) {
21365
21365
  const name2 = catalogEntryName(contentsPath, ".symbolset", readText2);
21366
21366
  if (name2 === null || name2 in table) continue;
21367
21367
  let symbols;
@@ -21394,8 +21394,8 @@ function enumerateBundleSymbols(paths, readText2) {
21394
21394
  viewBox: "0 0 24 24",
21395
21395
  advance,
21396
21396
  box: [12 - advance / 2, 12 - tall / 2, advance, tall],
21397
- layers: d.map((path27) => ({
21398
- d: (0, import_svgpath.default)(path27).abs().scale(scale).translate(translateX, translateY).round(3).toString()
21397
+ layers: d.map((path28) => ({
21398
+ d: (0, import_svgpath.default)(path28).abs().scale(scale).translate(translateX, translateY).round(3).toString()
21399
21399
  }))
21400
21400
  };
21401
21401
  }
@@ -21405,7 +21405,7 @@ function enumerateBundleJson(paths) {
21405
21405
  const found = [];
21406
21406
  const seen = /* @__PURE__ */ new Set();
21407
21407
  const ordered = [...paths].filter(
21408
- (path27) => path27.split("/").includes("Resources") && path27.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path27) === ".json" || extOf(path27) === ".xcstrings")
21408
+ (path28) => path28.split("/").includes("Resources") && path28.split("/").every((segment) => segment !== "" && segment !== "..") && (extOf(path28) === ".json" || extOf(path28) === ".xcstrings")
21409
21409
  ).sort((a, b) => {
21410
21410
  const aDepth = a.split("/").length;
21411
21411
  const bDepth = b.split("/").length;
@@ -22454,10 +22454,10 @@ async function compileSwiftProject(submit, work, origin, signal) {
22454
22454
  ...outcome.native === void 0 ? {} : { native: outcome.native }
22455
22455
  };
22456
22456
  case "compiling":
22457
- await new Promise((resolve9, reject) => {
22457
+ await new Promise((resolve10, reject) => {
22458
22458
  const finish = () => {
22459
22459
  signal?.removeEventListener("abort", abort);
22460
- resolve9();
22460
+ resolve10();
22461
22461
  };
22462
22462
  const timer = setTimeout(finish, POLL_INTERVAL_MS);
22463
22463
  const abort = () => {
@@ -22819,13 +22819,11 @@ async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, sn
22819
22819
  stamp,
22820
22820
  package: content
22821
22821
  };
22822
- const toolchain = JSON.parse(
22823
- import_node_fs9.default.readFileSync(import_node_path9.default.join(moduleRoot, "toolchain.json"), "utf8")
22824
- );
22825
- const release = toolchain && typeof toolchain === "object" ? Reflect.get(toolchain, "release") : void 0;
22826
- if (typeof release !== "string") {
22827
- throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`);
22828
- }
22822
+ const toolchain = localSwiftToolchain(moduleRoot);
22823
+ if (!toolchain)
22824
+ throw new Error(
22825
+ `the Swift toolchain ${moduleRoot}/toolchain.json names is not installed under ~/Library/Developer/Toolchains`
22826
+ );
22829
22827
  const artifact = await compileSwiftProjectUnit(snapshotCompileInput(snapshot, entry), {
22830
22828
  // the compile rewrites Sources/App in its root before swiftpm builds, and
22831
22829
  // its lock orders one process only: two vites on one root (a lane's dev
@@ -22838,14 +22836,24 @@ async function compile(packagePath, entry, stamp, moduleRootOverride, hosted, sn
22838
22836
  (0, import_node_crypto4.createHash)("sha256").update(`${moduleRoot}\0${import_node_path9.default.resolve(packagePath)}`).digest("hex").slice(0, 16)
22839
22837
  ),
22840
22838
  moduleRoot,
22841
- release,
22842
- toolchainBin: import_node_path9.default.join(
22843
- import_node_os3.default.homedir(),
22844
- `Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`
22845
- )
22839
+ ...toolchain
22846
22840
  });
22847
22841
  return { ...artifact, stamp, package: content };
22848
22842
  }
22843
+ function localSwiftToolchain(moduleRoot) {
22844
+ const manifest = import_node_path9.default.join(moduleRoot, "toolchain.json");
22845
+ if (!import_node_fs9.default.existsSync(manifest)) return null;
22846
+ const toolchain = JSON.parse(import_node_fs9.default.readFileSync(manifest, "utf8"));
22847
+ const release = toolchain && typeof toolchain === "object" ? Reflect.get(toolchain, "release") : void 0;
22848
+ if (typeof release !== "string") {
22849
+ throw new Error(`swift toolchain manifest at ${moduleRoot} has no release`);
22850
+ }
22851
+ const toolchainBin = import_node_path9.default.join(
22852
+ import_node_os3.default.homedir(),
22853
+ `Library/Developer/Toolchains/${release}.xctoolchain/usr/bin`
22854
+ );
22855
+ return import_node_fs9.default.existsSync(import_node_path9.default.join(toolchainBin, "swift")) ? { release, toolchainBin } : null;
22856
+ }
22849
22857
  async function compileRemote(packagePath, entry, snapshot, hosted) {
22850
22858
  const auth = hosted ? null : resolveCliAuth();
22851
22859
  if (!hosted && (!auth || auth.kind === "github")) {
@@ -23197,6 +23205,8 @@ async function handleExpoSwiftRequest(req, res) {
23197
23205
  pending = (async () => {
23198
23206
  const files = await collectExpoSwiftSources(root);
23199
23207
  if (!files) return null;
23208
+ const moduleRoot = import_node_path10.default.resolve(import_meta2.dirname, "../../sootsim-swift");
23209
+ if (!localSwiftToolchain(moduleRoot)) return null;
23200
23210
  const key = (0, import_node_crypto5.createHash)("sha256").update(import_node_fs10.default.realpathSync(root)).digest("hex");
23201
23211
  const packagePath = import_node_path10.default.join(import_node_os4.default.tmpdir(), "peach-expo-swift", key);
23202
23212
  const sources = import_node_path10.default.join(packagePath, "Sources");
@@ -23207,12 +23217,10 @@ async function handleExpoSwiftRequest(req, res) {
23207
23217
  import_node_fs10.default.mkdirSync(import_node_path10.default.dirname(target), { recursive: true });
23208
23218
  import_node_fs10.default.writeFileSync(target, content);
23209
23219
  }
23210
- const moduleRoot = import_node_path10.default.resolve(import_meta2.dirname, "../../sootsim-swift");
23211
- const local = import_node_fs10.default.existsSync(import_node_path10.default.join(moduleRoot, "toolchain.json"));
23212
23220
  const artifact = await artifactFor(
23213
23221
  projectFor(packagePath),
23214
23222
  EXPO_SWIFT_ENTRY,
23215
- local ? moduleRoot : void 0
23223
+ moduleRoot
23216
23224
  );
23217
23225
  const host2 = req.headers.host;
23218
23226
  if (!host2) throw new Error("Expo Swift request has no host");
@@ -23668,16 +23676,16 @@ async function downloadToFile(url, destPath) {
23668
23676
  }
23669
23677
  }
23670
23678
  function digestFile(filePath, algorithm, encoding) {
23671
- return new Promise((resolve9, reject) => {
23679
+ return new Promise((resolve10, reject) => {
23672
23680
  const hash = import_node_crypto6.default.createHash(algorithm);
23673
23681
  const stream = import_node_fs12.default.createReadStream(filePath);
23674
23682
  stream.on("data", (chunk) => hash.update(chunk));
23675
23683
  stream.on("error", reject);
23676
- stream.on("end", () => resolve9(hash.digest(encoding)));
23684
+ stream.on("end", () => resolve10(hash.digest(encoding)));
23677
23685
  });
23678
23686
  }
23679
23687
  function extractTarball(tarPath, destDir, stripComponents) {
23680
- return new Promise((resolve9, reject) => {
23688
+ return new Promise((resolve10, reject) => {
23681
23689
  const args = ["-xzf", tarPath, "-C", destDir];
23682
23690
  if (stripComponents > 0) args.push(`--strip-components=${stripComponents}`);
23683
23691
  const child = (0, import_node_child_process6.spawn)("tar", args, {
@@ -23685,7 +23693,7 @@ function extractTarball(tarPath, destDir, stripComponents) {
23685
23693
  });
23686
23694
  child.on("error", reject);
23687
23695
  child.on("exit", (code) => {
23688
- if (code === 0) resolve9();
23696
+ if (code === 0) resolve10();
23689
23697
  else reject(new Error(`tar exited with code ${code}`));
23690
23698
  });
23691
23699
  });
@@ -23880,8 +23888,8 @@ function sourceEntryPath() {
23880
23888
  return null;
23881
23889
  }
23882
23890
  }
23883
- function isCliEntry(path27) {
23884
- const name2 = (0, import_node_path13.basename)(path27);
23891
+ function isCliEntry(path28) {
23892
+ const name2 = (0, import_node_path13.basename)(path28);
23885
23893
  return name2 === "bin.ts" || name2 === "bin.js";
23886
23894
  }
23887
23895
  function rnxSelfInvocation() {
@@ -24890,9 +24898,9 @@ var init_agent_host = __esm({
24890
24898
  if (queue2.length === 0) this.inspectQueues.delete(simId);
24891
24899
  return Promise.resolve(queued);
24892
24900
  }
24893
- return new Promise((resolve9, reject) => {
24901
+ return new Promise((resolve10, reject) => {
24894
24902
  const listeners = this.inspectListeners.get(simId) ?? [];
24895
- listeners.push({ socket, resolve: resolve9, reject });
24903
+ listeners.push({ socket, resolve: resolve10, reject });
24896
24904
  this.inspectListeners.set(simId, listeners);
24897
24905
  });
24898
24906
  }
@@ -25419,7 +25427,7 @@ async function handleFetchProxyRequest(req, res) {
25419
25427
  } else if (nextBody) {
25420
25428
  targetHeaders["content-length"] = String(nextBody.byteLength);
25421
25429
  }
25422
- const proxyRes = await new Promise((resolve9, reject) => {
25430
+ const proxyRes = await new Promise((resolve10, reject) => {
25423
25431
  const proxyReq = transport.request(
25424
25432
  {
25425
25433
  hostname: normalizeHostname(targetUrl2.hostname),
@@ -25429,7 +25437,7 @@ async function handleFetchProxyRequest(req, res) {
25429
25437
  headers: targetHeaders,
25430
25438
  ...loopbackTlsOptions(targetUrl2)
25431
25439
  },
25432
- resolve9
25440
+ resolve10
25433
25441
  );
25434
25442
  const abort = () => proxyReq.destroy(new Error("fetch proxy client disconnected"));
25435
25443
  req.once("aborted", abort);
@@ -25657,7 +25665,7 @@ function buildOpenUrlCommand(url, options = {}) {
25657
25665
  };
25658
25666
  }
25659
25667
  async function spawnLaunch(command, args, detached) {
25660
- return new Promise((resolve9, reject) => {
25668
+ return new Promise((resolve10, reject) => {
25661
25669
  const child = (0, import_child_process2.spawn)(command, args, {
25662
25670
  detached,
25663
25671
  stdio: "ignore"
@@ -25665,7 +25673,7 @@ async function spawnLaunch(command, args, detached) {
25665
25673
  child.once("error", reject);
25666
25674
  child.once("spawn", () => {
25667
25675
  if (detached) child.unref();
25668
- resolve9(child.pid);
25676
+ resolve10(child.pid);
25669
25677
  });
25670
25678
  });
25671
25679
  }
@@ -25899,7 +25907,7 @@ var init_checkout_plane = __esm({
25899
25907
  }
25900
25908
  if (attempt < LIST_FILES_ATTEMPTS) {
25901
25909
  await new Promise(
25902
- (resolve9) => setTimeout(resolve9, LIST_FILES_RETRY_MS * attempt)
25910
+ (resolve10) => setTimeout(resolve10, LIST_FILES_RETRY_MS * attempt)
25903
25911
  );
25904
25912
  }
25905
25913
  }
@@ -28526,8 +28534,8 @@ function metroIosAssetDestRelatives(httpServerLocation, filename) {
28526
28534
  }
28527
28535
  const out = [];
28528
28536
  for (const dir of dirs) {
28529
- const path27 = `${dir}/${filename}`;
28530
- if (!out.includes(path27)) out.push(path27);
28537
+ const path28 = `${dir}/${filename}`;
28538
+ if (!out.includes(path28)) out.push(path28);
28531
28539
  }
28532
28540
  if (!out.includes(filename)) out.push(filename);
28533
28541
  return out;
@@ -28869,7 +28877,8 @@ async function readOrInferModuleIdentity(bundle, mode, inferModuleIdentity) {
28869
28877
  }
28870
28878
  async function buildRnxCloudArtifact(bundle, options = {}) {
28871
28879
  const mode = options.mode ?? "production";
28872
- const nativeIdentity = (0, import_native_app_identity.detachNativeAppIdentityFooter)(bundle);
28880
+ const firebase = (0, import_native_firebase_metadata.detachNativeFirebaseFooter)(bundle);
28881
+ const nativeIdentity = (0, import_native_app_identity.detachNativeAppIdentityFooter)(firebase.source);
28873
28882
  const identity = await readOrInferModuleIdentity(
28874
28883
  nativeIdentity.source,
28875
28884
  mode,
@@ -28897,7 +28906,7 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
28897
28906
  })
28898
28907
  ]);
28899
28908
  const body = pieces.map((piece) => piece.code).join("\n");
28900
- const code = body + (nativeIdentity.identity ? (0, import_native_app_identity.createNativeAppIdentityFooter)(nativeIdentity.identity) : "") + (0, import_metro_production_bundle.createRNXMetroModuleIdentityFooter)({
28909
+ const code = body + (nativeIdentity.identity ? (0, import_native_app_identity.createNativeAppIdentityFooter)(nativeIdentity.identity) : "") + (firebase.config ? (0, import_native_firebase_metadata.createNativeFirebaseFooter)(firebase.config) : "") + (0, import_metro_production_bundle.createRNXMetroModuleIdentityFooter)({
28901
28910
  version: identity.version,
28902
28911
  identitySource: identity.identitySource,
28903
28912
  modulePaths: identity.modulePaths,
@@ -28960,12 +28969,13 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
28960
28969
  }
28961
28970
  };
28962
28971
  }
28963
- var import_metro_production_bundle, import_native_app_identity, import_terser, MODULE_PATHS_REQUIRED, SOURCE_MAP_REQUIRED, MINIFY_OPTIONS;
28972
+ var import_metro_production_bundle, import_native_app_identity, import_native_firebase_metadata, import_terser, MODULE_PATHS_REQUIRED, SOURCE_MAP_REQUIRED, MINIFY_OPTIONS;
28964
28973
  var init_metroCloudArtifact = __esm({
28965
28974
  "../contrast-bundler/src/metroCloudArtifact.ts"() {
28966
28975
  "use strict";
28967
28976
  import_metro_production_bundle = require("peachsim/metro-production-bundle");
28968
28977
  import_native_app_identity = require("peachsim/native-app-identity");
28978
+ import_native_firebase_metadata = require("peachsim/native-firebase-metadata");
28969
28979
  import_terser = require("terser");
28970
28980
  init_metroAssetArtifact();
28971
28981
  init_metroDebugSourceMap();
@@ -29477,13 +29487,13 @@ function readFactoryStringLiterals(factory) {
29477
29487
  return literals;
29478
29488
  }
29479
29489
  function normalizeFingerprintLiteral(literal) {
29480
- const path27 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
29490
+ const path28 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
29481
29491
  const nodeModulesMarker = "/node_modules/";
29482
- const nodeModulesIndex = path27.lastIndexOf(nodeModulesMarker);
29492
+ const nodeModulesIndex = path28.lastIndexOf(nodeModulesMarker);
29483
29493
  if (nodeModulesIndex >= 0) {
29484
- return `node_modules/${path27.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
29494
+ return `node_modules/${path28.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
29485
29495
  }
29486
- if ((path27.startsWith("/") || /^[A-Za-z]:\//.test(path27) || path27.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path27)) {
29496
+ if ((path28.startsWith("/") || /^[A-Za-z]:\//.test(path28) || path28.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path28)) {
29487
29497
  return null;
29488
29498
  }
29489
29499
  return literal;
@@ -29721,10 +29731,10 @@ function templateAssignment(template, embeddings) {
29721
29731
  if (existingNode !== void 0 && existingNode !== nodeIndex) return null;
29722
29732
  nodesByModuleId.set(moduleId, nodeIndex);
29723
29733
  const node = template.nodes[nodeIndex];
29724
- const path27 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
29734
+ const path28 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
29725
29735
  const existingPath = pathsByModuleId.get(moduleId);
29726
- if (existingPath !== void 0 && existingPath !== path27) return null;
29727
- pathsByModuleId.set(moduleId, path27);
29736
+ if (existingPath !== void 0 && existingPath !== path28) return null;
29737
+ pathsByModuleId.set(moduleId, path28);
29728
29738
  }
29729
29739
  }
29730
29740
  return {
@@ -29886,14 +29896,14 @@ async function inferMetroModuleIdentity(args) {
29886
29896
  const packageClaims = claimsByPackage.values().next().value;
29887
29897
  if (!packageClaims) continue;
29888
29898
  const exactClaims = packageClaims.filter((assignment2) => {
29889
- const path27 = assignment2.pathsByModuleId.get(moduleId);
29890
- return path27 !== void 0 && !path27.includes("/__rnx_inferred__/");
29899
+ const path28 = assignment2.pathsByModuleId.get(moduleId);
29900
+ return path28 !== void 0 && !path28.includes("/__rnx_inferred__/");
29891
29901
  });
29892
29902
  const preferredClaims = exactClaims.length > 0 ? exactClaims : packageClaims;
29893
29903
  const routes = new Set(
29894
29904
  preferredClaims.flatMap((assignment2) => {
29895
- const path27 = assignment2.pathsByModuleId.get(moduleId);
29896
- return path27 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path27)] : [];
29905
+ const path28 = assignment2.pathsByModuleId.get(moduleId);
29906
+ return path28 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path28)] : [];
29897
29907
  })
29898
29908
  );
29899
29909
  if (routes.size !== 1) continue;
@@ -30214,11 +30224,11 @@ function detectProject(dir) {
30214
30224
  devCommand: typeof devCommand === "string" ? devCommand : null
30215
30225
  };
30216
30226
  }
30217
- function readProjectMetadata(path27) {
30227
+ function readProjectMetadata(path28) {
30218
30228
  try {
30219
- const info = (0, import_node_fs20.lstatSync)(path27);
30229
+ const info = (0, import_node_fs20.lstatSync)(path28);
30220
30230
  if (!info.isFile() || info.size > 4 * 1024 * 1024) return null;
30221
- return (0, import_node_fs20.readFileSync)(path27, "utf8");
30231
+ return (0, import_node_fs20.readFileSync)(path28, "utf8");
30222
30232
  } catch {
30223
30233
  return null;
30224
30234
  }
@@ -30227,8 +30237,8 @@ function metadataValue(value, key) {
30227
30237
  if (!value || typeof value !== "object") return void 0;
30228
30238
  return Object.getOwnPropertyDescriptor(value, key)?.value;
30229
30239
  }
30230
- function readProjectJson(path27) {
30231
- const text = readProjectMetadata(path27);
30240
+ function readProjectJson(path28) {
30241
+ const text = readProjectMetadata(path28);
30232
30242
  if (text === null) return null;
30233
30243
  try {
30234
30244
  const value = JSON.parse(text);
@@ -31325,7 +31335,7 @@ var init_bridge_host = __esm({
31325
31335
  );
31326
31336
  }
31327
31337
  bindOnce(port, _silent) {
31328
- return new Promise((resolve9, reject) => {
31338
+ return new Promise((resolve10, reject) => {
31329
31339
  const server = (0, import_http4.createServer)((req, res) => this.handleHttpRequest(req, res));
31330
31340
  let settled = false;
31331
31341
  const onError = (err) => {
@@ -31362,7 +31372,7 @@ var init_bridge_host = __esm({
31362
31372
  this.wss?.emit("connection", ws, req);
31363
31373
  });
31364
31374
  });
31365
- resolve9(address.port);
31375
+ resolve10(address.port);
31366
31376
  });
31367
31377
  });
31368
31378
  }
@@ -32571,7 +32581,7 @@ var init_bridge_host = __esm({
32571
32581
  async sendCommand(cmd) {
32572
32582
  const sim = await this.waitForSim(cmd.simId);
32573
32583
  const id = this.nextCommandId++;
32574
- return new Promise((resolve9, reject) => {
32584
+ return new Promise((resolve10, reject) => {
32575
32585
  const timeout = setTimeout(() => {
32576
32586
  this.pendingCommands.delete(id);
32577
32587
  this.broadcastSimClientStates();
@@ -32583,7 +32593,7 @@ var init_bridge_host = __esm({
32583
32593
  clearTimeout(timeout);
32584
32594
  this.pendingCommands.delete(id);
32585
32595
  this.broadcastSimClientStates();
32586
- resolve9(value);
32596
+ resolve10(value);
32587
32597
  },
32588
32598
  reject: (error) => {
32589
32599
  clearTimeout(timeout);
@@ -32609,23 +32619,23 @@ var init_bridge_host = __esm({
32609
32619
  async openPathInEditor(filePath, line, column) {
32610
32620
  const loc = line != null ? `:${line}${column != null ? `:${column}` : ""}` : "";
32611
32621
  const target = `${filePath}${loc}`;
32612
- const trySpawn = (cmd, args) => new Promise((resolve9) => {
32622
+ const trySpawn = (cmd, args) => new Promise((resolve10) => {
32613
32623
  try {
32614
32624
  const child = (0, import_child_process3.spawn)(cmd, args, { detached: true, stdio: "ignore" });
32615
32625
  let settled = false;
32616
32626
  child.on("error", () => {
32617
32627
  if (settled) return;
32618
32628
  settled = true;
32619
- resolve9(false);
32629
+ resolve10(false);
32620
32630
  });
32621
32631
  child.on("spawn", () => {
32622
32632
  if (settled) return;
32623
32633
  settled = true;
32624
32634
  child.unref();
32625
- resolve9(true);
32635
+ resolve10(true);
32626
32636
  });
32627
32637
  } catch {
32628
- resolve9(false);
32638
+ resolve10(false);
32629
32639
  }
32630
32640
  });
32631
32641
  const envEditor = process.env.REACT_EDITOR || process.env.EDITOR;
@@ -32706,7 +32716,7 @@ var init_bridge_host = __esm({
32706
32716
  }
32707
32717
  if (httpServer) {
32708
32718
  httpServer.closeAllConnections();
32709
- await new Promise((resolve9) => httpServer.close(() => resolve9()));
32719
+ await new Promise((resolve10) => httpServer.close(() => resolve10()));
32710
32720
  }
32711
32721
  }
32712
32722
  describeSim(sim, viewerIdentityKey) {
@@ -32875,7 +32885,7 @@ var init_bridge_host = __esm({
32875
32885
  const sim = this.getOpenSim(simId);
32876
32886
  if (sim) return sim;
32877
32887
  }
32878
- await new Promise((resolve9) => setTimeout(resolve9, intervalMs));
32888
+ await new Promise((resolve10) => setTimeout(resolve10, intervalMs));
32879
32889
  }
32880
32890
  if (!simId) throw new Error("no sim connected");
32881
32891
  const openSimIds = this.getDefaultSimCandidates().map((sim) => sim.id);
@@ -33687,7 +33697,7 @@ function createBridge(wsPort, opts = {}) {
33687
33697
  const pending = /* @__PURE__ */ new Map();
33688
33698
  const ws = new import_ws2.WebSocket(bridgeWsUrl(wsPort));
33689
33699
  const identity = getCliIdentity();
33690
- const ready = new Promise((resolve9, reject) => {
33700
+ const ready = new Promise((resolve10, reject) => {
33691
33701
  ws.on("open", () => {
33692
33702
  try {
33693
33703
  ws.send(
@@ -33701,7 +33711,7 @@ function createBridge(wsPort, opts = {}) {
33701
33711
  );
33702
33712
  } catch {
33703
33713
  }
33704
- resolve9();
33714
+ resolve10();
33705
33715
  });
33706
33716
  ws.on("error", (err) => {
33707
33717
  const cause = err.message ? `: ${err.message}` : "";
@@ -33791,7 +33801,7 @@ function createBridge(wsPort, opts = {}) {
33791
33801
  const sendOnce = async (defaultSimId, cmdOverride) => {
33792
33802
  await ready;
33793
33803
  const id = nextId++;
33794
- return new Promise((resolve9, reject) => {
33804
+ return new Promise((resolve10, reject) => {
33795
33805
  const timeout = setTimeout(() => {
33796
33806
  pending.delete(id);
33797
33807
  reject(
@@ -33803,7 +33813,7 @@ function createBridge(wsPort, opts = {}) {
33803
33813
  pending.set(id, {
33804
33814
  resolve: (v) => {
33805
33815
  clearTimeout(timeout);
33806
- resolve9(v);
33816
+ resolve10(v);
33807
33817
  },
33808
33818
  reject: (e) => {
33809
33819
  clearTimeout(timeout);
@@ -33973,11 +33983,11 @@ async function evalInBridge(bridge, code, opts = {}) {
33973
33983
  if (opts.acquireLock) payload.acquireLock = true;
33974
33984
  return bridge.send(payload);
33975
33985
  }
33976
- async function callInBridge(bridge, path27, ...args) {
33977
- return bridge.send({ type: "call", path: path27, args });
33986
+ async function callInBridge(bridge, path28, ...args) {
33987
+ return bridge.send({ type: "call", path: path28, args });
33978
33988
  }
33979
- async function callInBridgeWrite(bridge, path27, ...args) {
33980
- return bridge.send({ type: "call", path: path27, args, acquireLock: true });
33989
+ async function callInBridgeWrite(bridge, path28, ...args) {
33990
+ return bridge.send({ type: "call", path: path28, args, acquireLock: true });
33981
33991
  }
33982
33992
  var import_node_fs23, import_node_path23, import_ws2, PEACH_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError, BRIDGE_VALUE_FLAGS_TABLE, BRIDGE_VALUE_FLAGS;
33983
33993
  var init_ws_bridge = __esm({
@@ -34112,8 +34122,8 @@ function getDefaultPortForProtocol(protocol) {
34112
34122
  return protocol === "https:" ? 443 : 80;
34113
34123
  }
34114
34124
  function isBaseServerUrl(url) {
34115
- const path27 = url.pathname || "/";
34116
- return (path27 === "/" || path27 === "") && !url.search && !url.hash;
34125
+ const path28 = url.pathname || "/";
34126
+ return (path28 === "/" || path28 === "") && !url.search && !url.hash;
34117
34127
  }
34118
34128
  async function resolvePortViaServerScan(port) {
34119
34129
  try {
@@ -34154,8 +34164,8 @@ async function probeExpoManifest(normalizedBaseUrl, port) {
34154
34164
  let probeDeadline;
34155
34165
  const answered = await Promise.race([
34156
34166
  pending,
34157
- new Promise((resolve9) => {
34158
- probeDeadline = setTimeout(() => resolve9("timeout"), MANIFEST_PROBE_TIMEOUT_MS);
34167
+ new Promise((resolve10) => {
34168
+ probeDeadline = setTimeout(() => resolve10("timeout"), MANIFEST_PROBE_TIMEOUT_MS);
34159
34169
  })
34160
34170
  ]);
34161
34171
  clearTimeout(probeDeadline);
@@ -34203,7 +34213,7 @@ async function probeBaseUrlBundleDirect(baseUrl, port) {
34203
34213
  if (!packagerConfirmed) return null;
34204
34214
  const deadline = Date.now() + MANIFEST_BOOT_BUDGET_MS;
34205
34215
  while (manifest.state === "no-answer" && Date.now() < deadline) {
34206
- await new Promise((resolve9) => setTimeout(resolve9, MANIFEST_BOOT_RETRY_MS));
34216
+ await new Promise((resolve10) => setTimeout(resolve10, MANIFEST_BOOT_RETRY_MS));
34207
34217
  manifest = await probeExpoManifest(normalizedBaseUrl, port);
34208
34218
  }
34209
34219
  }
@@ -34406,27 +34416,177 @@ var init_flow_timeout_scale = __esm({
34406
34416
  });
34407
34417
 
34408
34418
  // src/native-firebase-config.ts
34409
- function readNativeFirebaseConfig(projectRoot) {
34419
+ function readNativeFirebaseConfig(projectRoot, platforms = ["ios", "android"]) {
34410
34420
  const result = {};
34411
- if (![
34412
- "app.json",
34421
+ let config = {};
34422
+ const appJsonPath = import_node_path25.default.join(projectRoot, "app.json");
34423
+ const appJson = import_node_fs25.default.existsSync(appJsonPath) ? JSON.parse(import_node_fs25.default.readFileSync(appJsonPath, "utf8")) : null;
34424
+ const staticExpo = isRecord(appJson) && (isRecord(appJson.expo) || [appJson.ios, appJson.android].some(
34425
+ (value) => isRecord(value) && typeof value.googleServicesFile === "string"
34426
+ ));
34427
+ const dynamicExpo = [
34413
34428
  "app.config.js",
34414
34429
  "app.config.ts",
34415
34430
  "app.config.cjs",
34416
34431
  "app.config.mjs"
34417
- ].some((name2) => import_node_fs25.default.existsSync(import_node_path25.default.join(projectRoot, name2))))
34418
- return result;
34419
- const require5 = (0, import_node_module2.createRequire)(import_node_path25.default.join(projectRoot, "package.json"));
34420
- const configModule = require5("@expo/config");
34421
- if (!isRecord(configModule) || typeof configModule.getConfig !== "function") {
34422
- throw new Error("Expo native configuration is unavailable.");
34423
- }
34424
- const resolved = Reflect.apply(configModule.getConfig, configModule, [
34425
- projectRoot,
34426
- { skipSDKVersionRequirement: true }
34427
- ]);
34428
- const config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {};
34429
- for (const platform of ["ios", "android"]) {
34432
+ ].some((name2) => import_node_fs25.default.existsSync(import_node_path25.default.join(projectRoot, name2)));
34433
+ if (staticExpo || dynamicExpo) {
34434
+ const require5 = (0, import_node_module2.createRequire)(import_node_path25.default.join(projectRoot, "package.json"));
34435
+ const configModule = require5("@expo/config");
34436
+ if (!isRecord(configModule) || typeof configModule.getConfig !== "function")
34437
+ throw new Error("Expo native configuration is unavailable.");
34438
+ const resolved = Reflect.apply(configModule.getConfig, configModule, [
34439
+ projectRoot,
34440
+ { skipSDKVersionRequirement: true }
34441
+ ]);
34442
+ config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {};
34443
+ }
34444
+ const ios = config.ios;
34445
+ if (platforms.includes("ios") && (!isRecord(ios) || typeof ios.googleServicesFile !== "string")) {
34446
+ const iosRoot = import_node_path25.default.join(projectRoot, "ios");
34447
+ if (import_node_fs25.default.existsSync(iosRoot)) {
34448
+ const projects2 = import_node_fs25.default.readdirSync(iosRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.endsWith(".xcodeproj"));
34449
+ if (projects2.length > 1)
34450
+ throw new Error("native Firebase configuration requires a selected Xcode project");
34451
+ if (projects2.length === 1) {
34452
+ const require5 = (0, import_node_module2.createRequire)(import_node_path25.default.join(projectRoot, "package.json"));
34453
+ const xcode = require5("xcode");
34454
+ if (!isRecord(xcode) || typeof xcode.project !== "function")
34455
+ throw new Error("native Xcode project parser is unavailable");
34456
+ const project = Reflect.apply(xcode.project, xcode, [
34457
+ import_node_path25.default.join(iosRoot, projects2[0].name, "project.pbxproj")
34458
+ ]);
34459
+ if (!isRecord(project) || typeof project.parseSync !== "function")
34460
+ throw new Error("native Xcode project is malformed");
34461
+ Reflect.apply(project.parseSync, project, []);
34462
+ const hash = project.hash;
34463
+ const native = isRecord(hash) ? hash.project : null;
34464
+ const objects = isRecord(native) ? native.objects : null;
34465
+ if (!isRecord(objects)) throw new Error("native Xcode objects are malformed");
34466
+ const unquote = (value) => typeof value === "string" ? value.replace(/^"|"$/g, "") : "";
34467
+ const targets = isRecord(objects.PBXNativeTarget) ? Object.values(objects.PBXNativeTarget).filter(
34468
+ (target2) => isRecord(target2) && unquote(target2.productType) === "com.apple.product-type.application"
34469
+ ) : [];
34470
+ if (targets.length > 1)
34471
+ throw new Error("native Firebase configuration requires a selected app target");
34472
+ const target = targets[0];
34473
+ if (isRecord(target) && Array.isArray(target.buildPhases)) {
34474
+ const buildPhases = target.buildPhases;
34475
+ const filePaths = /* @__PURE__ */ new Map();
34476
+ const groups = isRecord(objects.PBXGroup) ? objects.PBXGroup : {};
34477
+ const references = isRecord(objects.PBXFileReference) ? objects.PBXFileReference : {};
34478
+ const nativeProjects = isRecord(objects.PBXProject) ? Object.values(objects.PBXProject) : [];
34479
+ const roots = nativeProjects.filter(isRecord).map((value) => value.mainGroup);
34480
+ const pending = roots.filter((id) => typeof id === "string").map((id) => ({ id, base: iosRoot }));
34481
+ const visited = /* @__PURE__ */ new Map();
34482
+ while (pending.length) {
34483
+ const item = pending.pop();
34484
+ if (!item) break;
34485
+ const previous = visited.get(item.id);
34486
+ if (previous !== void 0) {
34487
+ if (previous !== item.base)
34488
+ throw new Error("native Xcode group has ambiguous parents");
34489
+ continue;
34490
+ }
34491
+ visited.set(item.id, item.base);
34492
+ const group = groups[item.id];
34493
+ if (!isRecord(group) || !Array.isArray(group.children)) continue;
34494
+ const sourceTree = unquote(group.sourceTree);
34495
+ if (sourceTree && sourceTree !== "<group>" && sourceTree !== "SOURCE_ROOT")
34496
+ continue;
34497
+ const directory = import_node_path25.default.resolve(
34498
+ sourceTree === "SOURCE_ROOT" ? iosRoot : item.base,
34499
+ unquote(group.path)
34500
+ );
34501
+ for (const child of group.children) {
34502
+ if (!isRecord(child) || typeof child.value !== "string") continue;
34503
+ if (isRecord(groups[child.value])) {
34504
+ pending.push({ id: child.value, base: directory });
34505
+ continue;
34506
+ }
34507
+ const file = references[child.value];
34508
+ if (!isRecord(file)) continue;
34509
+ const tree = unquote(file.sourceTree);
34510
+ if (tree !== "<group>" && tree !== "SOURCE_ROOT") continue;
34511
+ const filePath = import_node_path25.default.resolve(
34512
+ tree === "SOURCE_ROOT" ? iosRoot : directory,
34513
+ unquote(file.path)
34514
+ );
34515
+ const values = filePaths.get(child.value) ?? /* @__PURE__ */ new Set();
34516
+ values.add(filePath);
34517
+ filePaths.set(child.value, values);
34518
+ }
34519
+ }
34520
+ const buildFiles = isRecord(objects.PBXBuildFile) ? objects.PBXBuildFile : {};
34521
+ const filesInPhase = (section, name2) => {
34522
+ if (!isRecord(section)) return [];
34523
+ const paths = [];
34524
+ for (const phase of buildPhases) {
34525
+ if (!isRecord(phase) || typeof phase.value !== "string") continue;
34526
+ const value = section[phase.value];
34527
+ if (!isRecord(value) || !Array.isArray(value.files)) continue;
34528
+ for (const entry of value.files) {
34529
+ if (!isRecord(entry) || typeof entry.value !== "string") continue;
34530
+ const file = buildFiles[entry.value];
34531
+ if (!isRecord(file) || typeof file.fileRef !== "string") continue;
34532
+ const reference = references[file.fileRef];
34533
+ if (!isRecord(reference) || !name2.test(import_node_path25.default.basename(unquote(reference.path))))
34534
+ continue;
34535
+ const candidates = filePaths.get(file.fileRef);
34536
+ if (!candidates || candidates.size !== 1)
34537
+ throw new Error("native Firebase build resource path is unresolved");
34538
+ paths.push(...candidates);
34539
+ }
34540
+ }
34541
+ return paths;
34542
+ };
34543
+ const delegates = filesInPhase(
34544
+ objects.PBXSourcesBuildPhase,
34545
+ /^AppDelegate\.(swift|mm|m)$/
34546
+ );
34547
+ const defaultConfigured = delegates.some((file) => {
34548
+ const source = import_node_fs25.default.readFileSync(file, "utf8").replace(
34549
+ /\/\*[\s\S]*?\*\/|\/\/[^\n]*|"(?:\\.|[^"\\])*"/g,
34550
+ (token) => token.startsWith('"') ? '""' : token.replace(/[^\n]/g, " ")
34551
+ );
34552
+ const launch3 = /(?:\bfunc\s+application\s*\([\s\S]*?didFinishLaunchingWithOptions[\s\S]*?\)\s*->\s*Bool|^-\s*\(BOOL\)\s*application\s*:[\s\S]*?didFinishLaunchingWithOptions[^\{]*)\s*\{/m.exec(
34553
+ source
34554
+ );
34555
+ if (!launch3) return false;
34556
+ const body = source.slice(launch3.index + launch3[0].length);
34557
+ const configure = /^\s*(?:FirebaseApp\s*\.\s*configure\s*\(\s*\)|\[FIRApp\s+configure\])/m.exec(
34558
+ body
34559
+ );
34560
+ if (!configure) return false;
34561
+ const before = body.slice(0, configure.index);
34562
+ let depth = 1;
34563
+ for (const token of before) {
34564
+ if (token === "{") depth += 1;
34565
+ if (token === "}") depth -= 1;
34566
+ if (depth === 0) return false;
34567
+ }
34568
+ if (depth !== 1 || /\b(?:return|throw)\b|^\s*#(?:if|elseif|else)/m.test(before))
34569
+ throw new Error(
34570
+ "native Firebase initialization must be unconditional in the app launch method"
34571
+ );
34572
+ return true;
34573
+ });
34574
+ if (defaultConfigured) {
34575
+ const resources = filesInPhase(
34576
+ objects.PBXResourcesBuildPhase,
34577
+ /^GoogleService-Info\.plist$/
34578
+ );
34579
+ if (resources.length !== 1)
34580
+ throw new Error(
34581
+ "native Firebase default initialization requires one GoogleService-Info.plist build resource"
34582
+ );
34583
+ config.ios = { googleServicesFile: import_node_path25.default.relative(projectRoot, resources[0]) };
34584
+ }
34585
+ }
34586
+ }
34587
+ }
34588
+ }
34589
+ for (const platform of platforms) {
34430
34590
  const native = config[platform];
34431
34591
  if (!isRecord(native) || typeof native.googleServicesFile !== "string") continue;
34432
34592
  try {
@@ -36109,12 +36269,12 @@ function findDesktopCompanion() {
36109
36269
  }
36110
36270
  async function spawnDetached(command, args, opts = {}) {
36111
36271
  const stdio = opts.inheritStdio ? ["ignore", "inherit", "inherit"] : "ignore";
36112
- await new Promise((resolve9, reject) => {
36272
+ await new Promise((resolve10, reject) => {
36113
36273
  const child = (0, import_child_process5.spawn)(command, args, { detached: true, stdio });
36114
36274
  child.once("error", reject);
36115
36275
  child.once("spawn", () => {
36116
36276
  child.unref();
36117
- resolve9();
36277
+ resolve10();
36118
36278
  });
36119
36279
  });
36120
36280
  }
@@ -37766,11 +37926,11 @@ async function launch2(opts) {
37766
37926
  }
37767
37927
  );
37768
37928
  child.unref();
37769
- const earlyExit = await new Promise((resolve9) => {
37770
- const timer = setTimeout(() => resolve9(null), 4e3);
37929
+ const earlyExit = await new Promise((resolve10) => {
37930
+ const timer = setTimeout(() => resolve10(null), 4e3);
37771
37931
  child.once("exit", (code) => {
37772
37932
  clearTimeout(timer);
37773
- resolve9(code ?? 0);
37933
+ resolve10(code ?? 0);
37774
37934
  });
37775
37935
  });
37776
37936
  if (earlyExit !== null) {
@@ -37989,7 +38149,8 @@ var init_parse_args = __esm({
37989
38149
  // documented aliases for --sim (CLAUDE.md / skills / engine docs say
37990
38150
  // `--session <id>`). normalized to the sim target in bin.ts.
37991
38151
  "--session": { type: "string" },
37992
- "--tab": { type: "string" }
38152
+ "--tab": { type: "string" },
38153
+ "--redact": { type: "boolean" }
37993
38154
  };
37994
38155
  GLOBAL_FLAG_TAKES_VALUE = new Map(
37995
38156
  Object.entries(GLOBAL_FLAGS).flatMap(([name2, def]) => {
@@ -38101,6 +38262,118 @@ var init_runtime_diagnostics = __esm({
38101
38262
  }
38102
38263
  });
38103
38264
 
38265
+ // cli/commands/skills.ts
38266
+ function getSkillsDir() {
38267
+ if (typeof __PEACH_BUNDLED_SKILLS__ !== "undefined") {
38268
+ const dir = path24.join(rnxHomeDir(), "skills", getCliVersion());
38269
+ for (const [file, body] of Object.entries(__PEACH_BUNDLED_SKILLS__)) {
38270
+ const target = path24.join(dir, file);
38271
+ if (fs21.existsSync(target)) continue;
38272
+ fs21.mkdirSync(path24.dirname(target), { recursive: true });
38273
+ fs21.writeFileSync(target, body);
38274
+ }
38275
+ return dir;
38276
+ }
38277
+ try {
38278
+ const pkgPath = (0, import_url3.fileURLToPath)(
38279
+ import_meta4.resolve(`${rnxPublicBrand.packageName}/package.json`)
38280
+ );
38281
+ return path24.join(path24.dirname(pkgPath), "skills");
38282
+ } catch {
38283
+ const __dirname = path24.dirname((0, import_url3.fileURLToPath)(__sootsim_import_meta_url));
38284
+ return path24.resolve(__dirname, "../../skills");
38285
+ }
38286
+ }
38287
+ function skillsDir() {
38288
+ skillsDirPath ??= getSkillsDir();
38289
+ return skillsDirPath;
38290
+ }
38291
+ function targetFromHome(envName, fallbackDir) {
38292
+ const home = process.env[envName] || path24.join(os5.homedir(), fallbackDir);
38293
+ return path24.join(home, "skills");
38294
+ }
38295
+ function defaultAgentTargets() {
38296
+ return [
38297
+ { label: "codex", dir: targetFromHome("CODEX_HOME", ".codex") },
38298
+ { label: "claude", dir: targetFromHome("CLAUDE_CONFIG_DIR", ".claude") }
38299
+ ];
38300
+ }
38301
+ function hasInstalledPeachSkills() {
38302
+ const names = typeof __PEACH_BUNDLED_SKILLS__ !== "undefined" ? Object.keys(__PEACH_BUNDLED_SKILLS__).flatMap(
38303
+ (file) => /^([^/]+)\/SKILL\.md$/.exec(file)?.[1] ?? []
38304
+ ) : listSkills().map((skill7) => skill7.name);
38305
+ return defaultAgentTargets().some(
38306
+ ({ dir }) => names.some((name2) => fs21.existsSync(path24.join(dir, name2, "SKILL.md")))
38307
+ );
38308
+ }
38309
+ function parseSkillFrontmatter(content) {
38310
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
38311
+ if (!match) return null;
38312
+ const frontmatter = match[1];
38313
+ const name2 = readFrontmatterField(frontmatter, "name");
38314
+ if (!name2) return null;
38315
+ return {
38316
+ name: name2,
38317
+ description: readFrontmatterField(frontmatter, "description") || ""
38318
+ };
38319
+ }
38320
+ function readFrontmatterField(frontmatter, field) {
38321
+ const lines = frontmatter.split("\n");
38322
+ const prefix = `${field}:`;
38323
+ for (let index = 0; index < lines.length; index++) {
38324
+ const line = lines[index];
38325
+ if (!line.startsWith(prefix)) continue;
38326
+ const rawValue = line.slice(prefix.length).trim();
38327
+ if (rawValue === ">-" || rawValue === ">" || rawValue === "|-" || rawValue === "|") {
38328
+ const blockLines = [];
38329
+ for (let blockIndex = index + 1; blockIndex < lines.length; blockIndex++) {
38330
+ const blockLine = lines[blockIndex];
38331
+ if (/^[A-Za-z0-9_-]+:\s*/.test(blockLine)) break;
38332
+ if (blockLine.trim() === "") {
38333
+ blockLines.push("");
38334
+ continue;
38335
+ }
38336
+ if (!/^\s+/.test(blockLine)) break;
38337
+ blockLines.push(blockLine.trim());
38338
+ }
38339
+ return blockLines.join(rawValue.startsWith("|") ? "\n" : " ").trim();
38340
+ }
38341
+ if (rawValue.startsWith('"') && rawValue.endsWith('"') || rawValue.startsWith("'") && rawValue.endsWith("'")) {
38342
+ return rawValue.slice(1, -1);
38343
+ }
38344
+ return rawValue;
38345
+ }
38346
+ return null;
38347
+ }
38348
+ function listSkills() {
38349
+ if (!fs21.existsSync(skillsDir())) return [];
38350
+ const skills = [];
38351
+ for (const entry of fs21.readdirSync(skillsDir())) {
38352
+ const skillMd = path24.join(skillsDir(), entry, "SKILL.md");
38353
+ if (!fs21.existsSync(skillMd)) continue;
38354
+ const meta = parseSkillFrontmatter(fs21.readFileSync(skillMd, "utf8"));
38355
+ if (meta) {
38356
+ skills.push({ name: entry, description: meta.description });
38357
+ }
38358
+ }
38359
+ return skills.sort((a, b) => a.name.localeCompare(b.name));
38360
+ }
38361
+ var fs21, os5, path24, import_url3, import_meta4, skillsDirPath;
38362
+ var init_skills = __esm({
38363
+ "cli/commands/skills.ts"() {
38364
+ "use strict";
38365
+ fs21 = __toESM(require("fs"), 1);
38366
+ os5 = __toESM(require("os"), 1);
38367
+ path24 = __toESM(require("path"), 1);
38368
+ import_url3 = require("url");
38369
+ init_cli_version();
38370
+ init_home_paths();
38371
+ init_public_brand();
38372
+ init_run_rnx();
38373
+ import_meta4 = {};
38374
+ }
38375
+ });
38376
+
38104
38377
  // cli/runtime-notes.ts
38105
38378
  function isChangelogEntry(value) {
38106
38379
  if (!value || typeof value !== "object") return false;
@@ -38254,13 +38527,13 @@ async function tellDaemonRuntimeChanged(version) {
38254
38527
  const lock = readDaemonLockfile2();
38255
38528
  if (!isDaemonLockfileFresh2(lock)) return false;
38256
38529
  const port = resolveDefaultBridgePort();
38257
- return new Promise((resolve9) => {
38530
+ return new Promise((resolve10) => {
38258
38531
  let settled = false;
38259
38532
  let success = false;
38260
38533
  const finish = (ok) => {
38261
38534
  if (settled) return;
38262
38535
  settled = true;
38263
- resolve9(ok);
38536
+ resolve10(ok);
38264
38537
  };
38265
38538
  const ws = new import_ws3.WebSocket(`ws://127.0.0.1:${port}`, {
38266
38539
  handshakeTimeout: 800
@@ -38585,7 +38858,7 @@ function spawnSootsim(args) {
38585
38858
  });
38586
38859
  }
38587
38860
  function canConnectToBridge(port, timeoutMs) {
38588
- return new Promise((resolve9) => {
38861
+ return new Promise((resolve10) => {
38589
38862
  const ws = new import_ws4.WebSocket(`ws://127.0.0.1:${port}`, { handshakeTimeout: timeoutMs });
38590
38863
  let settled = false;
38591
38864
  const finish = (ok) => {
@@ -38593,7 +38866,7 @@ function canConnectToBridge(port, timeoutMs) {
38593
38866
  settled = true;
38594
38867
  if (ws.readyState === import_ws4.WebSocket.OPEN) ws.close();
38595
38868
  else if (ws.readyState === import_ws4.WebSocket.CONNECTING) ws.terminate();
38596
- resolve9(ok);
38869
+ resolve10(ok);
38597
38870
  };
38598
38871
  ws.once("open", () => finish(true));
38599
38872
  ws.on("error", () => finish(false));
@@ -39252,9 +39525,11 @@ function printOpenedSim(openUrl2, sim, mode, quiet = false) {
39252
39525
  console.log(` current sim: ${sim.id}`);
39253
39526
  console.log(JSON.stringify({ simId: sim.id, url: printableSimUrl }, null, 2));
39254
39527
  }
39255
- function printAgentListenHint(quiet) {
39256
- if (!quiet) {
39257
- console.log(" inspect messages: run `peach agent listen` when you finish your turn");
39528
+ function printAgentHints(quiet) {
39529
+ if (quiet) return;
39530
+ console.log(" inspect messages: run `peach agent listen` when you finish your turn");
39531
+ if (!hasInstalledPeachSkills()) {
39532
+ console.log(" driving peach from an agent? `peach skill install` adds its workflows");
39258
39533
  }
39259
39534
  }
39260
39535
  async function maybeDescribeAfterOpen(wsPort, simId, args) {
@@ -39737,7 +40012,7 @@ async function runOpenCommand(args, opts = {}) {
39737
40012
  quiet
39738
40013
  );
39739
40014
  await maybeDescribeAfterOpen(parsed.wsPort, targetSim.id, args);
39740
- printAgentListenHint(quiet);
40015
+ printAgentHints(quiet);
39741
40016
  return { simId: targetSim.id, launched: false };
39742
40017
  }
39743
40018
  } finally {
@@ -39820,7 +40095,7 @@ async function runOpenCommand(args, opts = {}) {
39820
40095
  signalDriverLaunchConnected(result);
39821
40096
  printOpenedSim(openUrl2, match, `${driver.name} driver`, quiet);
39822
40097
  await maybeDescribeAfterOpen(parsed.wsPort, match.id, args);
39823
- printAgentListenHint(quiet);
40098
+ printAgentHints(quiet);
39824
40099
  return { simId: match.id, launched: true };
39825
40100
  }
39826
40101
  async function runUseLikeCommand(args, opts = {}) {
@@ -40156,6 +40431,7 @@ var init_control = __esm({
40156
40431
  init_ws_bridge();
40157
40432
  init_core();
40158
40433
  init_env();
40434
+ init_skills();
40159
40435
  DEFAULT_DRIVER_CONNECT_TIMEOUT_MS = 12e4;
40160
40436
  DRIVER_CONNECT_INTERVAL_MS = 100;
40161
40437
  DRIVER_CONNECT_HOST_GRACE_MS = 5e3;
@@ -41467,16 +41743,16 @@ function readRecentShellAppId(state) {
41467
41743
  }
41468
41744
  function resolveProjectRelativeFlowBase(flowDir) {
41469
41745
  if (!flowDir) return process.cwd();
41470
- return path25.basename(flowDir) === ".maestro" ? path25.dirname(flowDir) : flowDir;
41746
+ return path26.basename(flowDir) === ".maestro" ? path26.dirname(flowDir) : flowDir;
41471
41747
  }
41472
41748
  function resolveFlowScreenshotPathWithMode(screenshotDir, name2, opts) {
41473
41749
  const normalizedName = name2.endsWith(".png") ? name2 : `${name2}.png`;
41474
- if (path25.isAbsolute(normalizedName)) return normalizedName;
41750
+ if (path26.isAbsolute(normalizedName)) return normalizedName;
41475
41751
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
41476
41752
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
41477
- return path25.resolve(baseDir, normalizedName);
41753
+ return path26.resolve(baseDir, normalizedName);
41478
41754
  }
41479
- return path25.join(screenshotDir, normalizedName);
41755
+ return path26.join(screenshotDir, normalizedName);
41480
41756
  }
41481
41757
  function normalizeFlowScreenshotSpec(step) {
41482
41758
  if (typeof step === "string") {
@@ -41533,12 +41809,12 @@ function parseFlowSteps(content) {
41533
41809
  const parsed = import_yaml2.default.parse(candidate);
41534
41810
  return Array.isArray(parsed) ? parsed : [];
41535
41811
  }
41536
- var fs23, path25, import_devices4, import_yaml2, import_proof_frame, DEFAULT_TIMEOUT, ASSERTION_LOOKUP_MS, FLOW_TIMEOUT_SCALE, scaledTimeout, MAESTRO_SELECTOR_KEYS, SELECTOR_FILTER_KEYS, UNSUPPORTED_SELECTOR_KEYS, ACCESSIBILITY_SELECTOR_KEYS, ACCESSIBILITY_TRAIT_FILTERS, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
41812
+ var fs24, path26, import_devices4, import_yaml2, import_proof_frame, DEFAULT_TIMEOUT, ASSERTION_LOOKUP_MS, FLOW_TIMEOUT_SCALE, scaledTimeout, MAESTRO_SELECTOR_KEYS, SELECTOR_FILTER_KEYS, UNSUPPORTED_SELECTOR_KEYS, ACCESSIBILITY_SELECTOR_KEYS, ACCESSIBILITY_TRAIT_FILTERS, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
41537
41813
  var init_bridge_flow_runner = __esm({
41538
41814
  "cli/bridge-flow-runner.ts"() {
41539
41815
  "use strict";
41540
- fs23 = __toESM(require("fs"), 1);
41541
- path25 = __toESM(require("path"), 1);
41816
+ fs24 = __toESM(require("fs"), 1);
41817
+ path26 = __toESM(require("path"), 1);
41542
41818
  import_devices4 = require("peach-engine/settings/devices");
41543
41819
  import_yaml2 = __toESM(require("yaml"), 1);
41544
41820
  import_proof_frame = __toESM(require_proof_frame(), 1);
@@ -41863,14 +42139,14 @@ var init_bridge_flow_runner = __esm({
41863
42139
  if (chunks.length === 0) {
41864
42140
  throw new Error("recording requested but no video buffer was produced");
41865
42141
  }
41866
- fs23.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
42142
+ fs24.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
41867
42143
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
41868
42144
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
41869
- const outputPath = path25.join(
42145
+ const outputPath = path26.join(
41870
42146
  this.opts.recordingOutputDir,
41871
42147
  `peach-${Date.now()}.${extension}`
41872
42148
  );
41873
- fs23.writeFileSync(outputPath, Buffer.concat(chunks));
42149
+ fs24.writeFileSync(outputPath, Buffer.concat(chunks));
41874
42150
  return outputPath;
41875
42151
  }
41876
42152
  async waitForRecordingTail(opts) {
@@ -42546,7 +42822,7 @@ var init_bridge_flow_runner = __esm({
42546
42822
  flowDir: this.opts.flowDir
42547
42823
  }
42548
42824
  );
42549
- fs23.mkdirSync(path25.dirname(outputPath), { recursive: true });
42825
+ fs24.mkdirSync(path26.dirname(outputPath), { recursive: true });
42550
42826
  const layers = spec.layers ?? this.opts.screenshotLayers;
42551
42827
  const screenshotRequest = {
42552
42828
  type: "screenshot",
@@ -42581,11 +42857,11 @@ var init_bridge_flow_runner = __esm({
42581
42857
  throw new Error("could not read current device model for framed screenshot");
42582
42858
  }
42583
42859
  const framed = await composeFramedScreenshot(rawBuffer, model);
42584
- fs23.writeFileSync(outputPath, framed);
42860
+ fs24.writeFileSync(outputPath, framed);
42585
42861
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
42586
42862
  return outputPath;
42587
42863
  }
42588
- fs23.writeFileSync(outputPath, rawBuffer);
42864
+ fs24.writeFileSync(outputPath, rawBuffer);
42589
42865
  console.log(`[flow] screenshot: ${outputPath}`);
42590
42866
  return outputPath;
42591
42867
  }
@@ -42607,10 +42883,10 @@ var init_bridge_flow_runner = __esm({
42607
42883
  // + a11y tree + console errors/warnings + failed network requests +
42608
42884
  // shell state, all under one directory so post-mortem is one grep away.
42609
42885
  async captureFailureBundle(outputDir, context) {
42610
- fs23.mkdirSync(outputDir, { recursive: true });
42886
+ fs24.mkdirSync(outputDir, { recursive: true });
42611
42887
  const write = (name2, content) => {
42612
42888
  try {
42613
- fs23.writeFileSync(path25.join(outputDir, name2), content);
42889
+ fs24.writeFileSync(path26.join(outputDir, name2), content);
42614
42890
  } catch {
42615
42891
  }
42616
42892
  };
@@ -43202,8 +43478,8 @@ var init_bridge_flow_runner = __esm({
43202
43478
  runScript(target) {
43203
43479
  const spec = typeof target === "string" ? { file: target } : target;
43204
43480
  if (!spec.file) throw new Error("runScript requires a file");
43205
- const scriptPath = path25.resolve(this.opts.flowDir, spec.file);
43206
- const source = fs23.readFileSync(scriptPath, "utf8");
43481
+ const scriptPath = path26.resolve(this.opts.flowDir, spec.file);
43482
+ const source = fs24.readFileSync(scriptPath, "utf8");
43207
43483
  this.js.evaluate(source, { env: spec.env });
43208
43484
  console.log(`[flow] runScript: ${spec.file} done`);
43209
43485
  }
@@ -43563,10 +43839,10 @@ var init_bridge_flow_runner = __esm({
43563
43839
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
43564
43840
  }
43565
43841
  if (file) {
43566
- const flowPath = path25.resolve(this.opts.flowDir, file);
43567
- const flowContent = fs23.readFileSync(flowPath, "utf8");
43842
+ const flowPath = path26.resolve(this.opts.flowDir, file);
43843
+ const flowContent = fs24.readFileSync(flowPath, "utf8");
43568
43844
  const previousDir = this.opts.flowDir;
43569
- this.opts.flowDir = path25.dirname(flowPath);
43845
+ this.opts.flowDir = path26.dirname(flowPath);
43570
43846
  try {
43571
43847
  await this.runFlow(parseFlowSteps(flowContent));
43572
43848
  } finally {
@@ -43737,8 +44013,8 @@ __export(registry_exports, {
43737
44013
  skillRegistry: () => skillRegistry
43738
44014
  });
43739
44015
  module.exports = __toCommonJS(registry_exports);
43740
- var fs24 = __toESM(require("fs"), 1);
43741
- var path26 = __toESM(require("path"), 1);
44016
+ var fs25 = __toESM(require("fs"), 1);
44017
+ var path27 = __toESM(require("path"), 1);
43742
44018
 
43743
44019
  // src/skills/builtin/a11y-review.ts
43744
44020
  init_reap_browser();
@@ -43757,8 +44033,8 @@ var skill = {
43757
44033
  },
43758
44034
  async execute(params, context) {
43759
44035
  const { chromium } = await import("playwright");
43760
- const path27 = await import("path");
43761
- const fs25 = await import("fs");
44036
+ const path28 = await import("path");
44037
+ const fs26 = await import("fs");
43762
44038
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
43763
44039
  headless: true
43764
44040
  });
@@ -43815,9 +44091,9 @@ var skill = {
43815
44091
  warnings: issues.filter((i) => i.severity === "warning").length,
43816
44092
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
43817
44093
  };
43818
- const reportPath = path27.join(context.outputDir, "a11y-report.json");
43819
- fs25.mkdirSync(path27.dirname(reportPath), { recursive: true });
43820
- fs25.writeFileSync(reportPath, JSON.stringify(report, null, 2));
44094
+ const reportPath = path28.join(context.outputDir, "a11y-report.json");
44095
+ fs26.mkdirSync(path28.dirname(reportPath), { recursive: true });
44096
+ fs26.writeFileSync(reportPath, JSON.stringify(report, null, 2));
43821
44097
  return {
43822
44098
  success: issues.filter((i) => i.severity === "error").length === 0,
43823
44099
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -43850,14 +44126,14 @@ var skill2 = {
43850
44126
  }
43851
44127
  },
43852
44128
  async execute(params, context) {
43853
- const fs25 = await import("node:fs");
43854
- const path27 = await import("node:path");
44129
+ const fs26 = await import("node:fs");
44130
+ const path28 = await import("node:path");
43855
44131
  const { COMPAT_RESULT_CAVEAT: COMPAT_RESULT_CAVEAT2, formatPackageStatus: formatPackageStatus2, formatScanCounts: formatScanCounts2, scanDeps: scanDeps2 } = await Promise.resolve().then(() => (init_web(), web_exports));
43856
- const packagePath = path27.join(context.projectDir, "package.json");
43857
- if (!fs25.existsSync(packagePath)) {
44132
+ const packagePath = path28.join(context.projectDir, "package.json");
44133
+ if (!fs26.existsSync(packagePath)) {
43858
44134
  return { success: false, message: "No package.json found" };
43859
44135
  }
43860
- const parsed = JSON.parse(fs25.readFileSync(packagePath, "utf8"));
44136
+ const parsed = JSON.parse(fs26.readFileSync(packagePath, "utf8"));
43861
44137
  if (!parsed || typeof parsed !== "object") {
43862
44138
  return { success: false, message: "package.json is not an object" };
43863
44139
  }
@@ -43869,9 +44145,9 @@ var skill2 = {
43869
44145
  }) : scanDeps2(parsed);
43870
44146
  const packageResult = params.packageName ? scan.packages[0] : void 0;
43871
44147
  const message = packageResult ? `${params.packageName}: ${formatPackageStatus2(packageResult)}. ${COMPAT_RESULT_CAVEAT2}` : `${formatScanCounts2(scan)}. ${COMPAT_RESULT_CAVEAT2}`;
43872
- const reportPath = path27.join(context.outputDir, "compat-report.json");
43873
- fs25.mkdirSync(path27.dirname(reportPath), { recursive: true });
43874
- fs25.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
44148
+ const reportPath = path28.join(context.outputDir, "compat-report.json");
44149
+ fs26.mkdirSync(path28.dirname(reportPath), { recursive: true });
44150
+ fs26.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
43875
44151
  `);
43876
44152
  return {
43877
44153
  success: true,
@@ -43913,8 +44189,8 @@ var skill3 = {
43913
44189
  record: { type: "boolean", description: "Record video of the flow" }
43914
44190
  },
43915
44191
  async execute(params, context) {
43916
- const fs25 = await import("fs");
43917
- const path27 = await import("path");
44192
+ const fs26 = await import("fs");
44193
+ const path28 = await import("path");
43918
44194
  const yaml2 = await import("yaml");
43919
44195
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT3 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
43920
44196
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -43924,7 +44200,7 @@ var skill3 = {
43924
44200
  const host2 = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT3 });
43925
44201
  host2.start({ silent: true });
43926
44202
  try {
43927
- const flowContent = fs25.readFileSync(params.flowPath, "utf8");
44203
+ const flowContent = fs26.readFileSync(params.flowPath, "utf8");
43928
44204
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
43929
44205
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
43930
44206
  const steps = yaml2.parse(stepsBody);
@@ -43951,7 +44227,7 @@ var skill3 = {
43951
44227
  });
43952
44228
  const driver = new SootSimBridgeFlowRunner2(bridge, {
43953
44229
  screenshotDir: context.outputDir,
43954
- flowDir: path27.dirname(path27.resolve(params.flowPath)),
44230
+ flowDir: path28.dirname(path28.resolve(params.flowPath)),
43955
44231
  simId,
43956
44232
  recordingOutputDir: params.record ? context.outputDir : void 0
43957
44233
  });
@@ -43973,7 +44249,7 @@ var skill3 = {
43973
44249
  simId,
43974
44250
  videoPath: videoPath || void 0
43975
44251
  },
43976
- artifacts: videoPath ? [{ type: "video", name: path27.basename(videoPath), path: videoPath }] : void 0
44252
+ artifacts: videoPath ? [{ type: "video", name: path28.basename(videoPath), path: videoPath }] : void 0
43977
44253
  };
43978
44254
  } finally {
43979
44255
  try {
@@ -44020,8 +44296,8 @@ var skill4 = {
44020
44296
  },
44021
44297
  async execute(params, context) {
44022
44298
  const { chromium } = await import("playwright");
44023
- const path27 = await import("path");
44024
- const fs25 = await import("fs");
44299
+ const path28 = await import("path");
44300
+ const fs26 = await import("fs");
44025
44301
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
44026
44302
  headless: true
44027
44303
  });
@@ -44049,9 +44325,9 @@ var skill4 = {
44049
44325
  ...profile,
44050
44326
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
44051
44327
  };
44052
- const reportPath = path27.join(context.outputDir, "perf-report.json");
44053
- fs25.mkdirSync(path27.dirname(reportPath), { recursive: true });
44054
- fs25.writeFileSync(reportPath, JSON.stringify(report, null, 2));
44328
+ const reportPath = path28.join(context.outputDir, "perf-report.json");
44329
+ fs26.mkdirSync(path28.dirname(reportPath), { recursive: true });
44330
+ fs26.writeFileSync(reportPath, JSON.stringify(report, null, 2));
44055
44331
  return {
44056
44332
  success: true,
44057
44333
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -44084,8 +44360,8 @@ var skill5 = {
44084
44360
  },
44085
44361
  async execute(params, context) {
44086
44362
  const { chromium } = await import("playwright");
44087
- const path27 = await import("path");
44088
- const fs25 = await import("fs");
44363
+ const path28 = await import("path");
44364
+ const fs26 = await import("fs");
44089
44365
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
44090
44366
  headless: true
44091
44367
  });
@@ -44093,8 +44369,8 @@ var skill5 = {
44093
44369
  try {
44094
44370
  await page.goto(context.url, { waitUntil: "networkidle" });
44095
44371
  await page.waitForTimeout(2e3);
44096
- const outputPath = path27.join(context.outputDir, `${params.name}.png`);
44097
- fs25.mkdirSync(path27.dirname(outputPath), { recursive: true });
44372
+ const outputPath = path28.join(context.outputDir, `${params.name}.png`);
44373
+ fs26.mkdirSync(path28.dirname(outputPath), { recursive: true });
44098
44374
  await page.screenshot({ path: outputPath });
44099
44375
  return {
44100
44376
  success: true,
@@ -44135,8 +44411,8 @@ var skill6 = {
44135
44411
  },
44136
44412
  async execute(params, context) {
44137
44413
  const { chromium } = await import("playwright");
44138
- const path27 = await import("path");
44139
- const fs25 = await import("fs");
44414
+ const path28 = await import("path");
44415
+ const fs26 = await import("fs");
44140
44416
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
44141
44417
  headless: true
44142
44418
  });
@@ -44144,14 +44420,14 @@ var skill6 = {
44144
44420
  try {
44145
44421
  await page.goto(context.url, { waitUntil: "networkidle" });
44146
44422
  await page.waitForTimeout(2e3);
44147
- const currentPath = path27.join(context.outputDir, `${params.name}-current.png`);
44148
- fs25.mkdirSync(path27.dirname(currentPath), { recursive: true });
44423
+ const currentPath = path28.join(context.outputDir, `${params.name}-current.png`);
44424
+ fs26.mkdirSync(path28.dirname(currentPath), { recursive: true });
44149
44425
  await page.screenshot({ path: currentPath });
44150
44426
  try {
44151
44427
  const { PNG } = await import("pngjs");
44152
44428
  const pixelmatch = (await import("pixelmatch")).default;
44153
- const baseline = PNG.sync.read(fs25.readFileSync(params.baseline));
44154
- const current = PNG.sync.read(fs25.readFileSync(currentPath));
44429
+ const baseline = PNG.sync.read(fs26.readFileSync(params.baseline));
44430
+ const current = PNG.sync.read(fs26.readFileSync(currentPath));
44155
44431
  const { width, height } = baseline;
44156
44432
  const diff = new PNG({ width, height });
44157
44433
  const numDiffPixels = pixelmatch(
@@ -44162,8 +44438,8 @@ var skill6 = {
44162
44438
  height,
44163
44439
  { threshold: params.threshold || 0.1 }
44164
44440
  );
44165
- const diffPath = path27.join(context.outputDir, `${params.name}-diff.png`);
44166
- fs25.writeFileSync(diffPath, PNG.sync.write(diff));
44441
+ const diffPath = path28.join(context.outputDir, `${params.name}-diff.png`);
44442
+ fs26.writeFileSync(diffPath, PNG.sync.write(diff));
44167
44443
  const totalPixels = width * height;
44168
44444
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
44169
44445
  return {
@@ -44227,10 +44503,10 @@ var skillRegistry = {
44227
44503
  },
44228
44504
  // load skills from a project manifest (rnx-skills.json)
44229
44505
  async loadFromManifest(projectDir) {
44230
- const manifestPath = path26.join(projectDir, "rnx-skills.json");
44231
- if (!fs24.existsSync(manifestPath)) return;
44506
+ const manifestPath = path27.join(projectDir, "rnx-skills.json");
44507
+ if (!fs25.existsSync(manifestPath)) return;
44232
44508
  try {
44233
- const manifest = JSON.parse(fs24.readFileSync(manifestPath, "utf8"));
44509
+ const manifest = JSON.parse(fs25.readFileSync(manifestPath, "utf8"));
44234
44510
  if (Array.isArray(manifest.skills)) {
44235
44511
  for (const entry of manifest.skills) {
44236
44512
  if (typeof entry === "string") {
@@ -44241,7 +44517,7 @@ var skillRegistry = {
44241
44517
  }
44242
44518
  } else if (entry.file) {
44243
44519
  try {
44244
- const mod = await import(path26.resolve(projectDir, entry.file));
44520
+ const mod = await import(path27.resolve(projectDir, entry.file));
44245
44521
  if (mod.skill) this.register(mod.skill);
44246
44522
  } catch {
44247
44523
  }
@@ -44254,10 +44530,10 @@ var skillRegistry = {
44254
44530
  // auto-discover skills based on project dependencies
44255
44531
  suggestSkills(projectDir) {
44256
44532
  const suggestions = [];
44257
- const pkgPath = path26.join(projectDir, "package.json");
44258
- if (!fs24.existsSync(pkgPath)) return suggestions;
44533
+ const pkgPath = path27.join(projectDir, "package.json");
44534
+ if (!fs25.existsSync(pkgPath)) return suggestions;
44259
44535
  try {
44260
- const pkg = JSON.parse(fs24.readFileSync(pkgPath, "utf8"));
44536
+ const pkg = JSON.parse(fs25.readFileSync(pkgPath, "utf8"));
44261
44537
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
44262
44538
  if (deps["detox"] || deps["maestro"]) {
44263
44539
  suggestions.push("maestro-test");