rnxsim 0.1.505 → 0.1.507

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 (63) hide show
  1. package/cli/bridge-flow-runner.ts +7 -2
  2. package/cli/commands/agent-wrapper.ts +7 -3
  3. package/cli/commands/control.ts +3 -3
  4. package/cli/commands/flow.ts +9 -12
  5. package/cli/commands/inspect.ts +2 -2
  6. package/cli/commands/platform.ts +2 -1
  7. package/cli/flow-live-status.ts +8 -2
  8. package/cli/ws-bridge.ts +28 -15
  9. package/detox/index.ts +24 -0
  10. package/dist-lib/agent-daemon-client.cjs +1 -1
  11. package/dist-lib/agent-events.cjs +1 -1
  12. package/dist-lib/agent-identity.cjs +1 -1
  13. package/dist-lib/agent-sessions.cjs +1 -1
  14. package/dist-lib/attached-projects.cjs +1 -1
  15. package/dist-lib/auth/shared-session.cjs +1 -1
  16. package/dist-lib/backend-origin.cjs +1 -1
  17. package/dist-lib/beta.cjs +1 -1
  18. package/dist-lib/beta.mjs +1 -1
  19. package/dist-lib/bridge-constants.cjs +1 -1
  20. package/dist-lib/bridge-contract-input.cjs +1 -1
  21. package/dist-lib/bridge-contract-input.mjs +1 -1
  22. package/dist-lib/bridge-contract.cjs +1 -1
  23. package/dist-lib/bridge-contract.mjs +1 -1
  24. package/dist-lib/capture-contract.cjs +1 -1
  25. package/dist-lib/capture-contract.mjs +1 -1
  26. package/dist-lib/cli-constants.cjs +1 -1
  27. package/dist-lib/cloud-contract.cjs +1 -1
  28. package/dist-lib/cloud-contract.mjs +1 -1
  29. package/dist-lib/cloud.cjs +1 -1
  30. package/dist-lib/cloud.mjs +1 -1
  31. package/dist-lib/config.cjs +1 -1
  32. package/dist-lib/detox/index.cjs +24 -1
  33. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  34. package/dist-lib/home-paths.cjs +1 -1
  35. package/dist-lib/host/bridge-host.cjs +142 -56
  36. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  37. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  38. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  39. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  40. package/dist-lib/host/websocket-proxy.cjs +1 -1
  41. package/dist-lib/index.cjs +18 -13
  42. package/dist-lib/jump-to-source-babel.cjs +1 -1
  43. package/dist-lib/jump-to-source-native.cjs +1 -1
  44. package/dist-lib/menu.cjs +1 -1
  45. package/dist-lib/menu.mjs +1 -1
  46. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  47. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  48. package/dist-lib/metro-production-bundle.cjs +1 -1
  49. package/dist-lib/metro-production-bundle.mjs +1 -1
  50. package/dist-lib/metro.cjs +1 -1
  51. package/dist-lib/profiles.cjs +1 -1
  52. package/dist-lib/public-brand.cjs +1 -1
  53. package/dist-lib/react-native-host-modules.cjs +1 -1
  54. package/dist-lib/react-native-host-modules.mjs +1 -1
  55. package/dist-lib/render-mode.cjs +1 -1
  56. package/dist-lib/scripts/dev-server-scanner.cjs +36 -18
  57. package/dist-lib/sdk.cjs +1 -1
  58. package/dist-lib/sdk.mjs +1 -1
  59. package/dist-lib/skills.cjs +214 -87
  60. package/dist-lib/vite.cjs +1 -1
  61. package/package.json +1 -1
  62. package/scripts/dev-server-scanner.ts +37 -20
  63. package/src/screenshots/frame-compose.ts +71 -11
@@ -21,6 +21,7 @@ import { realpathSync } from 'node:fs'
21
21
  import { resolve } from 'node:path'
22
22
  import {
23
23
  buildLoopbackProbeBaseUrl,
24
+ isLoopbackHost,
24
25
  LOOPBACK_PROBE_HOSTNAMES,
25
26
  normalizeHostname,
26
27
  } from '../src/backend-origin.ts'
