rnxsim 0.1.430 → 0.1.432

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 (54) hide show
  1. package/cli/commands/control.ts +78 -14
  2. package/cli/ws-bridge.ts +2 -0
  3. package/dist-lib/agent-daemon-client.cjs +1 -1
  4. package/dist-lib/agent-events.cjs +1 -1
  5. package/dist-lib/agent-identity.cjs +1 -1
  6. package/dist-lib/agent-sessions.cjs +1 -1
  7. package/dist-lib/attached-projects.cjs +1 -1
  8. package/dist-lib/auth/shared-session.cjs +1 -1
  9. package/dist-lib/backend-origin.cjs +1 -1
  10. package/dist-lib/beta.cjs +1 -1
  11. package/dist-lib/beta.mjs +1 -1
  12. package/dist-lib/bridge-constants.cjs +1 -1
  13. package/dist-lib/bridge-contract-input.cjs +1 -1
  14. package/dist-lib/bridge-contract-input.mjs +1 -1
  15. package/dist-lib/bridge-contract.cjs +1 -1
  16. package/dist-lib/bridge-contract.mjs +1 -1
  17. package/dist-lib/capture-contract.cjs +1 -1
  18. package/dist-lib/capture-contract.mjs +1 -1
  19. package/dist-lib/cli-constants.cjs +1 -1
  20. package/dist-lib/cloud-contract.cjs +1 -1
  21. package/dist-lib/cloud-contract.mjs +1 -1
  22. package/dist-lib/cloud.cjs +1 -1
  23. package/dist-lib/cloud.mjs +1 -1
  24. package/dist-lib/config.cjs +1 -1
  25. package/dist-lib/detox/index.cjs +1 -1
  26. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  27. package/dist-lib/home-paths.cjs +1 -1
  28. package/dist-lib/host/bridge-host.cjs +6 -5
  29. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  30. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  31. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  32. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  33. package/dist-lib/host/websocket-proxy.cjs +1 -1
  34. package/dist-lib/index.cjs +1 -1
  35. package/dist-lib/jump-to-source-babel.cjs +1 -1
  36. package/dist-lib/menu.cjs +1 -1
  37. package/dist-lib/menu.mjs +1 -1
  38. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  39. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  40. package/dist-lib/metro-production-bundle.cjs +1 -1
  41. package/dist-lib/metro-production-bundle.mjs +1 -1
  42. package/dist-lib/metro.cjs +1 -1
  43. package/dist-lib/profiles.cjs +1 -1
  44. package/dist-lib/public-brand.cjs +1 -1
  45. package/dist-lib/react-native-host-modules.cjs +1 -1
  46. package/dist-lib/react-native-host-modules.mjs +1 -1
  47. package/dist-lib/render-mode.cjs +1 -1
  48. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  49. package/dist-lib/sdk.cjs +1 -1
  50. package/dist-lib/sdk.mjs +1 -1
  51. package/dist-lib/skills.cjs +55 -20
  52. package/dist-lib/vite.cjs +1 -1
  53. package/package.json +1 -1
  54. package/src/host/bridge-host.ts +13 -4
@@ -527,11 +527,11 @@ function parseOpenRuntimeConfig(args: string[]): RNXConfig | undefined {
527
527
  return config.modules || config.network ? config : undefined
528
528
  }
529
529
 
530
- async function resolveOpenAppProject(
531
- resolvedBundle?: ResolvedDevBundle,
530
+ async function resolveAppProjectForBundleUrl(
531
+ bundleUrl?: string,
532
532
  ): Promise<ResolvedAppProject | null> {
533
- if (!resolvedBundle) return null
534
- const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl)
533
+ if (!bundleUrl) return null
534
+ const advertisedRoot = await resolveMetroProjectRoot(bundleUrl)
535
535
  return advertisedRoot ? resolveAppProject(advertisedRoot) : null
536
536
  }
