peachsim 0.1.629 → 0.1.631

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 (128) hide show
  1. package/README.md +8 -4
  2. package/cli/app-fonts.ts +23 -4
  3. package/cli/bridge-flow-runner.ts +45 -31
  4. package/cli/cli-update.ts +2 -7
  5. package/cli/cloud-test-tunnel.ts +16 -3
  6. package/cli/command-registry.ts +1 -0
  7. package/cli/commands/compat.ts +11 -60
  8. package/cli/commands/config.ts +1 -1
  9. package/cli/commands/control.ts +40 -8
  10. package/cli/commands/daemon-mac-app.ts +4 -2
  11. package/cli/commands/daemon.ts +4 -4
  12. package/cli/commands/detect.ts +289 -26
  13. package/cli/commands/device.ts +2 -3
  14. package/cli/commands/inspect/actions.ts +125 -90
  15. package/cli/commands/inspect/core.ts +1 -1
  16. package/cli/commands/inspect.ts +10 -1
  17. package/cli/commands/maestro.ts +3 -1
  18. package/cli/commands/platform.ts +1 -1
  19. package/cli/commands/project-report.ts +386 -0
  20. package/cli/commands/projectReportContract.ts +42 -0
  21. package/cli/commands/report-issue.ts +38 -54
  22. package/cli/commands/screenshot-layers.ts +1 -1
  23. package/cli/commands/screenshot.ts +1 -1
  24. package/cli/commands/setup.ts +6 -4
  25. package/cli/commands/skills.ts +0 -31
  26. package/cli/commands/telemetry.ts +8 -3
  27. package/cli/commands/test.ts +347 -134
  28. package/cli/drivers/playwright-provisioning.ts +3 -2
  29. package/cli/drivers/playwright-sim-host.ts +25 -9
  30. package/cli/main.ts +19 -3
  31. package/cli/outbound-endpoints.ts +2 -5
  32. package/cli/privacy.ts +1 -2
  33. package/cli/runtime-diagnostics.ts +51 -0
  34. package/cli/telemetry.ts +78 -7
  35. package/detox/index.ts +77 -51
  36. package/dist-lib/agent-daemon-client.cjs +1 -1
  37. package/dist-lib/agent-events.cjs +1 -1
  38. package/dist-lib/agent-identity.cjs +1 -1
  39. package/dist-lib/agent-sessions.cjs +1 -1
  40. package/dist-lib/attached-projects.cjs +1 -1
  41. package/dist-lib/auth/shared-session.cjs +1 -1
  42. package/dist-lib/backend-origin.cjs +1 -1
  43. package/dist-lib/beta.cjs +1 -1
  44. package/dist-lib/beta.mjs +1 -1
  45. package/dist-lib/bridge-constants.cjs +1 -1
  46. package/dist-lib/bridge-contract-input.cjs +1 -1
  47. package/dist-lib/bridge-contract-input.mjs +1 -1
  48. package/dist-lib/bridge-contract.cjs +1 -1
  49. package/dist-lib/bridge-contract.mjs +1 -1
  50. package/dist-lib/capture-contract.cjs +1 -1
  51. package/dist-lib/capture-contract.mjs +1 -1
  52. package/dist-lib/cli-constants.cjs +1 -1
  53. package/dist-lib/cloud-contract.cjs +1 -1
  54. package/dist-lib/cloud-contract.mjs +1 -1
  55. package/dist-lib/cloud-test-args.cjs +1 -1
  56. package/dist-lib/cloud-test-args.mjs +1 -1
  57. package/dist-lib/cloud.cjs +1 -1
  58. package/dist-lib/cloud.mjs +1 -1
  59. package/dist-lib/config.cjs +1 -1
  60. package/dist-lib/detox/index.cjs +130 -33
  61. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  62. package/dist-lib/home-paths.cjs +8 -5
  63. package/dist-lib/host/bridge-host.cjs +353 -290
  64. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  65. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  66. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  67. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  68. package/dist-lib/host/websocket-proxy.cjs +1 -1
  69. package/dist-lib/index.cjs +257 -121
  70. package/dist-lib/jump-to-source-babel.cjs +1 -1
  71. package/dist-lib/jump-to-source-native.cjs +1 -1
  72. package/dist-lib/{vite-kotlin.cjs → kotlin-host.cjs} +130 -19
  73. package/dist-lib/menu.cjs +11 -1
  74. package/dist-lib/menu.mjs +11 -1
  75. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  76. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  77. package/dist-lib/metro-production-bundle.cjs +1 -1
  78. package/dist-lib/metro-production-bundle.mjs +1 -1
  79. package/dist-lib/metro.cjs +132 -9
  80. package/dist-lib/native-app-identity.cjs +278 -0
  81. package/dist-lib/native-app-identity.mjs +245 -0
  82. package/dist-lib/profiles.cjs +1 -1
  83. package/dist-lib/public-brand.cjs +1 -1
  84. package/dist-lib/react-native-host-modules.cjs +1 -1
  85. package/dist-lib/react-native-host-modules.mjs +1 -1
  86. package/dist-lib/render-mode.cjs +1 -1
  87. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  88. package/dist-lib/sdk.cjs +112 -87
  89. package/dist-lib/sdk.mjs +111 -87
  90. package/dist-lib/skills.cjs +1270 -709
  91. package/dist-lib/swift-compile.cjs +1 -1
  92. package/dist-lib/swift-compile.mjs +1 -1
  93. package/dist-lib/swift-package.cjs +1 -1
  94. package/dist-lib/swift-package.mjs +1 -1
  95. package/dist-lib/swift-submit.cjs +1 -1
  96. package/dist-lib/swift-submit.mjs +1 -1
  97. package/dist-lib/swift.cjs +672 -275
  98. package/dist-lib/vite-swift.cjs +1 -1
  99. package/dist-lib/vite.cjs +11 -28
  100. package/kotlin/README.md +32 -4
  101. package/kotlin/fixtures/counter/Counter.kt +26 -0
  102. package/kotlin/fixtures/counter/CounterScreen.kt +40 -0
  103. package/kotlin/fixtures/headless-counter/Headless.kt +228 -0
  104. package/kotlin/fixtures/runtime-state/RuntimeState.kt +200 -0
  105. package/kotlin/fork/LICENSE +178 -0
  106. package/kotlin/fork/NOTICE +25 -0
  107. package/kotlin/fork/README.md +59 -0
  108. package/kotlin/fork/build.sh +128 -0
  109. package/kotlin/fork/compose-worker-globals.patch +96 -0
  110. package/kotlin/fork/fork.json +33 -0
  111. package/kotlin/fork/publish.ts +77 -0
  112. package/kotlin/fork/skiko-worker-clock.patch +33 -0
  113. package/kotlin/toolchain.json +288 -0
  114. package/package.json +13 -5
  115. package/skills/contrast/SKILL.md +1 -0
  116. package/src/automatic-update-policy.ts +17 -0
  117. package/src/home-paths.ts +11 -9
  118. package/src/host/bridge-host.ts +3 -1
  119. package/src/{vite-plugin-kotlin.ts → kotlin-host.ts} +155 -12
  120. package/src/menu.ts +11 -0
  121. package/src/metro-plugin.ts +18 -0
  122. package/src/native-app-identity.ts +376 -0
  123. package/src/native-firebase-config.ts +90 -0
  124. package/src/screenshots/frame-compose.ts +1 -1
  125. package/src/screenshots/registry.ts +1 -1
  126. package/src/screenshots/schema.ts +2 -2
  127. package/src/vite-plugin-one.ts +11 -28
  128. package/src/vite-plugin.ts +6 -1
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.629 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.631 | (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;
@@ -2079,8 +2079,8 @@ var init_capability_inventory_coverage = __esm({
2079
2079
  combined: {
2080
2080
  raw: {
2081
2081
  covered: 7,
2082
- ratio: 0.00432632880099,
2083
- total: 1618
2082
+ ratio: 0.00432365657813,
2083
+ total: 1619
2084
2084
  },
2085
2085
  weighted: {
2086
2086
  covered: 118953211737e-15,
@@ -2091,8 +2091,8 @@ var init_capability_inventory_coverage = __esm({
2091
2091
  semantic: {
2092
2092
  raw: {
2093
2093
  covered: 7,
2094
- ratio: 0.0061295971979,
2095
- total: 1142
2094
+ ratio: 0.00612423447069,
2095
+ total: 1143
2096
2096
  },
2097
2097
  weighted: {
2098
2098
  covered: 118953211737e-15,
@@ -2118,7 +2118,7 @@ var init_capability_inventory_coverage = __esm({
2118
2118
  raw: {
2119
2119
  covered: 0,
2120
2120
  ratio: 0,
2121
- total: 1419
2121
+ total: 1420
2122
2122
  },
2123
2123
  weighted: {
2124
2124
  covered: 0,
@@ -2130,7 +2130,7 @@ var init_capability_inventory_coverage = __esm({
2130
2130
  raw: {
2131
2131
  covered: 0,
2132
2132
  ratio: 0,
2133
- total: 990
2133
+ total: 991
2134
2134
  },
2135
2135
  weighted: {
2136
2136
  covered: 0,
@@ -2154,25 +2154,25 @@ var init_capability_inventory_coverage = __esm({
2154
2154
  ios: {
2155
2155
  combined: {
2156
2156
  raw: {
2157
- covered: 229,
2158
- ratio: 0.159248956885,
2159
- total: 1438
2157
+ covered: 242,
2158
+ ratio: 0.168172341904,
2159
+ total: 1439
2160
2160
  },
2161
2161
  weighted: {
2162
- covered: 0.5733148295,
2163
- ratio: 0.125605921087,
2162
+ covered: 0.587946074544,
2163
+ ratio: 0.128811439095,
2164
2164
  total: 4.56439333862
2165
2165
  }
2166
2166
  },
2167
2167
  semantic: {
2168
2168
  raw: {
2169
- covered: 229,
2170
- ratio: 0.224730127576,
2171
- total: 1019
2169
+ covered: 242,
2170
+ ratio: 0.237254901961,
2171
+ total: 1020
2172
2172
  },
2173
2173
  weighted: {
2174
- covered: 0.5733148295,
2175
- ratio: 0.526183631135,
2174
+ covered: 0.587946074544,
2175
+ ratio: 0.539612067396,
2176
2176
  total: 1.08957176844
2177
2177
  }
2178
2178
  },
@@ -3594,20 +3594,20 @@ var init_capability_outcomes2 = __esm({
3594
3594
  android: {
3595
3595
  passedWeight: 0,
3596
3596
  failedWeight: 0,
3597
- unassessedWeight: 1240,
3598
- totalWeight: 1240,
3597
+ unassessedWeight: 1241,
3598
+ totalWeight: 1241,
3599
3599
  assessedWeight: 0,
3600
3600
  compatibility: null,
3601
3601
  assessed: 0
3602
3602
  },
3603
3603
  ios: {
3604
- passedWeight: 176,
3604
+ passedWeight: 175,
3605
3605
  failedWeight: 0,
3606
- unassessedWeight: 1075,
3607
- totalWeight: 1251,
3608
- assessedWeight: 176,
3606
+ unassessedWeight: 1077,
3607
+ totalWeight: 1252,
3608
+ assessedWeight: 175,
3609
3609
  compatibility: 1,
3610
- assessed: 0.14068745003996802
3610
+ assessed: 0.13977635782747605
3611
3611
  }
3612
3612
  },
3613
3613
  usage: {
@@ -3621,22 +3621,19 @@ var init_capability_outcomes2 = __esm({
3621
3621
  assessed: 0
3622
3622
  },
3623
3623
  ios: {
3624
- passedWeight: 8041,
3624
+ passedWeight: 7981,
3625
3625
  failedWeight: 0,
3626
- unassessedWeight: 24473,
3626
+ unassessedWeight: 24533,
3627
3627
  totalWeight: 32514,
3628
- assessedWeight: 8041,
3628
+ assessedWeight: 7981,
3629
3629
  compatibility: 1,
3630
- assessed: 0.24730885157163068
3630
+ assessed: 0.2454634926493203
3631
3631
  }
3632
3632
  }
3633
3633
  },
3634
- capturedAt: "2026-09-25T14:01:15.160Z",
3635
- receipts: [
3636
- "core-paired-capture.2026-09-25T14:01:15.160Z.json",
3637
- "core-paired-capture.2026-09-26T12:47:39.597Z.json"
3638
- ],
3639
- sourceCommit: "dbfe444161bb1990b6f3264732e27e103798f5dc"
3634
+ capturedAt: "2026-10-01T07:50:49.727Z",
3635
+ receipts: ["core-paired-capture.2026-10-01T07:50:49.727Z.json"],
3636
+ sourceCommit: "7b3f26ea6413895ef474cf7adcbb130c5eb298c7"
3640
3637
  },
3641
3638
  unmatchedReferenceCount: 7368,
3642
3639
  byPlatform: {
@@ -3664,8 +3661,8 @@ var init_capability_outcomes2 = __esm({
3664
3661
  android: {
3665
3662
  passedWeight: 0,
3666
3663
  failedWeight: 0,
3667
- unassessedWeight: 1240,
3668
- totalWeight: 1240,
3664
+ unassessedWeight: 1241,
3665
+ totalWeight: 1241,
3669
3666
  assessedWeight: 0,
3670
3667
  compatibility: null,
3671
3668
  assessed: 0
@@ -3673,8 +3670,8 @@ var init_capability_outcomes2 = __esm({
3673
3670
  ios: {
3674
3671
  passedWeight: 0,
3675
3672
  failedWeight: 0,
3676
- unassessedWeight: 1251,
3677
- totalWeight: 1251,
3673
+ unassessedWeight: 1252,
3674
+ totalWeight: 1252,
3678
3675
  assessedWeight: 0,
3679
3676
  compatibility: null,
3680
3677
  assessed: 0
@@ -4404,6 +4401,8 @@ var init_supported_native_packages = __esm({
4404
4401
  // coverage
4405
4402
  "@expo/ui/community/menu",
4406
4403
  // coverage
4404
+ "@fingerprintjs/fingerprintjs-pro-react-native",
4405
+ // seam
4407
4406
  "@fugood/react-native-audio-pcm-stream",
4408
4407
  // seam
4409
4408
  "@fullstory/react-native",
@@ -4512,6 +4511,8 @@ var init_supported_native_packages = __esm({
4512
4511
  // seam
4513
4512
  "@react-native-firebase/functions",
4514
4513
  // seam
4514
+ "@react-native-firebase/messaging",
4515
+ // seam
4515
4516
  "@react-native-firebase/perf",
4516
4517
  // coverage
4517
4518
  "@react-native-firebase/storage",
@@ -4524,6 +4525,8 @@ var init_supported_native_packages = __esm({
4524
4525
  // seam
4525
4526
  "@react-native-picker/picker",
4526
4527
  // seam
4528
+ "@rive-app/react-native",
4529
+ // seam
4527
4530
  "@rn-org/react-native-shortcuts",
4528
4531
  // seam+coverage
4529
4532
  "@rocket.chat/mobile-crypto",
@@ -5196,6 +5199,8 @@ var init_supported_native_packages = __esm({
5196
5199
  // seam
5197
5200
  "react-native-view-pdf",
5198
5201
  // seam
5202
+ "react-native-view-shot",
5203
+ // seam
5199
5204
  "react-native-vision-camera",
5200
5205
  // coverage
5201
5206
  "react-native-vlc-media-player",
@@ -7041,9 +7046,9 @@ var init_registry = __esm({
7041
7046
  {
7042
7047
  range: ">=3.0.0",
7043
7048
  coverage: 0.82,
7044
- note: "captureRef/captureScreen return REAL captured pixels: the tenant resolves the target node's absolute rect (unstable_getBoundingClientRect), shell routes the native request, and the compositor pixel owner crops + re-encodes that region of the active app surface (createImageBitmap(offscreen, sx,sy,sw,sh) + OffscreenCanvas convertToBlob). The data-uri is coerced into the requested result shape (tmpfile blob URL / base64 / data-uri). validateOptions mirrors upstream src/index.tsx warning text; ViewShot exposes capture() with mount/continuous/update captureMode; releaseCapture revokes tracked blob URLs. When compositor cannot sample the surface (no painted pixels or fully out of bounds), it falls back to a validly-encoded placeholder of the right size so uploads/share/<Image> still get a working result \u2014 one fallback path, no toggle.",
7045
- working: "captureRef (real pixels of the target subtree region via shell snapshot), captureScreen (full app-surface snapshot), tmpfile/base64/data-uri results, png/jpg/webp formats with quality for lossy, explicit width/height as output dims, validateOptions parity with upstream warning text, ViewShot component with capture() ref method, captureMode mount/continuous/update, releaseCapture revoking tracked blob URLs",
7046
- missing: "true subtree isolation (the compositor crops a screen rectangle, so an overlapping sibling/overlay inside the bbox is included \u2014 real captureRef renders only the target's hierarchy), presentation-layer transforms (getBoundingClientRect reports the laid-out rect, not an animated/transformed on-screen position), zip-base64 falls back to plain base64, raw format falls back to png, snapshotContentContainer (full scroll content beyond the viewport \u2014 only the painted surface region is available)"
7049
+ note: "captureRef renders only the target view's own subtree, as RNViewShot.mm draws the view alone: the tenant sends the target's view tag, shell routes it to the compositor pixel owner, and the compositor draws that mirror node into an offscreen target at the device scale (drawIsolatedNode), clipped to the view's bounds, so an overlapping sibling or overlay is not in the image. snapshotContentContainer resolves the scroll view (the target or its first scroll view child, else rejects with the native message) and renders its whole content at offset zero. captureScreen crops the whole composited app surface, the keyWindow capture. the real package's JS runs from the bundle (per-platform option validation, ViewShot component, captureMode); the RNViewShot TurboModule seam answers captureRef/captureScreen/releaseCapture. a capture the compositor cannot produce rejects with the native error text; there is no placeholder image.",
7050
+ working: "captureRef (target subtree alone, sibling overlays excluded, clipped to its bounds), snapshotContentContainer (scroll view at full content size, non-scroll target rejects), captureScreen (full app-surface snapshot), tmpfile/base64/data-uri results, png/jpg with quality for jpg (webp on Android), explicit width/height as the drawn output size, upstream option validation, ViewShot component and captureMode (real package JS), releaseCapture revoking tracked blob URLs",
7051
+ missing: "tmpfile results are blob: URLs, not files under NSTemporaryDirectory/ReactNative, useRenderInContext is ignored (the view always scales to the requested size), presentation-layer transforms (getBoundingClientRect reports the laid-out rect, not an animated on-screen position), a content-container capture whose scroll view has no laid-out content rejects with the generic capture error rather than the zero-size message, a content-container capture draws the scroll view background and content but not the scroll view border, opacity, transform or filters (native resizes and draws the scroll view itself), Android zip-base64 falls back to plain base64 and raw to png"
7047
7052
  }
7048
7053
  ]
7049
7054
  },
@@ -7144,10 +7149,60 @@ var init_registry = __esm({
7144
7149
  versions: [
7145
7150
  {
7146
7151
  range: ">=18.0.0",
7147
- coverage: 0,
7148
- note: "the reference iOS simulator performs this package's behavior. Peach currently provides only this unsupported shape: development noop : push API surface resolves without real FCM delivery. imports and API shape receive no behavior credit",
7149
- working: "default messaging(), getToken/deleteToken, requestPermission/hasPermission AUTHORIZED, onMessage/onNotificationOpenedApp/onTokenRefresh subscriptions, getInitialNotification null, setBackgroundMessageHandler, topic subscribe/unsubscribe, auto-init/device registration helpers, AuthorizationStatus constants",
7150
- missing: "real FCM token, actual message receipt, background handler execution, notification-open events; intentionally absent for browser simulator"
7152
+ note: "native-seam only \u2014 the published @react-native-firebase/messaging JS runs unchanged against a NativeRNFBTurboMessaging seam read from the installed 26.4.0 iOS sources, modeled on the arm64 iOS simulator (never registered for remote notifications). Detox pushes with a gcm.message_id route through the notification bus to onMessage, onNotificationOpenedApp and getInitialNotification like RNFBMessaging+UNUserNotificationCenter. The opened event and one-shot initial notification are read from that native source but have no paired tap proof: on the iOS 27 scene life cycle Detox cannot deliver a tap response to RNFB (a launch tap is dispatched before RNFB installs its center delegate, and a background tap waits for an app delegate applicationDidBecomeActive that never comes). Estimates were reviewed against the installed native source by a second model.",
7153
+ features: [
7154
+ {
7155
+ id: "permission",
7156
+ usage: 3,
7157
+ importance: 3,
7158
+ estimate: 0.9,
7159
+ rationale: "hasPermission and requestPermission map every iOS authorization status like RNFBMessagingModule.mm. Absent: the provisional, announcement, carPlay and providesAppNotificationSettings request options, and the settings-open flag with its messaging_settings_for_notification_opened event."
7160
+ },
7161
+ {
7162
+ id: "foreground-messages",
7163
+ usage: 3,
7164
+ importance: 3,
7165
+ estimate: 0.9,
7166
+ rationale: "onMessage receives a foreground push through the RemoteMessage serializer. Differs: boolean fields such as aps content-available are not converted with RCTConvert BOOL semantics and integer fields use Number rather than intValue, and RNFB's own messaging_ios_foreground_presentation_options and interoperability with another center delegate are not modeled."
7167
+ },
7168
+ {
7169
+ id: "notification-opens",
7170
+ usage: 3,
7171
+ importance: 3,
7172
+ estimate: 1,
7173
+ rationale: "a default-action tap on a push with a gcm.message_id sends messaging_notification_opened and stores a one-shot initial notification, queued until the listener and JS are ready, as RNFBMessaging+UNUserNotificationCenter and RNFBRCTEventEmitter do."
7174
+ },
7175
+ {
7176
+ id: "tokens-and-registration",
7177
+ usage: 3,
7178
+ importance: 3,
7179
+ estimate: 0.9,
7180
+ rationale: "getToken and getAPNSToken reject messaging/unregistered, setAPNSToken reads back upper-case hex, and registerDeviceForRemoteMessages times out after ten seconds, as on the simulator. Absent: the FCM token fetch and onTokenRefresh that native runs after an app supplies an APNs token with setAPNSToken."
7181
+ },
7182
+ {
7183
+ id: "topics-and-token-deletion",
7184
+ usage: 2,
7185
+ importance: 2,
7186
+ estimate: 0,
7187
+ rationale: "deleteToken, subscribeToTopic and unsubscribeFromTopic reject as not available in Peach instead of settling through the FCM backend."
7188
+ },
7189
+ {
7190
+ id: "background-messages",
7191
+ usage: 2,
7192
+ importance: 3,
7193
+ estimate: 0,
7194
+ rationale: "setBackgroundMessageHandler and messaging_message_received_background, the app delegate path for data-only and background pushes, are not implemented."
7195
+ },
7196
+ {
7197
+ id: "auto-init",
7198
+ usage: 1,
7199
+ importance: 1,
7200
+ estimate: 0.5,
7201
+ rationale: "setAutoInitEnabled persists like FIRMessaging. Absent: the FirebaseMessagingAutoInitEnabled Info.plist and data collection defaults native falls back to, and the token request enabling it triggers."
7202
+ }
7203
+ ],
7204
+ working: "hasPermission and requestPermission for ordinary alert, badge, sound and critical alert requests with every iOS authorization status value, onMessage for a foreground push with the RemoteMessage fields (messageId, data, notification title/body/ios fields, category, threadId, contentAvailable), onNotificationOpenedApp and one-shot getInitialNotification from the native delegate source, getToken and getAPNSToken rejecting messaging/unregistered, setAPNSToken with upper-case hex readback, registerDeviceForRemoteMessages rejecting messaging/registration-timeout after ten seconds, constants (isDeviceRegisteredForRemoteMessages false, BigQuery flag), setAutoInitEnabled persistence, sendMessage rejecting as Android-only like iOS",
7205
+ missing: "FCM backend calls: deleteToken, subscribeToTopic and unsubscribeFromTopic reject as not available in Peach instead of settling from the backend; the background handler and messaging_message_received_background; the provisional, announcement, carPlay and providesAppNotificationSettings permission options; setOpenSettingsForNotificationsHandler and the settings-open flag; RNFB's own foreground presentation options and interoperability with another center delegate; RCTConvert BOOL and intValue semantics in the serializer; the FCM token fetch and onTokenRefresh after an app supplies an APNs token; auto-init defaults from Info.plist and data collection; app options: the seeded [DEFAULT] app carries placeholder options rather than the app's GoogleService-Info.plist values, and exists even for an app that never calls FirebaseApp.configure(); onDeletedMessages, onMessageSent and onSendError (Android only)"
7151
7206
  }
7152
7207
  ]
7153
7208
  },
@@ -7809,10 +7864,39 @@ var init_registry = __esm({
7809
7864
  versions: [
7810
7865
  {
7811
7866
  range: ">=50.0.0",
7812
- coverage: 0.2,
7813
- note: `unavailable-on-web shape per docs/compat-scoring.md ("keep low unless we add a real browser OAuth flow"): enums and button render, isAvailableAsync returns false, signInAsync/refreshAsync/signOutAsync reject with ERR_NOT_AVAILABLE matching how an unavailable native module behaves. Apps with graceful-degradation paths take the right branch. Returning a fake credential here would lie to consumer code that may try to verify the identityToken against Apple's keys. The 0.2 score is intentional: a real flow requires app-owned Apple ID JS SDK configuration, a Service ID, and an HTTPS redirect, so it cannot be supplied as a generic simulator seam.`,
7814
- working: "isAvailableAsync (false), AppleAuthenticationButton render (sign in / continue / sign up, WHITE/WHITE_OUTLINE/BLACK styles), all enum exports (Scope, Operation, CredentialState, UserDetectionStatus, ButtonType, ButtonStyle), formatFullName, getCredentialStateAsync (NOT_FOUND), addRevokeListener",
7815
- missing: "real Sign-in-with-Apple OAuth flow (would need AppleID JS SDK + Service ID + HTTPS)"
7867
+ note: "native-seam only \u2014 the published expo-apple-authentication JS runs unchanged over an ExpoAppleAuthentication module read from the installed iOS sources (AppleAuthenticationModule.swift), modeled on the iOS simulator with no Apple Account signed in, which is what the paired native iPhone 16 run uses.",
7868
+ features: [
7869
+ {
7870
+ id: "availability-and-button",
7871
+ usage: 3,
7872
+ importance: 3,
7873
+ estimate: 1,
7874
+ rationale: "isAvailableAsync resolves true as on iOS, and AppleAuthenticationButton renders every button type and style."
7875
+ },
7876
+ {
7877
+ id: "sign-in",
7878
+ usage: 3,
7879
+ importance: 3,
7880
+ estimate: 0.3,
7881
+ rationale: "signInAsync, refreshAsync and signOutAsync present the Sign in to your Apple Account alert and reject ERR_REQUEST_UNKNOWN when its Close or Settings button is tapped, as a simulator without an Apple Account does, and reject invalid scopes and operations with the native codes; after Settings rejects, Settings comes to the front on its Apple Account sign-in sheet and the app goes inactive then background. Absent: the credential a simulator or device signed in to an Apple Account issues, the sheet hero and device art (private system symbols) and the back-to-app breadcrumb, and the inactive app state while the out-of-process alert is up."
7882
+ },
7883
+ {
7884
+ id: "credential-state",
7885
+ usage: 2,
7886
+ importance: 2,
7887
+ estimate: 1,
7888
+ rationale: "getCredentialStateAsync resolves NOT_FOUND for any user, as a simulator without an Apple Account does; the revoke listener registers and never fires."
7889
+ },
7890
+ {
7891
+ id: "name-formatting",
7892
+ usage: 1,
7893
+ importance: 2,
7894
+ estimate: 0.8,
7895
+ rationale: "formatFullName formats the default, short, medium, long and abbreviated styles as PersonNameComponentsFormatter does on an en_US device for Latin, Cyrillic and Han script names: nickname fallbacks, one-letter given names, grapheme initials, family-first Han order and Han abbreviation by length. An unknown style throws ERR_ARGUMENT_CAST from the Expo bridge. Absent: its rules for kana, Hangul, Thai and mixed-script names and for components that start with a digit or symbol."
7896
+ }
7897
+ ],
7898
+ working: "isAvailableAsync (true), AppleAuthenticationButton render (sign in / continue / sign up, WHITE/WHITE_OUTLINE/BLACK styles), all enum exports, the Sign in to your Apple Account alert for signInAsync, refreshAsync and signOutAsync with ERR_REQUEST_UNKNOWN from Close or Settings, the Settings Apple Account sign-in sheet after Settings, ERR_INVALID_SCOPE and ERR_INVALID_OPERATION, getCredentialStateAsync (NOT_FOUND), formatFullName for Latin, Cyrillic and Han script names on an en_US device, addRevokeListener",
7899
+ missing: "a signed-in Apple Account: no credential, identity token or authorization code is ever issued; the Settings Apple Account sheet has no hero or device art (private system symbols) and no back-to-app breadcrumb; the app stays active while the alert is up where iOS makes it inactive; formatFullName rules for kana, Hangul, Thai and mixed-script names and for components that start with a digit or symbol"
7816
7900
  }
7817
7901
  ]
7818
7902
  },
@@ -9937,10 +10021,23 @@ var init_registry = __esm({
9937
10021
  stubType: "native",
9938
10022
  versions: [
9939
10023
  {
9940
- range: ">=8.0.0",
9941
- coverage: 0.6,
9942
- note: "identical surface to rive-react-native \u2014 the new official package is just a rename. shares the same noop stub",
9943
- missing: "same as rive-react-native \u2014 no .riv runtime"
10024
+ range: ">=0.4.19 <0.5.0",
10025
+ coverage: 0,
10026
+ note: "native seam: the published Nitro package JavaScript and hooks run unchanged. Rive canvas-advanced uses its C++ WASM core on the host for file parsing, artboard and view model metadata, instance creation, and async scalar data binding. The native view lays out and reports ready; rendering is not built. No visual or playback behavior credit is claimed.",
10027
+ working: "useRiveFile URL, file URL, and byte loading; artboard names/counts; async view model lookup and instance creation; async scalar reads/writes; RiveRuntime initialization; HybridView ref and readiness",
10028
+ missing: "Rive rendering and playback; RiveImage decoding; view binding and state machine inputs/events; referenced asset overrides; nested, trigger, list, image, and artboard binding; synchronous view model operations and scalar reads; instance names; UIKit fallback fonts"
10029
+ }
10030
+ ]
10031
+ },
10032
+ "@fingerprintjs/fingerprintjs-pro-react-native": {
10033
+ category: "Device & Platform",
10034
+ stubType: "native",
10035
+ versions: [
10036
+ {
10037
+ range: ">=3.17.1 <4.0.0",
10038
+ coverage: 0,
10039
+ note: "native seam only: upstream agent, provider, hooks, and error conversion run unchanged. RNFingerprintjsPro is present and identification calls reject with an explicit UnknownError because the native SDK is unavailable. No visitor identity or identification behavior is claimed.",
10040
+ missing: "FingerprintPro native device signal collection, API transport, visitor identities, extended and sealed responses, and location collection"
9944
10041
  }
9945
10042
  ]
9946
10043
  },
@@ -14375,9 +14472,9 @@ var init_registry = __esm({
14375
14472
  {
14376
14473
  range: ">=0.1.0",
14377
14474
  coverage: 0,
14378
- note: "getVideoDuration() resolves a hardcoded 0 instead of probing the asset",
14379
- working: "nothing \u2014 getVideoDuration() resolves a hardcoded 0",
14380
- missing: "no real AVFoundation duration probe in the simulator"
14475
+ note: "native-seam only: upstream JavaScript reads iOS duration in seconds from real MP4 container metadata; shared parser with expo-video-metadata",
14476
+ working: "iOS getVideoDuration for readable local VFS and HTTP MP4 assets; missing, invalid and unreachable sources resolve zero; published 0.1.2 API exercised",
14477
+ missing: "Android VideoDurationModule, non-MP4 media formats, streaming duration, and native iOS paired evidence"
14381
14478
  }
14382
14479
  ]
14383
14480
  },
@@ -19324,9 +19421,9 @@ function safeChildPlistName(value) {
19324
19421
  name: file.toLowerCase().endsWith(".plist") ? file : `${file}.plist`
19325
19422
  };
19326
19423
  }
19327
- async function readableSettingsBundle(path21) {
19424
+ async function readableSettingsBundle(path22) {
19328
19425
  try {
19329
- const root = await (0, import_promises.stat)((0, import_node_path.join)(path21, "Root.plist"));
19426
+ const root = await (0, import_promises.stat)((0, import_node_path.join)(path22, "Root.plist"));
19330
19427
  return root.isFile() && root.size <= MAX_PLIST_BYTES;
19331
19428
  } catch {
19332
19429
  return false;
@@ -19371,11 +19468,11 @@ async function settingsBundleFingerprint(bundlePath) {
19371
19468
  return null;
19372
19469
  }
19373
19470
  }
19374
- async function parsePlistRecord(path21) {
19471
+ async function parsePlistRecord(path22) {
19375
19472
  try {
19376
- const metadata = await (0, import_promises.stat)(path21);
19473
+ const metadata = await (0, import_promises.stat)(path22);
19377
19474
  if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;
19378
- const source = await (0, import_promises.readFile)(path21, "utf8");
19475
+ const source = await (0, import_promises.readFile)(path22, "utf8");
19379
19476
  const parsed = parsePlistSource(source);
19380
19477
  return isRecord2(parsed) ? parsed : null;
19381
19478
  } catch {
@@ -19699,7 +19796,7 @@ async function tcpPing(port, timeout = TCP_GATE_MS) {
19699
19796
  return null;
19700
19797
  }
19701
19798
  }
19702
- function httpGet(hostname, port, path21, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
19799
+ function httpGet(hostname, port, path22, method = "GET", timeout = TIMEOUT_MS, headers = {}) {
19703
19800
  return new Promise((resolve9) => {
19704
19801
  let settled = false;
19705
19802
  let killing = false;
@@ -19708,7 +19805,7 @@ function httpGet(hostname, port, path21, method = "GET", timeout = TIMEOUT_MS, h
19708
19805
  settled = true;
19709
19806
  resolve9(value);
19710
19807
  };
19711
- const req = import_http.default.request({ hostname, port, path: path21, method, headers }, (res) => {
19808
+ const req = import_http.default.request({ hostname, port, path: path22, method, headers }, (res) => {
19712
19809
  let body = "";
19713
19810
  res.on("data", (c) => body += c.toString());
19714
19811
  const contentType = (() => {
@@ -20357,59 +20454,6 @@ var init_dev_server_scanner = __esm({
20357
20454
  }
20358
20455
  });
20359
20456
 
20360
- // src/public-brand.ts
20361
- var name, peachPublicBrand, rnxPublicBrand;
20362
- var init_public_brand = __esm({
20363
- "src/public-brand.ts"() {
20364
- "use strict";
20365
- name = "Peach";
20366
- peachPublicBrand = Object.freeze({
20367
- name,
20368
- packageName: "peachsim",
20369
- commandName: "peach",
20370
- domain: "peachsim.com",
20371
- origin: "https://peachsim.com"
20372
- });
20373
- rnxPublicBrand = peachPublicBrand;
20374
- }
20375
- });
20376
-
20377
- // src/cli-version.ts
20378
- function getCliVersion() {
20379
- if (cached2 != null) return cached2;
20380
- if (typeof __PEACH_CLI_VERSION__ !== "undefined" && typeof __PEACH_CLI_VERSION__ === "string" && __PEACH_CLI_VERSION__) {
20381
- cached2 = __PEACH_CLI_VERSION__;
20382
- return cached2;
20383
- }
20384
- const candidates = [
20385
- () => (0, import_node_url2.fileURLToPath)(import_meta.resolve(`${rnxPublicBrand.packageName}/package.json`)),
20386
- () => (0, import_node_url2.fileURLToPath)(new URL("../package.json", __sootsim_import_meta_url))
20387
- ];
20388
- for (const resolve9 of candidates) {
20389
- try {
20390
- const version = JSON.parse((0, import_node_fs3.readFileSync)(resolve9(), "utf8")).version;
20391
- if (typeof version === "string" && version) {
20392
- cached2 = version;
20393
- return cached2;
20394
- }
20395
- } catch {
20396
- }
20397
- }
20398
- cached2 = "0.0.0";
20399
- return cached2;
20400
- }
20401
- var import_node_fs3, import_node_url2, import_meta, cached2;
20402
- var init_cli_version = __esm({
20403
- "src/cli-version.ts"() {
20404
- "use strict";
20405
- import_node_fs3 = require("node:fs");
20406
- import_node_url2 = require("node:url");
20407
- init_public_brand();
20408
- import_meta = {};
20409
- cached2 = null;
20410
- }
20411
- });
20412
-
20413
20457
  // src/home-paths.ts
20414
20458
  var home_paths_exports = {};
20415
20459
  __export(home_paths_exports, {
@@ -20482,7 +20526,7 @@ function isSootsimDevCheckout() {
20482
20526
  const argv1 = process.argv[1];
20483
20527
  if (!argv1) return false;
20484
20528
  try {
20485
- const real = import_node_fs4.default.realpathSync(argv1);
20529
+ const real = import_node_fs3.default.realpathSync(argv1);
20486
20530
  return real.includes(`${import_node_path4.default.sep}packages${import_node_path4.default.sep}peachsim${import_node_path4.default.sep}`);
20487
20531
  } catch {
20488
20532
  return false;
@@ -20551,7 +20595,7 @@ function cliUpdateFilePath() {
20551
20595
  }
20552
20596
  function readSharedConfig() {
20553
20597
  try {
20554
- const raw = import_node_fs4.default.readFileSync(configFilePath(), "utf8");
20598
+ const raw = import_node_fs3.default.readFileSync(configFilePath(), "utf8");
20555
20599
  const parsed = JSON.parse(raw);
20556
20600
  return parsed && typeof parsed === "object" ? parsed : {};
20557
20601
  } catch {
@@ -20569,9 +20613,9 @@ function writeSharedConfig(patch) {
20569
20613
  };
20570
20614
  }
20571
20615
  const tmp = `${configFilePath()}.tmp`;
20572
- import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
20616
+ import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
20573
20617
  `, "utf8");
20574
- import_node_fs4.default.renameSync(tmp, configFilePath());
20618
+ import_node_fs3.default.renameSync(tmp, configFilePath());
20575
20619
  return next;
20576
20620
  }
20577
20621
  function isOnboardingComplete() {
@@ -20594,7 +20638,7 @@ function readPrivacyPreferences() {
20594
20638
  return {
20595
20639
  productAnalytics: typeof productAnalytics === "boolean" ? productAnalytics : false,
20596
20640
  crashReports: typeof crashReports === "boolean" ? crashReports : false,
20597
- configured: typeof productAnalytics === "boolean" && typeof crashReports === "boolean"
20641
+ configured: typeof productAnalytics === "boolean"
20598
20642
  };
20599
20643
  }
20600
20644
  function writePrivacyPreferences(preferences) {
@@ -20606,10 +20650,13 @@ function writePrivacyPreferences(preferences) {
20606
20650
  });
20607
20651
  }
20608
20652
  function readOrCreateAnonymousId() {
20609
- const existing = readSharedConfig().anonymousId;
20610
- if (typeof existing === "string" && existing.trim()) return existing;
20653
+ const existing = readSharedConfig().settings?.anonymousId;
20654
+ if (typeof existing === "string" && /^anon-cli-[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(
20655
+ existing
20656
+ ))
20657
+ return existing;
20611
20658
  const created = `anon-cli-${(0, import_node_crypto.randomUUID)()}`;
20612
- writeSharedConfig({ anonymousId: created });
20659
+ writeSharedConfig({ settings: { anonymousId: created } });
20613
20660
  return created;
20614
20661
  }
20615
20662
  function readDefaultBox() {
@@ -20630,14 +20677,14 @@ function runtimeUpgradeNoticePath() {
20630
20677
  function writeRuntimeUpgradeNotice(notice) {
20631
20678
  ensureRnxHome();
20632
20679
  const tmp = `${runtimeUpgradeNoticePath()}.tmp`;
20633
- import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(notice)}
20680
+ import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(notice)}
20634
20681
  `, "utf8");
20635
- import_node_fs4.default.renameSync(tmp, runtimeUpgradeNoticePath());
20682
+ import_node_fs3.default.renameSync(tmp, runtimeUpgradeNoticePath());
20636
20683
  }
20637
20684
  function consumeRuntimeUpgradeNotice() {
20638
20685
  try {
20639
- const raw = import_node_fs4.default.readFileSync(runtimeUpgradeNoticePath(), "utf8");
20640
- import_node_fs4.default.unlinkSync(runtimeUpgradeNoticePath());
20686
+ const raw = import_node_fs3.default.readFileSync(runtimeUpgradeNoticePath(), "utf8");
20687
+ import_node_fs3.default.unlinkSync(runtimeUpgradeNoticePath());
20641
20688
  const parsed = JSON.parse(raw);
20642
20689
  if (typeof parsed?.to !== "string" || !parsed.to) return null;
20643
20690
  return {
@@ -20650,23 +20697,23 @@ function consumeRuntimeUpgradeNotice() {
20650
20697
  }
20651
20698
  }
20652
20699
  function ensureRnxHome() {
20653
- import_node_fs4.default.mkdirSync(rnxHomeDir(), { recursive: true });
20654
- import_node_fs4.default.mkdirSync(runtimesDir(), { recursive: true });
20655
- import_node_fs4.default.mkdirSync(electronDir(), { recursive: true });
20656
- import_node_fs4.default.mkdirSync(profilesDir(), { recursive: true });
20657
- import_node_fs4.default.mkdirSync(cacheDir(), { recursive: true });
20700
+ import_node_fs3.default.mkdirSync(rnxHomeDir(), { recursive: true });
20701
+ import_node_fs3.default.mkdirSync(runtimesDir(), { recursive: true });
20702
+ import_node_fs3.default.mkdirSync(electronDir(), { recursive: true });
20703
+ import_node_fs3.default.mkdirSync(profilesDir(), { recursive: true });
20704
+ import_node_fs3.default.mkdirSync(cacheDir(), { recursive: true });
20658
20705
  }
20659
20706
  function readActiveRuntime() {
20660
20707
  try {
20661
- const value = import_node_fs4.default.readFileSync(activeRuntimeFile(), "utf8").trim();
20708
+ const value = import_node_fs3.default.readFileSync(activeRuntimeFile(), "utf8").trim();
20662
20709
  return value.length > 0 ? value : null;
20663
20710
  } catch {
20664
20711
  return null;
20665
20712
  }
20666
20713
  }
20667
20714
  function writeActiveRuntime(version) {
20668
- import_node_fs4.default.mkdirSync(runtimesDir(), { recursive: true });
20669
- import_node_fs4.default.writeFileSync(activeRuntimeFile(), `${version}
20715
+ import_node_fs3.default.mkdirSync(runtimesDir(), { recursive: true });
20716
+ import_node_fs3.default.writeFileSync(activeRuntimeFile(), `${version}
20670
20717
  `, "utf8");
20671
20718
  }
20672
20719
  function activeRuntimeDir() {
@@ -20674,17 +20721,17 @@ function activeRuntimeDir() {
20674
20721
  if (!version) return null;
20675
20722
  const dir = runtimeDir(version);
20676
20723
  try {
20677
- if (import_node_fs4.default.statSync(dir).isDirectory()) return dir;
20724
+ if (import_node_fs3.default.statSync(dir).isDirectory()) return dir;
20678
20725
  } catch {
20679
20726
  }
20680
20727
  return null;
20681
20728
  }
20682
20729
  function readDaemonLockfile() {
20683
20730
  try {
20684
- const fd = import_node_fs4.default.openSync(daemonLockfilePath(), "r");
20731
+ const fd = import_node_fs3.default.openSync(daemonLockfilePath(), "r");
20685
20732
  try {
20686
20733
  const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
20687
- const bytesRead = import_node_fs4.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
20734
+ const bytesRead = import_node_fs3.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
20688
20735
  const raw = buf.subarray(0, bytesRead).toString("utf8");
20689
20736
  const parsed = JSON.parse(raw);
20690
20737
  if (parsed && parsed.schema === 1 && typeof parsed.pid === "number" && typeof parsed.bridgePort === "number" && typeof parsed.runtimePort === "number" && typeof parsed.startedAt === "number" && typeof parsed.heartbeatAt === "number" && (parsed.servedRuntimes === void 0 || Array.isArray(parsed.servedRuntimes) && parsed.servedRuntimes.every((version) => typeof version === "string"))) {
@@ -20692,7 +20739,7 @@ function readDaemonLockfile() {
20692
20739
  }
20693
20740
  return null;
20694
20741
  } finally {
20695
- import_node_fs4.default.closeSync(fd);
20742
+ import_node_fs3.default.closeSync(fd);
20696
20743
  }
20697
20744
  } catch {
20698
20745
  return null;
@@ -20712,7 +20759,7 @@ function parseDevBridgeLockfile(raw) {
20712
20759
  function readDevBridgeLockfiles() {
20713
20760
  let entries;
20714
20761
  try {
20715
- entries = import_node_fs4.default.readdirSync(devBridgesDir(), { withFileTypes: true });
20762
+ entries = import_node_fs3.default.readdirSync(devBridgesDir(), { withFileTypes: true });
20716
20763
  } catch {
20717
20764
  return [];
20718
20765
  }
@@ -20721,10 +20768,10 @@ function readDevBridgeLockfiles() {
20721
20768
  if (!entry.isFile() || !/^\d+\.json$/.test(entry.name)) continue;
20722
20769
  try {
20723
20770
  const filePath = import_node_path4.default.join(devBridgesDir(), entry.name);
20724
- const fd = import_node_fs4.default.openSync(filePath, "r");
20771
+ const fd = import_node_fs3.default.openSync(filePath, "r");
20725
20772
  try {
20726
20773
  const buf = Buffer.alloc(DAEMON_LOCKFILE_MAX_BYTES);
20727
- const bytesRead = import_node_fs4.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
20774
+ const bytesRead = import_node_fs3.default.readSync(fd, buf, 0, DAEMON_LOCKFILE_MAX_BYTES, 0);
20728
20775
  const lockfile = parseDevBridgeLockfile(
20729
20776
  buf.subarray(0, bytesRead).toString("utf8")
20730
20777
  );
@@ -20732,7 +20779,7 @@ function readDevBridgeLockfiles() {
20732
20779
  lockfiles.push(lockfile);
20733
20780
  }
20734
20781
  } finally {
20735
- import_node_fs4.default.closeSync(fd);
20782
+ import_node_fs3.default.closeSync(fd);
20736
20783
  }
20737
20784
  } catch {
20738
20785
  }
@@ -20784,28 +20831,28 @@ function writeDaemonLockfile(data) {
20784
20831
  throw new Error("refusing to overwrite another peach daemon lockfile");
20785
20832
  }
20786
20833
  const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.tmp`;
20787
- import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20834
+ import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20788
20835
  `, "utf8");
20789
20836
  try {
20790
20837
  const current = readDaemonLockfile();
20791
20838
  if (!current || !sameDaemonOwner(current, data)) {
20792
20839
  throw new Error("peach daemon lock ownership changed during heartbeat");
20793
20840
  }
20794
- import_node_fs4.default.renameSync(tmp, lockfilePath);
20841
+ import_node_fs3.default.renameSync(tmp, lockfilePath);
20795
20842
  } finally {
20796
20843
  try {
20797
- import_node_fs4.default.unlinkSync(tmp);
20844
+ import_node_fs3.default.unlinkSync(tmp);
20798
20845
  } catch {
20799
20846
  }
20800
20847
  }
20801
20848
  }
20802
20849
  function writeDevBridgeLockfile(data) {
20803
- import_node_fs4.default.mkdirSync(devBridgesDir(), { recursive: true });
20850
+ import_node_fs3.default.mkdirSync(devBridgesDir(), { recursive: true });
20804
20851
  const lockfilePath = devBridgeLockfilePath(data.bridgePort);
20805
20852
  const tmp = `${lockfilePath}.${data.pid}.tmp`;
20806
- import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20853
+ import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20807
20854
  `, "utf8");
20808
- import_node_fs4.default.renameSync(tmp, lockfilePath);
20855
+ import_node_fs3.default.renameSync(tmp, lockfilePath);
20809
20856
  }
20810
20857
  function sameDaemonOwner(left, right) {
20811
20858
  return left.pid === right.pid && left.startedAt === right.startedAt;
@@ -20816,17 +20863,17 @@ function isAlreadyExists(error) {
20816
20863
  function createDaemonLockfileExclusive(data) {
20817
20864
  const lockfilePath = daemonLockfilePath();
20818
20865
  const tmp = `${lockfilePath}.${data.pid}.${(0, import_node_crypto.randomUUID)()}.claim`;
20819
- import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20866
+ import_node_fs3.default.writeFileSync(tmp, `${JSON.stringify(data, null, 2)}
20820
20867
  `, "utf8");
20821
20868
  try {
20822
- import_node_fs4.default.linkSync(tmp, lockfilePath);
20869
+ import_node_fs3.default.linkSync(tmp, lockfilePath);
20823
20870
  return true;
20824
20871
  } catch (error) {
20825
20872
  if (isAlreadyExists(error)) return false;
20826
20873
  throw error;
20827
20874
  } finally {
20828
20875
  try {
20829
- import_node_fs4.default.unlinkSync(tmp);
20876
+ import_node_fs3.default.unlinkSync(tmp);
20830
20877
  } catch {
20831
20878
  }
20832
20879
  }
@@ -20850,7 +20897,7 @@ function parseDaemonClaim(raw) {
20850
20897
  }
20851
20898
  function readDaemonClaim() {
20852
20899
  try {
20853
- return parseDaemonClaim(import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8"));
20900
+ return parseDaemonClaim(import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8"));
20854
20901
  } catch {
20855
20902
  return null;
20856
20903
  }
@@ -20874,7 +20921,7 @@ function acquireDaemonClaim(data) {
20874
20921
  `;
20875
20922
  for (let attempt = 0; attempt < 8; attempt++) {
20876
20923
  try {
20877
- import_node_fs4.default.writeFileSync(daemonClaimPath(), serialized, { encoding: "utf8", flag: "wx" });
20924
+ import_node_fs3.default.writeFileSync(daemonClaimPath(), serialized, { encoding: "utf8", flag: "wx" });
20878
20925
  return true;
20879
20926
  } catch (error) {
20880
20927
  if (!isAlreadyExists(error)) throw error;
@@ -20884,11 +20931,11 @@ function acquireDaemonClaim(data) {
20884
20931
  if (existing && isDaemonClaimFresh(existing)) return false;
20885
20932
  let before;
20886
20933
  try {
20887
- before = import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8");
20934
+ before = import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8");
20888
20935
  const latest = parseDaemonClaim(before);
20889
20936
  if (latest && isDaemonClaimFresh(latest)) return false;
20890
- if (import_node_fs4.default.readFileSync(daemonClaimPath(), "utf8") !== before) continue;
20891
- import_node_fs4.default.unlinkSync(daemonClaimPath());
20937
+ if (import_node_fs3.default.readFileSync(daemonClaimPath(), "utf8") !== before) continue;
20938
+ import_node_fs3.default.unlinkSync(daemonClaimPath());
20892
20939
  } catch {
20893
20940
  }
20894
20941
  }
@@ -20898,7 +20945,7 @@ function releaseDaemonClaim(owner) {
20898
20945
  try {
20899
20946
  const claim = readDaemonClaim();
20900
20947
  if (!claim || !sameDaemonOwner(claim, owner)) return;
20901
- import_node_fs4.default.unlinkSync(daemonClaimPath());
20948
+ import_node_fs3.default.unlinkSync(daemonClaimPath());
20902
20949
  } catch {
20903
20950
  }
20904
20951
  }
@@ -20917,7 +20964,7 @@ function claimDaemonLockfile(data) {
20917
20964
  if (!latest || !sameDaemonOwner(latest, existing)) return false;
20918
20965
  if (isDaemonLockfileFresh(latest)) return false;
20919
20966
  try {
20920
- import_node_fs4.default.unlinkSync(daemonLockfilePath());
20967
+ import_node_fs3.default.unlinkSync(daemonLockfilePath());
20921
20968
  } catch {
20922
20969
  return false;
20923
20970
  }
@@ -20931,25 +20978,25 @@ function removeDaemonLockfile(owner) {
20931
20978
  try {
20932
20979
  const lockfile = readDaemonLockfile();
20933
20980
  if (!lockfile || !sameDaemonOwner(lockfile, owner)) return;
20934
- import_node_fs4.default.unlinkSync(daemonLockfilePath());
20981
+ import_node_fs3.default.unlinkSync(daemonLockfilePath());
20935
20982
  } catch {
20936
20983
  }
20937
20984
  }
20938
20985
  function removeDevBridgeLockfile(owner) {
20939
20986
  try {
20940
20987
  const lockfilePath = devBridgeLockfilePath(owner.bridgePort);
20941
- const lockfile = parseDevBridgeLockfile(import_node_fs4.default.readFileSync(lockfilePath, "utf8"));
20988
+ const lockfile = parseDevBridgeLockfile(import_node_fs3.default.readFileSync(lockfilePath, "utf8"));
20942
20989
  if (lockfile?.pid !== owner.pid || lockfile.startedAt !== owner.startedAt) return;
20943
- import_node_fs4.default.unlinkSync(lockfilePath);
20990
+ import_node_fs3.default.unlinkSync(lockfilePath);
20944
20991
  } catch {
20945
20992
  }
20946
20993
  }
20947
- var import_node_crypto, import_node_fs4, import_node_os, import_node_path4, PEACH_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, CLI_UPDATE_FILE, DAEMON_HEARTBEAT_STALE_MS, CURRENT_ONBOARDING_VERSION, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
20994
+ var import_node_crypto, import_node_fs3, import_node_os, import_node_path4, PEACH_HOME_ENV, ACTIVE_RUNTIME_FILE, DAEMON_LOCKFILE, DEV_BRIDGES_DIR, CONFIG_FILE, CLI_UPDATE_FILE, DAEMON_HEARTBEAT_STALE_MS, CURRENT_ONBOARDING_VERSION, DAEMON_LOCKFILE_MAX_BYTES, DAEMON_CLAIM_STALE_MS;
20948
20995
  var init_home_paths = __esm({
20949
20996
  "src/home-paths.ts"() {
20950
20997
  "use strict";
20951
20998
  import_node_crypto = require("node:crypto");
20952
- import_node_fs4 = __toESM(require("node:fs"), 1);
20999
+ import_node_fs3 = __toESM(require("node:fs"), 1);
20953
21000
  import_node_os = require("node:os");
20954
21001
  import_node_path4 = __toESM(require("node:path"), 1);
20955
21002
  PEACH_HOME_ENV = "PEACH_HOME";
@@ -20965,19 +21012,87 @@ var init_home_paths = __esm({
20965
21012
  }
20966
21013
  });
20967
21014
 
21015
+ // src/automatic-update-policy.ts
21016
+ function automaticPeachUpdatesEnabled(env = process.env) {
21017
+ const value = env.PEACH_UPDATE_CHECK?.toLowerCase();
21018
+ return value !== "0" && value !== "false" && value !== "off" && !(0, import_node_fs4.existsSync)((0, import_node_path5.join)(rnxHomeDir(), "runtime-update-disabled"));
21019
+ }
21020
+ var import_node_fs4, import_node_path5;
21021
+ var init_automatic_update_policy = __esm({
21022
+ "src/automatic-update-policy.ts"() {
21023
+ "use strict";
21024
+ import_node_fs4 = require("node:fs");
21025
+ import_node_path5 = require("node:path");
21026
+ init_home_paths();
21027
+ }
21028
+ });
21029
+
21030
+ // src/public-brand.ts
21031
+ var name, peachPublicBrand, rnxPublicBrand;
21032
+ var init_public_brand = __esm({
21033
+ "src/public-brand.ts"() {
21034
+ "use strict";
21035
+ name = "Peach";
21036
+ peachPublicBrand = Object.freeze({
21037
+ name,
21038
+ packageName: "peachsim",
21039
+ commandName: "peach",
21040
+ domain: "peachsim.com",
21041
+ origin: "https://peachsim.com"
21042
+ });
21043
+ rnxPublicBrand = peachPublicBrand;
21044
+ }
21045
+ });
21046
+
21047
+ // src/cli-version.ts
21048
+ function getCliVersion() {
21049
+ if (cached2 != null) return cached2;
21050
+ if (typeof __PEACH_CLI_VERSION__ !== "undefined" && typeof __PEACH_CLI_VERSION__ === "string" && __PEACH_CLI_VERSION__) {
21051
+ cached2 = __PEACH_CLI_VERSION__;
21052
+ return cached2;
21053
+ }
21054
+ const candidates = [
21055
+ () => (0, import_node_url2.fileURLToPath)(import_meta.resolve(`${rnxPublicBrand.packageName}/package.json`)),
21056
+ () => (0, import_node_url2.fileURLToPath)(new URL("../package.json", __sootsim_import_meta_url))
21057
+ ];
21058
+ for (const resolve9 of candidates) {
21059
+ try {
21060
+ const version = JSON.parse((0, import_node_fs5.readFileSync)(resolve9(), "utf8")).version;
21061
+ if (typeof version === "string" && version) {
21062
+ cached2 = version;
21063
+ return cached2;
21064
+ }
21065
+ } catch {
21066
+ }
21067
+ }
21068
+ cached2 = "0.0.0";
21069
+ return cached2;
21070
+ }
21071
+ var import_node_fs5, import_node_url2, import_meta, cached2;
21072
+ var init_cli_version = __esm({
21073
+ "src/cli-version.ts"() {
21074
+ "use strict";
21075
+ import_node_fs5 = require("node:fs");
21076
+ import_node_url2 = require("node:url");
21077
+ init_public_brand();
21078
+ import_meta = {};
21079
+ cached2 = null;
21080
+ }
21081
+ });
21082
+
20968
21083
  // ../contrast-runtime-delivery/src/product.ts
20969
21084
  function isValidRuntimeVersion(value) {
20970
21085
  return value.length <= 100 && /^[0-9A-Za-z][0-9A-Za-z._+-]*$/.test(value);
20971
21086
  }
20972
21087
  function listInstalledRuntimes(product) {
20973
21088
  try {
20974
- return import_node_fs5.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
21089
+ return import_node_fs6.default.readdirSync(product.runtimesDir(), { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort(compareSemver);
20975
21090
  } catch {
20976
21091
  return [];
20977
21092
  }
20978
21093
  }
20979
21094
  function runtimeTarballCacheName(product, version) {
20980
- return import_node_path5.default.posix.basename(product.tarballPath(version));
21095
+ return import_node_path6.default.posix.basename(product.tarballPath(version));
20981
21096
  }
20982
21097
  function compareSemver(a, b) {
20983
21098
  const parse2 = (v) => {
@@ -21000,12 +21115,12 @@ function compareSemver(a, b) {
21000
21115
  if (!bp) return -1;
21001
21116
  return ap < bp ? -1 : 1;
21002
21117
  }
21003
- var import_node_fs5, import_node_path5;
21118
+ var import_node_fs6, import_node_path6;
21004
21119
  var init_product = __esm({
21005
21120
  "../contrast-runtime-delivery/src/product.ts"() {
21006
21121
  "use strict";
21007
- import_node_fs5 = __toESM(require("node:fs"), 1);
21008
- import_node_path5 = __toESM(require("node:path"), 1);
21122
+ import_node_fs6 = __toESM(require("node:fs"), 1);
21123
+ import_node_path6 = __toESM(require("node:path"), 1);
21009
21124
  }
21010
21125
  });
21011
21126
 
@@ -21014,7 +21129,7 @@ function createRuntimeDelivery(product) {
21014
21129
  function readConfig() {
21015
21130
  try {
21016
21131
  const parsed = JSON.parse(
21017
- import_node_fs6.default.readFileSync(product.configFile(), "utf8")
21132
+ import_node_fs7.default.readFileSync(product.configFile(), "utf8")
21018
21133
  );
21019
21134
  return parsed && typeof parsed === "object" ? parsed : {};
21020
21135
  } catch {
@@ -21087,7 +21202,7 @@ function createRuntimeDelivery(product) {
21087
21202
  const setActive = opts.setActive !== false;
21088
21203
  const protectVersions = [version, ...opts.protectVersions ?? []];
21089
21204
  pruneLocalRetention({ protectVersions });
21090
- if (!opts.force && import_node_fs6.default.existsSync(import_node_path6.default.join(destDir, product.installedMarker))) {
21205
+ if (!opts.force && import_node_fs7.default.existsSync(import_node_path7.default.join(destDir, product.installedMarker))) {
21091
21206
  if (setActive) product.writeActiveRuntime(version);
21092
21207
  pruneLocalRetention({ protectVersions });
21093
21208
  return {
@@ -21101,18 +21216,18 @@ function createRuntimeDelivery(product) {
21101
21216
  };
21102
21217
  }
21103
21218
  const tarUrl = entry.tarball || tarballUrl(version, cdnOrigin);
21104
- const downloadDir = import_node_fs6.default.mkdtempSync(
21105
- import_node_path6.default.join(import_node_os2.default.tmpdir(), `${product.id}-runtime-download-`)
21219
+ const downloadDir = import_node_fs7.default.mkdtempSync(
21220
+ import_node_path7.default.join(import_node_os2.default.tmpdir(), `${product.id}-runtime-download-`)
21106
21221
  );
21107
- const runtimeArchivePath = import_node_path6.default.join(
21222
+ const runtimeArchivePath = import_node_path7.default.join(
21108
21223
  downloadDir,
21109
21224
  runtimeTarballCacheName(product, version)
21110
21225
  );
21111
- const tmpDir = import_node_path6.default.join(
21112
- import_node_path6.default.dirname(destDir),
21226
+ const tmpDir = import_node_path7.default.join(
21227
+ import_node_path7.default.dirname(destDir),
21113
21228
  `.installing-${version}-${process.pid}`
21114
21229
  );
21115
- import_node_fs6.default.rmSync(tmpDir, { recursive: true, force: true });
21230
+ import_node_fs7.default.rmSync(tmpDir, { recursive: true, force: true });
21116
21231
  try {
21117
21232
  if (!opts.quiet)
21118
21233
  process.stderr.write(`${product.id}: downloading runtime ${version}\u2026
@@ -21127,20 +21242,20 @@ function createRuntimeDelivery(product) {
21127
21242
  `sha256 mismatch for runtime ${version}: expected ${entry.sha256}, actual ${actualSha}`
21128
21243
  );
21129
21244
  }
21130
- import_node_fs6.default.mkdirSync(tmpDir, { recursive: true });
21245
+ import_node_fs7.default.mkdirSync(tmpDir, { recursive: true });
21131
21246
  await extractTarball(runtimeArchivePath, tmpDir);
21132
- if (!import_node_fs6.default.existsSync(import_node_path6.default.join(tmpDir, product.installedMarker))) {
21247
+ if (!import_node_fs7.default.existsSync(import_node_path7.default.join(tmpDir, product.installedMarker))) {
21133
21248
  throw new Error(
21134
21249
  `extracted tarball for runtime ${version} is missing ${product.installedMarker}`
21135
21250
  );
21136
21251
  }
21137
- import_node_fs6.default.rmSync(destDir, { recursive: true, force: true });
21138
- import_node_fs6.default.renameSync(tmpDir, destDir);
21252
+ import_node_fs7.default.rmSync(destDir, { recursive: true, force: true });
21253
+ import_node_fs7.default.renameSync(tmpDir, destDir);
21139
21254
  } catch (err) {
21140
- import_node_fs6.default.rmSync(tmpDir, { recursive: true, force: true });
21255
+ import_node_fs7.default.rmSync(tmpDir, { recursive: true, force: true });
21141
21256
  throw err;
21142
21257
  } finally {
21143
- import_node_fs6.default.rmSync(downloadDir, { recursive: true, force: true });
21258
+ import_node_fs7.default.rmSync(downloadDir, { recursive: true, force: true });
21144
21259
  }
21145
21260
  if (setActive) product.writeActiveRuntime(version);
21146
21261
  pruneLocalRetention({ protectVersions });
@@ -21162,8 +21277,8 @@ function createRuntimeDelivery(product) {
21162
21277
  const pin = resolvePin();
21163
21278
  if (pin) {
21164
21279
  const activeVersion2 = product.readActiveRuntime();
21165
- const pinInstalled = import_node_fs6.default.existsSync(
21166
- import_node_path6.default.join(product.runtimeDir(pin), product.installedMarker)
21280
+ const pinInstalled = import_node_fs7.default.existsSync(
21281
+ import_node_path7.default.join(product.runtimeDir(pin), product.installedMarker)
21167
21282
  );
21168
21283
  if (activeVersion2 === pin && pinInstalled) {
21169
21284
  return {
@@ -21212,7 +21327,7 @@ function createRuntimeDelivery(product) {
21212
21327
  }
21213
21328
  const activeVersion = product.readActiveRuntime();
21214
21329
  const activeDir = activeVersion ? product.runtimeDir(activeVersion) : null;
21215
- const activeInstalled = activeDir ? import_node_fs6.default.existsSync(import_node_path6.default.join(activeDir, product.installedMarker)) : false;
21330
+ const activeInstalled = activeDir ? import_node_fs7.default.existsSync(import_node_path7.default.join(activeDir, product.installedMarker)) : false;
21216
21331
  const shouldInstall = !activeVersion || !activeInstalled || compareSemver(latestVersion, activeVersion) > 0;
21217
21332
  if (!shouldInstall) {
21218
21333
  return {
@@ -21287,12 +21402,12 @@ function createRuntimeDelivery(product) {
21287
21402
  let removeCacheFiles = [];
21288
21403
  if (markerOffset >= 0) {
21289
21404
  try {
21290
- removeCacheFiles = import_node_fs6.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
21405
+ removeCacheFiles = import_node_fs7.default.readdirSync(product.cacheDir(), { withFileTypes: true }).filter((entry) => {
21291
21406
  if (!entry.isFile()) return false;
21292
21407
  const complete = entry.name.startsWith(cachePrefix) && entry.name.endsWith(cacheSuffix);
21293
21408
  const partial = entry.name.startsWith(cachePrefix) && entry.name.endsWith(`${cacheSuffix}.partial`);
21294
21409
  return complete || partial;
21295
- }).map((entry) => import_node_path6.default.join(product.cacheDir(), entry.name)).sort();
21410
+ }).map((entry) => import_node_path7.default.join(product.cacheDir(), entry.name)).sort();
21296
21411
  } catch {
21297
21412
  }
21298
21413
  }
@@ -21307,10 +21422,10 @@ function createRuntimeDelivery(product) {
21307
21422
  function pruneLocalRetention(opts = {}) {
21308
21423
  const plan = planLocalRetention(opts);
21309
21424
  for (const version of plan.removeVersions) {
21310
- import_node_fs6.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
21425
+ import_node_fs7.default.rmSync(product.runtimeDir(version), { recursive: true, force: true });
21311
21426
  }
21312
21427
  for (const cacheFile of plan.removeCacheFiles) {
21313
- import_node_fs6.default.rmSync(cacheFile, { force: true });
21428
+ import_node_fs7.default.rmSync(cacheFile, { force: true });
21314
21429
  }
21315
21430
  return plan;
21316
21431
  }
@@ -21336,17 +21451,17 @@ async function downloadToFile(url, destPath) {
21336
21451
  if (!res.ok || !res.body) {
21337
21452
  throw new Error(`download failed: ${res.status} ${res.statusText} (${url})`);
21338
21453
  }
21339
- import_node_fs6.default.mkdirSync(import_node_path6.default.dirname(destPath), { recursive: true });
21454
+ import_node_fs7.default.mkdirSync(import_node_path7.default.dirname(destPath), { recursive: true });
21340
21455
  const tmp = `${destPath}.partial`;
21341
21456
  try {
21342
21457
  await (0, import_promises3.pipeline)(
21343
21458
  import_node_stream.Readable.fromWeb(res.body),
21344
- import_node_fs6.default.createWriteStream(tmp)
21459
+ import_node_fs7.default.createWriteStream(tmp)
21345
21460
  );
21346
- import_node_fs6.default.renameSync(tmp, destPath);
21461
+ import_node_fs7.default.renameSync(tmp, destPath);
21347
21462
  } catch (err) {
21348
21463
  try {
21349
- import_node_fs6.default.unlinkSync(tmp);
21464
+ import_node_fs7.default.unlinkSync(tmp);
21350
21465
  } catch {
21351
21466
  }
21352
21467
  throw err;
@@ -21355,7 +21470,7 @@ async function downloadToFile(url, destPath) {
21355
21470
  function sha256File(filePath) {
21356
21471
  return new Promise((resolve9, reject) => {
21357
21472
  const hash = import_node_crypto2.default.createHash("sha256");
21358
- const stream = import_node_fs6.default.createReadStream(filePath);
21473
+ const stream = import_node_fs7.default.createReadStream(filePath);
21359
21474
  stream.on("data", (chunk) => hash.update(chunk));
21360
21475
  stream.on("error", reject);
21361
21476
  stream.on("end", () => resolve9(hash.digest("hex")));
@@ -21373,15 +21488,15 @@ function extractTarball(tarPath, destDir) {
21373
21488
  });
21374
21489
  });
21375
21490
  }
21376
- var import_node_child_process3, import_node_crypto2, import_node_fs6, import_node_os2, import_node_path6, import_node_stream, import_promises3, DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT;
21491
+ var import_node_child_process3, import_node_crypto2, import_node_fs7, import_node_os2, import_node_path7, import_node_stream, import_promises3, DEFAULT_LOCAL_RUNTIME_RETENTION_COUNT;
21377
21492
  var init_src = __esm({
21378
21493
  "../contrast-runtime-delivery/src/index.ts"() {
21379
21494
  "use strict";
21380
21495
  import_node_child_process3 = require("node:child_process");
21381
21496
  import_node_crypto2 = __toESM(require("node:crypto"), 1);
21382
- import_node_fs6 = __toESM(require("node:fs"), 1);
21497
+ import_node_fs7 = __toESM(require("node:fs"), 1);
21383
21498
  import_node_os2 = __toESM(require("node:os"), 1);
21384
- import_node_path6 = __toESM(require("node:path"), 1);
21499
+ import_node_path7 = __toESM(require("node:path"), 1);
21385
21500
  import_node_stream = require("node:stream");
21386
21501
  import_promises3 = require("node:stream/promises");
21387
21502
  init_product();
@@ -21557,14 +21672,14 @@ var init_standalone = __esm({
21557
21672
  // cli/self-invocation.ts
21558
21673
  function sourceEntryPath() {
21559
21674
  try {
21560
- const candidate = (0, import_node_path7.join)((0, import_node_path7.dirname)((0, import_node_url3.fileURLToPath)(__sootsim_import_meta_url)), "bin.ts");
21561
- return (0, import_node_fs7.existsSync)(candidate) ? candidate : null;
21675
+ const candidate = (0, import_node_path8.join)((0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(__sootsim_import_meta_url)), "bin.ts");
21676
+ return (0, import_node_fs8.existsSync)(candidate) ? candidate : null;
21562
21677
  } catch {
21563
21678
  return null;
21564
21679
  }
21565
21680
  }
21566
- function isCliEntry(path21) {
21567
- const name2 = (0, import_node_path7.basename)(path21);
21681
+ function isCliEntry(path22) {
21682
+ const name2 = (0, import_node_path8.basename)(path22);
21568
21683
  return name2 === "bin.ts" || name2 === "bin.js";
21569
21684
  }
21570
21685
  function rnxSelfInvocation() {
@@ -21582,12 +21697,12 @@ function rnxSelfInvocation() {
21582
21697
  }
21583
21698
  return { executable: process.execPath, prefixArgs: [entry] };
21584
21699
  }
21585
- var import_node_fs7, import_node_path7, import_node_url3;
21700
+ var import_node_fs8, import_node_path8, import_node_url3;
21586
21701
  var init_self_invocation = __esm({
21587
21702
  "cli/self-invocation.ts"() {
21588
21703
  "use strict";
21589
- import_node_fs7 = require("node:fs");
21590
- import_node_path7 = require("node:path");
21704
+ import_node_fs8 = require("node:fs");
21705
+ import_node_path8 = require("node:path");
21591
21706
  import_node_url3 = require("node:url");
21592
21707
  init_public_brand();
21593
21708
  init_standalone();
@@ -21655,7 +21770,7 @@ function getUserDataDir() {
21655
21770
  return userDataDir();
21656
21771
  }
21657
21772
  function storeFile() {
21658
- return import_node_path8.default.join(userDataDir(), "attached-projects.json");
21773
+ return import_node_path9.default.join(userDataDir(), "attached-projects.json");
21659
21774
  }
21660
21775
  function cloneEmpty() {
21661
21776
  return {
@@ -21669,7 +21784,7 @@ function loadStore() {
21669
21784
  const file = storeFile();
21670
21785
  let raw;
21671
21786
  try {
21672
- raw = import_node_fs8.default.readFileSync(file, "utf8");
21787
+ raw = import_node_fs9.default.readFileSync(file, "utf8");
21673
21788
  } catch (err) {
21674
21789
  if (err.code === "ENOENT") return cloneEmpty();
21675
21790
  throw err;
@@ -21686,7 +21801,7 @@ function loadStore() {
21686
21801
  } catch (err) {
21687
21802
  const quarantine = `${file}.corrupt-${Date.now()}`;
21688
21803
  try {
21689
- import_node_fs8.default.renameSync(file, quarantine);
21804
+ import_node_fs9.default.renameSync(file, quarantine);
21690
21805
  console.warn(
21691
21806
  `[sootsim] attached-projects.json was unparseable; quarantined to ${quarantine}. original error: ${err.message}`
21692
21807
  );
@@ -21697,16 +21812,16 @@ function loadStore() {
21697
21812
  }
21698
21813
  function writeStore(store) {
21699
21814
  const file = storeFile();
21700
- import_node_fs8.default.mkdirSync(import_node_path8.default.dirname(file), { recursive: true });
21815
+ import_node_fs9.default.mkdirSync(import_node_path9.default.dirname(file), { recursive: true });
21701
21816
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
21702
- const fd = import_node_fs8.default.openSync(tmp, "w", 384);
21817
+ const fd = import_node_fs9.default.openSync(tmp, "w", 384);
21703
21818
  try {
21704
- import_node_fs8.default.writeFileSync(fd, JSON.stringify(store, null, 2));
21705
- import_node_fs8.default.fsyncSync(fd);
21819
+ import_node_fs9.default.writeFileSync(fd, JSON.stringify(store, null, 2));
21820
+ import_node_fs9.default.fsyncSync(fd);
21706
21821
  } finally {
21707
- import_node_fs8.default.closeSync(fd);
21822
+ import_node_fs9.default.closeSync(fd);
21708
21823
  }
21709
- import_node_fs8.default.renameSync(tmp, file);
21824
+ import_node_fs9.default.renameSync(tmp, file);
21710
21825
  }
21711
21826
  function mutateStore(fn) {
21712
21827
  const store = loadStore();
@@ -21715,13 +21830,13 @@ function mutateStore(fn) {
21715
21830
  return store;
21716
21831
  }
21717
21832
  function projectIdForCwd(cwd) {
21718
- return (0, import_node_crypto3.createHash)("sha256").update(import_node_path8.default.resolve(cwd)).digest("hex").slice(0, 16);
21833
+ return (0, import_node_crypto3.createHash)("sha256").update(import_node_path9.default.resolve(cwd)).digest("hex").slice(0, 16);
21719
21834
  }
21720
21835
  function newSessionId() {
21721
21836
  return `s_${(0, import_node_crypto3.randomBytes)(10).toString("hex")}`;
21722
21837
  }
21723
21838
  function upsertProject(input) {
21724
- const cwd = import_node_path8.default.resolve(input.cwd);
21839
+ const cwd = import_node_path9.default.resolve(input.cwd);
21725
21840
  const id = projectIdForCwd(cwd);
21726
21841
  let result;
21727
21842
  mutateStore((store) => {
@@ -21747,7 +21862,7 @@ function upsertProject(input) {
21747
21862
  const now = Date.now();
21748
21863
  const created = {
21749
21864
  id,
21750
- name: input.name ?? import_node_path8.default.basename(cwd),
21865
+ name: input.name ?? import_node_path9.default.basename(cwd),
21751
21866
  cwd,
21752
21867
  repoRoot: input.repoRoot,
21753
21868
  sourceRoots: input.sourceRoots ?? [cwd],
@@ -21892,8 +22007,8 @@ async function seedFromDemoAppRegistry() {
21892
22007
  if (apps.length === 0) return;
21893
22008
  mutateStore((store) => {
21894
22009
  for (const app of apps) {
21895
- if (!import_node_fs8.default.existsSync(app.dir)) continue;
21896
- const cwd = import_node_path8.default.resolve(app.dir);
22010
+ if (!import_node_fs9.default.existsSync(app.dir)) continue;
22011
+ const cwd = import_node_path9.default.resolve(app.dir);
21897
22012
  const id = projectIdForCwd(cwd);
21898
22013
  if (store.attachedProjects.some((p) => p.id === id)) continue;
21899
22014
  const now = Date.now();
@@ -21914,13 +22029,13 @@ async function seedFromDemoAppRegistry() {
21914
22029
  }
21915
22030
  });
21916
22031
  }
21917
- var import_node_crypto3, import_node_fs8, import_node_path8, overrideDir, COST_HISTORY_MAX_AGE_MS;
22032
+ var import_node_crypto3, import_node_fs9, import_node_path9, overrideDir, COST_HISTORY_MAX_AGE_MS;
21918
22033
  var init_attached_projects = __esm({
21919
22034
  "src/attached-projects.ts"() {
21920
22035
  "use strict";
21921
22036
  import_node_crypto3 = require("node:crypto");
21922
- import_node_fs8 = __toESM(require("node:fs"), 1);
21923
- import_node_path8 = __toESM(require("node:path"), 1);
22037
+ import_node_fs9 = __toESM(require("node:fs"), 1);
22038
+ import_node_path9 = __toESM(require("node:path"), 1);
21924
22039
  init_home_paths();
21925
22040
  overrideDir = null;
21926
22041
  COST_HISTORY_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
@@ -21929,16 +22044,16 @@ var init_attached_projects = __esm({
21929
22044
 
21930
22045
  // src/agent-sessions.ts
21931
22046
  function sessionDir(sessionId) {
21932
- return import_node_path9.default.join(getUserDataDir(), "sessions", sessionId);
22047
+ return import_node_path10.default.join(getUserDataDir(), "sessions", sessionId);
21933
22048
  }
21934
22049
  function promptFifoPath(sessionId) {
21935
- return import_node_path9.default.join(sessionDir(sessionId), "prompt.in");
22050
+ return import_node_path10.default.join(sessionDir(sessionId), "prompt.in");
21936
22051
  }
21937
22052
  function eventsFifoPath(sessionId) {
21938
- return import_node_path9.default.join(sessionDir(sessionId), "events.out");
22053
+ return import_node_path10.default.join(sessionDir(sessionId), "events.out");
21939
22054
  }
21940
22055
  function transcriptPath(sessionId) {
21941
- return import_node_path9.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
22056
+ return import_node_path10.default.join(getUserDataDir(), "transcripts", `${sessionId}.log`);
21942
22057
  }
21943
22058
  function pidIsAlive(pid, sessionId) {
21944
22059
  if (!pid) return false;
@@ -21948,7 +22063,7 @@ function pidIsAlive(pid, sessionId) {
21948
22063
  return false;
21949
22064
  }
21950
22065
  if (sessionId) {
21951
- if (!import_node_fs9.default.existsSync(sessionDir(sessionId))) return false;
22066
+ if (!import_node_fs10.default.existsSync(sessionDir(sessionId))) return false;
21952
22067
  }
21953
22068
  return true;
21954
22069
  }
@@ -21961,11 +22076,11 @@ function resolveSootsimInvocation() {
21961
22076
  const resourcesPath = process.resourcesPath;
21962
22077
  if (resourcesPath) {
21963
22078
  const candidates = [
21964
- import_node_path9.default.join(resourcesPath, "bin", "sootsim"),
21965
- import_node_path9.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
22079
+ import_node_path10.default.join(resourcesPath, "bin", "sootsim"),
22080
+ import_node_path10.default.join(resourcesPath, "bin", `sootsim-${process.platform}-${process.arch}`)
21966
22081
  ];
21967
22082
  for (const c of candidates) {
21968
- if (import_node_fs9.default.existsSync(c)) return { executable: c, prefixArgs: [] };
22083
+ if (import_node_fs10.default.existsSync(c)) return { executable: c, prefixArgs: [] };
21969
22084
  }
21970
22085
  }
21971
22086
  }
@@ -21984,15 +22099,15 @@ function tryWorkspaceSootsim() {
21984
22099
  const sootsimDir = resolveSootsimPackageDir();
21985
22100
  if (!sootsimDir) return null;
21986
22101
  const binaryName = `peach-${process.platform === "win32" ? "windows" : process.platform}-${process.arch}${process.platform === "win32" ? ".exe" : ""}`;
21987
- const distBinary = import_node_path9.default.join(sootsimDir, "dist-bin", binaryName);
21988
- if (import_node_fs9.default.existsSync(distBinary)) return { executable: distBinary, prefixArgs: [] };
21989
- const distBin = import_node_path9.default.join(sootsimDir, "dist-cli", "bin.js");
21990
- if (import_node_fs9.default.existsSync(distBin)) {
22102
+ const distBinary = import_node_path10.default.join(sootsimDir, "dist-bin", binaryName);
22103
+ if (import_node_fs10.default.existsSync(distBinary)) return { executable: distBinary, prefixArgs: [] };
22104
+ const distBin = import_node_path10.default.join(sootsimDir, "dist-cli", "bin.js");
22105
+ if (import_node_fs10.default.existsSync(distBin)) {
21991
22106
  try {
21992
- const src = import_node_path9.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
21993
- if (import_node_fs9.default.existsSync(src)) {
21994
- const srcMtime = import_node_fs9.default.statSync(src).mtimeMs;
21995
- const buildMtime = import_node_fs9.default.statSync(distBin).mtimeMs;
22107
+ const src = import_node_path10.default.join(sootsimDir, "cli", "commands", "agent-wrapper.ts");
22108
+ if (import_node_fs10.default.existsSync(src)) {
22109
+ const srcMtime = import_node_fs10.default.statSync(src).mtimeMs;
22110
+ const buildMtime = import_node_fs10.default.statSync(distBin).mtimeMs;
21996
22111
  if (buildMtime < srcMtime) {
21997
22112
  console.warn(
21998
22113
  `[peach] dist-cli/bin.js is older than agent-wrapper.ts \u2014 rebuild with \`bun run --cwd packages/peachsim build:cli\`.`
@@ -22011,22 +22126,22 @@ function tryWorkspaceSootsim() {
22011
22126
  function resolveSootsimPackageDir() {
22012
22127
  try {
22013
22128
  const resolved = require.resolve(`${rnxPublicBrand.packageName}/package.json`);
22014
- return import_node_path9.default.dirname(resolved);
22129
+ return import_node_path10.default.dirname(resolved);
22015
22130
  } catch {
22016
22131
  }
22017
22132
  const here = fileFromImportMeta();
22018
22133
  if (!here) return null;
22019
- let cur = import_node_path9.default.dirname(here);
22134
+ let cur = import_node_path10.default.dirname(here);
22020
22135
  for (let i = 0; i < 8; i++) {
22021
- const pkg = import_node_path9.default.join(cur, "package.json");
22136
+ const pkg = import_node_path10.default.join(cur, "package.json");
22022
22137
  try {
22023
- if (import_node_fs9.default.existsSync(pkg)) {
22024
- const parsed = JSON.parse(import_node_fs9.default.readFileSync(pkg, "utf8"));
22138
+ if (import_node_fs10.default.existsSync(pkg)) {
22139
+ const parsed = JSON.parse(import_node_fs10.default.readFileSync(pkg, "utf8"));
22025
22140
  if (parsed.name === rnxPublicBrand.packageName) return cur;
22026
22141
  }
22027
22142
  } catch {
22028
22143
  }
22029
- const parent = import_node_path9.default.dirname(cur);
22144
+ const parent = import_node_path10.default.dirname(cur);
22030
22145
  if (parent === cur) break;
22031
22146
  cur = parent;
22032
22147
  }
@@ -22042,28 +22157,28 @@ function fileFromImportMeta() {
22042
22157
  }
22043
22158
  }
22044
22159
  async function withStartLock(projectId, provider, fn) {
22045
- const lockDir = import_node_path9.default.join(getUserDataDir(), "locks");
22046
- import_node_fs9.default.mkdirSync(lockDir, { recursive: true });
22160
+ const lockDir = import_node_path10.default.join(getUserDataDir(), "locks");
22161
+ import_node_fs10.default.mkdirSync(lockDir, { recursive: true });
22047
22162
  try {
22048
- import_node_fs9.default.chmodSync(lockDir, 448);
22163
+ import_node_fs10.default.chmodSync(lockDir, 448);
22049
22164
  } catch {
22050
22165
  }
22051
- const lockPath = import_node_path9.default.join(lockDir, `start-${projectId}-${provider}.lock`);
22166
+ const lockPath = import_node_path10.default.join(lockDir, `start-${projectId}-${provider}.lock`);
22052
22167
  const deadline = Date.now() + 4e3;
22053
22168
  let fd = null;
22054
22169
  while (fd === null) {
22055
22170
  try {
22056
- fd = import_node_fs9.default.openSync(
22171
+ fd = import_node_fs10.default.openSync(
22057
22172
  lockPath,
22058
- import_node_fs9.constants.O_WRONLY | import_node_fs9.constants.O_CREAT | import_node_fs9.constants.O_EXCL,
22173
+ import_node_fs10.constants.O_WRONLY | import_node_fs10.constants.O_CREAT | import_node_fs10.constants.O_EXCL,
22059
22174
  384
22060
22175
  );
22061
22176
  } catch (err) {
22062
22177
  if (err.code !== "EEXIST") throw err;
22063
22178
  try {
22064
- const stale = Number(import_node_fs9.default.readFileSync(lockPath, "utf8").trim());
22179
+ const stale = Number(import_node_fs10.default.readFileSync(lockPath, "utf8").trim());
22065
22180
  if (stale && !isProcessAlive(stale)) {
22066
- import_node_fs9.default.unlinkSync(lockPath);
22181
+ import_node_fs10.default.unlinkSync(lockPath);
22067
22182
  continue;
22068
22183
  }
22069
22184
  } catch {
@@ -22077,15 +22192,15 @@ async function withStartLock(projectId, provider, fn) {
22077
22192
  }
22078
22193
  }
22079
22194
  try {
22080
- import_node_fs9.default.writeFileSync(fd, String(process.pid));
22195
+ import_node_fs10.default.writeFileSync(fd, String(process.pid));
22081
22196
  return await fn();
22082
22197
  } finally {
22083
22198
  try {
22084
- import_node_fs9.default.closeSync(fd);
22199
+ import_node_fs10.default.closeSync(fd);
22085
22200
  } catch {
22086
22201
  }
22087
22202
  try {
22088
- import_node_fs9.default.unlinkSync(lockPath);
22203
+ import_node_fs10.default.unlinkSync(lockPath);
22089
22204
  } catch {
22090
22205
  }
22091
22206
  }
@@ -22099,25 +22214,25 @@ function isProcessAlive(pid) {
22099
22214
  }
22100
22215
  }
22101
22216
  function mkfifoSync(p) {
22102
- const parent = import_node_path9.default.dirname(p);
22103
- import_node_fs9.default.mkdirSync(parent, { recursive: true });
22217
+ const parent = import_node_path10.default.dirname(p);
22218
+ import_node_fs10.default.mkdirSync(parent, { recursive: true });
22104
22219
  try {
22105
- import_node_fs9.default.chmodSync(parent, 448);
22220
+ import_node_fs10.default.chmodSync(parent, 448);
22106
22221
  } catch {
22107
22222
  }
22108
- if (import_node_fs9.default.existsSync(p)) {
22223
+ if (import_node_fs10.default.existsSync(p)) {
22109
22224
  try {
22110
- const stat2 = import_node_fs9.default.statSync(p);
22225
+ const stat2 = import_node_fs10.default.statSync(p);
22111
22226
  if (stat2.isFIFO()) {
22112
22227
  try {
22113
- import_node_fs9.default.chmodSync(p, 384);
22228
+ import_node_fs10.default.chmodSync(p, 384);
22114
22229
  } catch {
22115
22230
  }
22116
22231
  return;
22117
22232
  }
22118
- import_node_fs9.default.unlinkSync(p);
22233
+ import_node_fs10.default.unlinkSync(p);
22119
22234
  } catch {
22120
- import_node_fs9.default.unlinkSync(p);
22235
+ import_node_fs10.default.unlinkSync(p);
22121
22236
  }
22122
22237
  }
22123
22238
  const result = (0, import_node_child_process4.spawnSync)("mkfifo", ["-m", "600", p]);
@@ -22157,10 +22272,10 @@ async function startSession(opts) {
22157
22272
  const transcript = transcriptPath(session.id);
22158
22273
  mkfifoSync(promptIn);
22159
22274
  mkfifoSync(eventsOut);
22160
- const transcriptDir = import_node_path9.default.dirname(transcript);
22161
- import_node_fs9.default.mkdirSync(transcriptDir, { recursive: true });
22275
+ const transcriptDir = import_node_path10.default.dirname(transcript);
22276
+ import_node_fs10.default.mkdirSync(transcriptDir, { recursive: true });
22162
22277
  try {
22163
- import_node_fs9.default.chmodSync(transcriptDir, 448);
22278
+ import_node_fs10.default.chmodSync(transcriptDir, 448);
22164
22279
  } catch {
22165
22280
  }
22166
22281
  const { executable, prefixArgs } = resolveSootsimInvocation();
@@ -22211,7 +22326,7 @@ async function startSession(opts) {
22211
22326
  }
22212
22327
  }
22213
22328
  try {
22214
- import_node_fs9.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
22329
+ import_node_fs10.default.rmSync(sessionDir(session.id), { recursive: true, force: true });
22215
22330
  } catch {
22216
22331
  }
22217
22332
  updateSessionStatus(session.id, { status: "ended" });
@@ -22239,18 +22354,18 @@ async function sendPrompt(sessionId, prompt) {
22239
22354
  );
22240
22355
  }
22241
22356
  const fifo = promptFifoPath(sessionId);
22242
- if (!import_node_fs9.default.existsSync(fifo)) {
22357
+ if (!import_node_fs10.default.existsSync(fifo)) {
22243
22358
  throw new AgentSessionError("NO_FIFO", `prompt FIFO missing: ${fifo}`);
22244
22359
  }
22245
- const fd = import_node_fs9.default.openSync(fifo, import_node_fs9.constants.O_WRONLY);
22360
+ const fd = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_WRONLY);
22246
22361
  try {
22247
22362
  const wireText = encodeAgentPromptEnvelope(prompt);
22248
22363
  if (!wireText) {
22249
22364
  throw new AgentSessionError("EMPTY_PROMPT", "prompt text is empty");
22250
22365
  }
22251
- import_node_fs9.default.writeSync(fd, wireText + "\n");
22366
+ import_node_fs10.default.writeSync(fd, wireText + "\n");
22252
22367
  } finally {
22253
- import_node_fs9.default.closeSync(fd);
22368
+ import_node_fs10.default.closeSync(fd);
22254
22369
  }
22255
22370
  updateSessionStatus(sessionId, {
22256
22371
  lastPrompt: prompt.displayText ?? prompt.text,
@@ -22272,7 +22387,7 @@ async function endSession(sessionId) {
22272
22387
  const base = getUserDataDir();
22273
22388
  if (dir.startsWith(base)) {
22274
22389
  try {
22275
- import_node_fs9.default.rmSync(dir, { recursive: true, force: true });
22390
+ import_node_fs10.default.rmSync(dir, { recursive: true, force: true });
22276
22391
  } catch {
22277
22392
  }
22278
22393
  }
@@ -22280,11 +22395,11 @@ async function endSession(sessionId) {
22280
22395
  }
22281
22396
  function subscribeEvents(sessionId, onEvent) {
22282
22397
  const fifo = eventsFifoPath(sessionId);
22283
- if (!import_node_fs9.default.existsSync(fifo)) {
22398
+ if (!import_node_fs10.default.existsSync(fifo)) {
22284
22399
  throw new AgentSessionError("NO_FIFO", `events FIFO missing: ${fifo}`);
22285
22400
  }
22286
- const fd = import_node_fs9.default.openSync(fifo, import_node_fs9.constants.O_RDWR);
22287
- const stream = import_node_fs9.default.createReadStream("", { fd, autoClose: true });
22401
+ const fd = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_RDWR);
22402
+ const stream = import_node_fs10.default.createReadStream("", { fd, autoClose: true });
22288
22403
  const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
22289
22404
  rl.on("line", (line) => {
22290
22405
  const event = parseAgentEventLine(line);
@@ -22295,7 +22410,7 @@ function subscribeEvents(sessionId, onEvent) {
22295
22410
  if (closed) return;
22296
22411
  closed = true;
22297
22412
  try {
22298
- import_node_fs9.default.writeSync(fd, "\n");
22413
+ import_node_fs10.default.writeSync(fd, "\n");
22299
22414
  } catch {
22300
22415
  }
22301
22416
  try {
@@ -22309,7 +22424,7 @@ function subscribeEvents(sessionId, onEvent) {
22309
22424
  };
22310
22425
  }
22311
22426
  async function waitForFirstEvent(fifo, predicate, timeoutMs) {
22312
- const fd = import_node_fs9.default.openSync(fifo, import_node_fs9.constants.O_RDWR | import_node_fs9.constants.O_NONBLOCK);
22427
+ const fd = import_node_fs10.default.openSync(fifo, import_node_fs10.constants.O_RDWR | import_node_fs10.constants.O_NONBLOCK);
22313
22428
  const buf = Buffer.alloc(8192);
22314
22429
  let leftover = "";
22315
22430
  const deadline = Date.now() + timeoutMs;
@@ -22317,7 +22432,7 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
22317
22432
  while (Date.now() < deadline) {
22318
22433
  let n = 0;
22319
22434
  try {
22320
- n = import_node_fs9.default.readSync(fd, buf, 0, buf.length, null);
22435
+ n = import_node_fs10.default.readSync(fd, buf, 0, buf.length, null);
22321
22436
  } catch (err) {
22322
22437
  if (err.code !== "EAGAIN") throw err;
22323
22438
  n = 0;
@@ -22337,17 +22452,17 @@ async function waitForFirstEvent(fifo, predicate, timeoutMs) {
22337
22452
  }
22338
22453
  return null;
22339
22454
  } finally {
22340
- import_node_fs9.default.closeSync(fd);
22455
+ import_node_fs10.default.closeSync(fd);
22341
22456
  }
22342
22457
  }
22343
- var import_node_child_process4, import_node_crypto4, import_node_fs9, import_node_path9, import_node_readline, AgentSessionError;
22458
+ var import_node_child_process4, import_node_crypto4, import_node_fs10, import_node_path10, import_node_readline, AgentSessionError;
22344
22459
  var init_agent_sessions = __esm({
22345
22460
  "src/agent-sessions.ts"() {
22346
22461
  "use strict";
22347
22462
  import_node_child_process4 = require("node:child_process");
22348
22463
  import_node_crypto4 = require("node:crypto");
22349
- import_node_fs9 = __toESM(require("node:fs"), 1);
22350
- import_node_path9 = __toESM(require("node:path"), 1);
22464
+ import_node_fs10 = __toESM(require("node:fs"), 1);
22465
+ import_node_path10 = __toESM(require("node:path"), 1);
22351
22466
  import_node_readline = __toESM(require("node:readline"), 1);
22352
22467
  init_self_invocation();
22353
22468
  init_standalone();
@@ -22378,13 +22493,13 @@ function mapFrameworkToProjectFramework(fw) {
22378
22493
  if (fw === "one" || fw === "vxrn") return "one";
22379
22494
  return "unknown";
22380
22495
  }
22381
- var import_node_crypto5, import_node_fs10, import_node_path10, WS_OPEN, SESSION_STATUS_PERSIST_DELAY_MS, AgentHost;
22496
+ var import_node_crypto5, import_node_fs11, import_node_path11, WS_OPEN, SESSION_STATUS_PERSIST_DELAY_MS, AgentHost;
22382
22497
  var init_agent_host = __esm({
22383
22498
  "src/host/agent-host.ts"() {
22384
22499
  "use strict";
22385
22500
  import_node_crypto5 = require("node:crypto");
22386
- import_node_fs10 = __toESM(require("node:fs"), 1);
22387
- import_node_path10 = __toESM(require("node:path"), 1);
22501
+ import_node_fs11 = __toESM(require("node:fs"), 1);
22502
+ import_node_path11 = __toESM(require("node:path"), 1);
22388
22503
  init_dev_server_scanner();
22389
22504
  init_agent_sessions();
22390
22505
  init_attached_projects();
@@ -22567,10 +22682,10 @@ var init_agent_host = __esm({
22567
22682
  return simId;
22568
22683
  }
22569
22684
  listenForInspect(socket, simId) {
22570
- const queue = this.inspectQueues.get(simId);
22571
- const queued = queue?.shift();
22572
- if (queued && queue) {
22573
- if (queue.length === 0) this.inspectQueues.delete(simId);
22685
+ const queue2 = this.inspectQueues.get(simId);
22686
+ const queued = queue2?.shift();
22687
+ if (queued && queue2) {
22688
+ if (queue2.length === 0) this.inspectQueues.delete(simId);
22574
22689
  return Promise.resolve(queued);
22575
22690
  }
22576
22691
  return new Promise((resolve9, reject) => {
@@ -22596,9 +22711,9 @@ var init_agent_host = __esm({
22596
22711
  listener.resolve(message);
22597
22712
  return { ok: true, queued: false, messageId: message.id };
22598
22713
  }
22599
- const queue = this.inspectQueues.get(simId) ?? [];
22600
- queue.push(message);
22601
- this.inspectQueues.set(simId, queue);
22714
+ const queue2 = this.inspectQueues.get(simId) ?? [];
22715
+ queue2.push(message);
22716
+ this.inspectQueues.set(simId, queue2);
22602
22717
  return { ok: true, queued: true, messageId: message.id };
22603
22718
  }
22604
22719
  async doStartSession(input) {
@@ -22630,7 +22745,7 @@ var init_agent_host = __esm({
22630
22745
  );
22631
22746
  const project = upsertProject({
22632
22747
  cwd: match.cwd,
22633
- name: match.projectName ?? import_node_path10.default.basename(match.cwd),
22748
+ name: match.projectName ?? import_node_path11.default.basename(match.cwd),
22634
22749
  preferredProvider: input.provider ?? existing?.preferredProvider,
22635
22750
  sourceRoots: existing?.sourceRoots ?? [match.cwd],
22636
22751
  knownBundleUrls,
@@ -22641,18 +22756,18 @@ var init_agent_host = __esm({
22641
22756
  }
22642
22757
  getTranscript(sessionId) {
22643
22758
  const p = transcriptPath(sessionId);
22644
- if (!import_node_fs10.default.existsSync(p)) {
22759
+ if (!import_node_fs11.default.existsSync(p)) {
22645
22760
  return { error: "transcript not found", code: "NO_TRANSCRIPT" };
22646
22761
  }
22647
- return import_node_fs10.default.readFileSync(p, "utf8");
22762
+ return import_node_fs11.default.readFileSync(p, "utf8");
22648
22763
  }
22649
22764
  getPaths() {
22650
22765
  const dir = getUserDataDir();
22651
22766
  return {
22652
22767
  userDataDir: dir,
22653
- storeFile: import_node_path10.default.join(dir, "attached-projects.json"),
22654
- sessionsDir: import_node_path10.default.join(dir, "sessions"),
22655
- transcriptsDir: import_node_path10.default.join(dir, "transcripts")
22768
+ storeFile: import_node_path11.default.join(dir, "attached-projects.json"),
22769
+ sessionsDir: import_node_path11.default.join(dir, "sessions"),
22770
+ transcriptsDir: import_node_path11.default.join(dir, "transcripts")
22656
22771
  };
22657
22772
  }
22658
22773
  // --- subscription management ---
@@ -23502,23 +23617,23 @@ function looksBinary(filePath, size) {
23502
23617
  if (size === 0) return false;
23503
23618
  let fd;
23504
23619
  try {
23505
- fd = import_node_fs11.default.openSync(filePath, "r");
23620
+ fd = import_node_fs12.default.openSync(filePath, "r");
23506
23621
  const buffer = Buffer.alloc(Math.min(BINARY_SNIFF_BYTES, size));
23507
- const read = import_node_fs11.default.readSync(fd, buffer, 0, buffer.length, 0);
23622
+ const read = import_node_fs12.default.readSync(fd, buffer, 0, buffer.length, 0);
23508
23623
  return buffer.subarray(0, read).includes(0);
23509
23624
  } catch {
23510
23625
  return false;
23511
23626
  } finally {
23512
- if (fd !== void 0) import_node_fs11.default.closeSync(fd);
23627
+ if (fd !== void 0) import_node_fs12.default.closeSync(fd);
23513
23628
  }
23514
23629
  }
23515
- var import_node_child_process5, import_node_fs11, import_node_path11, CheckoutRequiresGitError, BINARY_SNIFF_BYTES, LIST_FILES_TIMEOUT_MS, LIST_FILES_ATTEMPTS, LIST_FILES_RETRY_MS, CheckoutFilePlane;
23630
+ var import_node_child_process5, import_node_fs12, import_node_path12, CheckoutRequiresGitError, BINARY_SNIFF_BYTES, LIST_FILES_TIMEOUT_MS, LIST_FILES_ATTEMPTS, LIST_FILES_RETRY_MS, CheckoutFilePlane;
23516
23631
  var init_checkout_plane = __esm({
23517
23632
  "cli/commands/box/checkout-plane.ts"() {
23518
23633
  "use strict";
23519
23634
  import_node_child_process5 = require("node:child_process");
23520
- import_node_fs11 = __toESM(require("node:fs"), 1);
23521
- import_node_path11 = __toESM(require("node:path"), 1);
23635
+ import_node_fs12 = __toESM(require("node:fs"), 1);
23636
+ import_node_path12 = __toESM(require("node:path"), 1);
23522
23637
  CheckoutRequiresGitError = class extends Error {
23523
23638
  };
23524
23639
  BINARY_SNIFF_BYTES = 8192;
@@ -23535,7 +23650,7 @@ var init_checkout_plane = __esm({
23535
23650
  listTimeoutMs;
23536
23651
  trackedOnly;
23537
23652
  constructor(root, options = {}) {
23538
- this.root = import_node_path11.default.resolve(root);
23653
+ this.root = import_node_path12.default.resolve(root);
23539
23654
  this.listTimeoutMs = options.listTimeoutMs ?? LIST_FILES_TIMEOUT_MS;
23540
23655
  this.trackedOnly = options.trackedOnly ?? false;
23541
23656
  }
@@ -23597,13 +23712,13 @@ var init_checkout_plane = __esm({
23597
23712
  if (!relative2) continue;
23598
23713
  let stat2;
23599
23714
  try {
23600
- stat2 = import_node_fs11.default.statSync(import_node_path11.default.join(this.root, relative2));
23715
+ stat2 = import_node_fs12.default.statSync(import_node_path12.default.join(this.root, relative2));
23601
23716
  } catch {
23602
23717
  continue;
23603
23718
  }
23604
23719
  if (!stat2.isFile()) continue;
23605
23720
  const seen = this.sniffed.get(relative2);
23606
- const binary = seen && seen.size === stat2.size && seen.mtimeMs === stat2.mtimeMs ? seen.binary : looksBinary(import_node_path11.default.join(this.root, relative2), stat2.size);
23721
+ const binary = seen && seen.size === stat2.size && seen.mtimeMs === stat2.mtimeMs ? seen.binary : looksBinary(import_node_path12.default.join(this.root, relative2), stat2.size);
23607
23722
  nextSniffed.set(relative2, { size: stat2.size, mtimeMs: stat2.mtimeMs, binary });
23608
23723
  next.set(relative2, {
23609
23724
  size: stat2.size,
@@ -23617,22 +23732,22 @@ var init_checkout_plane = __esm({
23617
23732
  this.sniffed = nextSniffed;
23618
23733
  }
23619
23734
  absolute(planePath) {
23620
- const resolved = import_node_path11.default.resolve(this.root, planePath);
23621
- if (resolved !== this.root && !resolved.startsWith(`${this.root}${import_node_path11.default.sep}`)) {
23735
+ const resolved = import_node_path12.default.resolve(this.root, planePath);
23736
+ if (resolved !== this.root && !resolved.startsWith(`${this.root}${import_node_path12.default.sep}`)) {
23622
23737
  throw new Error(`path escapes the project: ${planePath}`);
23623
23738
  }
23624
23739
  return resolved;
23625
23740
  }
23626
23741
  async read(planePath) {
23627
- return import_node_fs11.default.promises.readFile(this.absolute(planePath), "utf8");
23742
+ return import_node_fs12.default.promises.readFile(this.absolute(planePath), "utf8");
23628
23743
  }
23629
23744
  async readBytes(planePath) {
23630
- return import_node_fs11.default.promises.readFile(this.absolute(planePath));
23745
+ return import_node_fs12.default.promises.readFile(this.absolute(planePath));
23631
23746
  }
23632
23747
  async write(planePath, content) {
23633
23748
  const absolute = this.absolute(planePath);
23634
- await import_node_fs11.default.promises.mkdir(import_node_path11.default.dirname(absolute), { recursive: true });
23635
- await import_node_fs11.default.promises.writeFile(absolute, content);
23749
+ await import_node_fs12.default.promises.mkdir(import_node_path12.default.dirname(absolute), { recursive: true });
23750
+ await import_node_fs12.default.promises.writeFile(absolute, content);
23636
23751
  this.entries.set(planePath, {
23637
23752
  size: content.byteLength,
23638
23753
  readOnly: false,
@@ -23641,7 +23756,7 @@ var init_checkout_plane = __esm({
23641
23756
  });
23642
23757
  }
23643
23758
  async delete(planePath) {
23644
- await import_node_fs11.default.promises.rm(this.absolute(planePath), { force: true });
23759
+ await import_node_fs12.default.promises.rm(this.absolute(planePath), { force: true });
23645
23760
  this.entries.delete(planePath);
23646
23761
  }
23647
23762
  };
@@ -23649,12 +23764,12 @@ var init_checkout_plane = __esm({
23649
23764
  });
23650
23765
 
23651
23766
  // src/host/plane-host.ts
23652
- var import_node_fs12, import_node_path12, WS_OPEN2, PlaneNotRegisteredError, PlaneHost;
23767
+ var import_node_fs13, import_node_path13, WS_OPEN2, PlaneNotRegisteredError, PlaneHost;
23653
23768
  var init_plane_host = __esm({
23654
23769
  "src/host/plane-host.ts"() {
23655
23770
  "use strict";
23656
- import_node_fs12 = __toESM(require("node:fs"), 1);
23657
- import_node_path12 = __toESM(require("node:path"), 1);
23771
+ import_node_fs13 = __toESM(require("node:fs"), 1);
23772
+ import_node_path13 = __toESM(require("node:path"), 1);
23658
23773
  init_plane();
23659
23774
  init_checkout_plane();
23660
23775
  WS_OPEN2 = 1;
@@ -23777,14 +23892,14 @@ var init_plane_host = __esm({
23777
23892
  // root and an opened one cannot disagree about the same directory.
23778
23893
  realRoot(root) {
23779
23894
  if (!root) throw new Error("root is required");
23780
- const resolved = import_node_path12.default.resolve(root);
23895
+ const resolved = import_node_path13.default.resolve(root);
23781
23896
  let real;
23782
23897
  try {
23783
- real = import_node_fs12.default.realpathSync(resolved);
23898
+ real = import_node_fs13.default.realpathSync(resolved);
23784
23899
  } catch {
23785
23900
  throw new Error(`no such directory: ${resolved}`);
23786
23901
  }
23787
- if (!import_node_fs12.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
23902
+ if (!import_node_fs13.default.statSync(real).isDirectory()) throw new Error(`not a directory: ${real}`);
23788
23903
  return real;
23789
23904
  }
23790
23905
  respond(ws, id, result) {
@@ -23835,7 +23950,7 @@ function normalize(p) {
23835
23950
  if (trailingSlash) joined += "/";
23836
23951
  return absolute ? "/" + joined : joined;
23837
23952
  }
23838
- function join4(...parts) {
23953
+ function join5(...parts) {
23839
23954
  const present = parts.filter((part) => part.length > 0);
23840
23955
  if (present.length === 0) return ".";
23841
23956
  return normalize(present.join("/"));
@@ -23898,7 +24013,7 @@ var init_posixPath = __esm({
23898
24013
  delimiter,
23899
24014
  isAbsolute,
23900
24015
  normalize,
23901
- join: join4,
24016
+ join: join5,
23902
24017
  resolve: resolve2,
23903
24018
  dirname: dirname3,
23904
24019
  basename: basename3,
@@ -24166,13 +24281,13 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24166
24281
  res.end("missing path param");
24167
24282
  return true;
24168
24283
  }
24169
- const extension = import_node_path13.default.extname(targetPath).toLowerCase();
24284
+ const extension = import_node_path14.default.extname(targetPath).toLowerCase();
24170
24285
  if (!REPLACEMENT_MODULE_EXTENSIONS.some((allowed) => allowed === extension)) {
24171
24286
  res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
24172
24287
  res.end(`replacement files must be ${REPLACEMENT_MODULE_EXTENSIONS.join(", ")}`);
24173
24288
  return true;
24174
24289
  }
24175
- if (!import_node_path13.default.isAbsolute(targetPath)) {
24290
+ if (!import_node_path14.default.isAbsolute(targetPath)) {
24176
24291
  res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8" });
24177
24292
  res.end("replacement file path must be absolute");
24178
24293
  return true;
@@ -24180,10 +24295,10 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24180
24295
  const runtimePackages = new Set(url.searchParams.getAll("runtimePackage"));
24181
24296
  let resolvedProjectRoot;
24182
24297
  if (options.projectRoot) {
24183
- const lexicalProjectRoot = import_node_path13.default.resolve(options.projectRoot);
24298
+ const lexicalProjectRoot = import_node_path14.default.resolve(options.projectRoot);
24184
24299
  resolvedProjectRoot = await import_promises5.default.realpath(options.projectRoot);
24185
- const lexicalTarget = import_node_path13.default.relative(lexicalProjectRoot, targetPath);
24186
- if (lexicalTarget.startsWith("..") || import_node_path13.default.isAbsolute(lexicalTarget)) {
24300
+ const lexicalTarget = import_node_path14.default.relative(lexicalProjectRoot, targetPath);
24301
+ if (lexicalTarget.startsWith("..") || import_node_path14.default.isAbsolute(lexicalTarget)) {
24187
24302
  res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
24188
24303
  res.end("replacement file must be inside the project root");
24189
24304
  return true;
@@ -24199,8 +24314,8 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24199
24314
  return true;
24200
24315
  }
24201
24316
  if (resolvedProjectRoot) {
24202
- const relativeTarget = import_node_path13.default.relative(resolvedProjectRoot, resolvedTargetPath);
24203
- if (relativeTarget.startsWith("..") || import_node_path13.default.isAbsolute(relativeTarget)) {
24317
+ const relativeTarget = import_node_path14.default.relative(resolvedProjectRoot, resolvedTargetPath);
24318
+ if (relativeTarget.startsWith("..") || import_node_path14.default.isAbsolute(relativeTarget)) {
24204
24319
  res.writeHead(403, { "Content-Type": "text/plain; charset=utf-8" });
24205
24320
  res.end("replacement file must be inside the project root");
24206
24321
  return true;
@@ -24227,12 +24342,12 @@ async function handleReplacementModuleRequest(req, res, options = {}) {
24227
24342
  }
24228
24343
  return true;
24229
24344
  }
24230
- var import_promises5, import_node_path13, REPLACEMENT_MODULE_ROUTE;
24345
+ var import_promises5, import_node_path14, REPLACEMENT_MODULE_ROUTE;
24231
24346
  var init_replacement_module_handler = __esm({
24232
24347
  "src/host/replacement-module-handler.ts"() {
24233
24348
  "use strict";
24234
24349
  import_promises5 = __toESM(require("node:fs/promises"), 1);
24235
- import_node_path13 = __toESM(require("node:path"), 1);
24350
+ import_node_path14 = __toESM(require("node:path"), 1);
24236
24351
  init_replacementModule();
24237
24352
  init_backend_origin();
24238
24353
  REPLACEMENT_MODULE_ROUTE = "/__sootsim-replacement-module";
@@ -24518,14 +24633,14 @@ function sharedDesktopAuthAccounts(user) {
24518
24633
  function getBaseDir() {
24519
24634
  const explicit = process.env[SESSION_FILE_ENV];
24520
24635
  if (explicit?.trim()) {
24521
- return (0, import_node_path14.dirname)((0, import_node_path14.resolve)(explicit));
24636
+ return (0, import_node_path15.dirname)((0, import_node_path15.resolve)(explicit));
24522
24637
  }
24523
24638
  return electronUserDataDir();
24524
24639
  }
24525
24640
  function getSharedDesktopAuthFilePath() {
24526
24641
  const explicit = process.env[SESSION_FILE_ENV];
24527
- if (explicit?.trim()) return (0, import_node_path14.resolve)(explicit);
24528
- return (0, import_node_path14.join)(getBaseDir(), "desktop-auth.json");
24642
+ if (explicit?.trim()) return (0, import_node_path15.resolve)(explicit);
24643
+ return (0, import_node_path15.join)(getBaseDir(), "desktop-auth.json");
24529
24644
  }
24530
24645
  function normalizeUser(input) {
24531
24646
  if (!input || typeof input !== "object") return null;
@@ -24575,26 +24690,26 @@ function normalizeSession(input) {
24575
24690
  }
24576
24691
  function readSharedDesktopAuthSession() {
24577
24692
  const filepath = getSharedDesktopAuthFilePath();
24578
- if (!(0, import_node_fs13.existsSync)(filepath)) return null;
24693
+ if (!(0, import_node_fs14.existsSync)(filepath)) return null;
24579
24694
  try {
24580
- const parsed = JSON.parse((0, import_node_fs13.readFileSync)(filepath, "utf8"));
24695
+ const parsed = JSON.parse((0, import_node_fs14.readFileSync)(filepath, "utf8"));
24581
24696
  const normalized = normalizeSession(parsed);
24582
24697
  if (!normalized) {
24583
- (0, import_node_fs13.rmSync)(filepath, { force: true });
24698
+ (0, import_node_fs14.rmSync)(filepath, { force: true });
24584
24699
  return null;
24585
24700
  }
24586
24701
  return normalized;
24587
24702
  } catch {
24588
- (0, import_node_fs13.rmSync)(filepath, { force: true });
24703
+ (0, import_node_fs14.rmSync)(filepath, { force: true });
24589
24704
  return null;
24590
24705
  }
24591
24706
  }
24592
- var import_node_fs13, import_node_path14, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
24707
+ var import_node_fs14, import_node_path15, SESSION_VERSION, SESSION_FILE_ENV, DEFAULT_ORIGIN;
24593
24708
  var init_shared_session = __esm({
24594
24709
  "src/auth/shared-session.ts"() {
24595
24710
  "use strict";
24596
- import_node_fs13 = require("node:fs");
24597
- import_node_path14 = require("node:path");
24711
+ import_node_fs14 = require("node:fs");
24712
+ import_node_path15 = require("node:path");
24598
24713
  init_home_paths();
24599
24714
  SESSION_VERSION = 1;
24600
24715
  SESSION_FILE_ENV = "SOOTSIM_SHARED_AUTH_FILE";
@@ -26402,8 +26517,8 @@ function metroIosAssetDestRelatives(httpServerLocation, filename) {
26402
26517
  }
26403
26518
  const out = [];
26404
26519
  for (const dir of dirs) {
26405
- const path21 = `${dir}/${filename}`;
26406
- if (!out.includes(path21)) out.push(path21);
26520
+ const path22 = `${dir}/${filename}`;
26521
+ if (!out.includes(path22)) out.push(path22);
26407
26522
  }
26408
26523
  if (!out.includes(filename)) out.push(filename);
26409
26524
  return out;
@@ -26679,7 +26794,9 @@ async function minify(code, sourceLine, options, withMap) {
26679
26794
  }
26680
26795
  const map = withMap && typeof result.map === "string" ? result.map : null;
26681
26796
  if (withMap && map === null) {
26682
- throw new Error(`peach Cloud got no source map for the statement at line ${sourceLine}`);
26797
+ throw new Error(
26798
+ `peach Cloud got no source map for the statement at line ${sourceLine}`
26799
+ );
26683
26800
  }
26684
26801
  return { code: result.code.trimEnd(), map, sourceLine };
26685
26802
  }
@@ -26743,8 +26860,9 @@ async function readOrInferModuleIdentity(bundle, mode, inferModuleIdentity) {
26743
26860
  }
26744
26861
  async function buildRnxCloudArtifact(bundle, options = {}) {
26745
26862
  const mode = options.mode ?? "production";
26863
+ const nativeIdentity = (0, import_native_app_identity.detachNativeAppIdentityFooter)(bundle);
26746
26864
  const identity = await readOrInferModuleIdentity(
26747
- bundle,
26865
+ nativeIdentity.source,
26748
26866
  mode,
26749
26867
  options.inferModuleIdentity
26750
26868
  );
@@ -26770,7 +26888,7 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
26770
26888
  })
26771
26889
  ]);
26772
26890
  const body = pieces.map((piece) => piece.code).join("\n");
26773
- const code = body + (0, import_metro_production_bundle.createRNXMetroModuleIdentityFooter)({
26891
+ const code = body + (nativeIdentity.identity ? (0, import_native_app_identity.createNativeAppIdentityFooter)(nativeIdentity.identity) : "") + (0, import_metro_production_bundle.createRNXMetroModuleIdentityFooter)({
26774
26892
  version: identity.version,
26775
26893
  identitySource: identity.identitySource,
26776
26894
  modulePaths: identity.modulePaths,
@@ -26833,11 +26951,12 @@ async function buildRnxCloudArtifact(bundle, options = {}) {
26833
26951
  }
26834
26952
  };
26835
26953
  }
26836
- var import_metro_production_bundle, import_terser, MODULE_PATHS_REQUIRED, SOURCE_MAP_REQUIRED, MINIFY_OPTIONS;
26954
+ var import_metro_production_bundle, import_native_app_identity, import_terser, MODULE_PATHS_REQUIRED, SOURCE_MAP_REQUIRED, MINIFY_OPTIONS;
26837
26955
  var init_metroCloudArtifact = __esm({
26838
26956
  "../contrast-bundler/src/metroCloudArtifact.ts"() {
26839
26957
  "use strict";
26840
26958
  import_metro_production_bundle = require("peachsim/metro-production-bundle");
26959
+ import_native_app_identity = require("peachsim/native-app-identity");
26841
26960
  import_terser = require("terser");
26842
26961
  init_metroAssetArtifact();
26843
26962
  init_metroDebugSourceMap();
@@ -27066,6 +27185,12 @@ var init_stub_manifest = __esm({
27066
27185
  runtimeTier: "core",
27067
27186
  buildResolvers: ["vite", "dep-prebundle"]
27068
27187
  },
27188
+ vendorEventEmitter: {
27189
+ specifier: "react-native/Libraries/vendor/emitter/EventEmitter",
27190
+ stubFile: "rn-libraries/EventEmitter.ts",
27191
+ runtimeTier: "core",
27192
+ buildResolvers: ["vite", "dep-prebundle"]
27193
+ },
27069
27194
  rctDeviceEventEmitter: {
27070
27195
  specifier: "react-native/Libraries/EventEmitter/RCTDeviceEventEmitter",
27071
27196
  stubFile: "rn-libraries/RCTDeviceEventEmitter.ts",
@@ -27343,13 +27468,13 @@ function readFactoryStringLiterals(factory) {
27343
27468
  return literals;
27344
27469
  }
27345
27470
  function normalizeFingerprintLiteral(literal) {
27346
- const path21 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
27471
+ const path22 = literal.replaceAll("\\\\", "/").replaceAll("\\/", "/");
27347
27472
  const nodeModulesMarker = "/node_modules/";
27348
- const nodeModulesIndex = path21.lastIndexOf(nodeModulesMarker);
27473
+ const nodeModulesIndex = path22.lastIndexOf(nodeModulesMarker);
27349
27474
  if (nodeModulesIndex >= 0) {
27350
- return `node_modules/${path21.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
27475
+ return `node_modules/${path22.slice(nodeModulesIndex + nodeModulesMarker.length)}`;
27351
27476
  }
27352
- if ((path21.startsWith("/") || /^[A-Za-z]:\//.test(path21) || path21.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path21)) {
27477
+ if ((path22.startsWith("/") || /^[A-Za-z]:\//.test(path22) || path22.startsWith("file:/")) && /\.[cm]?[jt]sx?(?::\d+(?::\d+)?)?$/.test(path22)) {
27353
27478
  return null;
27354
27479
  }
27355
27480
  return literal;
@@ -27479,13 +27604,13 @@ function embedTemplateRoot(args) {
27479
27604
  const root = template.roots[args.rootIndex];
27480
27605
  const moduleIdsByNode = /* @__PURE__ */ new Map([[root.node, args.bundleRoot.moduleId]]);
27481
27606
  const nodesByModuleId = /* @__PURE__ */ new Map([[args.bundleRoot.moduleId, root.node]]);
27482
- const queue = [root.node];
27607
+ const queue2 = [root.node];
27483
27608
  let exactFactoryMatches = 0;
27484
27609
  let uniqueChildFactoryMatches = 0;
27485
27610
  let uniqueChildAtomMatches = 0;
27486
27611
  let weakRootMatch = false;
27487
- for (let cursor = 0; cursor < queue.length; cursor++) {
27488
- const nodeIndex = queue[cursor];
27612
+ for (let cursor = 0; cursor < queue2.length; cursor++) {
27613
+ const nodeIndex = queue2[cursor];
27489
27614
  const moduleId = moduleIdsByNode.get(nodeIndex);
27490
27615
  if (moduleId === void 0) return null;
27491
27616
  const bundleModule = args.bundleById.get(moduleId);
@@ -27524,7 +27649,7 @@ function embedTemplateRoot(args) {
27524
27649
  if (existingModuleId === void 0) {
27525
27650
  moduleIdsByNode.set(edge.node, dependencyId);
27526
27651
  nodesByModuleId.set(dependencyId, edge.node);
27527
- queue.push(edge.node);
27652
+ queue2.push(edge.node);
27528
27653
  }
27529
27654
  }
27530
27655
  }
@@ -27587,10 +27712,10 @@ function templateAssignment(template, embeddings) {
27587
27712
  if (existingNode !== void 0 && existingNode !== nodeIndex) return null;
27588
27713
  nodesByModuleId.set(moduleId, nodeIndex);
27589
27714
  const node = template.nodes[nodeIndex];
27590
- const path21 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
27715
+ const path22 = node.landmarkPath ?? `node_modules/${template.packageName}/__rnx_inferred__/${moduleId}.js`;
27591
27716
  const existingPath = pathsByModuleId.get(moduleId);
27592
- if (existingPath !== void 0 && existingPath !== path21) return null;
27593
- pathsByModuleId.set(moduleId, path21);
27717
+ if (existingPath !== void 0 && existingPath !== path22) return null;
27718
+ pathsByModuleId.set(moduleId, path22);
27594
27719
  }
27595
27720
  }
27596
27721
  return {
@@ -27752,14 +27877,14 @@ async function inferMetroModuleIdentity(args) {
27752
27877
  const packageClaims = claimsByPackage.values().next().value;
27753
27878
  if (!packageClaims) continue;
27754
27879
  const exactClaims = packageClaims.filter((assignment2) => {
27755
- const path21 = assignment2.pathsByModuleId.get(moduleId);
27756
- return path21 !== void 0 && !path21.includes("/__rnx_inferred__/");
27880
+ const path22 = assignment2.pathsByModuleId.get(moduleId);
27881
+ return path22 !== void 0 && !path22.includes("/__rnx_inferred__/");
27757
27882
  });
27758
27883
  const preferredClaims = exactClaims.length > 0 ? exactClaims : packageClaims;
27759
27884
  const routes = new Set(
27760
27885
  preferredClaims.flatMap((assignment2) => {
27761
- const path21 = assignment2.pathsByModuleId.get(moduleId);
27762
- return path21 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path21)] : [];
27886
+ const path22 = assignment2.pathsByModuleId.get(moduleId);
27887
+ return path22 ? [metroFingerprintModuleClaimRoute(assignment2.packageName, path22)] : [];
27763
27888
  })
27764
27889
  );
27765
27890
  if (routes.size !== 1) continue;
@@ -28053,39 +28178,82 @@ function detectFramework2(deps) {
28053
28178
  return "unknown";
28054
28179
  }
28055
28180
  function detectProject(dir) {
28056
- const pkgPath = (0, import_path2.join)(dir, "package.json");
28057
- if (!(0, import_fs2.existsSync)(pkgPath)) return null;
28058
- let pkg;
28059
- try {
28060
- pkg = JSON.parse((0, import_fs2.readFileSync)(pkgPath, "utf8"));
28061
- } catch {
28062
- return null;
28063
- }
28181
+ const pkgPath = (0, import_node_path16.join)(dir, "package.json");
28182
+ if (!(0, import_node_fs15.existsSync)(pkgPath)) return null;
28183
+ const pkg = readProjectManifest(dir);
28184
+ if (!pkg) return null;
28064
28185
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
28186
+ const devCommand = metadataValue(
28187
+ metadataValue(readProjectJson(pkgPath), "scripts"),
28188
+ "dev"
28189
+ );
28065
28190
  const framework = detectFramework2(deps);
28066
28191
  if (framework === "unknown") return null;
28067
28192
  return {
28068
28193
  dir,
28069
- name: pkg.name || (0, import_path2.basename)(dir),
28194
+ name: pkg.name || (0, import_node_path16.basename)(dir),
28070
28195
  framework,
28071
28196
  // a config file is a config file whatever module system it declares. real
28072
28197
  // apps write .cjs as often as .js, and missing one reads as "this project
28073
28198
  // has no bundler config" and sends the user to create a second one.
28074
28199
  hasViteConfig: CONFIG_EXTENSIONS.some(
28075
- (ext) => (0, import_fs2.existsSync)((0, import_path2.join)(dir, `vite.config.${ext}`))
28200
+ (ext) => (0, import_node_fs15.existsSync)((0, import_node_path16.join)(dir, `vite.config.${ext}`))
28076
28201
  ),
28077
28202
  hasMetroConfig: CONFIG_EXTENSIONS.some(
28078
- (ext) => (0, import_fs2.existsSync)((0, import_path2.join)(dir, `metro.config.${ext}`))
28203
+ (ext) => (0, import_node_fs15.existsSync)((0, import_node_path16.join)(dir, `metro.config.${ext}`))
28079
28204
  ),
28080
- devCommand: pkg.scripts?.dev || null
28205
+ devCommand: typeof devCommand === "string" ? devCommand : null
28206
+ };
28207
+ }
28208
+ function readProjectMetadata(path22) {
28209
+ try {
28210
+ const info = (0, import_node_fs15.lstatSync)(path22);
28211
+ if (!info.isFile() || info.size > 4 * 1024 * 1024) return null;
28212
+ return (0, import_node_fs15.readFileSync)(path22, "utf8");
28213
+ } catch {
28214
+ return null;
28215
+ }
28216
+ }
28217
+ function metadataValue(value, key) {
28218
+ if (!value || typeof value !== "object") return void 0;
28219
+ return Object.getOwnPropertyDescriptor(value, key)?.value;
28220
+ }
28221
+ function readProjectJson(path22) {
28222
+ const text = readProjectMetadata(path22);
28223
+ if (text === null) return null;
28224
+ try {
28225
+ const value = JSON.parse(text);
28226
+ return value;
28227
+ } catch {
28228
+ return null;
28229
+ }
28230
+ }
28231
+ function readProjectManifest(dir) {
28232
+ const parsed = readProjectJson((0, import_node_path16.join)(dir, "package.json"));
28233
+ if (!parsed || typeof parsed !== "object") return null;
28234
+ const record = (value) => {
28235
+ if (!value || typeof value !== "object") return {};
28236
+ return Object.fromEntries(
28237
+ Object.entries(value).filter(
28238
+ (entry) => typeof entry[1] === "string" && /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/i.test(entry[0]) && entry[0] !== "." && entry[0] !== ".."
28239
+ )
28240
+ );
28241
+ };
28242
+ const name2 = metadataValue(parsed, "name");
28243
+ return {
28244
+ ...typeof name2 === "string" ? { name: name2 } : {},
28245
+ dependencies: record(metadataValue(parsed, "dependencies")),
28246
+ devDependencies: record(metadataValue(parsed, "devDependencies"))
28081
28247
  };
28082
28248
  }
28083
- var import_fs2, import_path2, CONFIG_EXTENSIONS;
28249
+ var import_node_fs15, import_node_path16, import_json5, import_yaml, CONFIG_EXTENSIONS;
28084
28250
  var init_detect = __esm({
28085
28251
  "cli/commands/detect.ts"() {
28086
28252
  "use strict";
28087
- import_fs2 = require("fs");
28088
- import_path2 = require("path");
28253
+ import_node_fs15 = require("node:fs");
28254
+ import_node_path16 = require("node:path");
28255
+ import_json5 = __toESM(require("json5"), 1);
28256
+ import_yaml = require("yaml");
28089
28257
  CONFIG_EXTENSIONS = ["ts", "js", "cjs", "mjs", "mts", "cts"];
28090
28258
  }
28091
28259
  });
@@ -28120,21 +28288,21 @@ function resolveCloudOrigin(value) {
28120
28288
  return normalizeCloudOrigin(source);
28121
28289
  }
28122
28290
  function readImmutableBundleSource(bundlePath) {
28123
- const filepath = (0, import_node_path15.resolve)(bundlePath);
28124
- if ((0, import_node_path15.extname)(filepath) !== ".js") {
28291
+ const filepath = (0, import_node_path17.resolve)(bundlePath);
28292
+ if ((0, import_node_path17.extname)(filepath) !== ".js") {
28125
28293
  throw new Error(`${REMOTE_COMMAND} requires one local Metro .js bundle`);
28126
28294
  }
28127
- const descriptor = (0, import_node_fs14.openSync)(filepath, "r");
28295
+ const descriptor = (0, import_node_fs16.openSync)(filepath, "r");
28128
28296
  try {
28129
- const before = (0, import_node_fs14.fstatSync)(descriptor, { bigint: true });
28297
+ const before = (0, import_node_fs16.fstatSync)(descriptor, { bigint: true });
28130
28298
  if (!before.isFile()) {
28131
28299
  throw new Error(`${REMOTE_COMMAND} bundle must be a regular local file`);
28132
28300
  }
28133
28301
  if (before.size <= 0n) {
28134
28302
  throw new Error(`${REMOTE_COMMAND} bundle is empty`);
28135
28303
  }
28136
- const bytes = (0, import_node_fs14.readFileSync)(descriptor);
28137
- const after = (0, import_node_fs14.fstatSync)(descriptor, { bigint: true });
28304
+ const bytes = (0, import_node_fs16.readFileSync)(descriptor);
28305
+ const after = (0, import_node_fs16.fstatSync)(descriptor, { bigint: true });
28138
28306
  if (before.dev !== after.dev || before.ino !== after.ino || before.size !== after.size || before.mtimeNs !== after.mtimeNs || bytes.length !== Number(before.size)) {
28139
28307
  throw new Error(`${REMOTE_COMMAND} bundle changed while it was being read`);
28140
28308
  }
@@ -28149,7 +28317,7 @@ function readImmutableBundleSource(bundlePath) {
28149
28317
  }
28150
28318
  return source;
28151
28319
  } finally {
28152
- (0, import_node_fs14.closeSync)(descriptor);
28320
+ (0, import_node_fs16.closeSync)(descriptor);
28153
28321
  }
28154
28322
  }
28155
28323
  async function fetchBundleSource(bundleUrl) {
@@ -28196,15 +28364,15 @@ async function loadBundleSource(bundleInput) {
28196
28364
  return readImmutableBundleSource(bundleInput);
28197
28365
  }
28198
28366
  function listMetroAssetDest(assetsPath) {
28199
- const directory = (0, import_node_path15.resolve)(assetsPath);
28200
- if (!(0, import_node_fs14.existsSync)(directory)) return { directory, files: [], truncated: false };
28201
- const skipNested = (0, import_node_fs14.existsSync)((0, import_node_path15.join)(directory, "package.json"));
28367
+ const directory = (0, import_node_path17.resolve)(assetsPath);
28368
+ if (!(0, import_node_fs16.existsSync)(directory)) return { directory, files: [], truncated: false };
28369
+ const skipNested = (0, import_node_fs16.existsSync)((0, import_node_path17.join)(directory, "package.json"));
28202
28370
  const files = [];
28203
28371
  let truncated = false;
28204
28372
  const walk = (dir, prefix) => {
28205
28373
  let entries;
28206
28374
  try {
28207
- entries = (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true });
28375
+ entries = (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true });
28208
28376
  } catch {
28209
28377
  return;
28210
28378
  }
@@ -28216,7 +28384,7 @@ function listMetroAssetDest(assetsPath) {
28216
28384
  if (entry.isDirectory()) {
28217
28385
  if (entry.name === ".git") continue;
28218
28386
  if (skipNested && PROJECT_ONLY_DIRECTORIES.has(entry.name)) continue;
28219
- walk((0, import_node_path15.join)(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name);
28387
+ walk((0, import_node_path17.join)(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name);
28220
28388
  } else if (entry.isFile()) {
28221
28389
  files.push(prefix ? `${prefix}/${entry.name}` : entry.name);
28222
28390
  }
@@ -28251,7 +28419,7 @@ function distinctByContent(directory, options) {
28251
28419
  for (const relative2 of options) {
28252
28420
  let bytes;
28253
28421
  try {
28254
- bytes = (0, import_node_fs14.readFileSync)((0, import_node_path15.join)(directory, relative2));
28422
+ bytes = (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(directory, relative2));
28255
28423
  } catch {
28256
28424
  continue;
28257
28425
  }
@@ -28283,7 +28451,7 @@ function placeMetroDescriptor(listing, descriptor) {
28283
28451
  let bytes;
28284
28452
  try {
28285
28453
  bytes = combination.map(
28286
- (relative2) => (0, import_node_fs14.readFileSync)((0, import_node_path15.join)(listing.directory, relative2))
28454
+ (relative2) => (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(listing.directory, relative2))
28287
28455
  );
28288
28456
  } catch {
28289
28457
  continue;
@@ -28309,26 +28477,26 @@ function placeMetroDescriptor(listing, descriptor) {
28309
28477
  }
28310
28478
  function unverifiedFileKey(dest) {
28311
28479
  return dest.placements.filter((placement) => !placement.verified).flatMap(
28312
- (placement) => [...placement.files.values()].map((relative2) => (0, import_node_path15.join)(dest.directory, relative2))
28480
+ (placement) => [...placement.files.values()].map((relative2) => (0, import_node_path17.join)(dest.directory, relative2))
28313
28481
  ).sort().join("\n");
28314
28482
  }
28315
28483
  function searchMetroAssetDest(bundlePath, descriptors) {
28316
- const bundleDirectory = (0, import_node_path15.dirname)((0, import_node_path15.resolve)(bundlePath));
28484
+ const bundleDirectory = (0, import_node_path17.dirname)((0, import_node_path17.resolve)(bundlePath));
28317
28485
  const candidates = [
28318
- (0, import_node_path15.join)(bundleDirectory, "assets"),
28486
+ (0, import_node_path17.join)(bundleDirectory, "assets"),
28319
28487
  bundleDirectory,
28320
- (0, import_node_path15.resolve)(bundleDirectory, "..", "assets")
28488
+ (0, import_node_path17.resolve)(bundleDirectory, "..", "assets")
28321
28489
  ];
28322
28490
  const cwd = process.cwd();
28323
28491
  let projectDirectory = null;
28324
28492
  for (const start of [bundleDirectory, cwd]) {
28325
- let directory = (0, import_node_path15.resolve)(start);
28493
+ let directory = (0, import_node_path17.resolve)(start);
28326
28494
  while (true) {
28327
28495
  if (detectProject(directory)?.hasMetroConfig) {
28328
28496
  projectDirectory = directory;
28329
28497
  break;
28330
28498
  }
28331
- const parent = (0, import_node_path15.dirname)(directory);
28499
+ const parent = (0, import_node_path17.dirname)(directory);
28332
28500
  if (parent === directory) break;
28333
28501
  directory = parent;
28334
28502
  }
@@ -28336,11 +28504,11 @@ function searchMetroAssetDest(bundlePath, descriptors) {
28336
28504
  }
28337
28505
  if (projectDirectory) {
28338
28506
  candidates.push(
28339
- (0, import_node_path15.join)(projectDirectory, "assets"),
28340
- (0, import_node_path15.join)(projectDirectory, "dist"),
28341
- (0, import_node_path15.join)(projectDirectory, "dist", "assets"),
28342
- (0, import_node_path15.join)(projectDirectory, "build"),
28343
- (0, import_node_path15.join)(projectDirectory, "build", "assets")
28507
+ (0, import_node_path17.join)(projectDirectory, "assets"),
28508
+ (0, import_node_path17.join)(projectDirectory, "dist"),
28509
+ (0, import_node_path17.join)(projectDirectory, "dist", "assets"),
28510
+ (0, import_node_path17.join)(projectDirectory, "build"),
28511
+ (0, import_node_path17.join)(projectDirectory, "build", "assets")
28344
28512
  );
28345
28513
  }
28346
28514
  const searched = [];
@@ -28348,7 +28516,7 @@ function searchMetroAssetDest(bundlePath, descriptors) {
28348
28516
  const stale = [];
28349
28517
  let truncated = false;
28350
28518
  for (const candidate of candidates) {
28351
- const directory = (0, import_node_path15.resolve)(candidate);
28519
+ const directory = (0, import_node_path17.resolve)(candidate);
28352
28520
  if (searched.includes(directory)) continue;
28353
28521
  searched.push(directory);
28354
28522
  const listing = listMetroAssetDest(directory);
@@ -28454,7 +28622,7 @@ async function embedBundleAssets(bundlePath, command, assetPolicy) {
28454
28622
  );
28455
28623
  }
28456
28624
  const relative2 = placement?.files.get(variant.scale);
28457
- if (relative2 && dest) return (0, import_node_fs14.readFileSync)((0, import_node_path15.join)(dest.directory, relative2));
28625
+ if (relative2 && dest) return (0, import_node_fs16.readFileSync)((0, import_node_path17.join)(dest.directory, relative2));
28458
28626
  if (placement && placement.files.size > 0) return null;
28459
28627
  if (placement && placement.ambiguous.length > 0 && dest) {
28460
28628
  throw new Error(
@@ -28483,7 +28651,7 @@ async function embedBundleAssets(bundlePath, command, assetPolicy) {
28483
28651
  );
28484
28652
  const classic = metroIosAssetDestRelatives(variant.descriptor.httpServerLocation, filename)[0] ?? filename;
28485
28653
  throw new Error(
28486
- `${command} could not read ${(0, import_node_path15.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`
28654
+ `${command} could not read ${(0, import_node_path17.join)(dest?.directory ?? ".", classic)} for ${variant.descriptor.name}.${variant.descriptor.type} at scale ${variant.scale}, and has no stand-in for a .${variant.descriptor.type} asset. Rebuild with \`react-native bundle --assets-dest\`.`
28487
28655
  );
28488
28656
  });
28489
28657
  return {
@@ -28669,13 +28837,13 @@ function createCloudBridgeForParsed(parsed) {
28669
28837
  if (!session) return null;
28670
28838
  return session.service === "box" ? new CloudBoxBridge(session) : new CloudBridge(session);
28671
28839
  }
28672
- var import_node_crypto6, import_node_fs14, import_node_path15, 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;
28840
+ 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;
28673
28841
  var init_cloud_client = __esm({
28674
28842
  "cli/cloud-client.ts"() {
28675
28843
  "use strict";
28676
28844
  import_node_crypto6 = require("node:crypto");
28677
- import_node_fs14 = require("node:fs");
28678
- import_node_path15 = require("node:path");
28845
+ import_node_fs16 = require("node:fs");
28846
+ import_node_path17 = require("node:path");
28679
28847
  init_metroAssetArtifact();
28680
28848
  init_metroCloudArtifact();
28681
28849
  init_metro_fingerprint_registry_client();
@@ -28946,17 +29114,18 @@ function unrefTimer(timer) {
28946
29114
  timer.unref();
28947
29115
  }
28948
29116
  }
28949
- var import_child_process3, import_fs3, import_http4, import_path3, import_ws, SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, CAMERA_FIXTURE_ROUTE, CAMERA_FIXTURE_NAME_RE, SootSimBridgeHost;
29117
+ var import_child_process3, import_fs2, import_http4, import_path2, import_ws, SOOTSIM_CROSS_ORIGIN_EMBEDDER_POLICY, WRITE_COMMAND_TYPES, FORCE_CLOSE_GRACE_MS, FORCE_CLOSE_TERMINATE_MS, DAEMON_HEARTBEAT_INTERVAL_MS, DEFAULT_RUNTIME_UPDATE_INTERVAL_MS, RUNTIME_UPDATE_INTERVAL_ENV, HTTP_MIME_TYPES, CAMERA_FIXTURE_ROUTE, CAMERA_FIXTURE_NAME_RE, SootSimBridgeHost;
28950
29118
  var init_bridge_host = __esm({
28951
29119
  "src/host/bridge-host.ts"() {
28952
29120
  "use strict";
28953
29121
  import_child_process3 = require("child_process");
28954
- import_fs3 = __toESM(require("fs"), 1);
29122
+ import_fs2 = __toESM(require("fs"), 1);
28955
29123
  import_http4 = require("http");
28956
- import_path3 = __toESM(require("path"), 1);
29124
+ import_path2 = __toESM(require("path"), 1);
28957
29125
  import_ws = require("ws");
28958
29126
  init_dev_server_scanner();
28959
29127
  init_backend_origin();
29128
+ init_automatic_update_policy();
28960
29129
  init_bridge_constants();
28961
29130
  init_cli_version();
28962
29131
  init_home_paths();
@@ -29110,7 +29279,7 @@ var init_bridge_host = __esm({
29110
29279
  async startAsync(options) {
29111
29280
  if (this.httpServer || this.wss) return this.effectivePort;
29112
29281
  this.refreshActiveRuntime();
29113
- this.bootstrapping = !this.activeRuntimeDirPath || !import_fs3.default.existsSync(import_path3.default.join(this.activeRuntimeDirPath, "index.html"));
29282
+ this.bootstrapping = !this.activeRuntimeDirPath || !import_fs2.default.existsSync(import_path2.default.join(this.activeRuntimeDirPath, "index.html"));
29114
29283
  for (let attempt = 0; attempt < this.portFallbackCount; attempt++) {
29115
29284
  const candidate = this.preferredPort + attempt;
29116
29285
  try {
@@ -29782,10 +29951,10 @@ var init_bridge_host = __esm({
29782
29951
  return;
29783
29952
  }
29784
29953
  const root = cameraFixturesDir();
29785
- const filePath = import_path3.default.join(root, name2);
29954
+ const filePath = import_path2.default.join(root, name2);
29786
29955
  let stats;
29787
29956
  try {
29788
- stats = import_fs3.default.lstatSync(filePath);
29957
+ stats = import_fs2.default.lstatSync(filePath);
29789
29958
  } catch {
29790
29959
  res.writeHead(404, { ...cors, "Content-Type": "text/plain; charset=utf-8" });
29791
29960
  res.end("not found");
@@ -29796,7 +29965,7 @@ var init_bridge_host = __esm({
29796
29965
  res.end("forbidden");
29797
29966
  return;
29798
29967
  }
29799
- const contentType = HTTP_MIME_TYPES[import_path3.default.extname(filePath).toLowerCase()] || "application/octet-stream";
29968
+ const contentType = HTTP_MIME_TYPES[import_path2.default.extname(filePath).toLowerCase()] || "application/octet-stream";
29800
29969
  sendFileWithRanges(req, res, filePath, stats.size, {
29801
29970
  ...cors,
29802
29971
  "Content-Type": contentType
@@ -29830,7 +29999,7 @@ var init_bridge_host = __esm({
29830
29999
  }
29831
30000
  startRuntimeUpdater() {
29832
30001
  if (!this.shouldWriteLockfile || this.runtimeUpdateTimer) return;
29833
- if (import_fs3.default.existsSync(import_path3.default.join(rnxHomeDir(), "runtime-update-disabled"))) {
30002
+ if (!automaticPeachUpdatesEnabled()) {
29834
30003
  this.bootstrapping = false;
29835
30004
  if (this.httpServer) this.writeLockfileSnapshot();
29836
30005
  return;
@@ -29846,6 +30015,7 @@ var init_bridge_host = __esm({
29846
30015
  this.runtimeUpdateTimer.unref();
29847
30016
  }
29848
30017
  runRuntimeUpdate(reason) {
30018
+ if (!automaticPeachUpdatesEnabled()) return Promise.resolve();
29849
30019
  if (this.runtimeUpdateInFlight) return this.runtimeUpdateInFlight;
29850
30020
  this.runtimeUpdateInFlight = (async () => {
29851
30021
  try {
@@ -30172,34 +30342,34 @@ var init_bridge_host = __esm({
30172
30342
  return;
30173
30343
  }
30174
30344
  }
30175
- const resolved = import_path3.default.resolve(baseDir, "." + rel);
30176
- const baseWithSep = baseDir.endsWith(import_path3.default.sep) ? baseDir : baseDir + import_path3.default.sep;
30345
+ const resolved = import_path2.default.resolve(baseDir, "." + rel);
30346
+ const baseWithSep = baseDir.endsWith(import_path2.default.sep) ? baseDir : baseDir + import_path2.default.sep;
30177
30347
  if (!resolved.startsWith(baseWithSep) && resolved !== baseDir) {
30178
30348
  res.writeHead(403);
30179
30349
  res.end("forbidden");
30180
30350
  return;
30181
30351
  }
30182
- import_fs3.default.realpath(resolved, (realErr, realResolved) => {
30352
+ import_fs2.default.realpath(resolved, (realErr, realResolved) => {
30183
30353
  const servePath = realErr ? resolved : realResolved;
30184
- const servePathWithSep = servePath.endsWith(import_path3.default.sep) ? servePath : servePath + import_path3.default.sep;
30354
+ const servePathWithSep = servePath.endsWith(import_path2.default.sep) ? servePath : servePath + import_path2.default.sep;
30185
30355
  if (!realErr) {
30186
30356
  const realBaseWithSep = (() => {
30187
30357
  try {
30188
- const rb = import_fs3.default.realpathSync(baseDir);
30189
- return rb.endsWith(import_path3.default.sep) ? rb : rb + import_path3.default.sep;
30358
+ const rb = import_fs2.default.realpathSync(baseDir);
30359
+ return rb.endsWith(import_path2.default.sep) ? rb : rb + import_path2.default.sep;
30190
30360
  } catch {
30191
30361
  return baseWithSep;
30192
30362
  }
30193
30363
  })();
30194
- if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path3.default.sep !== realBaseWithSep) {
30364
+ if (!servePathWithSep.startsWith(realBaseWithSep) && servePath + import_path2.default.sep !== realBaseWithSep) {
30195
30365
  res.writeHead(403);
30196
30366
  res.end("forbidden");
30197
30367
  return;
30198
30368
  }
30199
30369
  }
30200
- import_fs3.default.stat(servePath, (err, stats) => {
30370
+ import_fs2.default.stat(servePath, (err, stats) => {
30201
30371
  if (err || !stats?.isFile()) {
30202
- const ext2 = import_path3.default.extname(rel).toLowerCase();
30372
+ const ext2 = import_path2.default.extname(rel).toLowerCase();
30203
30373
  if (ext2 && ext2 !== ".html") {
30204
30374
  res.writeHead(404);
30205
30375
  res.end("not found");
@@ -30210,8 +30380,8 @@ var init_bridge_host = __esm({
30210
30380
  res.end("not found");
30211
30381
  return;
30212
30382
  }
30213
- const indexPath = import_path3.default.join(baseDir, "index.html");
30214
- import_fs3.default.readFile(indexPath, (err2, data) => {
30383
+ const indexPath = import_path2.default.join(baseDir, "index.html");
30384
+ import_fs2.default.readFile(indexPath, (err2, data) => {
30215
30385
  if (err2) {
30216
30386
  res.writeHead(404);
30217
30387
  res.end("not found");
@@ -30231,7 +30401,7 @@ var init_bridge_host = __esm({
30231
30401
  });
30232
30402
  return;
30233
30403
  }
30234
- const ext = import_path3.default.extname(servePath).toLowerCase();
30404
+ const ext = import_path2.default.extname(servePath).toLowerCase();
30235
30405
  const contentType = HTTP_MIME_TYPES[ext] || "application/octet-stream";
30236
30406
  res.writeHead(200, {
30237
30407
  "Content-Type": contentType,
@@ -30242,7 +30412,7 @@ var init_bridge_host = __esm({
30242
30412
  return;
30243
30413
  }
30244
30414
  if (ext === ".html") {
30245
- import_fs3.default.readFile(servePath, (readErr, data) => {
30415
+ import_fs2.default.readFile(servePath, (readErr, data) => {
30246
30416
  if (readErr) {
30247
30417
  try {
30248
30418
  res.end();
@@ -30256,7 +30426,7 @@ var init_bridge_host = __esm({
30256
30426
  });
30257
30427
  return;
30258
30428
  }
30259
- const stream = import_fs3.default.createReadStream(servePath);
30429
+ const stream = import_fs2.default.createReadStream(servePath);
30260
30430
  stream.pipe(res);
30261
30431
  stream.on("error", () => {
30262
30432
  try {
@@ -30943,7 +31113,7 @@ function buildComm() {
30943
31113
  if (process.platform === "linux") {
30944
31114
  return (pid) => {
30945
31115
  try {
30946
- return (0, import_fs4.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
31116
+ return (0, import_fs3.readFileSync)(`/proc/${pid}/comm`, "utf8").trim() || null;
30947
31117
  } catch {
30948
31118
  return null;
30949
31119
  }
@@ -31001,7 +31171,7 @@ function readProcessTable() {
31001
31171
  function buildLinux() {
31002
31172
  return (pid) => {
31003
31173
  try {
31004
- const raw = (0, import_fs4.readFileSync)(`/proc/${pid}/stat`, "utf8");
31174
+ const raw = (0, import_fs3.readFileSync)(`/proc/${pid}/stat`, "utf8");
31005
31175
  const end = raw.lastIndexOf(")");
31006
31176
  if (end < 0) return null;
31007
31177
  const rest = raw.slice(end + 1).trim().split(/\s+/);
@@ -31062,12 +31232,12 @@ function tryBuildDarwinCommFfi() {
31062
31232
  return null;
31063
31233
  }
31064
31234
  }
31065
- var import_child_process4, import_fs4, import_module, cached3, cachedComm, PROCESS_TABLE_TTL_MS, processTable, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET, PBI_COMM_OFFSET, PBI_COMM_LEN;
31235
+ var import_child_process4, import_fs3, import_module, cached3, cachedComm, PROCESS_TABLE_TTL_MS, processTable, PROC_PIDTBSDINFO, PROC_BSDINFO_SIZE, PBI_PPID_OFFSET, PBI_COMM_OFFSET, PBI_COMM_LEN;
31066
31236
  var init_parent_pid = __esm({
31067
31237
  "cli/parent-pid.ts"() {
31068
31238
  "use strict";
31069
31239
  import_child_process4 = require("child_process");
31070
- import_fs4 = require("fs");
31240
+ import_fs3 = require("fs");
31071
31241
  import_module = require("module");
31072
31242
  cached3 = null;
31073
31243
  cachedComm = null;
@@ -31083,31 +31253,31 @@ var init_parent_pid = __esm({
31083
31253
 
31084
31254
  // cli/secure-file.ts
31085
31255
  function writeSecureJsonAtomic(filepath, value) {
31086
- (0, import_node_fs15.mkdirSync)((0, import_node_path16.dirname)(filepath), { recursive: true });
31256
+ (0, import_node_fs17.mkdirSync)((0, import_node_path18.dirname)(filepath), { recursive: true });
31087
31257
  const temporary = `${filepath}.tmp-${process.pid}-${(0, import_node_crypto7.randomUUID)()}`;
31088
31258
  let descriptor = null;
31089
31259
  try {
31090
- descriptor = (0, import_node_fs15.openSync)(temporary, "wx", 384);
31091
- (0, import_node_fs15.fchmodSync)(descriptor, 384);
31092
- (0, import_node_fs15.writeFileSync)(descriptor, `${JSON.stringify(value, null, 2)}
31260
+ descriptor = (0, import_node_fs17.openSync)(temporary, "wx", 384);
31261
+ (0, import_node_fs17.fchmodSync)(descriptor, 384);
31262
+ (0, import_node_fs17.writeFileSync)(descriptor, `${JSON.stringify(value, null, 2)}
31093
31263
  `);
31094
- (0, import_node_fs15.fsyncSync)(descriptor);
31095
- (0, import_node_fs15.closeSync)(descriptor);
31264
+ (0, import_node_fs17.fsyncSync)(descriptor);
31265
+ (0, import_node_fs17.closeSync)(descriptor);
31096
31266
  descriptor = null;
31097
- (0, import_node_fs15.renameSync)(temporary, filepath);
31267
+ (0, import_node_fs17.renameSync)(temporary, filepath);
31098
31268
  } catch (error) {
31099
- if (descriptor !== null) (0, import_node_fs15.closeSync)(descriptor);
31100
- (0, import_node_fs15.rmSync)(temporary, { force: true });
31269
+ if (descriptor !== null) (0, import_node_fs17.closeSync)(descriptor);
31270
+ (0, import_node_fs17.rmSync)(temporary, { force: true });
31101
31271
  throw error;
31102
31272
  }
31103
31273
  }
31104
- var import_node_crypto7, import_node_fs15, import_node_path16;
31274
+ var import_node_crypto7, import_node_fs17, import_node_path18;
31105
31275
  var init_secure_file = __esm({
31106
31276
  "cli/secure-file.ts"() {
31107
31277
  "use strict";
31108
31278
  import_node_crypto7 = require("node:crypto");
31109
- import_node_fs15 = require("node:fs");
31110
- import_node_path16 = require("node:path");
31279
+ import_node_fs17 = require("node:fs");
31280
+ import_node_path18 = require("node:path");
31111
31281
  }
31112
31282
  });
31113
31283
 
@@ -31152,22 +31322,22 @@ function getStableOwnerPid() {
31152
31322
  }
31153
31323
  function getCurrentSimPath() {
31154
31324
  if (process.env[CURRENT_SIM_PATH_ENV]) {
31155
- return (0, import_path4.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
31325
+ return (0, import_path3.resolve)(process.env[CURRENT_SIM_PATH_ENV]);
31156
31326
  }
31157
31327
  const key = getCliIdentityKey();
31158
- return (0, import_path4.join)((0, import_os.tmpdir)(), `peach-current-sim-${key}.json`);
31328
+ return (0, import_path3.join)((0, import_os.tmpdir)(), `peach-current-sim-${key}.json`);
31159
31329
  }
31160
31330
  function legacyCloudCredentialDirectory(filepath) {
31161
- return (0, import_path4.join)((0, import_path4.dirname)(filepath), `${(0, import_path4.basename)(filepath)}.credentials`);
31331
+ return (0, import_path3.join)((0, import_path3.dirname)(filepath), `${(0, import_path3.basename)(filepath)}.credentials`);
31162
31332
  }
31163
31333
  function readCurrentTarget() {
31164
31334
  const filepath = getCurrentSimPath();
31165
- (0, import_fs5.rmSync)(legacyCloudCredentialDirectory(filepath), { recursive: true, force: true });
31166
- if (!(0, import_fs5.existsSync)(filepath)) return null;
31335
+ (0, import_fs4.rmSync)(legacyCloudCredentialDirectory(filepath), { recursive: true, force: true });
31336
+ if (!(0, import_fs4.existsSync)(filepath)) return null;
31167
31337
  try {
31168
- const parsed = JSON.parse((0, import_fs5.readFileSync)(filepath, "utf8"));
31338
+ const parsed = JSON.parse((0, import_fs4.readFileSync)(filepath, "utf8"));
31169
31339
  if (parsed === null || typeof parsed !== "object") {
31170
- (0, import_fs5.rmSync)(filepath, { force: true });
31340
+ (0, import_fs4.rmSync)(filepath, { force: true });
31171
31341
  return null;
31172
31342
  }
31173
31343
  const version = Reflect.get(parsed, "version");
@@ -31175,7 +31345,7 @@ function readCurrentTarget() {
31175
31345
  const simId = Reflect.get(parsed, "simId");
31176
31346
  const updatedAt = Reflect.get(parsed, "updatedAt");
31177
31347
  if (version !== 1 && version !== CURRENT_SIM_VERSION || version === CURRENT_SIM_VERSION && plane !== "local" || typeof simId !== "string" || !simId.trim() || typeof updatedAt !== "string") {
31178
- (0, import_fs5.rmSync)(filepath, { force: true });
31348
+ (0, import_fs4.rmSync)(filepath, { force: true });
31179
31349
  return null;
31180
31350
  }
31181
31351
  const target = {
@@ -31187,7 +31357,7 @@ function readCurrentTarget() {
31187
31357
  if (version === 1) writeSecureJsonAtomic(filepath, target);
31188
31358
  return target;
31189
31359
  } catch {
31190
- (0, import_fs5.rmSync)(filepath, { force: true });
31360
+ (0, import_fs4.rmSync)(filepath, { force: true });
31191
31361
  return null;
31192
31362
  }
31193
31363
  }
@@ -31205,15 +31375,15 @@ function saveCurrentSimId(simId) {
31205
31375
  });
31206
31376
  }
31207
31377
  function clearCurrentSimId() {
31208
- (0, import_fs5.rmSync)(getCurrentSimPath(), { force: true });
31378
+ (0, import_fs4.rmSync)(getCurrentSimPath(), { force: true });
31209
31379
  }
31210
- var import_fs5, import_os, import_path4, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE, readCurrentSim;
31380
+ var import_fs4, import_os, import_path3, CURRENT_SIM_VERSION, CURRENT_SIM_PATH_ENV, IDENTITY_ENV_VARS, IMMORTAL_HOST_COMM_RE, readCurrentSim;
31211
31381
  var init_current_sim = __esm({
31212
31382
  "cli/current-sim.ts"() {
31213
31383
  "use strict";
31214
- import_fs5 = require("fs");
31384
+ import_fs4 = require("fs");
31215
31385
  import_os = require("os");
31216
- import_path4 = require("path");
31386
+ import_path3 = require("path");
31217
31387
  init_parent_pid();
31218
31388
  init_secure_file();
31219
31389
  CURRENT_SIM_VERSION = 2;
@@ -31282,17 +31452,17 @@ function liveDevBridgeLockfiles() {
31282
31452
  return readDevBridgeLockfiles().filter((lockfile) => isDevBridgeLockfileFresh(lockfile));
31283
31453
  }
31284
31454
  function checkoutRoot(cwd) {
31285
- let current = import_node_path17.default.resolve(cwd);
31455
+ let current = import_node_path19.default.resolve(cwd);
31286
31456
  while (true) {
31287
- if (import_node_fs16.default.existsSync(import_node_path17.default.join(current, ".git"))) return current;
31288
- const parent = import_node_path17.default.dirname(current);
31457
+ if (import_node_fs18.default.existsSync(import_node_path19.default.join(current, ".git"))) return current;
31458
+ const parent = import_node_path19.default.dirname(current);
31289
31459
  if (parent === current) return null;
31290
31460
  current = parent;
31291
31461
  }
31292
31462
  }
31293
31463
  function pathContains(parent, child) {
31294
- const relative2 = import_node_path17.default.relative(parent, child);
31295
- return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${import_node_path17.default.sep}`) && !import_node_path17.default.isAbsolute(relative2);
31464
+ const relative2 = import_node_path19.default.relative(parent, child);
31465
+ return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${import_node_path19.default.sep}`) && !import_node_path19.default.isAbsolute(relative2);
31296
31466
  }
31297
31467
  function resolveDefaultDevBridgeLockfile() {
31298
31468
  const lockfiles = liveDevBridgeLockfiles();
@@ -31784,18 +31954,18 @@ async function evalInBridge(bridge, code, opts = {}) {
31784
31954
  if (opts.acquireLock) payload.acquireLock = true;
31785
31955
  return bridge.send(payload);
31786
31956
  }
31787
- async function callInBridge(bridge, path21, ...args) {
31788
- return bridge.send({ type: "call", path: path21, args });
31957
+ async function callInBridge(bridge, path22, ...args) {
31958
+ return bridge.send({ type: "call", path: path22, args });
31789
31959
  }
31790
- async function callInBridgeWrite(bridge, path21, ...args) {
31791
- return bridge.send({ type: "call", path: path21, args, acquireLock: true });
31960
+ async function callInBridgeWrite(bridge, path22, ...args) {
31961
+ return bridge.send({ type: "call", path: path22, args, acquireLock: true });
31792
31962
  }
31793
- var import_node_fs16, import_node_path17, import_ws2, PEACH_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError, BRIDGE_VALUE_FLAGS_TABLE, BRIDGE_VALUE_FLAGS;
31963
+ var import_node_fs18, import_node_path19, import_ws2, PEACH_PLACEMENT_ENV, resolvedWorld, BridgeSimLockedError, BRIDGE_VALUE_FLAGS_TABLE, BRIDGE_VALUE_FLAGS;
31794
31964
  var init_ws_bridge = __esm({
31795
31965
  "cli/ws-bridge.ts"() {
31796
31966
  "use strict";
31797
- import_node_fs16 = __toESM(require("node:fs"), 1);
31798
- import_node_path17 = __toESM(require("node:path"), 1);
31967
+ import_node_fs18 = __toESM(require("node:fs"), 1);
31968
+ import_node_path19 = __toESM(require("node:path"), 1);
31799
31969
  import_ws2 = require("ws");
31800
31970
  init_bridge_constants();
31801
31971
  init_cli_constants();
@@ -31923,8 +32093,8 @@ function getDefaultPortForProtocol(protocol) {
31923
32093
  return protocol === "https:" ? 443 : 80;
31924
32094
  }
31925
32095
  function isBaseServerUrl(url) {
31926
- const path21 = url.pathname || "/";
31927
- return (path21 === "/" || path21 === "") && !url.search && !url.hash;
32096
+ const path22 = url.pathname || "/";
32097
+ return (path22 === "/" || path22 === "") && !url.search && !url.hash;
31928
32098
  }
31929
32099
  async function resolvePortViaServerScan(port) {
31930
32100
  try {
@@ -32098,6 +32268,96 @@ var init_flow_timeout_scale = __esm({
32098
32268
  }
32099
32269
  });
32100
32270
 
32271
+ // src/native-firebase-config.ts
32272
+ function readNativeFirebaseConfig(projectRoot) {
32273
+ const result = {};
32274
+ if (![
32275
+ "app.json",
32276
+ "app.config.js",
32277
+ "app.config.ts",
32278
+ "app.config.cjs",
32279
+ "app.config.mjs"
32280
+ ].some((name2) => import_node_fs19.default.existsSync(import_node_path20.default.join(projectRoot, name2))))
32281
+ return result;
32282
+ const require5 = (0, import_node_module.createRequire)(import_node_path20.default.join(projectRoot, "package.json"));
32283
+ const configModule = require5("@expo/config");
32284
+ if (!isRecord(configModule) || typeof configModule.getConfig !== "function") {
32285
+ throw new Error("Expo native configuration is unavailable.");
32286
+ }
32287
+ const resolved = Reflect.apply(configModule.getConfig, configModule, [
32288
+ projectRoot,
32289
+ { skipSDKVersionRequirement: true }
32290
+ ]);
32291
+ const config = isRecord(resolved) && isRecord(resolved.exp) ? resolved.exp : {};
32292
+ for (const platform of ["ios", "android"]) {
32293
+ const native = config[platform];
32294
+ if (!isRecord(native) || typeof native.googleServicesFile !== "string") continue;
32295
+ try {
32296
+ const source = import_node_fs19.default.readFileSync(
32297
+ import_node_path20.default.resolve(projectRoot, native.googleServicesFile),
32298
+ "utf8"
32299
+ );
32300
+ const parsed = platform === "ios" ? parsePlistSource(source) : JSON.parse(source);
32301
+ if (!isRecord(parsed)) throw new Error("Invalid Google services file.");
32302
+ if (platform === "ios") {
32303
+ result[platform] = {
32304
+ apiKey: parsed.API_KEY,
32305
+ appId: parsed.GOOGLE_APP_ID,
32306
+ projectId: parsed.PROJECT_ID,
32307
+ databaseURL: parsed.DATABASE_URL,
32308
+ gaTrackingId: parsed.TRACKING_ID,
32309
+ storageBucket: parsed.STORAGE_BUCKET,
32310
+ messagingSenderId: parsed.GCM_SENDER_ID,
32311
+ clientId: parsed.CLIENT_ID,
32312
+ androidClientID: parsed.ANDROID_CLIENT_ID,
32313
+ deepLinkUrlScheme: parsed.REVERSED_CLIENT_ID
32314
+ };
32315
+ } else {
32316
+ const project = isRecord(parsed.project_info) ? parsed.project_info : {};
32317
+ const clients = Array.isArray(parsed.client) ? parsed.client : [];
32318
+ const client = clients.find((value) => {
32319
+ if (!isRecord(value) || !isRecord(value.client_info)) return false;
32320
+ const android = value.client_info.android_client_info;
32321
+ return isRecord(android) && android.package_name === native.package;
32322
+ });
32323
+ if (!isRecord(client) || !isRecord(client.client_info))
32324
+ throw new Error("No Google services client matches the Android package.");
32325
+ const apiKeys = Array.isArray(client.api_key) ? client.api_key : [];
32326
+ const apiKey = apiKeys.find(
32327
+ (value) => isRecord(value) && typeof value.current_key === "string"
32328
+ );
32329
+ const oauthClients = Array.isArray(client.oauth_client) ? client.oauth_client : [];
32330
+ const oauth = oauthClients.find(
32331
+ (value) => isRecord(value) && value.client_type === 3
32332
+ );
32333
+ result[platform] = {
32334
+ apiKey: isRecord(apiKey) ? apiKey.current_key : void 0,
32335
+ appId: client.client_info.mobilesdk_app_id,
32336
+ projectId: project.project_id,
32337
+ databaseURL: project.firebase_url,
32338
+ storageBucket: project.storage_bucket,
32339
+ messagingSenderId: project.project_number,
32340
+ clientId: isRecord(oauth) ? oauth.client_id : void 0
32341
+ };
32342
+ }
32343
+ } catch (error) {
32344
+ result[platform] = { error: error instanceof Error ? error.message : String(error) };
32345
+ }
32346
+ }
32347
+ return result;
32348
+ }
32349
+ var import_node_fs19, import_node_module, import_node_path20;
32350
+ var init_native_firebase_config = __esm({
32351
+ "src/native-firebase-config.ts"() {
32352
+ "use strict";
32353
+ import_node_fs19 = __toESM(require("node:fs"), 1);
32354
+ import_node_module = require("node:module");
32355
+ import_node_path20 = __toESM(require("node:path"), 1);
32356
+ init_is_record();
32357
+ init_plist();
32358
+ }
32359
+ });
32360
+
32101
32361
  // src/profiles.ts
32102
32362
  function normalizeProfileId(input) {
32103
32363
  const id = input.trim();
@@ -32111,15 +32371,15 @@ function normalizeProfileId(input) {
32111
32371
  return id;
32112
32372
  }
32113
32373
  function profileIndexPath() {
32114
- return import_path5.default.join(profilesDir(), PROFILE_INDEX_FILE);
32374
+ return import_path4.default.join(profilesDir(), PROFILE_INDEX_FILE);
32115
32375
  }
32116
32376
  function playwrightProfileUserDataDir(profileId) {
32117
- return import_path5.default.join(profilesDir(), "playwright", normalizeProfileId(profileId));
32377
+ return import_path4.default.join(profilesDir(), "playwright", normalizeProfileId(profileId));
32118
32378
  }
32119
32379
  function readIndexRaw() {
32120
32380
  try {
32121
32381
  const parsed = JSON.parse(
32122
- import_fs6.default.readFileSync(profileIndexPath(), "utf8")
32382
+ import_fs5.default.readFileSync(profileIndexPath(), "utf8")
32123
32383
  );
32124
32384
  if (!parsed || parsed.version !== PROFILE_INDEX_VERSION) {
32125
32385
  return { version: PROFILE_INDEX_VERSION, profiles: [] };
@@ -32160,9 +32420,9 @@ function writeIndex(index) {
32160
32420
  ensureRnxHome();
32161
32421
  const next = withDefault(index);
32162
32422
  const tmp = `${profileIndexPath()}.tmp`;
32163
- import_fs6.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
32423
+ import_fs5.default.writeFileSync(tmp, `${JSON.stringify(next, null, 2)}
32164
32424
  `, "utf8");
32165
- import_fs6.default.renameSync(tmp, profileIndexPath());
32425
+ import_fs5.default.renameSync(tmp, profileIndexPath());
32166
32426
  return next;
32167
32427
  }
32168
32428
  function listProfiles() {
@@ -32189,12 +32449,12 @@ function createProfile(id) {
32189
32449
  writeIndex({ version: PROFILE_INDEX_VERSION, profiles: [...index.profiles, profile] });
32190
32450
  return profile;
32191
32451
  }
32192
- var import_fs6, import_path5, DEFAULT_PROFILE_ID, PROFILE_INDEX_FILE, PROFILE_INDEX_VERSION;
32452
+ var import_fs5, import_path4, DEFAULT_PROFILE_ID, PROFILE_INDEX_FILE, PROFILE_INDEX_VERSION;
32193
32453
  var init_profiles = __esm({
32194
32454
  "src/profiles.ts"() {
32195
32455
  "use strict";
32196
- import_fs6 = __toESM(require("fs"), 1);
32197
- import_path5 = __toESM(require("path"), 1);
32456
+ import_fs5 = __toESM(require("fs"), 1);
32457
+ import_path4 = __toESM(require("path"), 1);
32198
32458
  init_home_paths();
32199
32459
  DEFAULT_PROFILE_ID = "default";
32200
32460
  PROFILE_INDEX_FILE = "profiles.json";
@@ -32256,7 +32516,7 @@ function colorsetValue(color) {
32256
32516
  }
32257
32517
  function enumerateBundleColors(paths, readText2) {
32258
32518
  const table = {};
32259
- for (const contentsPath of paths.filter((path21) => baseOf(path21) === "Contents.json")) {
32519
+ for (const contentsPath of paths.filter((path22) => baseOf(path22) === "Contents.json")) {
32260
32520
  const name2 = catalogEntryName(contentsPath, ".colorset", readText2);
32261
32521
  if (name2 === null || name2 in table) continue;
32262
32522
  let colors;
@@ -32304,59 +32564,59 @@ var init_bundleAssets = __esm({
32304
32564
  // cli/app-catalog.ts
32305
32565
  function listDir(dir) {
32306
32566
  try {
32307
- return import_node_fs17.default.readdirSync(dir, { withFileTypes: true });
32567
+ return import_node_fs20.default.readdirSync(dir, { withFileTypes: true });
32308
32568
  } catch {
32309
32569
  return [];
32310
32570
  }
32311
32571
  }
32312
32572
  function readText(file) {
32313
32573
  try {
32314
- return import_node_fs17.default.readFileSync(file, "utf8");
32574
+ return import_node_fs20.default.readFileSync(file, "utf8");
32315
32575
  } catch {
32316
32576
  return null;
32317
32577
  }
32318
32578
  }
32319
32579
  function catalogFiles(dir, found) {
32320
32580
  for (const entry of listDir(dir)) {
32321
- const full = import_node_path18.default.join(dir, entry.name);
32581
+ const full = import_node_path21.default.join(dir, entry.name);
32322
32582
  if (entry.isDirectory()) catalogFiles(full, found);
32323
32583
  else if (entry.name === "Contents.json") found.push(full);
32324
32584
  }
32325
32585
  }
32326
32586
  function discoverAppCatalog(appDir) {
32327
- const iosDir = import_node_path18.default.join(appDir, "ios");
32587
+ const iosDir = import_node_path21.default.join(appDir, "ios");
32328
32588
  const target = listDir(iosDir).find(
32329
- (entry) => entry.isDirectory() && entry.name !== "Pods" && listDir(import_node_path18.default.join(iosDir, entry.name)).some(
32589
+ (entry) => entry.isDirectory() && entry.name !== "Pods" && listDir(import_node_path21.default.join(iosDir, entry.name)).some(
32330
32590
  (file) => /^AppDelegate\.(swift|mm|m)$/.test(file.name)
32331
32591
  )
32332
32592
  );
32333
32593
  if (!target) return null;
32334
- const targetDir = import_node_path18.default.join(iosDir, target.name);
32594
+ const targetDir = import_node_path21.default.join(iosDir, target.name);
32335
32595
  const files = [];
32336
32596
  for (const entry of listDir(targetDir)) {
32337
32597
  if (entry.isDirectory() && entry.name.endsWith(".xcassets"))
32338
- catalogFiles(import_node_path18.default.join(targetDir, entry.name), files);
32598
+ catalogFiles(import_node_path21.default.join(targetDir, entry.name), files);
32339
32599
  }
32340
32600
  const relative2 = files.map(
32341
- (file) => import_node_path18.default.relative(targetDir, file).split(import_node_path18.default.sep).join(import_node_path18.default.posix.sep)
32601
+ (file) => import_node_path21.default.relative(targetDir, file).split(import_node_path21.default.sep).join(import_node_path21.default.posix.sep)
32342
32602
  );
32343
32603
  const colors = enumerateBundleColors(
32344
32604
  relative2,
32345
- (candidate) => candidate.endsWith("Contents.json") ? readText(import_node_path18.default.join(targetDir, candidate)) : null
32605
+ (candidate) => candidate.endsWith("Contents.json") ? readText(import_node_path21.default.join(targetDir, candidate)) : null
32346
32606
  );
32347
32607
  const pbxproj = listDir(iosDir).find((entry) => entry.name.endsWith(".xcodeproj"));
32348
- const accentName = readText(import_node_path18.default.join(targetDir, "Info.plist"))?.match(PLIST_ACCENT)?.[1] ?? (pbxproj ? readText(import_node_path18.default.join(iosDir, pbxproj.name, "project.pbxproj"))?.match(
32608
+ const accentName = readText(import_node_path21.default.join(targetDir, "Info.plist"))?.match(PLIST_ACCENT)?.[1] ?? (pbxproj ? readText(import_node_path21.default.join(iosDir, pbxproj.name, "project.pbxproj"))?.match(
32349
32609
  ACCENT_BUILD_SETTING
32350
32610
  )?.[1] : void 0) ?? null;
32351
32611
  if (accentName === null && Object.keys(colors).length === 0) return null;
32352
32612
  return { colors, accentName };
32353
32613
  }
32354
- var import_node_fs17, import_node_path18, ACCENT_BUILD_SETTING, PLIST_ACCENT;
32614
+ var import_node_fs20, import_node_path21, ACCENT_BUILD_SETTING, PLIST_ACCENT;
32355
32615
  var init_app_catalog = __esm({
32356
32616
  "cli/app-catalog.ts"() {
32357
32617
  "use strict";
32358
- import_node_fs17 = __toESM(require("node:fs"), 1);
32359
- import_node_path18 = __toESM(require("node:path"), 1);
32618
+ import_node_fs20 = __toESM(require("node:fs"), 1);
32619
+ import_node_path21 = __toESM(require("node:path"), 1);
32360
32620
  init_bundleAssets();
32361
32621
  ACCENT_BUILD_SETTING = /ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "?([^";]+)"?;/;
32362
32622
  PLIST_ACCENT = /<key>NSAccentColorName<\/key>\s*<string>([^<]+)<\/string>/;
@@ -32366,9 +32626,9 @@ var init_app_catalog = __esm({
32366
32626
  // cli/app-project.ts
32367
32627
  function firstNamedFile(dir, names) {
32368
32628
  for (const name2 of names) {
32369
- const candidate = import_node_path19.default.join(dir, name2);
32629
+ const candidate = import_node_path22.default.join(dir, name2);
32370
32630
  try {
32371
- if (import_node_fs18.default.statSync(candidate).isFile()) return candidate;
32631
+ if (import_node_fs21.default.statSync(candidate).isFile()) return candidate;
32372
32632
  } catch {
32373
32633
  }
32374
32634
  }
@@ -32381,24 +32641,24 @@ function findRNXAppConfig(dir) {
32381
32641
  return firstNamedFile(dir, RNX_APP_CONFIG_NAMES);
32382
32642
  }
32383
32643
  function resolveAppProject(projectRoot) {
32384
- const appDir = import_node_path19.default.resolve(projectRoot);
32644
+ const appDir = import_node_path22.default.resolve(projectRoot);
32385
32645
  try {
32386
- if (!import_node_fs18.default.statSync(appDir).isDirectory()) return null;
32646
+ if (!import_node_fs21.default.statSync(appDir).isDirectory()) return null;
32387
32647
  } catch {
32388
32648
  return null;
32389
32649
  }
32390
32650
  const configPath = findRNXAppConfig(appDir);
32391
- if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs18.default.existsSync(import_node_path19.default.join(appDir, "package.json"))) {
32651
+ if (!configPath && !findExpoAppConfig(appDir) && !import_node_fs21.default.existsSync(import_node_path22.default.join(appDir, "package.json"))) {
32392
32652
  return null;
32393
32653
  }
32394
32654
  return { appDir, configPath };
32395
32655
  }
32396
- var import_node_fs18, import_node_path19, EXPO_APP_CONFIG_NAMES, RNX_APP_CONFIG_NAMES;
32656
+ var import_node_fs21, import_node_path22, EXPO_APP_CONFIG_NAMES, RNX_APP_CONFIG_NAMES;
32397
32657
  var init_app_project = __esm({
32398
32658
  "cli/app-project.ts"() {
32399
32659
  "use strict";
32400
- import_node_fs18 = __toESM(require("node:fs"), 1);
32401
- import_node_path19 = __toESM(require("node:path"), 1);
32660
+ import_node_fs21 = __toESM(require("node:fs"), 1);
32661
+ import_node_path22 = __toESM(require("node:path"), 1);
32402
32662
  EXPO_APP_CONFIG_NAMES = [
32403
32663
  "app.config.js",
32404
32664
  "app.config.ts",
@@ -32427,13 +32687,13 @@ function isRNXConfig(value) {
32427
32687
  }
32428
32688
  function resolveConfigReplacementFiles(config, configPath) {
32429
32689
  if (!config.modules) return config;
32430
- const configDir = import_node_path20.default.dirname(configPath);
32690
+ const configDir = import_node_path23.default.dirname(configPath);
32431
32691
  return {
32432
32692
  ...config,
32433
32693
  modules: Object.fromEntries(
32434
32694
  Object.entries(config.modules).map(([name2, resolution]) => [
32435
32695
  name2,
32436
- resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file: import_node_path20.default.resolve(configDir, resolution.file) } : resolution
32696
+ resolution && typeof resolution === "object" && "file" in resolution ? { ...resolution, file: import_node_path23.default.resolve(configDir, resolution.file) } : resolution
32437
32697
  ])
32438
32698
  )
32439
32699
  };
@@ -32463,17 +32723,17 @@ async function resolveRNXAppConfig(startDir = process.cwd()) {
32463
32723
  const project = resolveAppProject(startDir);
32464
32724
  return { project, config: await loadRNXAppConfig(project) };
32465
32725
  }
32466
- var import_node_module, import_node_path20, import_jiti, require2;
32726
+ var import_node_module2, import_node_path23, import_jiti, require2;
32467
32727
  var init_app_config = __esm({
32468
32728
  "cli/app-config.ts"() {
32469
32729
  "use strict";
32470
- import_node_module = require("node:module");
32471
- import_node_path20 = __toESM(require("node:path"), 1);
32730
+ import_node_module2 = require("node:module");
32731
+ import_node_path23 = __toESM(require("node:path"), 1);
32472
32732
  init_src();
32473
32733
  import_jiti = require("jiti");
32474
32734
  init_public_brand();
32475
32735
  init_app_project();
32476
- require2 = (0, import_node_module.createRequire)(__sootsim_import_meta_url);
32736
+ require2 = (0, import_node_module2.createRequire)(__sootsim_import_meta_url);
32477
32737
  }
32478
32738
  });
32479
32739
 
@@ -32525,13 +32785,13 @@ function discoverNativeLinkedAppFonts(opts) {
32525
32785
  scannedFontDirectories++;
32526
32786
  let entries;
32527
32787
  try {
32528
- entries = import_node_fs19.default.readdirSync(current.dir, { withFileTypes: true });
32788
+ entries = import_node_fs22.default.readdirSync(current.dir, { withFileTypes: true });
32529
32789
  } catch {
32530
32790
  continue;
32531
32791
  }
32532
32792
  for (const entry of entries) {
32533
32793
  if (entry.isSymbolicLink()) continue;
32534
- const fullPath = import_node_path21.default.join(current.dir, entry.name);
32794
+ const fullPath = import_node_path24.default.join(current.dir, entry.name);
32535
32795
  if (entry.isDirectory()) {
32536
32796
  if (current.depth < 4 && pending.length < 64 && !entry.name.startsWith(".")) {
32537
32797
  pending.push({ dir: fullPath, depth: current.depth + 1 });
@@ -32539,15 +32799,15 @@ function discoverNativeLinkedAppFonts(opts) {
32539
32799
  continue;
32540
32800
  }
32541
32801
  if (!entry.isFile() || !/\.(ttf|otf|woff|woff2)$/i.test(entry.name)) continue;
32542
- const relative2 = import_node_path21.default.relative(root, fullPath).split(import_node_path21.default.sep).join("/");
32543
- fontPaths.push(import_node_path21.default.posix.join(metroPathPrefix, relative2));
32802
+ const relative2 = import_node_path24.default.relative(root, fullPath).split(import_node_path24.default.sep).join("/");
32803
+ fontPaths.push(import_node_path24.default.posix.join(metroPathPrefix, relative2));
32544
32804
  if (fontPaths.length >= 256) break;
32545
32805
  }
32546
32806
  }
32547
32807
  };
32548
32808
  try {
32549
32809
  const packageJson = JSON.parse(
32550
- import_node_fs19.default.readFileSync(import_node_path21.default.join(selectedAppDir, "package.json"), "utf8")
32810
+ import_node_fs22.default.readFileSync(import_node_path24.default.join(selectedAppDir, "package.json"), "utf8")
32551
32811
  );
32552
32812
  const dependencyNames = /* @__PURE__ */ new Set();
32553
32813
  for (const field of ["dependencies", "devDependencies", "optionalDependencies"]) {
@@ -32562,25 +32822,34 @@ function discoverNativeLinkedAppFonts(opts) {
32562
32822
  const config = Reflect.get(packageJson, "reactNativeVectorIcons");
32563
32823
  const configuredFontDir = config && typeof config === "object" ? Reflect.get(config, "fontDir") : null;
32564
32824
  const configuredDir = typeof configuredFontDir === "string" ? configuredFontDir : "rnvi-fonts";
32565
- const root = import_node_path21.default.resolve(selectedAppDir, configuredDir);
32566
- const relativeRoot = import_node_path21.default.relative(selectedAppDir, root);
32567
- if (!relativeRoot.startsWith("..") && !import_node_path21.default.isAbsolute(relativeRoot)) {
32568
- collectFontFiles(root, relativeRoot.split(import_node_path21.default.sep).join("/"));
32569
- }
32570
- const vectorIconRequire = (0, import_node_module2.createRequire)(import_node_path21.default.join(selectedAppDir, "package.json"));
32825
+ const root = import_node_path24.default.resolve(selectedAppDir, configuredDir);
32826
+ const relativeRoot = import_node_path24.default.relative(selectedAppDir, root);
32827
+ if (!relativeRoot.startsWith("..") && !import_node_path24.default.isAbsolute(relativeRoot)) {
32828
+ collectFontFiles(root, relativeRoot.split(import_node_path24.default.sep).join("/"));
32829
+ }
32830
+ const bundleDir = import_node_path24.default.posix.dirname(new URL(opts.bundleUrl).pathname).replace(/^\/+/, "");
32831
+ const appRelativeDir = bundleDir.split("/").join(import_node_path24.default.sep);
32832
+ const metroRootCandidates = [selectedAppDir];
32833
+ if (bundleDir && selectedAppDir.endsWith(import_node_path24.default.sep + appRelativeDir)) {
32834
+ metroRootCandidates.push(selectedAppDir.slice(0, -appRelativeDir.length - 1));
32835
+ }
32836
+ const vectorIconRequire = (0, import_node_module3.createRequire)(import_node_path24.default.join(selectedAppDir, "package.json"));
32571
32837
  for (const dependencyName of vectorIconDependencies) {
32572
32838
  try {
32573
32839
  const entryPath = vectorIconRequire.resolve(dependencyName);
32574
- const dependencyPath = dependencyName.split("/").join(import_node_path21.default.sep);
32575
- const marker = `${import_node_path21.default.sep}node_modules${import_node_path21.default.sep}${dependencyPath}${import_node_path21.default.sep}`;
32840
+ const dependencyPath = dependencyName.split("/").join(import_node_path24.default.sep);
32841
+ const marker = `${import_node_path24.default.sep}node_modules${import_node_path24.default.sep}${dependencyPath}${import_node_path24.default.sep}`;
32576
32842
  const markerIndex = entryPath.lastIndexOf(marker);
32577
32843
  if (markerIndex === -1) continue;
32578
32844
  const packageRoot = entryPath.slice(0, markerIndex + marker.length - 1);
32579
32845
  const fontsDir = dependencyName === "react-native-vector-icons" ? "Fonts" : "fonts";
32580
- collectFontFiles(
32581
- import_node_path21.default.join(packageRoot, fontsDir),
32582
- import_node_path21.default.posix.join("node_modules", dependencyName, fontsDir)
32583
- );
32846
+ const fontsRoot = import_node_path24.default.join(packageRoot, fontsDir);
32847
+ for (const metroRoot of metroRootCandidates) {
32848
+ collectFontFiles(
32849
+ fontsRoot,
32850
+ import_node_path24.default.relative(metroRoot, fontsRoot).split(import_node_path24.default.sep).join("/")
32851
+ );
32852
+ }
32584
32853
  } catch {
32585
32854
  }
32586
32855
  }
@@ -32588,37 +32857,37 @@ function discoverNativeLinkedAppFonts(opts) {
32588
32857
  } catch {
32589
32858
  }
32590
32859
  try {
32591
- const configPath = import_node_path21.default.join(selectedAppDir, "react-native.config.js");
32592
- if (import_node_fs19.default.statSync(configPath).isFile()) {
32593
- const appConfigRequire = (0, import_node_module2.createRequire)(import_node_path21.default.join(selectedAppDir, "package.json"));
32860
+ const configPath = import_node_path24.default.join(selectedAppDir, "react-native.config.js");
32861
+ if (import_node_fs22.default.statSync(configPath).isFile()) {
32862
+ const appConfigRequire = (0, import_node_module3.createRequire)(import_node_path24.default.join(selectedAppDir, "package.json"));
32594
32863
  const rnConfig = appConfigRequire(configPath);
32595
32864
  const assets = rnConfig && typeof rnConfig === "object" ? Reflect.get(rnConfig, "assets") : null;
32596
32865
  if (Array.isArray(assets)) {
32597
32866
  for (const assetDir of assets) {
32598
32867
  if (typeof assetDir !== "string") continue;
32599
- const root = import_node_path21.default.resolve(selectedAppDir, assetDir);
32600
- const relativeRoot = import_node_path21.default.relative(selectedAppDir, root);
32601
- if (relativeRoot.startsWith("..") || import_node_path21.default.isAbsolute(relativeRoot)) continue;
32602
- collectFontFiles(root, relativeRoot.split(import_node_path21.default.sep).join("/"));
32868
+ const root = import_node_path24.default.resolve(selectedAppDir, assetDir);
32869
+ const relativeRoot = import_node_path24.default.relative(selectedAppDir, root);
32870
+ if (relativeRoot.startsWith("..") || import_node_path24.default.isAbsolute(relativeRoot)) continue;
32871
+ collectFontFiles(root, relativeRoot.split(import_node_path24.default.sep).join("/"));
32603
32872
  }
32604
32873
  }
32605
32874
  }
32606
32875
  } catch {
32607
32876
  }
32608
32877
  if (platform === "ios") {
32609
- const iosDir = import_node_path21.default.join(selectedAppDir, "ios");
32878
+ const iosDir = import_node_path24.default.join(selectedAppDir, "ios");
32610
32879
  try {
32611
- const targetDirs = import_node_fs19.default.readdirSync(iosDir, { withFileTypes: true }).filter(
32880
+ const targetDirs = import_node_fs22.default.readdirSync(iosDir, { withFileTypes: true }).filter(
32612
32881
  (entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name !== "Pods" && entry.name !== "build" && !entry.name.startsWith(".")
32613
32882
  ).slice(0, 64);
32614
- const plistPaths = [import_node_path21.default.join(iosDir, "Info.plist")];
32883
+ const plistPaths = [import_node_path24.default.join(iosDir, "Info.plist")];
32615
32884
  for (const entry of targetDirs) {
32616
- plistPaths.push(import_node_path21.default.join(iosDir, entry.name, "Info.plist"));
32885
+ plistPaths.push(import_node_path24.default.join(iosDir, entry.name, "Info.plist"));
32617
32886
  }
32618
32887
  for (const plistPath of plistPaths) {
32619
32888
  let parsed;
32620
32889
  try {
32621
- parsed = parsePlistSource(import_node_fs19.default.readFileSync(plistPath, "utf8"));
32890
+ parsed = parsePlistSource(import_node_fs22.default.readFileSync(plistPath, "utf8"));
32622
32891
  } catch {
32623
32892
  continue;
32624
32893
  }
@@ -32628,21 +32897,21 @@ function discoverNativeLinkedAppFonts(opts) {
32628
32897
  for (const declaredFont of declaredFonts) {
32629
32898
  if (typeof declaredFont !== "string") continue;
32630
32899
  const candidates = [
32631
- import_node_path21.default.resolve(import_node_path21.default.dirname(plistPath), declaredFont),
32632
- import_node_path21.default.resolve(iosDir, declaredFont)
32900
+ import_node_path24.default.resolve(import_node_path24.default.dirname(plistPath), declaredFont),
32901
+ import_node_path24.default.resolve(iosDir, declaredFont)
32633
32902
  ];
32634
32903
  const fontPath = candidates.find((candidate) => {
32635
- const relative2 = import_node_path21.default.relative(selectedAppDir, candidate);
32636
- if (relative2.startsWith("..") || import_node_path21.default.isAbsolute(relative2)) return false;
32904
+ const relative2 = import_node_path24.default.relative(selectedAppDir, candidate);
32905
+ if (relative2.startsWith("..") || import_node_path24.default.isAbsolute(relative2)) return false;
32637
32906
  try {
32638
- return import_node_fs19.default.statSync(candidate).isFile();
32907
+ return import_node_fs22.default.statSync(candidate).isFile();
32639
32908
  } catch {
32640
32909
  return false;
32641
32910
  }
32642
32911
  });
32643
32912
  if (!fontPath) continue;
32644
32913
  fontPaths.push(
32645
- import_node_path21.default.relative(selectedAppDir, fontPath).split(import_node_path21.default.sep).join("/")
32914
+ import_node_path24.default.relative(selectedAppDir, fontPath).split(import_node_path24.default.sep).join("/")
32646
32915
  );
32647
32916
  }
32648
32917
  }
@@ -32681,19 +32950,19 @@ async function resolveMetroProjectRoot(bundleUrl, opts) {
32681
32950
  function encodeAppFontsWire(specs) {
32682
32951
  return specs.map((spec) => `${encodeURIComponent(spec.url)}::${encodeURIComponent(spec.family)}`).join(",");
32683
32952
  }
32684
- var import_node_fs19, import_node_module2, import_node_path21, import_config_plugin_fonts, require3;
32953
+ var import_node_fs22, import_node_module3, import_node_path24, import_config_plugin_fonts, require3;
32685
32954
  var init_app_fonts = __esm({
32686
32955
  "cli/app-fonts.ts"() {
32687
32956
  "use strict";
32688
- import_node_fs19 = __toESM(require("node:fs"), 1);
32689
- import_node_module2 = require("node:module");
32690
- import_node_path21 = __toESM(require("node:path"), 1);
32957
+ import_node_fs22 = __toESM(require("node:fs"), 1);
32958
+ import_node_module3 = require("node:module");
32959
+ import_node_path24 = __toESM(require("node:path"), 1);
32691
32960
  import_config_plugin_fonts = require("peach-engine/engine/config-plugin-fonts");
32692
32961
  init_dev_server_scanner();
32693
32962
  init_backend_origin();
32694
32963
  init_plist();
32695
32964
  init_app_project();
32696
- require3 = (0, import_node_module2.createRequire)(__sootsim_import_meta_url);
32965
+ require3 = (0, import_node_module3.createRequire)(__sootsim_import_meta_url);
32697
32966
  }
32698
32967
  });
32699
32968
 
@@ -32762,15 +33031,15 @@ function splashImageUrls(spec) {
32762
33031
  if (spec.dark?.backgroundImageUrl) urls.add(spec.dark.backgroundImageUrl);
32763
33032
  return [...urls];
32764
33033
  }
32765
- var import_node_module3, import_config_plugin_splash, require4;
33034
+ var import_node_module4, import_config_plugin_splash, require4;
32766
33035
  var init_app_splash = __esm({
32767
33036
  "cli/app-splash.ts"() {
32768
33037
  "use strict";
32769
- import_node_module3 = require("node:module");
33038
+ import_node_module4 = require("node:module");
32770
33039
  import_config_plugin_splash = require("peach-engine/engine/config-plugin-splash");
32771
33040
  init_backend_origin();
32772
33041
  init_app_project();
32773
- require4 = (0, import_node_module3.createRequire)(__sootsim_import_meta_url);
33042
+ require4 = (0, import_node_module4.createRequire)(__sootsim_import_meta_url);
32774
33043
  }
32775
33044
  });
32776
33045
 
@@ -33546,7 +33815,7 @@ var init_bridge_diagnostics = __esm({
33546
33815
  function getSootsimRoot() {
33547
33816
  if (_sootsimRoot !== void 0) return _sootsimRoot;
33548
33817
  try {
33549
- _sootsimRoot = (0, import_path6.dirname)(
33818
+ _sootsimRoot = (0, import_path5.dirname)(
33550
33819
  (0, import_url2.fileURLToPath)(import_meta2.resolve("peach-engine/package.json"))
33551
33820
  );
33552
33821
  } catch {
@@ -33557,8 +33826,8 @@ function getSootsimRoot() {
33557
33826
  function findDevElectron() {
33558
33827
  const engineDir = getSootsimRoot();
33559
33828
  if (!engineDir) return null;
33560
- const engineMain = (0, import_path6.join)(engineDir, "dist-electron/main.cjs");
33561
- if (!(0, import_fs7.existsSync)(engineMain)) return null;
33829
+ const engineMain = (0, import_path5.join)(engineDir, "dist-electron/main.cjs");
33830
+ if (!(0, import_fs6.existsSync)(engineMain)) return null;
33562
33831
  const electronBin = findElectronBin(engineDir);
33563
33832
  if (!electronBin) return null;
33564
33833
  return {
@@ -33571,14 +33840,14 @@ function findDevElectron() {
33571
33840
  function isInRepoCheckout() {
33572
33841
  const root = getSootsimRoot();
33573
33842
  if (!root) return false;
33574
- return (0, import_fs7.existsSync)((0, import_path6.join)(root, "src-electron/main.ts"));
33843
+ return (0, import_fs6.existsSync)((0, import_path5.join)(root, "src-electron/main.ts"));
33575
33844
  }
33576
33845
  function findElectronBin(startDir) {
33577
33846
  let dir = startDir;
33578
33847
  for (let i = 0; i < 6; i++) {
33579
- const candidate = (0, import_path6.join)(dir, "node_modules/.bin/electron");
33580
- if ((0, import_fs7.existsSync)(candidate)) return candidate;
33581
- const parent = (0, import_path6.dirname)(dir);
33848
+ const candidate = (0, import_path5.join)(dir, "node_modules/.bin/electron");
33849
+ if ((0, import_fs6.existsSync)(candidate)) return candidate;
33850
+ const parent = (0, import_path5.dirname)(dir);
33582
33851
  if (parent === dir) break;
33583
33852
  dir = parent;
33584
33853
  }
@@ -33587,9 +33856,9 @@ function findElectronBin(startDir) {
33587
33856
  function findInstalledMacApp() {
33588
33857
  const candidates = [
33589
33858
  "/Applications/peach.app",
33590
- (0, import_path6.resolve)(process.env.HOME || "", "Applications/peach.app")
33859
+ (0, import_path5.resolve)(process.env.HOME || "", "Applications/peach.app")
33591
33860
  ];
33592
- const found = candidates.find((candidate) => (0, import_fs7.existsSync)(candidate));
33861
+ const found = candidates.find((candidate) => (0, import_fs6.existsSync)(candidate));
33593
33862
  if (found) {
33594
33863
  return {
33595
33864
  path: found,
@@ -33603,8 +33872,8 @@ function findMacApp() {
33603
33872
  const installed2 = findInstalledMacApp();
33604
33873
  if (installed2) return installed2;
33605
33874
  const root = getSootsimRoot();
33606
- const builtApp = root ? (0, import_path6.resolve)(root, "app/peach.app") : null;
33607
- if (builtApp && (0, import_fs7.existsSync)(builtApp)) {
33875
+ const builtApp = root ? (0, import_path5.resolve)(root, "app/peach.app") : null;
33876
+ if (builtApp && (0, import_fs6.existsSync)(builtApp)) {
33608
33877
  return { path: builtApp, platform: "darwin", kind: "mac-app" };
33609
33878
  }
33610
33879
  try {
@@ -33625,18 +33894,18 @@ function findMacApp() {
33625
33894
  return null;
33626
33895
  }
33627
33896
  function findFirstAppImage(dir) {
33628
- if (!(0, import_fs7.existsSync)(dir)) return null;
33629
- const match = (0, import_fs7.readdirSync)(dir).filter((entry) => entry.startsWith("peach") && entry.endsWith(".AppImage")).sort().reverse()[0];
33630
- return match ? (0, import_path6.join)(dir, match) : null;
33897
+ if (!(0, import_fs6.existsSync)(dir)) return null;
33898
+ const match = (0, import_fs6.readdirSync)(dir).filter((entry) => entry.startsWith("peach") && entry.endsWith(".AppImage")).sort().reverse()[0];
33899
+ return match ? (0, import_path5.join)(dir, match) : null;
33631
33900
  }
33632
33901
  function findInstalledLinuxApp() {
33633
33902
  const directCandidates = [
33634
- (0, import_path6.resolve)(process.env.HOME || "", "Applications/peach.AppImage"),
33635
- (0, import_path6.resolve)(process.env.HOME || "", ".local/bin/peach.AppImage"),
33903
+ (0, import_path5.resolve)(process.env.HOME || "", "Applications/peach.AppImage"),
33904
+ (0, import_path5.resolve)(process.env.HOME || "", ".local/bin/peach.AppImage"),
33636
33905
  "/opt/peach/peach.AppImage",
33637
33906
  "/opt/peach/peach"
33638
33907
  ];
33639
- const directMatch = directCandidates.find((candidate) => (0, import_fs7.existsSync)(candidate));
33908
+ const directMatch = directCandidates.find((candidate) => (0, import_fs6.existsSync)(candidate));
33640
33909
  if (directMatch) {
33641
33910
  return {
33642
33911
  path: directMatch,
@@ -33650,8 +33919,8 @@ function findLinuxInstall() {
33650
33919
  const installed2 = findInstalledLinuxApp();
33651
33920
  if (installed2) return installed2;
33652
33921
  const root = getSootsimRoot();
33653
- const directCandidates = root ? [(0, import_path6.resolve)(root, "app/peach.AppImage"), (0, import_path6.resolve)(root, "release/linux-unpacked/peach")] : [];
33654
- const directMatch = directCandidates.find((candidate) => (0, import_fs7.existsSync)(candidate));
33922
+ const directCandidates = root ? [(0, import_path5.resolve)(root, "app/peach.AppImage"), (0, import_path5.resolve)(root, "release/linux-unpacked/peach")] : [];
33923
+ const directMatch = directCandidates.find((candidate) => (0, import_fs6.existsSync)(candidate));
33655
33924
  if (directMatch) {
33656
33925
  return {
33657
33926
  path: directMatch,
@@ -33659,7 +33928,7 @@ function findLinuxInstall() {
33659
33928
  kind: directMatch.endsWith(".AppImage") ? "linux-appimage" : "linux-binary"
33660
33929
  };
33661
33930
  }
33662
- const scannedMatch = root ? findFirstAppImage((0, import_path6.resolve)(root, "app")) || findFirstAppImage((0, import_path6.resolve)(root, "release")) : null;
33931
+ const scannedMatch = root ? findFirstAppImage((0, import_path5.resolve)(root, "app")) || findFirstAppImage((0, import_path5.resolve)(root, "release")) : null;
33663
33932
  if (!scannedMatch) return null;
33664
33933
  return {
33665
33934
  path: scannedMatch,
@@ -33676,7 +33945,7 @@ function findWindowsInstall() {
33676
33945
  { encoding: "utf8", timeout: 3e3 }
33677
33946
  );
33678
33947
  const executable = /"([^"\r\n]+\.exe)"/i.exec(output)?.[1];
33679
- if (executable && (0, import_fs7.existsSync)(executable)) {
33948
+ if (executable && (0, import_fs6.existsSync)(executable)) {
33680
33949
  return { path: executable, platform: "win32", kind: "win-exe" };
33681
33950
  }
33682
33951
  } catch {
@@ -33689,8 +33958,8 @@ function findDesktopCompanion() {
33689
33958
  if (dev) return dev;
33690
33959
  if (isInRepoCheckout()) {
33691
33960
  const engineDir = getSootsimRoot();
33692
- const engineMain = (0, import_path6.join)(engineDir, "dist-electron/main.cjs");
33693
- if (!(0, import_fs7.existsSync)(engineMain)) {
33961
+ const engineMain = (0, import_path5.join)(engineDir, "dist-electron/main.cjs");
33962
+ if (!(0, import_fs6.existsSync)(engineMain)) {
33694
33963
  console.error(
33695
33964
  ` dist-electron/main.cjs missing in ${engineDir}.
33696
33965
  run: bun run --cwd packages/peach-engine build:electron-main
@@ -33761,13 +34030,13 @@ function buildMacLaunchUrl(url, opts) {
33761
34030
  }
33762
34031
  return deepLink.toString();
33763
34032
  }
33764
- var import_child_process5, import_fs7, import_path6, import_url2, import_meta2, _sootsimRoot, PEACH_BUNDLE_ID;
34033
+ var import_child_process5, import_fs6, import_path5, import_url2, import_meta2, _sootsimRoot, PEACH_BUNDLE_ID;
33765
34034
  var init_desktop_companion = __esm({
33766
34035
  "cli/desktop-companion.ts"() {
33767
34036
  "use strict";
33768
34037
  import_child_process5 = require("child_process");
33769
- import_fs7 = require("fs");
33770
- import_path6 = require("path");
34038
+ import_fs6 = require("fs");
34039
+ import_path5 = require("path");
33771
34040
  import_url2 = require("url");
33772
34041
  import_meta2 = {};
33773
34042
  PEACH_BUNDLE_ID = "dev.peachsim.simulator";
@@ -33866,15 +34135,16 @@ var init_internal_child = __esm({
33866
34135
  // cli/drivers/playwright-provisioning.ts
33867
34136
  function resolvePlaywright() {
33868
34137
  const roots = [`${process.cwd()}/`];
33869
- if (process.argv[1]) roots.push(process.argv[1]);
34138
+ const self = rnxSelfInvocation();
34139
+ roots.push(self.prefixArgs[0] ?? self.executable);
33870
34140
  for (const root of roots) {
33871
34141
  try {
33872
- const requireFromRoot = (0, import_node_module4.createRequire)(root);
34142
+ const requireFromRoot = (0, import_node_module5.createRequire)(root);
33873
34143
  for (const spec of ["playwright", "playwright-chromium", "playwright-core"]) {
33874
34144
  try {
33875
34145
  const modulePath = requireFromRoot.resolve(spec);
33876
34146
  const packageJsonPath = requireFromRoot.resolve(`${spec}/package.json`);
33877
- const parsed = JSON.parse((0, import_node_fs20.readFileSync)(packageJsonPath, "utf8"));
34147
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(packageJsonPath, "utf8"));
33878
34148
  if (!isRecord(parsed) || typeof parsed.version !== "string") continue;
33879
34149
  const bin = parsed.bin;
33880
34150
  let binPath = null;
@@ -33886,8 +34156,8 @@ function resolvePlaywright() {
33886
34156
  binPath = typeof named === "string" ? named : typeof first === "string" ? first : null;
33887
34157
  }
33888
34158
  if (!binPath) continue;
33889
- const cliPath = (0, import_node_path22.join)((0, import_node_path22.dirname)(packageJsonPath), binPath);
33890
- if (!(0, import_node_fs20.existsSync)(cliPath)) continue;
34159
+ const cliPath = (0, import_node_path25.join)((0, import_node_path25.dirname)(packageJsonPath), binPath);
34160
+ if (!(0, import_node_fs23.existsSync)(cliPath)) continue;
33891
34161
  return {
33892
34162
  spec,
33893
34163
  modulePath,
@@ -33931,7 +34201,7 @@ function probeBrowser(resolved, env) {
33931
34201
  return {
33932
34202
  ok: true,
33933
34203
  executablePath: parsed.executablePath,
33934
- exists: parsed.exists && (0, import_node_fs20.existsSync)(parsed.executablePath)
34204
+ exists: parsed.exists && (0, import_node_fs23.existsSync)(parsed.executablePath)
33935
34205
  };
33936
34206
  } catch (error) {
33937
34207
  return {
@@ -33982,17 +34252,17 @@ ${detail}` : ""}`
33982
34252
  }
33983
34253
  return { ok: true, executablePath: after.executablePath, installed: true };
33984
34254
  }
33985
- var import_node_child_process6, import_node_fs20, import_node_module4, import_node_path22;
34255
+ var import_node_child_process6, import_node_fs23, import_node_module5, import_node_path25;
33986
34256
  var init_playwright_provisioning = __esm({
33987
34257
  "cli/drivers/playwright-provisioning.ts"() {
33988
34258
  "use strict";
33989
34259
  import_node_child_process6 = require("node:child_process");
33990
- import_node_fs20 = require("node:fs");
33991
- import_node_module4 = require("node:module");
33992
- import_node_path22 = require("node:path");
34260
+ import_node_fs23 = require("node:fs");
34261
+ import_node_module5 = require("node:module");
34262
+ import_node_path25 = require("node:path");
34263
+ init_is_record();
33993
34264
  init_internal_child();
33994
34265
  init_self_invocation();
33995
- init_is_record();
33996
34266
  }
33997
34267
  });
33998
34268
 
@@ -34025,7 +34295,7 @@ function resolveUserDataDir(opts) {
34025
34295
  return playwrightProfileUserDataDir(ensureProfile(opts.profileId).id);
34026
34296
  }
34027
34297
  if (opts.ephemeralProfile) {
34028
- return (0, import_fs8.mkdtempSync)((0, import_path7.join)((0, import_os2.tmpdir)(), "peach-playwright-profile-"));
34298
+ return (0, import_fs7.mkdtempSync)((0, import_path6.join)((0, import_os2.tmpdir)(), "peach-playwright-profile-"));
34029
34299
  }
34030
34300
  return "";
34031
34301
  }
@@ -34055,9 +34325,9 @@ async function launch2(opts) {
34055
34325
  message: `playwright browser provisioning failed: ${provisioning.message}`
34056
34326
  };
34057
34327
  }
34058
- const errLog = (0, import_path7.join)((0, import_os2.tmpdir)(), playwrightHostLogName(Date.now(), process.pid));
34328
+ const errLog = (0, import_path6.join)((0, import_os2.tmpdir)(), playwrightHostLogName(Date.now(), process.pid));
34059
34329
  const connectAckFile = `${errLog}.connected`;
34060
- const errFd = (0, import_fs8.openSync)(errLog, "a");
34330
+ const errFd = (0, import_fs7.openSync)(errLog, "a");
34061
34331
  try {
34062
34332
  const self = rnxSelfInvocation();
34063
34333
  const child = (0, import_child_process6.spawn)(
@@ -34093,7 +34363,7 @@ async function launch2(opts) {
34093
34363
  });
34094
34364
  });
34095
34365
  if (earlyExit !== null) {
34096
- const detail = (0, import_fs8.readFileSync)(errLog, "utf8").trim();
34366
+ const detail = (0, import_fs7.readFileSync)(errLog, "utf8").trim();
34097
34367
  const hint = headlessHintForLinuxFailure(opts, detail);
34098
34368
  return {
34099
34369
  launched: false,
@@ -34120,17 +34390,17 @@ ${hint}` : ""}`
34120
34390
  message: `playwright launch failed: ${err instanceof Error ? err.message : String(err)}`
34121
34391
  };
34122
34392
  } finally {
34123
- (0, import_fs8.closeSync)(errFd);
34393
+ (0, import_fs7.closeSync)(errFd);
34124
34394
  }
34125
34395
  }
34126
- var import_child_process6, import_fs8, import_os2, import_path7, playwrightDriver;
34396
+ var import_child_process6, import_fs7, import_os2, import_path6, playwrightDriver;
34127
34397
  var init_playwright = __esm({
34128
34398
  "cli/drivers/playwright.ts"() {
34129
34399
  "use strict";
34130
34400
  import_child_process6 = require("child_process");
34131
- import_fs8 = require("fs");
34401
+ import_fs7 = require("fs");
34132
34402
  import_os2 = require("os");
34133
- import_path7 = require("path");
34403
+ import_path6 = require("path");
34134
34404
  init_bridge_constants();
34135
34405
  init_playwright_host_log();
34136
34406
  init_profiles();
@@ -34197,6 +34467,264 @@ var init_env = __esm({
34197
34467
  }
34198
34468
  });
34199
34469
 
34470
+ // cli/ui.ts
34471
+ var init_ui = __esm({
34472
+ "cli/ui.ts"() {
34473
+ "use strict";
34474
+ }
34475
+ });
34476
+
34477
+ // cli/prompt.ts
34478
+ var init_prompt = __esm({
34479
+ "cli/prompt.ts"() {
34480
+ "use strict";
34481
+ init_ui();
34482
+ }
34483
+ });
34484
+
34485
+ // cli/privacy.ts
34486
+ function diagnosticsAllowedForCurrentProcess(preferences = readPrivacyPreferences()) {
34487
+ const doNotTrack = process.env.DO_NOT_TRACK;
34488
+ if (doNotTrack === "1" || doNotTrack === "true") return false;
34489
+ return preferences.configured && preferences.productAnalytics;
34490
+ }
34491
+ var init_privacy = __esm({
34492
+ "cli/privacy.ts"() {
34493
+ "use strict";
34494
+ init_home_paths();
34495
+ init_env();
34496
+ init_prompt();
34497
+ }
34498
+ });
34499
+
34500
+ // cli/command-registry.ts
34501
+ var NODE_COMMAND_NAMES, BROWSER_FAMILIES, registrations, RNX_COMMAND_NAMES, RNX_NODE_COMMAND_NAMES;
34502
+ var init_command_registry = __esm({
34503
+ "cli/command-registry.ts"() {
34504
+ "use strict";
34505
+ NODE_COMMAND_NAMES = [
34506
+ "test",
34507
+ "detox",
34508
+ "maestro",
34509
+ "record",
34510
+ "film",
34511
+ "storage",
34512
+ "permissions",
34513
+ "perf",
34514
+ "screenshot",
34515
+ "state",
34516
+ "reset",
34517
+ "camera",
34518
+ "mode",
34519
+ "debug",
34520
+ "timeline",
34521
+ "what-happened",
34522
+ "shell",
34523
+ "assert",
34524
+ "device",
34525
+ "open",
34526
+ "ios",
34527
+ "android",
34528
+ "remote",
34529
+ "preview",
34530
+ "box",
34531
+ "list",
34532
+ "use",
34533
+ "claim",
34534
+ "close",
34535
+ "compat",
34536
+ "project-report",
34537
+ "report-issue",
34538
+ "desktop",
34539
+ "login",
34540
+ "logout",
34541
+ "auth",
34542
+ "cli",
34543
+ "setup",
34544
+ "serve",
34545
+ "daemon",
34546
+ "runtime",
34547
+ "upgrade",
34548
+ "version",
34549
+ "skill",
34550
+ "config",
34551
+ "cleanup",
34552
+ "app-fonts",
34553
+ "agent-wrapper",
34554
+ "agent",
34555
+ "describe",
34556
+ "find",
34557
+ "get",
34558
+ "do",
34559
+ "wait",
34560
+ "network",
34561
+ "logs"
34562
+ ];
34563
+ BROWSER_FAMILIES = /* @__PURE__ */ new Map([
34564
+ ["web", "preview"],
34565
+ ["ios", "preview"],
34566
+ ["android", "preview"],
34567
+ ["list", "runtime"],
34568
+ ["use", "runtime"],
34569
+ ["state", "runtime"],
34570
+ ["describe", "tree"],
34571
+ ["find", "find"],
34572
+ ["get", "runtime"],
34573
+ ["wait", "wait"],
34574
+ ["do", "action"],
34575
+ ["shell", "action"],
34576
+ ["reset", "action"],
34577
+ ["screenshot", "screenshot"],
34578
+ ["logs", "logs"],
34579
+ ["network", "network"],
34580
+ ["storage", "storage"],
34581
+ ["timeline", "history"],
34582
+ ["what-happened", "history"],
34583
+ ["assert", "evidence"],
34584
+ ["debug", "evidence"],
34585
+ ["perf", "evidence"]
34586
+ ]);
34587
+ registrations = [
34588
+ .../* @__PURE__ */ new Set([...NODE_COMMAND_NAMES, "web"])
34589
+ ].map((name2) => ({
34590
+ name: name2,
34591
+ node: name2 !== "web",
34592
+ browserFamily: BROWSER_FAMILIES.get(name2) ?? null
34593
+ }));
34594
+ RNX_COMMAND_NAMES = new Set(registrations.map((entry) => entry.name));
34595
+ RNX_NODE_COMMAND_NAMES = new Set(NODE_COMMAND_NAMES);
34596
+ }
34597
+ });
34598
+
34599
+ // cli/parse-args.ts
34600
+ var GLOBAL_FLAGS, GLOBAL_FLAG_TAKES_VALUE, COMMANDS;
34601
+ var init_parse_args = __esm({
34602
+ "cli/parse-args.ts"() {
34603
+ "use strict";
34604
+ init_command_registry();
34605
+ GLOBAL_FLAGS = {
34606
+ "--help": { type: "boolean", short: "-h" },
34607
+ "--version": { type: "boolean", short: "-V" },
34608
+ "--verbose": { type: "boolean", short: "-v" },
34609
+ "--port": { type: "number", short: "-p" },
34610
+ "--device": { type: "string", short: "-d" },
34611
+ "--theme": { type: "string", short: "-t" },
34612
+ "--headless": { type: "boolean" },
34613
+ "--driver": { type: "string" },
34614
+ "--sim": { type: "string" },
34615
+ // documented aliases for --sim (CLAUDE.md / skills / engine docs say
34616
+ // `--session <id>`). normalized to the sim target in bin.ts.
34617
+ "--session": { type: "string" },
34618
+ "--tab": { type: "string" }
34619
+ };
34620
+ GLOBAL_FLAG_TAKES_VALUE = new Map(
34621
+ Object.entries(GLOBAL_FLAGS).flatMap(([name2, def]) => {
34622
+ const takesValue = def.type !== "boolean";
34623
+ return def.short ? [
34624
+ [name2, takesValue],
34625
+ [def.short, takesValue]
34626
+ ] : [[name2, takesValue]];
34627
+ })
34628
+ );
34629
+ COMMANDS = new Set(RNX_NODE_COMMAND_NAMES);
34630
+ }
34631
+ });
34632
+
34633
+ // cli/telemetry.ts
34634
+ function sanitizeDiagnosticMessage(value) {
34635
+ const firstLine = value.slice(0, 2048).split(/[\r\n\u2028\u2029]/, 1)[0] ?? "";
34636
+ return firstLine.split((0, import_node_os3.homedir)()).join("<home>").replace(
34637
+ /<package:(?:@[\w.-]+\/)?[\w.-]+>|(?:https?:\/\/|file:\/\/|[A-Za-z]:[\\/]|<home>[\\/]|\/|\.{1,2}[\\/]|\b[\w.-]+[\\/])[^\s"'<>]+/g,
34638
+ (location2) => {
34639
+ if (location2.startsWith("<package:")) return location2;
34640
+ const dependency = /(?:^|[\\/])node_modules[\\/]((?:@[^\\/]+[\\/])?[^\\/]+)/.exec(
34641
+ location2
34642
+ );
34643
+ return dependency ? `<package:${dependency[1]?.replace(/\\/g, "/")}>` : "<path>";
34644
+ }
34645
+ ).replace(/\b[\w.-]+\.(?:tsx?|jsx?|swift|m|mm|kt|java)(?::\d+(?::\d+)?)?/g, "<source>").replace(/\{.*$|\[(?:\s*["'{\d]|$).*$/g, "<data>").replace(
34646
+ /\b(?:const|let|var)\s+\w+\s*=.*$|\b(?:function|class)\s+\w+.*$|\b(?:import|export)\s+.*$|\breturn\s*[({<].*$/g,
34647
+ "<source>"
34648
+ ).replace(/^\s*at\s+.*$|\bat\s+[\w.$<>]+\s*\([^)]*\)/g, "<stack>").trim().slice(0, 300);
34649
+ }
34650
+ function diagnosticVersion(version) {
34651
+ return version && version.length <= 80 && /^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(version) ? version : null;
34652
+ }
34653
+ function setDiagnosticRuntimeVersion(version) {
34654
+ observedRuntimeVersion = diagnosticVersion(version);
34655
+ }
34656
+ function trackCliDiagnostic(diagnostic) {
34657
+ if (!diagnosticsAllowedForCurrentProcess()) return;
34658
+ if (queue.length >= 50) return;
34659
+ const entry = diagnostic.kind === "package_incompatibility" ? diagnostic : { ...diagnostic, message: sanitizeDiagnosticMessage(diagnostic.message) };
34660
+ if (queue.some((queued) => JSON.stringify(queued) === JSON.stringify(entry))) return;
34661
+ queue.push(entry);
34662
+ }
34663
+ var import_node_os3, observedRuntimeVersion, queue;
34664
+ var init_telemetry = __esm({
34665
+ "cli/telemetry.ts"() {
34666
+ "use strict";
34667
+ import_node_os3 = require("node:os");
34668
+ init_cli_version();
34669
+ init_home_paths();
34670
+ init_parse_args();
34671
+ init_privacy();
34672
+ observedRuntimeVersion = null;
34673
+ queue = [];
34674
+ }
34675
+ });
34676
+
34677
+ // cli/runtime-diagnostics.ts
34678
+ async function collectRuntimeDiagnostics(bridge) {
34679
+ if (!diagnosticsAllowedForCurrentProcess()) return;
34680
+ try {
34681
+ const result = await bridge.send(
34682
+ {
34683
+ type: "evaluate",
34684
+ code: `(() => {
34685
+ const messages = []
34686
+ const add = (kind, message) => {
34687
+ if (typeof message === 'string' && message) messages.push({ kind, message: message.slice(0, 2048) })
34688
+ }
34689
+ const obs = window.__sootsimObservability
34690
+ for (const e of (obs?.reportedErrors?.getSnapshot?.() || []).slice(-20)) add('runtime_error', e.message)
34691
+ for (const [kind, entries] of [
34692
+ ['runtime_error', ${consoleEntriesEval("error", 20)}],
34693
+ ['runtime_warning', ${consoleEntriesEval("warn", 20)}],
34694
+ ]) {
34695
+ for (const e of entries) {
34696
+ const parts = e.args.map(a => typeof a === 'string' ? a : typeof a?.message === 'string' ? a.message : '').filter(Boolean)
34697
+ add(kind, parts.join(' '))
34698
+ }
34699
+ }
34700
+ return { runtimeVersion: window.__sootsimRuntimeVersion, messages: messages.slice(0, 50) }
34701
+ })()`
34702
+ },
34703
+ { timeoutMs: 1e3 }
34704
+ );
34705
+ if (!result || typeof result !== "object") return;
34706
+ if ("runtimeVersion" in result && typeof result.runtimeVersion === "string") {
34707
+ setDiagnosticRuntimeVersion(result.runtimeVersion);
34708
+ }
34709
+ if (!("messages" in result) || !Array.isArray(result.messages)) return;
34710
+ for (const entry of result.messages.slice(0, 50)) {
34711
+ if (!entry || typeof entry !== "object") continue;
34712
+ if ((entry.kind === "runtime_error" || entry.kind === "runtime_warning") && typeof entry.message === "string") {
34713
+ trackCliDiagnostic({ kind: entry.kind, message: entry.message });
34714
+ }
34715
+ }
34716
+ } catch {
34717
+ }
34718
+ }
34719
+ var init_runtime_diagnostics = __esm({
34720
+ "cli/runtime-diagnostics.ts"() {
34721
+ "use strict";
34722
+ init_core();
34723
+ init_privacy();
34724
+ init_telemetry();
34725
+ }
34726
+ });
34727
+
34200
34728
  // cli/runtime-notes.ts
34201
34729
  function isChangelogEntry(value) {
34202
34730
  if (!value || typeof value !== "object") return false;
@@ -34452,11 +34980,11 @@ async function runtimeRemove(args) {
34452
34980
  rnxExit(1);
34453
34981
  }
34454
34982
  const dir = runtimeDir(version);
34455
- if (!import_fs9.default.existsSync(dir)) {
34983
+ if (!import_fs8.default.existsSync(dir)) {
34456
34984
  console.error(` ${version} is not installed`);
34457
34985
  return;
34458
34986
  }
34459
- import_fs9.default.rmSync(dir, { recursive: true, force: true });
34987
+ import_fs8.default.rmSync(dir, { recursive: true, force: true });
34460
34988
  console.log(` removed ${version}`);
34461
34989
  }
34462
34990
  async function runtimeWhich() {
@@ -34511,11 +35039,11 @@ function describeError(err) {
34511
35039
  if (err instanceof Error) return err.message;
34512
35040
  return String(err);
34513
35041
  }
34514
- var import_fs9, import_ws3;
35042
+ var import_fs8, import_ws3;
34515
35043
  var init_runtime = __esm({
34516
35044
  "cli/commands/runtime.ts"() {
34517
35045
  "use strict";
34518
- import_fs9 = __toESM(require("fs"), 1);
35046
+ import_fs8 = __toESM(require("fs"), 1);
34519
35047
  init_src();
34520
35048
  import_ws3 = require("ws");
34521
35049
  init_home_paths();
@@ -34658,7 +35186,7 @@ function assertExplicitBridgeLock(preferredPort, explicitPort, lock) {
34658
35186
  async function ensureRuntimeForOpen() {
34659
35187
  if (resolveDevCheckoutRuntimeRoot()) return;
34660
35188
  const active = readActiveRuntime();
34661
- if (active && import_node_fs21.default.existsSync(runtimeDir(active))) return;
35189
+ if (active && import_node_fs24.default.existsSync(runtimeDir(active))) return;
34662
35190
  console.error(" installing peach engine runtime...");
34663
35191
  const { runRuntime: runRuntime2 } = await Promise.resolve().then(() => (init_runtime(), runtime_exports));
34664
35192
  await runRuntime2(["install"], {});
@@ -34812,10 +35340,10 @@ async function buildResolvedBundleOpenUrl(target, baseUrl, opts = {}) {
34812
35340
  }
34813
35341
  function normalizeReplacementPath(filePath) {
34814
35342
  if (filePath.startsWith("~/")) {
34815
- return import_node_path23.default.join(import_node_os3.default.homedir(), filePath.slice(2));
35343
+ return import_node_path26.default.join(import_node_os4.default.homedir(), filePath.slice(2));
34816
35344
  }
34817
- if (import_node_path23.default.isAbsolute(filePath)) return filePath;
34818
- return import_node_path23.default.resolve(process.cwd(), filePath);
35345
+ if (import_node_path26.default.isAbsolute(filePath)) return filePath;
35346
+ return import_node_path26.default.resolve(process.cwd(), filePath);
34819
35347
  }
34820
35348
  function parseOpenRuntimeConfig(args) {
34821
35349
  const modules = {};
@@ -34834,7 +35362,7 @@ function parseOpenRuntimeConfig(args) {
34834
35362
  }
34835
35363
  const moduleName = raw.slice(0, eqIndex).trim();
34836
35364
  const filePath = normalizeReplacementPath(raw.slice(eqIndex + 1).trim());
34837
- if (!import_node_fs21.default.existsSync(filePath)) {
35365
+ if (!import_node_fs24.default.existsSync(filePath)) {
34838
35366
  console.error(` peach open: replacement file not found: ${filePath}`);
34839
35367
  rnxExit(1);
34840
35368
  }
@@ -34865,7 +35393,7 @@ async function resolveAppProjectForBundleUrl(bundleUrl) {
34865
35393
  return advertisedRoot ? resolveAppProject(advertisedRoot) : null;
34866
35394
  }
34867
35395
  async function ensureConfiguredRuntime(version) {
34868
- if (import_node_fs21.default.existsSync(import_node_path23.default.join(runtimeDir(version), "index.html"))) return;
35396
+ if (import_node_fs24.default.existsSync(import_node_path26.default.join(runtimeDir(version), "index.html"))) return;
34869
35397
  console.error(` installing configured engine runtime ${version}...`);
34870
35398
  const result = await rnxRuntime.install({
34871
35399
  version,
@@ -34930,11 +35458,11 @@ async function filterReachableAppFonts(specs) {
34930
35458
  }
34931
35459
  })
34932
35460
  );
34933
- const reachable = [];
35461
+ const reachable = /* @__PURE__ */ new Map();
34934
35462
  for (const spec of results) {
34935
- if (spec !== null) reachable.push(spec);
35463
+ if (spec !== null && !reachable.has(spec.family)) reachable.set(spec.family, spec);
34936
35464
  }
34937
- return reachable;
35465
+ return [...reachable.values()];
34938
35466
  }
34939
35467
  async function resolveShellUrl(target, baseUrl, opts = {}) {
34940
35468
  if (!target) {
@@ -34983,6 +35511,22 @@ async function stampAppSplash(urlStr, project) {
34983
35511
  return urlStr;
34984
35512
  }
34985
35513
  }
35514
+ function stampNativeFirebaseConfig(urlStr, project) {
35515
+ const url = new URL(urlStr);
35516
+ if (!url.searchParams.get("bundle") || !project) return urlStr;
35517
+ try {
35518
+ url.searchParams.set(
35519
+ "nativeFirebase",
35520
+ JSON.stringify(readNativeFirebaseConfig(project.appDir))
35521
+ );
35522
+ } catch (error) {
35523
+ url.searchParams.set(
35524
+ "nativeFirebase",
35525
+ JSON.stringify({ error: error instanceof Error ? error.message : String(error) })
35526
+ );
35527
+ }
35528
+ return url.toString();
35529
+ }
34986
35530
  function stampAppCatalog(urlStr, project) {
34987
35531
  try {
34988
35532
  const url = new URL(urlStr);
@@ -35017,8 +35561,11 @@ function bundleUrlOf(urlStr) {
35017
35561
  async function buildShellUrl(target, baseUrl = resolveDefaultShellBaseUrl(), opts = {}) {
35018
35562
  const resolved = await resolveShellUrl(target, baseUrl, opts);
35019
35563
  const project = opts.project ?? await resolveAppProjectForBundleUrl(bundleUrlOf(resolved));
35020
- const stamped = stampAppCatalog(
35021
- await stampAppSplash(await stampAppFonts(resolved, project), project),
35564
+ const stamped = stampNativeFirebaseConfig(
35565
+ stampAppCatalog(
35566
+ await stampAppSplash(await stampAppFonts(resolved, project), project),
35567
+ project
35568
+ ),
35022
35569
  project
35023
35570
  );
35024
35571
  if (!opts.device && !opts.proof && !opts.posture && !opts.osVersion && !opts.env?.length)
@@ -35044,6 +35591,7 @@ function deriveCurrentSimBaseUrl(sim, fallback) {
35044
35591
  url.searchParams.delete("appFonts");
35045
35592
  url.searchParams.delete("appSplash");
35046
35593
  url.searchParams.delete("appCatalog");
35594
+ url.searchParams.delete("nativeFirebase");
35047
35595
  return url.toString();
35048
35596
  } catch {
35049
35597
  return fallback;
@@ -35159,7 +35707,7 @@ function playwrightHostPidForSim(sim) {
35159
35707
  function signalDriverLaunchConnected(result) {
35160
35708
  if (!result.connectAckFile) return false;
35161
35709
  try {
35162
- import_node_fs21.default.writeFileSync(
35710
+ import_node_fs24.default.writeFileSync(
35163
35711
  result.connectAckFile,
35164
35712
  `${JSON.stringify({ connectedAt: Date.now(), pid: result.pid ?? null })}
35165
35713
  `,
@@ -35173,19 +35721,19 @@ function signalDriverLaunchConnected(result) {
35173
35721
  function printDriverDiagnosticLogTail(result) {
35174
35722
  if (!result.diagnosticLogPath) return;
35175
35723
  try {
35176
- const detail = import_node_fs21.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
35724
+ const detail = import_node_fs24.default.readFileSync(result.diagnosticLogPath, "utf8").trim();
35177
35725
  if (!detail) {
35178
- console.error(` ${import_node_path23.default.basename(result.diagnosticLogPath)} was empty`);
35726
+ console.error(` ${import_node_path26.default.basename(result.diagnosticLogPath)} was empty`);
35179
35727
  return;
35180
35728
  }
35181
35729
  const shown = detail.length > 4e3 ? `\u2026
35182
35730
  ${detail.slice(-4e3)}` : detail;
35183
- console.error(` ${import_node_path23.default.basename(result.diagnosticLogPath)}:`);
35731
+ console.error(` ${import_node_path26.default.basename(result.diagnosticLogPath)}:`);
35184
35732
  console.error(shown);
35185
35733
  } catch (err) {
35186
35734
  const message = err instanceof Error ? err.message : String(err);
35187
35735
  console.error(
35188
- ` failed to read ${import_node_path23.default.basename(result.diagnosticLogPath)}: ${message}`
35736
+ ` failed to read ${import_node_path26.default.basename(result.diagnosticLogPath)}: ${message}`
35189
35737
  );
35190
35738
  }
35191
35739
  }
@@ -35306,11 +35854,12 @@ function printAgentListenHint(quiet) {
35306
35854
  }
35307
35855
  }
35308
35856
  async function maybeDescribeAfterOpen(wsPort, simId, args) {
35309
- if (args.includes("--no-describe")) return;
35857
+ const noDescribe = args.includes("--no-describe");
35858
+ if (noDescribe && !diagnosticsAllowedForCurrentProcess()) return;
35310
35859
  const prevQuiet = process.env.SOOTSIM_QUIET_TARGET_NOTICE;
35311
35860
  process.env.SOOTSIM_QUIET_TARGET_NOTICE = "1";
35312
35861
  try {
35313
- await waitForTreeStable(wsPort, simId, { stableMs: 150, maxMs: 400 });
35862
+ if (!noDescribe) await waitForTreeStable(wsPort, simId, { stableMs: 150, maxMs: 400 });
35314
35863
  const bridge = createBridge(wsPort, {
35315
35864
  commandTimeoutMs: 3e3,
35316
35865
  simId,
@@ -35318,6 +35867,7 @@ async function maybeDescribeAfterOpen(wsPort, simId, args) {
35318
35867
  simIdSource: "flag"
35319
35868
  });
35320
35869
  try {
35870
+ if (noDescribe) return;
35321
35871
  let readyProbe = null;
35322
35872
  try {
35323
35873
  readyProbe = await inspectWaitReady(bridge, 1);
@@ -35344,6 +35894,7 @@ async function maybeDescribeAfterOpen(wsPort, simId, args) {
35344
35894
  console.log("");
35345
35895
  console.log(result.tree);
35346
35896
  } finally {
35897
+ await collectRuntimeDiagnostics(bridge);
35347
35898
  bridge.close();
35348
35899
  }
35349
35900
  } catch {
@@ -35558,9 +36109,9 @@ async function runOpenCommand(args, opts = {}) {
35558
36109
  }
35559
36110
  const hotMode = hotFlag ? true : noHmrFlag ? false : driverId !== "playwright";
35560
36111
  const deviceArg = args.find((_, i) => args[i - 1] === "--device");
35561
- if (deviceArg && !(deviceArg in import_settings.devices)) {
36112
+ if (deviceArg && !(deviceArg in import_devices2.devices)) {
35562
36113
  console.error(` peach open: unknown device "${deviceArg}"`);
35563
- console.error(` known devices: ${(0, import_settings.listSelectableDeviceModels)().join(", ")}`);
36114
+ console.error(` known devices: ${(0, import_devices2.listSelectableDeviceModels)().join(", ")}`);
35564
36115
  rnxExit(1);
35565
36116
  }
35566
36117
  const postureArg = args.find((_, i) => args[i - 1] === "--posture");
@@ -35568,7 +36119,7 @@ async function runOpenCommand(args, opts = {}) {
35568
36119
  console.error(` peach open: --posture must be open or closed, got "${postureArg}"`);
35569
36120
  rnxExit(1);
35570
36121
  }
35571
- const deviceFitBox = deviceArg ? (0, import_settings.resolveDeviceFitBox)(
36122
+ const deviceFitBox = deviceArg ? (0, import_devices2.resolveDeviceFitBox)(
35572
36123
  deviceArg,
35573
36124
  false,
35574
36125
  void 0,
@@ -36115,16 +36666,16 @@ async function runCloseCommand(args, opts = {}) {
36115
36666
  bridge.close();
36116
36667
  }
36117
36668
  }
36118
- var import_node_child_process7, import_node_fs21, import_node_os3, import_node_path23, import_app_catalog_wire, import_settings, import_ws4, DEFAULT_DRIVER_CONNECT_TIMEOUT_MS, DRIVER_CONNECT_INTERVAL_MS, DRIVER_CONNECT_HOST_GRACE_MS, OPEN_BRIDGE_SPAWN_TIMEOUT_MS, SHELL_APPS, DEV_BUNDLE_RESOLVE_ATTEMPTS, DEV_BUNDLE_RESOLVE_INTERVAL_MS;
36669
+ var import_node_child_process7, import_node_fs24, import_node_os4, import_node_path26, 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;
36119
36670
  var init_control = __esm({
36120
36671
  "cli/commands/control.ts"() {
36121
36672
  "use strict";
36122
36673
  import_node_child_process7 = require("node:child_process");
36123
- import_node_fs21 = __toESM(require("node:fs"), 1);
36124
- import_node_os3 = __toESM(require("node:os"), 1);
36125
- import_node_path23 = __toESM(require("node:path"), 1);
36674
+ import_node_fs24 = __toESM(require("node:fs"), 1);
36675
+ import_node_os4 = __toESM(require("node:os"), 1);
36676
+ import_node_path26 = __toESM(require("node:path"), 1);
36126
36677
  import_app_catalog_wire = require("peach-engine/engine/app-catalog-wire");
36127
- import_settings = require("peach-engine/settings");
36678
+ import_devices2 = require("peach-engine/settings/devices");
36128
36679
  import_ws4 = require("ws");
36129
36680
  init_dev_server_scanner();
36130
36681
  init_app_url();
@@ -36135,6 +36686,7 @@ var init_control = __esm({
36135
36686
  init_flow_timeout_scale();
36136
36687
  init_home_paths();
36137
36688
  init_native_dev_bundle_url();
36689
+ init_native_firebase_config();
36138
36690
  init_profiles();
36139
36691
  init_public_brand();
36140
36692
  init_runtime_assets();
@@ -36149,7 +36701,9 @@ var init_control = __esm({
36149
36701
  init_current_sim();
36150
36702
  init_registry2();
36151
36703
  init_open_url2();
36704
+ init_privacy();
36152
36705
  init_run_rnx();
36706
+ init_runtime_diagnostics();
36153
36707
  init_self_invocation();
36154
36708
  init_ws_bridge();
36155
36709
  init_core();
@@ -36264,13 +36818,13 @@ var require_proof_frame = __commonJS({
36264
36818
 
36265
36819
  // src/screenshots/frame-compose.ts
36266
36820
  function getFramedScreenshotLayout(model) {
36267
- const spec = (0, import_settings2.getDevice)(model);
36821
+ const spec = (0, import_devices3.getDevice)(model);
36268
36822
  const renderScale = spec.scale;
36269
36823
  const isLegacyHardware = spec.statusBarHeight > 0 && !spec.dynamicIsland && spec.homeIndicatorHeight === 0 && // home-button iphones have a square display, so any corner reads 0
36270
36824
  spec.cornerRadius.topLeft === 0;
36271
36825
  const logicalScreenWidth = spec.width;
36272
36826
  const logicalScreenHeight = spec.height;
36273
- const modernGeometry = (0, import_settings2.resolveDeviceFrameGeometry)(spec);
36827
+ const modernGeometry = (0, import_devices3.resolveDeviceFrameGeometry)(spec);
36274
36828
  const housingLayers = isLegacyHardware ? null : (0, import_duo_housing.resolveHousingArt)(spec.posture ?? "closed", modernGeometry, {
36275
36829
  orientation: spec.orientation,
36276
36830
  landscapeSide: spec.landscapeSide
@@ -36283,7 +36837,7 @@ function getFramedScreenshotLayout(model) {
36283
36837
  const logicalOuterHeight = logicalFrameHeight + FRAME_OUTLINE_BLEED * 2;
36284
36838
  const logicalScreenLeft = logicalFrameLeft + (isLegacyHardware ? import_chrome_metrics.LEGACY_SIDE_BEZEL : modernGeometry.screenLeft);
36285
36839
  const logicalScreenTop = isLegacyHardware ? import_chrome_metrics.LEGACY_TOP_BEZEL : modernGeometry.screenTop;
36286
- const logicalFrameRadius = isLegacyHardware ? (0, import_settings2.cornerRadii)(import_chrome_metrics.LEGACY_FRAME_RADIUS) : modernGeometry.frameRadius;
36840
+ const logicalFrameRadius = isLegacyHardware ? (0, import_devices3.cornerRadii)(import_chrome_metrics.LEGACY_FRAME_RADIUS) : modernGeometry.frameRadius;
36287
36841
  const buttons = [
36288
36842
  {
36289
36843
  side: spec.hardwareButtons.lock.side,
@@ -36325,7 +36879,7 @@ function getFramedScreenshotLayout(model) {
36325
36879
  logicalScreenHeight,
36326
36880
  logicalScreenLeft,
36327
36881
  logicalScreenTop,
36328
- logicalScreenRadius: isLegacyHardware ? (0, import_settings2.cornerRadii)(0) : modernGeometry.screenRadius,
36882
+ logicalScreenRadius: isLegacyHardware ? (0, import_devices3.cornerRadii)(0) : modernGeometry.screenRadius,
36329
36883
  logicalFrameRadius,
36330
36884
  housingLayers,
36331
36885
  // the housing paints its own body layer, shadow included: its frame box is
@@ -36383,7 +36937,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
36383
36937
  style="
36384
36938
  position:absolute;
36385
36939
  inset:0;
36386
- border-radius:${(0, import_settings2.formatCornerRadii)(layout.logicalFrameRadius)};
36940
+ border-radius:${(0, import_devices3.formatCornerRadii)(layout.logicalFrameRadius)};
36387
36941
  box-shadow:${layout.metallicRingShadow};
36388
36942
  pointer-events:none;
36389
36943
  z-index:10;
@@ -36504,7 +37058,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
36504
37058
  left:${layout.logicalFrameLeft}px;
36505
37059
  width:${layout.logicalFrameWidth}px;
36506
37060
  height:${layout.logicalFrameHeight}px;
36507
- border-radius:${layout.housingLayers ? "0" : (0, import_settings2.formatCornerRadii)(layout.logicalFrameRadius)};
37061
+ border-radius:${layout.housingLayers ? "0" : (0, import_devices3.formatCornerRadii)(layout.logicalFrameRadius)};
36508
37062
  box-sizing:border-box;
36509
37063
  overflow:visible;
36510
37064
  background:${layout.frameBackground};
@@ -36523,7 +37077,7 @@ function renderFrameHtml(layout, rawImageDataUrl) {
36523
37077
  left:${layout.logicalScreenLeft - layout.logicalFrameLeft}px;
36524
37078
  width:${layout.logicalScreenWidth}px;
36525
37079
  height:${layout.logicalScreenHeight}px;
36526
- border-radius:${(0, import_settings2.formatCornerRadii)(layout.logicalScreenRadius)};
37080
+ border-radius:${(0, import_devices3.formatCornerRadii)(layout.logicalScreenRadius)};
36527
37081
  overflow:hidden;
36528
37082
  background:#000;
36529
37083
  "
@@ -36595,13 +37149,13 @@ async function createFramedScreenshotComposer(browser) {
36595
37149
  }
36596
37150
  };
36597
37151
  }
36598
- var import_chrome_metrics, import_duo_housing, import_settings2, METALLIC_RING_SHADOW, FRAME_OUTLINE_BLEED;
37152
+ var import_chrome_metrics, import_duo_housing, import_devices3, METALLIC_RING_SHADOW, FRAME_OUTLINE_BLEED;
36599
37153
  var init_frame_compose = __esm({
36600
37154
  "src/screenshots/frame-compose.ts"() {
36601
37155
  "use strict";
36602
37156
  import_chrome_metrics = require("peach-engine/ios/chrome-metrics");
36603
37157
  import_duo_housing = require("peach-engine/ios/duo-housing");
36604
- import_settings2 = require("peach-engine/settings");
37158
+ import_devices3 = require("peach-engine/settings/devices");
36605
37159
  init_reap_browser();
36606
37160
  METALLIC_RING_SHADOW = "inset 0 0 0 0.5px #000, inset 0 0 0 2px #757575, inset 0 0 0 5px #212121";
36607
37161
  FRAME_OUTLINE_BLEED = 1;
@@ -37245,16 +37799,16 @@ function readRecentShellAppId(state) {
37245
37799
  }
37246
37800
  function resolveProjectRelativeFlowBase(flowDir) {
37247
37801
  if (!flowDir) return process.cwd();
37248
- return path19.basename(flowDir) === ".maestro" ? path19.dirname(flowDir) : flowDir;
37802
+ return path20.basename(flowDir) === ".maestro" ? path20.dirname(flowDir) : flowDir;
37249
37803
  }
37250
37804
  function resolveFlowScreenshotPathWithMode(screenshotDir, name2, opts) {
37251
37805
  const normalizedName = name2.endsWith(".png") ? name2 : `${name2}.png`;
37252
- if (path19.isAbsolute(normalizedName)) return normalizedName;
37806
+ if (path20.isAbsolute(normalizedName)) return normalizedName;
37253
37807
  if (opts.mode === "flow" && /[\\/]/.test(normalizedName)) {
37254
37808
  const baseDir = normalizedName.startsWith("./") || normalizedName.startsWith("../") ? opts.flowDir ?? process.cwd() : resolveProjectRelativeFlowBase(opts.flowDir);
37255
- return path19.resolve(baseDir, normalizedName);
37809
+ return path20.resolve(baseDir, normalizedName);
37256
37810
  }
37257
- return path19.join(screenshotDir, normalizedName);
37811
+ return path20.join(screenshotDir, normalizedName);
37258
37812
  }
37259
37813
  function normalizeFlowScreenshotSpec(step) {
37260
37814
  if (typeof step === "string") {
@@ -37308,17 +37862,17 @@ function normalizeBareStringStep(verb) {
37308
37862
  function parseFlowSteps(content) {
37309
37863
  const parts = content.split(/^---$/m);
37310
37864
  const candidate = parts.length > 1 ? parts[parts.length - 1] : content;
37311
- const parsed = import_yaml.default.parse(candidate);
37865
+ const parsed = import_yaml2.default.parse(candidate);
37312
37866
  return Array.isArray(parsed) ? parsed : [];
37313
37867
  }
37314
- var fs19, path19, import_settings3, import_yaml, import_proof_frame, DEFAULT_TIMEOUT, ASSERTION_LOOKUP_MS, FLOW_TIMEOUT_SCALE, scaledTimeout, MAESTRO_SELECTOR_KEYS, SELECTOR_FILTER_KEYS, UNSUPPORTED_SELECTOR_KEYS, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
37868
+ var fs20, path20, 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, MAESTRO_PERMISSION_KINDS, MAESTRO_PERMISSION_STATUS, SootSimBridgeFlowRunner;
37315
37869
  var init_bridge_flow_runner = __esm({
37316
37870
  "cli/bridge-flow-runner.ts"() {
37317
37871
  "use strict";
37318
- fs19 = __toESM(require("fs"), 1);
37319
- path19 = __toESM(require("path"), 1);
37320
- import_settings3 = require("peach-engine/settings");
37321
- import_yaml = __toESM(require("yaml"), 1);
37872
+ fs20 = __toESM(require("fs"), 1);
37873
+ path20 = __toESM(require("path"), 1);
37874
+ import_devices4 = require("peach-engine/settings/devices");
37875
+ import_yaml2 = __toESM(require("yaml"), 1);
37322
37876
  import_proof_frame = __toESM(require_proof_frame(), 1);
37323
37877
  init_flow_timeout_scale();
37324
37878
  init_frame_compose();
@@ -37633,14 +38187,14 @@ var init_bridge_flow_runner = __esm({
37633
38187
  if (chunks.length === 0) {
37634
38188
  throw new Error("recording requested but no video buffer was produced");
37635
38189
  }
37636
- fs19.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
38190
+ fs20.mkdirSync(this.opts.recordingOutputDir, { recursive: true });
37637
38191
  const videoMime = stopped.mime || this.opts.recordingFormat || "video/webm";
37638
38192
  const extension = videoMime.includes("mp4") ? "mp4" : "webm";
37639
- const outputPath = path19.join(
38193
+ const outputPath = path20.join(
37640
38194
  this.opts.recordingOutputDir,
37641
38195
  `peach-${Date.now()}.${extension}`
37642
38196
  );
37643
- fs19.writeFileSync(outputPath, Buffer.concat(chunks));
38197
+ fs20.writeFileSync(outputPath, Buffer.concat(chunks));
37644
38198
  return outputPath;
37645
38199
  }
37646
38200
  async waitForRecordingTail(opts) {
@@ -38000,6 +38554,7 @@ var init_bridge_flow_runner = __esm({
38000
38554
  }
38001
38555
  async tapOn(target) {
38002
38556
  const opts = typeof target === "string" ? { text: target } : target;
38557
+ await this.waitForAppToSettle();
38003
38558
  const repeat = Math.max(1, Math.trunc(opts.repeat ?? 1));
38004
38559
  const repeatDelay = opts.delay !== void 0 && opts.delay >= 0 ? opts.delay : 100;
38005
38560
  const repeatTaps = async (tappedAtMs, tapAgain) => {
@@ -38272,7 +38827,7 @@ var init_bridge_flow_runner = __esm({
38272
38827
  flowDir: this.opts.flowDir
38273
38828
  }
38274
38829
  );
38275
- fs19.mkdirSync(path19.dirname(outputPath), { recursive: true });
38830
+ fs20.mkdirSync(path20.dirname(outputPath), { recursive: true });
38276
38831
  const layers = spec.layers ?? this.opts.screenshotLayers;
38277
38832
  const screenshotRequest = {
38278
38833
  type: "screenshot",
@@ -38307,11 +38862,11 @@ var init_bridge_flow_runner = __esm({
38307
38862
  throw new Error("could not read current device model for framed screenshot");
38308
38863
  }
38309
38864
  const framed = await composeFramedScreenshot(rawBuffer, model);
38310
- fs19.writeFileSync(outputPath, framed);
38865
+ fs20.writeFileSync(outputPath, framed);
38311
38866
  console.log(`[flow] screenshot: ${outputPath} (frame: ${model})`);
38312
38867
  return outputPath;
38313
38868
  }
38314
- fs19.writeFileSync(outputPath, rawBuffer);
38869
+ fs20.writeFileSync(outputPath, rawBuffer);
38315
38870
  console.log(`[flow] screenshot: ${outputPath}`);
38316
38871
  return outputPath;
38317
38872
  }
@@ -38323,7 +38878,7 @@ var init_bridge_flow_runner = __esm({
38323
38878
  args: []
38324
38879
  });
38325
38880
  const model = settings && typeof settings.deviceModel === "string" ? settings.deviceModel : null;
38326
- if (!model || !(model in import_settings3.devices)) return null;
38881
+ if (!model || !(model in import_devices4.devices)) return null;
38327
38882
  return model;
38328
38883
  }
38329
38884
  async captureScreenshot(outputPath) {
@@ -38333,10 +38888,10 @@ var init_bridge_flow_runner = __esm({
38333
38888
  // + a11y tree + console errors/warnings + failed network requests +
38334
38889
  // shell state, all under one directory so post-mortem is one grep away.
38335
38890
  async captureFailureBundle(outputDir, context) {
38336
- fs19.mkdirSync(outputDir, { recursive: true });
38891
+ fs20.mkdirSync(outputDir, { recursive: true });
38337
38892
  const write = (name2, content) => {
38338
38893
  try {
38339
- fs19.writeFileSync(path19.join(outputDir, name2), content);
38894
+ fs20.writeFileSync(path20.join(outputDir, name2), content);
38340
38895
  } catch {
38341
38896
  }
38342
38897
  };
@@ -38783,14 +39338,14 @@ var init_bridge_flow_runner = __esm({
38783
39338
  );
38784
39339
  }
38785
39340
  }
38786
- // maestro waits after every input for the screen to stop changing, up to
39341
+ // maestro waits around taps for the screen to stop changing, up to
38787
39342
  // its ios driver's 3 s settle budget, comparing screenshots, so an action
38788
39343
  // still in flight (a submit spinner, a sheet closing) finishes before the
38789
39344
  // next command resolves its target. an app can take a few hundred ms to
38790
39345
  // react to a press, so stillness must hold about half a second, and it
38791
39346
  // counts painted frames because a spinner repaints without moving layout.
38792
39347
  // a screen that never stops proceeds when the budget runs out, as there.
38793
- async settleAfterInput() {
39348
+ async waitForAppToSettle() {
38794
39349
  await waitForSootsimIdle({
38795
39350
  bridge: this.bridge,
38796
39351
  simId: this.opts.simId,
@@ -38800,6 +39355,9 @@ var init_bridge_flow_runner = __esm({
38800
39355
  strict: true,
38801
39356
  paintStill: true
38802
39357
  });
39358
+ }
39359
+ async settleAfterInput() {
39360
+ await this.waitForAppToSettle();
38803
39361
  this.lastInteractionAt = Date.now();
38804
39362
  }
38805
39363
  async waitForVisualSettle() {
@@ -38931,8 +39489,8 @@ var init_bridge_flow_runner = __esm({
38931
39489
  runScript(target) {
38932
39490
  const spec = typeof target === "string" ? { file: target } : target;
38933
39491
  if (!spec.file) throw new Error("runScript requires a file");
38934
- const scriptPath = path19.resolve(this.opts.flowDir, spec.file);
38935
- const source = fs19.readFileSync(scriptPath, "utf8");
39492
+ const scriptPath = path20.resolve(this.opts.flowDir, spec.file);
39493
+ const source = fs20.readFileSync(scriptPath, "utf8");
38936
39494
  this.js.evaluate(source, { env: spec.env });
38937
39495
  console.log(`[flow] runScript: ${spec.file} done`);
38938
39496
  }
@@ -39044,7 +39602,10 @@ var init_bridge_flow_runner = __esm({
39044
39602
  }
39045
39603
  }
39046
39604
  try {
39047
- const hasExplicitWait = !!(step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow || // retry reruns its body on failure, so its wall time is the body's
39605
+ const hasBoundedWait = !!// taps combine bounded lookup, settling and delivery. a wall-clock
39606
+ // watchdog can finish the step while that action is still running.
39607
+ // let these operations finish before starting the next command.
39608
+ (step.tapOn || step.doubleTapOn || step.longPressOn || step.extendedWaitUntil || step.waitFor || step.scrollUntilVisible || step.launchApp || step.runFlow || // retry reruns its body on failure, so its wall time is the body's
39048
39609
  // times the retry count — the 10s no-progress watchdog is the wrong
39049
39610
  // budget and would report "bridge probably hung" for a slow retry.
39050
39611
  step.retry || // runScript http calls are synchronous with a 5-minute upstream
@@ -39060,7 +39621,7 @@ var init_bridge_flow_runner = __esm({
39060
39621
  const STEP_WATCHDOG_MS = 1e4;
39061
39622
  const body = this.runStepInner(step);
39062
39623
  let screenshotPath;
39063
- if (hasExplicitWait) {
39624
+ if (hasBoundedWait) {
39064
39625
  const result = await body;
39065
39626
  if (typeof result === "string") screenshotPath = result;
39066
39627
  } else {
@@ -39289,10 +39850,10 @@ var init_bridge_flow_runner = __esm({
39289
39850
  for (const [k, v] of Object.entries(env)) this.js.putEnv(k, v);
39290
39851
  }
39291
39852
  if (file) {
39292
- const flowPath = path19.resolve(this.opts.flowDir, file);
39293
- const flowContent = fs19.readFileSync(flowPath, "utf8");
39853
+ const flowPath = path20.resolve(this.opts.flowDir, file);
39854
+ const flowContent = fs20.readFileSync(flowPath, "utf8");
39294
39855
  const previousDir = this.opts.flowDir;
39295
- this.opts.flowDir = path19.dirname(flowPath);
39856
+ this.opts.flowDir = path20.dirname(flowPath);
39296
39857
  try {
39297
39858
  await this.runFlow(parseFlowSteps(flowContent));
39298
39859
  } finally {
@@ -39463,8 +40024,8 @@ __export(registry_exports, {
39463
40024
  skillRegistry: () => skillRegistry
39464
40025
  });
39465
40026
  module.exports = __toCommonJS(registry_exports);
39466
- var fs20 = __toESM(require("fs"), 1);
39467
- var path20 = __toESM(require("path"), 1);
40027
+ var fs21 = __toESM(require("fs"), 1);
40028
+ var path21 = __toESM(require("path"), 1);
39468
40029
 
39469
40030
  // src/skills/builtin/a11y-review.ts
39470
40031
  init_reap_browser();
@@ -39483,8 +40044,8 @@ var skill = {
39483
40044
  },
39484
40045
  async execute(params, context) {
39485
40046
  const { chromium } = await import("playwright");
39486
- const path21 = await import("path");
39487
- const fs21 = await import("fs");
40047
+ const path22 = await import("path");
40048
+ const fs22 = await import("fs");
39488
40049
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
39489
40050
  headless: true
39490
40051
  });
@@ -39539,9 +40100,9 @@ var skill = {
39539
40100
  warnings: issues.filter((i) => i.severity === "warning").length,
39540
40101
  tree: typeof tree === "string" ? tree : JSON.stringify(tree)
39541
40102
  };
39542
- const reportPath = path21.join(context.outputDir, "a11y-report.json");
39543
- fs21.mkdirSync(path21.dirname(reportPath), { recursive: true });
39544
- fs21.writeFileSync(reportPath, JSON.stringify(report, null, 2));
40103
+ const reportPath = path22.join(context.outputDir, "a11y-report.json");
40104
+ fs22.mkdirSync(path22.dirname(reportPath), { recursive: true });
40105
+ fs22.writeFileSync(reportPath, JSON.stringify(report, null, 2));
39545
40106
  return {
39546
40107
  success: issues.filter((i) => i.severity === "error").length === 0,
39547
40108
  message: `${report.errors} errors, ${report.warnings} warnings across ${report.nodeCount} nodes`,
@@ -39574,14 +40135,14 @@ var skill2 = {
39574
40135
  }
39575
40136
  },
39576
40137
  async execute(params, context) {
39577
- const fs21 = await import("node:fs");
39578
- const path21 = await import("node:path");
40138
+ const fs22 = await import("node:fs");
40139
+ const path22 = await import("node:path");
39579
40140
  const { COMPAT_RESULT_CAVEAT: COMPAT_RESULT_CAVEAT2, formatPackageStatus: formatPackageStatus2, formatScanCounts: formatScanCounts2, scanDeps: scanDeps2 } = await Promise.resolve().then(() => (init_web(), web_exports));
39580
- const packagePath = path21.join(context.projectDir, "package.json");
39581
- if (!fs21.existsSync(packagePath)) {
40141
+ const packagePath = path22.join(context.projectDir, "package.json");
40142
+ if (!fs22.existsSync(packagePath)) {
39582
40143
  return { success: false, message: "No package.json found" };
39583
40144
  }
39584
- const parsed = JSON.parse(fs21.readFileSync(packagePath, "utf8"));
40145
+ const parsed = JSON.parse(fs22.readFileSync(packagePath, "utf8"));
39585
40146
  if (!parsed || typeof parsed !== "object") {
39586
40147
  return { success: false, message: "package.json is not an object" };
39587
40148
  }
@@ -39593,9 +40154,9 @@ var skill2 = {
39593
40154
  }) : scanDeps2(parsed);
39594
40155
  const packageResult = params.packageName ? scan.packages[0] : void 0;
39595
40156
  const message = packageResult ? `${params.packageName}: ${formatPackageStatus2(packageResult)}. ${COMPAT_RESULT_CAVEAT2}` : `${formatScanCounts2(scan)}. ${COMPAT_RESULT_CAVEAT2}`;
39596
- const reportPath = path21.join(context.outputDir, "compat-report.json");
39597
- fs21.mkdirSync(path21.dirname(reportPath), { recursive: true });
39598
- fs21.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
40157
+ const reportPath = path22.join(context.outputDir, "compat-report.json");
40158
+ fs22.mkdirSync(path22.dirname(reportPath), { recursive: true });
40159
+ fs22.writeFileSync(reportPath, `${JSON.stringify(scan, null, 2)}
39599
40160
  `);
39600
40161
  return {
39601
40162
  success: true,
@@ -39637,8 +40198,8 @@ var skill3 = {
39637
40198
  record: { type: "boolean", description: "Record video of the flow" }
39638
40199
  },
39639
40200
  async execute(params, context) {
39640
- const fs21 = await import("fs");
39641
- const path21 = await import("path");
40201
+ const fs22 = await import("fs");
40202
+ const path22 = await import("path");
39642
40203
  const yaml2 = await import("yaml");
39643
40204
  const { DEFAULT_SOOTSIM_BRIDGE_PORT: DEFAULT_SOOTSIM_BRIDGE_PORT3 } = await Promise.resolve().then(() => (init_bridge_constants(), bridge_constants_exports));
39644
40205
  const { SootSimBridgeHost: SootSimBridgeHost2 } = await Promise.resolve().then(() => (init_bridge_host(), bridge_host_exports));
@@ -39648,7 +40209,7 @@ var skill3 = {
39648
40209
  const host = new SootSimBridgeHost2({ port: DEFAULT_SOOTSIM_BRIDGE_PORT3 });
39649
40210
  host.start({ silent: true });
39650
40211
  try {
39651
- const flowContent = fs21.readFileSync(params.flowPath, "utf8");
40212
+ const flowContent = fs22.readFileSync(params.flowPath, "utf8");
39652
40213
  const fmMatch = flowContent.match(/^---\n([\s\S]*?)\n---\n?/);
39653
40214
  const stepsBody = fmMatch ? flowContent.slice(fmMatch[0].length) : flowContent;
39654
40215
  const steps = yaml2.parse(stepsBody);
@@ -39675,7 +40236,7 @@ var skill3 = {
39675
40236
  });
39676
40237
  const driver = new SootSimBridgeFlowRunner2(bridge, {
39677
40238
  screenshotDir: context.outputDir,
39678
- flowDir: path21.dirname(path21.resolve(params.flowPath)),
40239
+ flowDir: path22.dirname(path22.resolve(params.flowPath)),
39679
40240
  simId,
39680
40241
  recordingOutputDir: params.record ? context.outputDir : void 0
39681
40242
  });
@@ -39697,7 +40258,7 @@ var skill3 = {
39697
40258
  simId,
39698
40259
  videoPath: videoPath || void 0
39699
40260
  },
39700
- artifacts: videoPath ? [{ type: "video", name: path21.basename(videoPath), path: videoPath }] : void 0
40261
+ artifacts: videoPath ? [{ type: "video", name: path22.basename(videoPath), path: videoPath }] : void 0
39701
40262
  };
39702
40263
  } finally {
39703
40264
  try {
@@ -39744,8 +40305,8 @@ var skill4 = {
39744
40305
  },
39745
40306
  async execute(params, context) {
39746
40307
  const { chromium } = await import("playwright");
39747
- const path21 = await import("path");
39748
- const fs21 = await import("fs");
40308
+ const path22 = await import("path");
40309
+ const fs22 = await import("fs");
39749
40310
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
39750
40311
  headless: true
39751
40312
  });
@@ -39771,9 +40332,9 @@ var skill4 = {
39771
40332
  ...profile,
39772
40333
  fps: syncCount > 0 ? (syncCount / (duration / 1e3)).toFixed(1) : "0"
39773
40334
  };
39774
- const reportPath = path21.join(context.outputDir, "perf-report.json");
39775
- fs21.mkdirSync(path21.dirname(reportPath), { recursive: true });
39776
- fs21.writeFileSync(reportPath, JSON.stringify(report, null, 2));
40335
+ const reportPath = path22.join(context.outputDir, "perf-report.json");
40336
+ fs22.mkdirSync(path22.dirname(reportPath), { recursive: true });
40337
+ fs22.writeFileSync(reportPath, JSON.stringify(report, null, 2));
39777
40338
  return {
39778
40339
  success: true,
39779
40340
  message: `${report.fps} fps, ${profile.avgSyncMs?.toFixed(1)}ms avg sync, ${nodeCount} nodes`,
@@ -39806,8 +40367,8 @@ var skill5 = {
39806
40367
  },
39807
40368
  async execute(params, context) {
39808
40369
  const { chromium } = await import("playwright");
39809
- const path21 = await import("path");
39810
- const fs21 = await import("fs");
40370
+ const path22 = await import("path");
40371
+ const fs22 = await import("fs");
39811
40372
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
39812
40373
  headless: true
39813
40374
  });
@@ -39815,8 +40376,8 @@ var skill5 = {
39815
40376
  try {
39816
40377
  await page.goto(context.url, { waitUntil: "networkidle" });
39817
40378
  await page.waitForTimeout(2e3);
39818
- const outputPath = path21.join(context.outputDir, `${params.name}.png`);
39819
- fs21.mkdirSync(path21.dirname(outputPath), { recursive: true });
40379
+ const outputPath = path22.join(context.outputDir, `${params.name}.png`);
40380
+ fs22.mkdirSync(path22.dirname(outputPath), { recursive: true });
39820
40381
  await page.screenshot({ path: outputPath });
39821
40382
  return {
39822
40383
  success: true,
@@ -39857,8 +40418,8 @@ var skill6 = {
39857
40418
  },
39858
40419
  async execute(params, context) {
39859
40420
  const { chromium } = await import("playwright");
39860
- const path21 = await import("path");
39861
- const fs21 = await import("fs");
40421
+ const path22 = await import("path");
40422
+ const fs22 = await import("fs");
39862
40423
  const browser = await launchReapedChrome((options) => chromium.launch(options), {
39863
40424
  headless: true
39864
40425
  });
@@ -39866,14 +40427,14 @@ var skill6 = {
39866
40427
  try {
39867
40428
  await page.goto(context.url, { waitUntil: "networkidle" });
39868
40429
  await page.waitForTimeout(2e3);
39869
- const currentPath = path21.join(context.outputDir, `${params.name}-current.png`);
39870
- fs21.mkdirSync(path21.dirname(currentPath), { recursive: true });
40430
+ const currentPath = path22.join(context.outputDir, `${params.name}-current.png`);
40431
+ fs22.mkdirSync(path22.dirname(currentPath), { recursive: true });
39871
40432
  await page.screenshot({ path: currentPath });
39872
40433
  try {
39873
40434
  const { PNG } = await import("pngjs");
39874
40435
  const pixelmatch = (await import("pixelmatch")).default;
39875
- const baseline = PNG.sync.read(fs21.readFileSync(params.baseline));
39876
- const current = PNG.sync.read(fs21.readFileSync(currentPath));
40436
+ const baseline = PNG.sync.read(fs22.readFileSync(params.baseline));
40437
+ const current = PNG.sync.read(fs22.readFileSync(currentPath));
39877
40438
  const { width, height } = baseline;
39878
40439
  const diff = new PNG({ width, height });
39879
40440
  const numDiffPixels = pixelmatch(
@@ -39884,8 +40445,8 @@ var skill6 = {
39884
40445
  height,
39885
40446
  { threshold: params.threshold || 0.1 }
39886
40447
  );
39887
- const diffPath = path21.join(context.outputDir, `${params.name}-diff.png`);
39888
- fs21.writeFileSync(diffPath, PNG.sync.write(diff));
40448
+ const diffPath = path22.join(context.outputDir, `${params.name}-diff.png`);
40449
+ fs22.writeFileSync(diffPath, PNG.sync.write(diff));
39889
40450
  const totalPixels = width * height;
39890
40451
  const diffPercent = (numDiffPixels / totalPixels * 100).toFixed(2);
39891
40452
  return {
@@ -39949,10 +40510,10 @@ var skillRegistry = {
39949
40510
  },
39950
40511
  // load skills from a project manifest (rnx-skills.json)
39951
40512
  async loadFromManifest(projectDir) {
39952
- const manifestPath = path20.join(projectDir, "rnx-skills.json");
39953
- if (!fs20.existsSync(manifestPath)) return;
40513
+ const manifestPath = path21.join(projectDir, "rnx-skills.json");
40514
+ if (!fs21.existsSync(manifestPath)) return;
39954
40515
  try {
39955
- const manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf8"));
40516
+ const manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf8"));
39956
40517
  if (Array.isArray(manifest.skills)) {
39957
40518
  for (const entry of manifest.skills) {
39958
40519
  if (typeof entry === "string") {
@@ -39963,7 +40524,7 @@ var skillRegistry = {
39963
40524
  }
39964
40525
  } else if (entry.file) {
39965
40526
  try {
39966
- const mod = await import(path20.resolve(projectDir, entry.file));
40527
+ const mod = await import(path21.resolve(projectDir, entry.file));
39967
40528
  if (mod.skill) this.register(mod.skill);
39968
40529
  } catch {
39969
40530
  }
@@ -39976,10 +40537,10 @@ var skillRegistry = {
39976
40537
  // auto-discover skills based on project dependencies
39977
40538
  suggestSkills(projectDir) {
39978
40539
  const suggestions = [];
39979
- const pkgPath = path20.join(projectDir, "package.json");
39980
- if (!fs20.existsSync(pkgPath)) return suggestions;
40540
+ const pkgPath = path21.join(projectDir, "package.json");
40541
+ if (!fs21.existsSync(pkgPath)) return suggestions;
39981
40542
  try {
39982
- const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf8"));
40543
+ const pkg = JSON.parse(fs21.readFileSync(pkgPath, "utf8"));
39983
40544
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
39984
40545
  if (deps["detox"] || deps["maestro"]) {
39985
40546
  suggestions.push("maestro-test");