@@ -624,24 +625,35 @@ function applyManifest(
624
625
  if (launchUrl && !result.patched && !isDirectOneBundleUrl(result.bundleUrl)) {
625
626
  result.bundleUrl = withRuntimeConfig(result.port, launchUrl, result.cwd)
626
627
  }
627
- const rawIconUrl =
628
- client.iconUrl || client.ios?.iconUrl || client.icon || client.ios?.icon
629
- if (rawIconUrl) {
630
- result.iconPath = rawIconUrl
631
- if (buildIconProxyUrl) {
632
- if (rawIconUrl.startsWith('http')) {
633
- result.iconUrl = buildIconProxyUrl(rawIconUrl)
628
+ const localIcon = client.icon || client.ios?.icon
629
+ const remoteIcon = client.iconUrl || client.ios?.iconUrl
630
+ const rawIcon = localIcon || remoteIcon
631
+ if (rawIcon) {
632
+ result.iconPath = rawIcon
633
+ let resolvedIconUrl: string | undefined
634
+ if (rawIcon.startsWith('http://') || rawIcon.startsWith('https://')) {
635
+ let isLoopback = false
636
+ try {
637
+ const parsed = new URL(rawIcon)
638
+ isLoopback = isLoopbackHost(parsed.hostname)
639
+ } catch {}
640
+ if (buildIconProxyUrl) {
641
+ if (isLoopback) {
642
+ resolvedIconUrl = buildIconProxyUrl(rawIcon)
643
+ }
634
644
  } else {
635
- const cleanPath = rawIconUrl.replace(/^\.\//, '')
636
- result.iconUrl = buildIconProxyUrl(
637
- `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}/assets/${cleanPath}`,
638
- )
645
+ resolvedIconUrl = rawIcon
639
646
  }
640
647
  } else {
641
- // no proxy requested — use the raw URL
642
- result.iconUrl = rawIconUrl.startsWith('http')
643
- ? rawIconUrl
644
- : `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}/assets/${rawIconUrl.replace(/^\.\//, '')}`
648
+ const cleanPath = rawIcon.replace(/^\.?\//, '')
649
+ const assetPath = cleanPath.startsWith('assets/')
650
+ ? `/${cleanPath}`
651
+ : `/assets/${cleanPath}`
652
+ const localUrl = `${buildLoopbackProbeBaseUrl('http:', manifestRes.hostname, result.port)}${assetPath}`
653
+ resolvedIconUrl = buildIconProxyUrl ? buildIconProxyUrl(localUrl) : localUrl
654
+ }
655
+ if (resolvedIconUrl) {
656
+ result.iconUrl = resolvedIconUrl
645
657
  }
646
658
  }
647
659
  } catch {}
@@ -651,12 +663,17 @@ function applyManifest(
651
663
  export function __applyManifestForTests(
652
664
  result: DiscoveredServer,
653
665
  manifestBody: string,
666
+ buildIconProxyUrl?: (externalUrl: string) => string,
654
667
  ): DiscoveredServer {
655
- return applyManifest(result, {
656
- statusCode: 200,
657
- body: manifestBody,
658
- hostname: new URL(result.bundleUrl).hostname,
659
- })
668
+ return applyManifest(
669
+ result,
670
+ {
671
+ statusCode: 200,
672
+ body: manifestBody,
673
+ hostname: new URL(result.bundleUrl).hostname,
674
+ },
675
+ buildIconProxyUrl,
676
+ )
660
677
  }
661
678
 
662
679
  // ── name/icon enrichment ────────────────────────────────────────────────────
@@ -5,11 +5,18 @@ import {
5
5
  LEGACY_HOME_BUTTON_SIZE,
6
6
  LEGACY_SIDE_BEZEL,
7
7
  LEGACY_TOP_BEZEL,
8
+ HINGE_BARREL_BACKGROUND,
9
+ HINGE_BARREL_SHADOW,
10
+ HOUSING_RAIL_COLOR,
11
+ HOUSING_RAIL_OUTLINE,
8
12
  SIDE_BUTTON_RESERVE,
9
13
  } from 'sootsim-engine/ios/chrome-metrics'
10
14
  import {
15
+ cornerRadii,
16
+ formatCornerRadii,
11
17
  getDevice,
12
18
  resolveDeviceFrameGeometry,
19
+ type CornerRadii,
13
20
  type DeviceModel,
14
21
  } from 'sootsim-engine/settings'
15
22
  import { launchReapedChrome } from '../../../../scripts/lib/reap-browser'
@@ -47,8 +54,10 @@ export interface FramedScreenshotLayout {
47
54
  logicalScreenHeight: number
48
55
  logicalScreenLeft: number
49
56
  logicalScreenTop: number
50
- logicalScreenRadius: number
51
- logicalFrameRadius: number
57
+ logicalScreenRadius: CornerRadii
58
+ logicalFrameRadius: CornerRadii
59
+ // light rail around a black glass ring; null draws one black body
60
+ housing: ReturnType<typeof resolveDeviceFrameGeometry>['housing']
52
61
  frameBackground: string
53
62
  frameOutline: string
54
63
  metallicRingShadow: string | null
@@ -73,10 +82,12 @@ export function getFramedScreenshotLayout(model: DeviceModel): FramedScreenshotL
73
82
  spec.statusBarHeight > 0 &&
74
83
  !spec.dynamicIsland &&
75
84
  spec.homeIndicatorHeight === 0 &&
76
- spec.cornerRadius === 0
85
+ // home-button iphones have a square display, so any corner reads 0
86
+ spec.cornerRadius.topLeft === 0
77
87
  const logicalScreenWidth = spec.width
78
88
  const logicalScreenHeight = spec.height
79
89
  const modernGeometry = resolveDeviceFrameGeometry(spec)
90
+ const housing = isLegacyHardware ? null : modernGeometry.housing
80
91
  const logicalFrameWidth = isLegacyHardware
81
92
  ? spec.width + LEGACY_SIDE_BEZEL * 2
82
93
  : modernGeometry.frameWidth
@@ -91,7 +102,7 @@ export function getFramedScreenshotLayout(model: DeviceModel): FramedScreenshotL
91
102
  logicalFrameLeft + (isLegacyHardware ? LEGACY_SIDE_BEZEL : modernGeometry.screenLeft)
92
103
  const logicalScreenTop = isLegacyHardware ? LEGACY_TOP_BEZEL : modernGeometry.screenTop
93
104
  const logicalFrameRadius = isLegacyHardware
94
- ? LEGACY_FRAME_RADIUS
105
+ ? cornerRadii(LEGACY_FRAME_RADIUS)
95
106
  : modernGeometry.frameRadius
96
107
  const buttons: FrameButtonLayout[] = [
97
108
  {
@@ -135,13 +146,20 @@ export function getFramedScreenshotLayout(model: DeviceModel): FramedScreenshotL
135
146
  logicalScreenHeight,
136
147
  logicalScreenLeft,
137
148
  logicalScreenTop,
138
- logicalScreenRadius: isLegacyHardware ? 0 : modernGeometry.screenRadius,
149
+ logicalScreenRadius: isLegacyHardware ? cornerRadii(0) : modernGeometry.screenRadius,
139
150
  logicalFrameRadius,
151
+ housing,
140
152
  frameBackground: isLegacyHardware
141
153
  ? 'linear-gradient(180deg, #1b1c20 0%, #0f1012 42%, #050608 100%)'
142
- : '#000000',
143
- frameOutline: isLegacyHardware ? '0 0 0 1px #1f2125' : '0 0 0 1px #333',
144
- metallicRingShadow: isLegacyHardware ? null : METALLIC_RING_SHADOW,
154
+ : housing
155
+ ? HOUSING_RAIL_COLOR
156
+ : '#000000',
157
+ frameOutline: isLegacyHardware
158
+ ? '0 0 0 1px #1f2125'
159
+ : housing
160
+ ? HOUSING_RAIL_OUTLINE
161
+ : '0 0 0 1px #333',
162
+ metallicRingShadow: isLegacyHardware || housing ? null : METALLIC_RING_SHADOW,
145
163
  buttons,
146
164
  legacyHomeButton: isLegacyHardware
147
165
  ? {
@@ -203,7 +221,7 @@ function renderFrameHtml(
203
221
  style="
204
222
  position:absolute;
205
223
  inset:0;
206
- border-radius:${layout.logicalFrameRadius}px;
224
+ border-radius:${formatCornerRadii(layout.logicalFrameRadius)};
207
225
  box-shadow:${layout.metallicRingShadow};
208
226
  pointer-events:none;
209
227
  z-index:10;
@@ -212,6 +230,47 @@ function renderFrameHtml(
212
230
  `
213
231
  : ''
214
232
 
233
+ // black glass ring inside the rail, then the hinge barrel over the leading
234
+ // rail. the ring carries no z-index so the screen div after it paints on top.
235
+ const housingHtml = layout.housing
236
+ ? `
237
+ <div
238
+ aria-hidden="true"
239
+ style="
240
+ position:absolute;
241
+ top:${layout.housing.rail.top}px;
242
+ right:${layout.housing.rail.right}px;
243
+ bottom:${layout.housing.rail.bottom}px;
244
+ left:${layout.housing.rail.left}px;
245
+ border-radius:${formatCornerRadii(layout.housing.glassRadius)};
246
+ background:#000000;
247
+ pointer-events:none;
248
+ "
249
+ ></div>
250
+ ${
251
+ layout.housing.hingeBarrel
252
+ ? `
253
+ <div
254
+ aria-hidden="true"
255
+ style="
256
+ position:absolute;
257
+ top:${layout.housing.hingeBarrel.endInset}px;
258
+ bottom:${layout.housing.hingeBarrel.endInset}px;
259
+ left:0;
260
+ width:${layout.housing.hingeBarrel.width}px;
261
+ border-radius:${layout.housing.hingeBarrel.width / 2}px 0 0 ${layout.housing.hingeBarrel.width / 2}px;
262
+ background:${HINGE_BARREL_BACKGROUND};
263
+ box-shadow:${HINGE_BARREL_SHADOW};
264
+ pointer-events:none;
265
+ z-index:11;
266
+ "
267
+ ></div>
268
+ `
269
+ : ''
270
+ }
271
+ `
272
+ : ''
273
+
215
274
  const legacyHomeButtonHtml = layout.legacyHomeButton
216
275
  ? `
217
276
  <div
@@ -331,7 +390,7 @@ function renderFrameHtml(
331
390
  left:${layout.logicalFrameLeft}px;
332
391
  width:${layout.logicalFrameWidth}px;
333
392
  height:${layout.logicalFrameHeight}px;
334
- border-radius:${layout.logicalFrameRadius}px;
393
+ border-radius:${formatCornerRadii(layout.logicalFrameRadius)};
335
394
  box-sizing:border-box;
336
395
  overflow:visible;
337
396
  background:${layout.frameBackground};
@@ -340,6 +399,7 @@ function renderFrameHtml(
340
399
  >
341
400
  ${buttonsHtml}
342
401
  ${ringHtml}
402
+ ${housingHtml}
343
403
  ${legacyHomeButtonHtml}
344
404
  <div
345
405
  id="screen"
@@ -349,7 +409,7 @@ function renderFrameHtml(
349
409
  left:${layout.logicalScreenLeft - layout.logicalFrameLeft}px;
350
410
  width:${layout.logicalScreenWidth}px;
351
411
  height:${layout.logicalScreenHeight}px;
352
- border-radius:${layout.logicalScreenRadius}px;
412
+ border-radius:${formatCornerRadii(layout.logicalScreenRadius)};
353
413
  overflow:hidden;
354
414
  background:#000;
355
415
  "