537
537
 
@@ -749,16 +749,28 @@ export interface BuildShellUrlOptions {
749
749
  project?: ResolvedAppProject | null
750
750
  }
751
751
 
752
+ function bundleUrlOf(urlStr: string): string | undefined {
753
+ try {
754
+ return new URL(urlStr).searchParams.get('bundle') || undefined
755
+ } catch {
756
+ return undefined
757
+ }
758
+ }
759
+
752
760
  export async function buildShellUrl(
753
761
  target: string,
754
762
  baseUrl: string = resolveDefaultShellBaseUrl(),
755
763
  opts: BuildShellUrlOptions = {},
756
764
  ): Promise<string> {
757
765
  const resolved = await resolveShellUrl(target, baseUrl, opts)
758
- const stamped = await stampAppSplash(
759
- await stampAppFonts(resolved, opts.project),
760
- opts.project,
761
- )
766
+ // callers that hand us a bare port or url (the flow/maestro runner, the
767
+ // electron companion) have no project to pass. derive it from the bundle
768
+ // metro advertises so those paths get the same UIAppFonts and splash
769
+ // stamping an `rnx open` gets. without it a flow renders the app's text in a
770
+ // fallback typeface, which then reads as a conformance diff.
771
+ const project =
772
+ opts.project ?? (await resolveAppProjectForBundleUrl(bundleUrlOf(resolved)))
773
+ const stamped = await stampAppSplash(await stampAppFonts(resolved, project), project)
762
774
  if (!opts.device) return stamped
763
775
  const url = new URL(stamped)
764
776
  url.searchParams.set('device', opts.device)
@@ -1490,7 +1502,7 @@ export async function runOpenCommand(
1490
1502
  const resolvedBundle = shouldResolveBundleTargetInCli(target)
1491
1503
  ? await resolveConnectionInputForCli(target)
1492
1504
  : undefined
1493
- const project = await resolveOpenAppProject(resolvedBundle)
1505
+ const project = await resolveAppProjectForBundleUrl(resolvedBundle?.bundleUrl)
1494
1506
  const appConfig = await loadRNXAppConfig(project)
1495
1507
  const configuredRuntimeVersion = appConfig?.runtimeVersion
1496
1508
  const runtimeConfig = mergeRNXConfig(
@@ -1953,6 +1965,13 @@ export async function closeSimsBulk(
1953
1965
  return { closed: [...wanted], remaining: [] }
1954
1966
  }
1955
1967
 
1968
+ export interface BulkCloseRefusal {
1969
+ id: string
1970
+ lockedBy: string
1971
+ kind: 'cli' | 'user-active'
1972
+ expiresInMs: number
1973
+ }
1974
+
1956
1975
  export interface BulkClosePlan {
1957
1976
  openIds: string[]
1958
1977
  keepId: string | null
@@ -1960,6 +1979,7 @@ export interface BulkClosePlan {
1960
1979
  staleSavedId: string | null
1961
1980
  missingExplicitKeepId: string | null
1962
1981
  fallbackKeepId: string | null
1982
+ refused: BulkCloseRefusal[]
1963
1983
  }
1964
1984
 
1965
1985
  export function planBulkCloseTargets(
@@ -1968,6 +1988,8 @@ export function planBulkCloseTargets(
1968
1988
  closeOthers: boolean
1969
1989
  explicitKeepId?: string
1970
1990
  savedKeepId?: string | null
1991
+ force?: boolean
1992
+ now?: number
1971
1993
  },
1972
1994
  ): BulkClosePlan {
1973
1995
  const open = sims.filter((sim) => sim.readyState === 'open')
@@ -1999,13 +2021,40 @@ export function planBulkCloseTargets(
1999
2021
  }
2000
2022
  }
2001
2023
 
2024
+ // a sim another agent holds is not ours to close. `use`/`focus`/`claim` all
2025
+ // refuse a live lease; bulk close historically did not look at leases at
2026
+ // all, so `close --all` silently killed other agents' sims mid-capture.
2027
+ const now = opts.now ?? Date.now()
2028
+ const refused: BulkCloseRefusal[] = []
2029
+ for (const sim of open) {
2030
+ if (sim.id === keepId) continue
2031
+ const lockedBy = sim.lockedBy
2032
+ const expiresAt = sim.lockExpiresAt
2033
+ if (!lockedBy || !expiresAt || expiresAt <= now || sim.lockedByMe) continue
2034
+ const kind = sim.lockedByKind ?? 'cli'
2035
+ // --force takes over another agent's cli lease, the same escape hatch
2036
+ // `use --force` offers. a `user-active` lease is a live human tab and is
2037
+ // never closable, matching `claim`, which refuses to report a takeover.
2038
+ if (kind === 'cli' && opts.force) continue
2039
+ refused.push({
2040
+ id: sim.id,
2041
+ lockedBy,
2042
+ kind,
2043
+ expiresInMs: Math.max(0, expiresAt - now),
2044
+ })
2045
+ }
2046
+ const refusedIds = new Set(refused.map((entry) => entry.id))
2047
+
2002
2048
  return {
2003
2049
  openIds,
2004
2050
  keepId,
2005
- targets: missingExplicitKeepId ? [] : openIds.filter((id) => id !== keepId),
2051
+ targets: missingExplicitKeepId
2052
+ ? []
2053
+ : openIds.filter((id) => id !== keepId && !refusedIds.has(id)),
2006
2054
  staleSavedId,
2007
2055
  missingExplicitKeepId,
2008
2056
  fallbackKeepId,
2057
+ refused,
2009
2058
  }
2010
2059
  }
2011
2060
 
@@ -2013,12 +2062,13 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
2013
2062
  const parsed = parseBridgeCliArgs(args, {
2014
2063
  port: opts.port,
2015
2064
  commandTimeoutMs: opts.timeoutMs,
2016
- stripBooleanFlags: ['--all', '--others'],
2065
+ stripBooleanFlags: ['--all', '--others', '--force'],
2017
2066
  })
2018
2067
  const bridge = createBridgeFromParsed(parsed)
2019
2068
  const simHint = parsed.simId ? ` --sim ${parsed.simId}` : ''
2020
2069
  const closeAll = args.includes('--all')
2021
2070
  const closeOthers = args.includes('--others')
2071
+ const force = args.includes('--force')
2022
2072
 
2023
2073
  if (closeAll || closeOthers) {
2024
2074
  try {
@@ -2033,7 +2083,19 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
2033
2083
  closeOthers,
2034
2084
  explicitKeepId,
2035
2085
  savedKeepId: savedId,
2086
+ force,
2036
2087
  })
2088
+ for (const entry of plan.refused) {
2089
+ const secs = Math.round(entry.expiresInMs / 1000)
2090
+ console.error(
2091
+ entry.kind === 'user-active'
2092
+ ? ` skipped: ${entry.id} is locked by the active user (${secs}s) — that's a live human tab`
2093
+ : ` skipped: ${entry.id} is leased by ${formatLockOwner(entry.lockedBy)} (${secs}s)`,
2094
+ )
2095
+ }
2096
+ if (plan.refused.some((entry) => entry.kind === 'cli') && !force) {
2097
+ console.error(` \`rnx close --all --force\` to close leased sims too`)
2098
+ }
2037
2099
  if (plan.staleSavedId) {
2038
2100
  clearCurrentSimId()
2039
2101
  }
@@ -2053,9 +2115,11 @@ export async function runCloseCommand(args: string[], opts: ControlCommandOption
2053
2115
  console.log(
2054
2116
  plan.keepId
2055
2117
  ? ` nothing to close — only the kept sim ${plan.keepId} is connected`
2056
- : plan.staleSavedId
2057
- ? ` nothing to close — no sims connected (cleared stale current sim ${plan.staleSavedId})`
2058
- : ' nothing to close — no sims connected',
2118
+ : plan.refused.length > 0
2119
+ ? ` nothing to close — every other connected sim is leased by someone else`
2120
+ : plan.staleSavedId
2121
+ ? ` nothing to close — no sims connected (cleared stale current sim ${plan.staleSavedId})`
2122
+ : ' nothing to close — no sims connected',
2059
2123
  )
2060
2124
  return
2061
2125
  }
package/cli/ws-bridge.ts CHANGED
@@ -359,6 +359,8 @@ export interface BridgeSimInfo {
359
359
  lockedBy?: string
360
360
  lockedByKind?: 'cli' | 'user-active'
361
361
  lockExpiresAt?: number
362
+ /** true when this sim's lease belongs to us. computed server-side. */
363
+ lockedByMe?: boolean
362
364
  userFocused?: boolean
363
365
  userVisible?: boolean
364
366
  visibilityState?: string
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
package/dist-lib/beta.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/beta.ts
4
4
  var IS_BETA = true;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_MAX_MS = 5e3;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/bridge-contract.ts
4
4
  var SIM_LONG_PRESS_DEFAULT_MS = 500;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/capture-contract.ts
4
4
  var RNX_SCREEN_CAPTURE_VERSION = 1;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/cloud-contract.ts
4
4
  var RNX_CLOUD_MAX_ARTIFACT_BYTES = 20 * 1024 * 1024;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -5221,7 +5221,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
5221
5221
  ws.send(
5222
5222
  JSON.stringify({
5223
5223
  id: msg.id,
5224
- result: this.listSims()
5224
+ result: this.listSims(this.cliIdentityKeyBySocket.get(ws))
5225
5225
  })
5226
5226
  );
5227
5227
  }
@@ -6131,12 +6131,12 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
6131
6131
  }, FORCE_CLOSE_TERMINATE_MS);
6132
6132
  unrefTimer(terminateTimer);
6133
6133
  }
6134
- listSims() {
6134
+ listSims(viewerIdentityKey) {
6135
6135
  return Array.from(this.sims.values()).sort((a, b) => {
6136
6136
  if (a.id === this.primarySimId) return -1;
6137
6137
  if (b.id === this.primarySimId) return 1;
6138
6138
  return a.connectedAt - b.connectedAt;
6139
- }).map((sim) => this.describeSim(sim));
6139
+ }).map((sim) => this.describeSim(sim, viewerIdentityKey));
6140
6140
  }
6141
6141
  async sendCommand(cmd) {
6142
6142
  const sim = await this.waitForSim(cmd.simId);
@@ -6281,7 +6281,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
6281
6281
  }
6282
6282
  }
6283
6283
  }
6284
- describeSim(sim) {
6284
+ describeSim(sim, viewerIdentityKey) {
6285
6285
  let readyState;
6286
6286
  try {
6287
6287
  readyState = sim.ws.readyState;
@@ -6302,6 +6302,7 @@ var SootSimBridgeHost = class _SootSimBridgeHost {
6302
6302
  readyState: readyState === import_ws.WebSocket.OPEN ? "open" : readyState === import_ws.WebSocket.CLOSING ? "closing" : "closed",
6303
6303
  attachedCliCount: this.getAttachedCliCount(sim.id),
6304
6304
  lockedBy: lease ? lease.cliLabel || lease.cliIdentityKey : void 0,
6305
+ lockedByMe: lease ? lease.cliIdentityKey === viewerIdentityKey : void 0,
6305
6306
  lockedByKind: lease ? lease.kind : void 0,
6306
6307
  lockExpiresAt: lease ? lease.expiresAt : void 0,
6307
6308
  userFocused: sim.userFocused || void 0,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/host/fetch-proxy-overrides.ts
4
4
  var FETCH_PROXY_BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
package/dist-lib/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
package/dist-lib/menu.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/public-brand.ts
4
4
  var name = "rnx";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-fingerprint-registry.ts
4
4
  var RNX_METRO_FINGERPRINT_SCHEMA_VERSION = 2;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/metro-production-bundle.ts
4
4
  var RNXSIM_METRO_MODULE_PATHS_PREFIX = "globalThis.__sootsimModulePaths=";
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
 
3
3
  // src/react-native-host-modules.ts
4
4
  var REACT_NATIVE_PASSTHROUGH_SPECIFIERS = [
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
package/dist-lib/sdk.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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 __defProp = Object.defineProperty;
package/dist-lib/sdk.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
@@ -1808,9 +1808,9 @@ var init_registry = __esm({
1808
1808
  coverage: 0.97,
1809
1809
  coverageSource: "estimated",
1810
1810
  capabilityCoverage: CAPABILITY_INVENTORY_PACKAGE_COVERAGE["react-native-reanimated"],
1811
- note: "core animations, gestures, scroll, layout transitions, common CSS opacity and transform transitions and keyframes, keyboard, sensors, reduced motion, native view property reads, and direct static style snapshots",
1811
+ note: "core animations, gestures, scroll, layout transitions, common CSS opacity, transform, and processed-color transitions and keyframes, keyboard, sensors, reduced motion, native view property reads, and direct static style snapshots",
1812
1812
  working: "useSharedValue, useAnimatedStyle/Props/Reaction, useDerivedValue, useAnimatedScrollHandler, useScrollViewOffset, useFrameCallback, useAnimatedRef, useAnimatedKeyboard, useAnimatedSensor, useReducedMotion, entering/exiting/layout transitions, css/createCSSAnimatedComponent with cubicBezier/linear/steps timing for common opacity and transform transitions, opacity and transform keyframes with retained forwards fill, withTiming/Spring/Decay/Delay/Sequence/Repeat/Clamp, interpolate, interpolateColor, runOnJS/UI, measure, scrollTo, getViewProp (layout, opacity, zIndex, backgroundColor, boxShadow), direct setViewStyle snapshots, Easing, createAnimatedComponent, Animated.View/Text/Image/ScrollView/FlatList",
1813
- missing: "Reanimated 4 CSS transitions and keyframes beyond opacity and transform remain incomplete"
1813
+ missing: "Reanimated 4 CSS layout, border metrics, shadows, filters, and complex-value transitions and keyframes remain incomplete"
1814
1814
  }
1815
1815
  ]
1816
1816
  },
@@ -20118,7 +20118,7 @@ var init_bridge_host = __esm({
20118
20118
  ws.send(
20119
20119
  JSON.stringify({
20120
20120
  id: msg.id,
20121
- result: this.listSims()
20121
+ result: this.listSims(this.cliIdentityKeyBySocket.get(ws))
20122
20122
  })
20123
20123
  );
20124
20124
  }
@@ -21028,12 +21028,12 @@ var init_bridge_host = __esm({
21028
21028
  }, FORCE_CLOSE_TERMINATE_MS);
21029
21029
  unrefTimer(terminateTimer);
21030
21030
  }
21031
- listSims() {
21031
+ listSims(viewerIdentityKey) {
21032
21032
  return Array.from(this.sims.values()).sort((a, b) => {
21033
21033
  if (a.id === this.primarySimId) return -1;
21034
21034
  if (b.id === this.primarySimId) return 1;
21035
21035
  return a.connectedAt - b.connectedAt;
21036
- }).map((sim) => this.describeSim(sim));
21036
+ }).map((sim) => this.describeSim(sim, viewerIdentityKey));
21037
21037
  }
21038
21038
  async sendCommand(cmd) {
21039
21039
  const sim = await this.waitForSim(cmd.simId);
@@ -21178,7 +21178,7 @@ var init_bridge_host = __esm({
21178
21178
  }
21179
21179
  }
21180
21180
  }
21181
- describeSim(sim) {
21181
+ describeSim(sim, viewerIdentityKey) {
21182
21182
  let readyState;
21183
21183
  try {
21184
21184
  readyState = sim.ws.readyState;
@@ -21199,6 +21199,7 @@ var init_bridge_host = __esm({
21199
21199
  readyState: readyState === import_ws.WebSocket.OPEN ? "open" : readyState === import_ws.WebSocket.CLOSING ? "closing" : "closed",
21200
21200
  attachedCliCount: this.getAttachedCliCount(sim.id),
21201
21201
  lockedBy: lease ? lease.cliLabel || lease.cliIdentityKey : void 0,
21202
+ lockedByMe: lease ? lease.cliIdentityKey === viewerIdentityKey : void 0,
21202
21203
  lockedByKind: lease ? lease.kind : void 0,
21203
21204
  lockExpiresAt: lease ? lease.expiresAt : void 0,
21204
21205
  userFocused: sim.userFocused || void 0,
@@ -25482,9 +25483,9 @@ function parseOpenRuntimeConfig(args) {
25482
25483
  if (Object.keys(remap).length > 0) config.network = { remap };
25483
25484
  return config.modules || config.network ? config : void 0;
25484
25485
  }
25485
- async function resolveOpenAppProject(resolvedBundle) {
25486
- if (!resolvedBundle) return null;
25487
- const advertisedRoot = await resolveMetroProjectRoot(resolvedBundle.bundleUrl);
25486
+ async function resolveAppProjectForBundleUrl(bundleUrl) {
25487
+ if (!bundleUrl) return null;
25488
+ const advertisedRoot = await resolveMetroProjectRoot(bundleUrl);
25488
25489
  return advertisedRoot ? resolveAppProject(advertisedRoot) : null;
25489
25490
  }
25490
25491
  async function ensureConfiguredRuntime(version) {
@@ -25619,12 +25620,17 @@ async function splashImageReachable(imageUrl) {
25619
25620
  clearTimeout(timer);
25620
25621
  }
25621
25622
  }
25623
+ function bundleUrlOf(urlStr) {
25624
+ try {
25625
+ return new URL(urlStr).searchParams.get("bundle") || void 0;
25626
+ } catch {
25627
+ return void 0;
25628
+ }
25629
+ }
25622
25630
  async function buildShellUrl(target, baseUrl = resolveDefaultShellBaseUrl(), opts = {}) {
25623
25631
  const resolved = await resolveShellUrl(target, baseUrl, opts);
25624
- const stamped = await stampAppSplash(
25625
- await stampAppFonts(resolved, opts.project),
25626
- opts.project
25627
- );
25632
+ const project = opts.project ?? await resolveAppProjectForBundleUrl(bundleUrlOf(resolved));
25633
+ const stamped = await stampAppSplash(await stampAppFonts(resolved, project), project);
25628
25634
  if (!opts.device) return stamped;
25629
25635
  const url = new URL(stamped);
25630
25636
  url.searchParams.set("device", opts.device);
@@ -26188,7 +26194,7 @@ async function runOpenCommand(args, opts = {}) {
26188
26194
  return;
26189
26195
  }
26190
26196
  const resolvedBundle = shouldResolveBundleTargetInCli(target) ? await resolveConnectionInputForCli(target) : void 0;
26191
- const project = await resolveOpenAppProject(resolvedBundle);
26197
+ const project = await resolveAppProjectForBundleUrl(resolvedBundle?.bundleUrl);
26192
26198
  const appConfig = await loadRNXAppConfig(project);
26193
26199
  const configuredRuntimeVersion = appConfig?.runtimeVersion;
26194
26200
  const runtimeConfig = mergeRNXConfig(
@@ -26576,25 +26582,44 @@ function planBulkCloseTargets(sims, opts) {
26576
26582
  }
26577
26583
  }
26578
26584
  }
26585
+ const now = opts.now ?? Date.now();
26586
+ const refused = [];
26587
+ for (const sim of open) {
26588
+ if (sim.id === keepId) continue;
26589
+ const lockedBy = sim.lockedBy;
26590
+ const expiresAt = sim.lockExpiresAt;
26591
+ if (!lockedBy || !expiresAt || expiresAt <= now || sim.lockedByMe) continue;
26592
+ const kind = sim.lockedByKind ?? "cli";
26593
+ if (kind === "cli" && opts.force) continue;
26594
+ refused.push({
26595
+ id: sim.id,
26596
+ lockedBy,
26597
+ kind,
26598
+ expiresInMs: Math.max(0, expiresAt - now)
26599
+ });
26600
+ }
26601
+ const refusedIds = new Set(refused.map((entry) => entry.id));
26579
26602
  return {
26580
26603
  openIds,
26581
26604
  keepId,
26582
- targets: missingExplicitKeepId ? [] : openIds.filter((id) => id !== keepId),
26605
+ targets: missingExplicitKeepId ? [] : openIds.filter((id) => id !== keepId && !refusedIds.has(id)),
26583
26606
  staleSavedId,
26584
26607
  missingExplicitKeepId,
26585
- fallbackKeepId
26608
+ fallbackKeepId,
26609
+ refused
26586
26610
  };
26587
26611
  }
26588
26612
  async function runCloseCommand(args, opts = {}) {
26589
26613
  const parsed = parseBridgeCliArgs(args, {
26590
26614
  port: opts.port,
26591
26615
  commandTimeoutMs: opts.timeoutMs,
26592
- stripBooleanFlags: ["--all", "--others"]
26616
+ stripBooleanFlags: ["--all", "--others", "--force"]
26593
26617
  });
26594
26618
  const bridge = createBridgeFromParsed(parsed);
26595
26619
  const simHint = parsed.simId ? ` --sim ${parsed.simId}` : "";
26596
26620
  const closeAll = args.includes("--all");
26597
26621
  const closeOthers = args.includes("--others");
26622
+ const force = args.includes("--force");
26598
26623
  if (closeAll || closeOthers) {
26599
26624
  try {
26600
26625
  const sims = await bridge.listSims();
@@ -26603,8 +26628,18 @@ async function runCloseCommand(args, opts = {}) {
26603
26628
  const plan = planBulkCloseTargets(sims, {
26604
26629
  closeOthers,
26605
26630
  explicitKeepId,
26606
- savedKeepId: savedId
26631
+ savedKeepId: savedId,
26632
+ force
26607
26633
  });
26634
+ for (const entry of plan.refused) {
26635
+ const secs = Math.round(entry.expiresInMs / 1e3);
26636
+ console.error(
26637
+ entry.kind === "user-active" ? ` skipped: ${entry.id} is locked by the active user (${secs}s) \u2014 that's a live human tab` : ` skipped: ${entry.id} is leased by ${formatLockOwner(entry.lockedBy)} (${secs}s)`
26638
+ );
26639
+ }
26640
+ if (plan.refused.some((entry) => entry.kind === "cli") && !force) {
26641
+ console.error(` \`rnx close --all --force\` to close leased sims too`);
26642
+ }
26608
26643
  if (plan.staleSavedId) {
26609
26644
  clearCurrentSimId();
26610
26645
  }
@@ -26622,7 +26657,7 @@ async function runCloseCommand(args, opts = {}) {
26622
26657
  }
26623
26658
  if (plan.targets.length === 0) {
26624
26659
  console.log(
26625
- plan.keepId ? ` nothing to close \u2014 only the kept sim ${plan.keepId} is connected` : plan.staleSavedId ? ` nothing to close \u2014 no sims connected (cleared stale current sim ${plan.staleSavedId})` : " nothing to close \u2014 no sims connected"
26660
+ plan.keepId ? ` nothing to close \u2014 only the kept sim ${plan.keepId} is connected` : plan.refused.length > 0 ? ` nothing to close \u2014 every other connected sim is leased by someone else` : plan.staleSavedId ? ` nothing to close \u2014 no sims connected (cleared stale current sim ${plan.staleSavedId})` : " nothing to close \u2014 no sims connected"
26626
26661
  );
26627
26662
  return;
26628
26663
  }
package/dist-lib/vite.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.430 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.432 | (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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnxsim",
3
- "version": "0.1.430",
3
+ "version": "0.1.432",
4
4
  "description": "Vite and Metro plugins, testing drivers, and SDK exports for rnx.",
5
5
  "author": "Tamagui LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -74,6 +74,11 @@ export interface BridgeSimInfo {
74
74
  lockedBy?: string
75
75
  lockedByKind?: 'cli' | 'user-active'
76
76
  lockExpiresAt?: number
77
+ // true when the lease belongs to the caller asking for this list. the
78
+ // server computes it because `lockedBy` is a display string (a cliLabel
79
+ // like "open --describe", or "active user") and cannot be compared
80
+ // against an identity key by the client.
81
+ lockedByMe?: boolean
77
82
  userFocused?: boolean
78
83
  userVisible?: boolean
79
84
  visibilityState?: string
@@ -961,7 +966,7 @@ export class SootSimBridgeHost {
961
966
  ws.send(
962
967
  JSON.stringify({
963
968
  id: msg.id,
964
- result: this.listSims(),
969
+ result: this.listSims(this.cliIdentityKeyBySocket.get(ws)),
965
970
  }),
966
971
  )
967
972
  }
@@ -2051,14 +2056,14 @@ export class SootSimBridgeHost {
2051
2056
  unrefTimer(terminateTimer)
2052
2057
  }
2053
2058
 
2054
- listSims(): BridgeSimInfo[] {
2059
+ listSims(viewerIdentityKey?: string): BridgeSimInfo[] {
2055
2060
  return Array.from(this.sims.values())
2056
2061
  .sort((a, b) => {
2057
2062
  if (a.id === this.primarySimId) return -1
2058
2063
  if (b.id === this.primarySimId) return 1
2059
2064
  return a.connectedAt - b.connectedAt
2060
2065
  })
2061
- .map((sim) => this.describeSim(sim))
2066
+ .map((sim) => this.describeSim(sim, viewerIdentityKey))
2062
2067
  }
2063
2068
 
2064
2069
  async sendCommand(cmd: Omit<BridgeSimCommand, 'id'>): Promise<any> {
@@ -2218,7 +2223,10 @@ export class SootSimBridgeHost {
2218
2223
  }
2219
2224
  }
2220
2225
 
2221
- private describeSim(sim: BridgeSimConnection): BridgeSimInfo {
2226
+ private describeSim(
2227
+ sim: BridgeSimConnection,
2228
+ viewerIdentityKey?: string,
2229
+ ): BridgeSimInfo {
2222
2230
  let readyState: BridgeSimConnection['ws']['readyState']
2223
2231
  try {
2224
2232
  readyState = sim.ws.readyState
@@ -2244,6 +2252,7 @@ export class SootSimBridgeHost {
2244
2252
  : 'closed',
2245
2253
  attachedCliCount: this.getAttachedCliCount(sim.id),
2246
2254
  lockedBy: lease ? lease.cliLabel || lease.cliIdentityKey : undefined,
2255
+ lockedByMe: lease ? lease.cliIdentityKey === viewerIdentityKey : undefined,
2247
2256
  lockedByKind: lease ? lease.kind : undefined,
2248
2257
  lockExpiresAt: lease ? lease.expiresAt : undefined,
2249
2258
  userFocused: sim.userFocused || undefined,