rnxsim 0.1.442 → 0.1.443

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 (71) hide show
  1. package/cli/bin.ts +3 -1
  2. package/cli/cloud-client.ts +153 -17
  3. package/cli/cloud-dispatch.ts +15 -0
  4. package/cli/cloud-session.ts +69 -17
  5. package/cli/commands/box/bundle-plane.ts +71 -0
  6. package/cli/commands/box.ts +274 -115
  7. package/cli/commands/control.ts +1 -137
  8. package/cli/commands/flow.ts +1 -1
  9. package/cli/commands/inspect/list.ts +119 -2
  10. package/cli/commands/inspect.ts +3 -2
  11. package/cli/commands/platform.ts +95 -12
  12. package/cli/commands/reset.ts +7 -3
  13. package/cli/commands/state.ts +7 -3
  14. package/cli/flow-export.ts +55 -0
  15. package/cli/flow-session.ts +0 -47
  16. package/cli/outbound-endpoints.ts +5 -0
  17. package/cli/rnx-in-process.ts +98 -0
  18. package/cli/ws-bridge.ts +30 -0
  19. package/dist-lib/agent-daemon-client.cjs +1 -1
  20. package/dist-lib/agent-events.cjs +1 -1
  21. package/dist-lib/agent-identity.cjs +1 -1
  22. package/dist-lib/agent-sessions.cjs +1 -1
  23. package/dist-lib/attached-projects.cjs +1 -1
  24. package/dist-lib/auth/shared-session.cjs +1 -1
  25. package/dist-lib/backend-origin.cjs +1 -1
  26. package/dist-lib/beta.cjs +1 -1
  27. package/dist-lib/beta.mjs +1 -1
  28. package/dist-lib/bridge-constants.cjs +1 -1
  29. package/dist-lib/bridge-contract-input.cjs +1 -1
  30. package/dist-lib/bridge-contract-input.mjs +1 -1
  31. package/dist-lib/bridge-contract.cjs +1 -1
  32. package/dist-lib/bridge-contract.mjs +1 -1
  33. package/dist-lib/capture-contract.cjs +1 -1
  34. package/dist-lib/capture-contract.mjs +1 -1
  35. package/dist-lib/cli-constants.cjs +1 -1
  36. package/dist-lib/cloud-contract.cjs +1 -1
  37. package/dist-lib/cloud-contract.mjs +1 -1
  38. package/dist-lib/cloud.cjs +1 -1
  39. package/dist-lib/cloud.mjs +1 -1
  40. package/dist-lib/config.cjs +1 -1
  41. package/dist-lib/detox/index.cjs +69 -14
  42. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  43. package/dist-lib/home-paths.cjs +17 -1
  44. package/dist-lib/host/bridge-host.cjs +24 -13
  45. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  46. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  47. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  48. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  49. package/dist-lib/host/websocket-proxy.cjs +1 -1
  50. package/dist-lib/index.cjs +1 -3
  51. package/dist-lib/jump-to-source-babel.cjs +1 -1
  52. package/dist-lib/menu.cjs +6 -19
  53. package/dist-lib/menu.mjs +6 -19
  54. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  55. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  56. package/dist-lib/metro-production-bundle.cjs +1 -1
  57. package/dist-lib/metro-production-bundle.mjs +1 -1
  58. package/dist-lib/metro.cjs +1 -1
  59. package/dist-lib/profiles.cjs +1 -1
  60. package/dist-lib/public-brand.cjs +1 -1
  61. package/dist-lib/react-native-host-modules.cjs +1 -1
  62. package/dist-lib/react-native-host-modules.mjs +1 -1
  63. package/dist-lib/render-mode.cjs +1 -1
  64. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  65. package/dist-lib/sdk.cjs +1 -1
  66. package/dist-lib/sdk.mjs +1 -1
  67. package/dist-lib/skills.cjs +274 -195
  68. package/dist-lib/vite.cjs +1 -1
  69. package/package.json +8 -1
  70. package/src/home-paths.ts +31 -1
  71. package/src/menu.ts +4 -17
@@ -0,0 +1,98 @@
1
+ // running an rnx command inside the calling process instead of spawning the CLI.
2
+ //
3
+ // the parse and the dispatch here are the CLI's own: parseRnxArgs, the command
4
+ // registry behind it, and the same per-command handlers main.ts reaches. what
5
+ // changes is the transport and the boundary. the caller hands in the WsBridge,
6
+ // so one vocabulary and one parser run against three of them: the local ws
7
+ // daemon, a cloud box's commands route, and, inside a box shell in workerd, the
8
+ // Box Durable Object's own command router with no network hop.
9
+ //
10
+ // the boundary is run-rnx.ts: output comes back as a value rather than reaching
11
+ // a terminal, and a command that would have called process.exit throws instead,
12
+ // which is what makes this safe to call in workerd, where process.exit cancels
13
+ // the whole request.
14
+
15
+ import { parseRnxArgs, TOP_LEVEL_RUNTIME_COMMANDS } from './parse-args'
16
+ import { type RnxRunResult, runRnx } from './run-rnx'
17
+ import type { ParsedBridgeCliArgs, WsBridge } from './ws-bridge'
18
+
19
+ // the verbs that reach a simulator through the bridge and nothing else. every
20
+ // other registered command needs the machine rnx is installed on: a device to
21
+ // boot, a browser to open, a credential store, the bridge daemon, or the local
22
+ // filesystem. `state` and `reset` sit outside runInspect but take the same
23
+ // bridge, so they belong here too.
24
+ const IN_PROCESS_COMMANDS: ReadonlySet<string> = new Set([
25
+ ...TOP_LEVEL_RUNTIME_COMMANDS,
26
+ 'state',
27
+ 'reset',
28
+ ])
29
+
30
+ const RUNNABLE = [...IN_PROCESS_COMMANDS].sort().join(', ')
31
+
32
+ export interface RnxInProcessOptions {
33
+ /** the command and its arguments, with no node/script prefix. */
34
+ argv: string[]
35
+ /**
36
+ * the transport the command runs against. it takes the parsed bridge args
37
+ * because the local host builds its bridge out of `--sim`, `--port`, and
38
+ * `--timeout`, while a box ignores all three and answers on its own socket.
39
+ */
40
+ createBridge: (parsed: ParsedBridgeCliArgs) => WsBridge
41
+ }
42
+
43
+ export async function runRnxInProcess(
44
+ options: RnxInProcessOptions,
45
+ ): Promise<RnxRunResult> {
46
+ return runRnx(options.argv, async (argv) => {
47
+ const parsed = parseRnxArgs(argv)
48
+ for (const warning of parsed.warnings) console.error(warning)
49
+ const command = parsed.command
50
+ if (!command || !IN_PROCESS_COMMANDS.has(command)) {
51
+ const named = command ? `rnx ${command}` : 'rnx'
52
+ console.error(
53
+ ` ${named} is not available here; this rnx drives a simulator and has no machine to run on. runs here: ${RUNNABLE}`,
54
+ )
55
+ return 1
56
+ }
57
+
58
+ const simTarget = parsed.globalFlags['sim'] ?? parsed.globalFlags['session']
59
+ const commandArgs =
60
+ typeof simTarget === 'string'
61
+ ? ['--sim', simTarget, ...parsed.commandArgs]
62
+ : parsed.commandArgs
63
+ if (commandArgs.includes('--then')) {
64
+ console.error(
65
+ ' rnx do --then is not available here; a chain runs against a sim connection rather than the bridge. run the actions one at a time.',
66
+ )
67
+ return 1
68
+ }
69
+
70
+ const port = parsed.globalFlags['port']
71
+ const opts = {
72
+ ...(typeof port === 'number' ? { port } : {}),
73
+ createBridge: options.createBridge,
74
+ }
75
+ if (command === 'state') {
76
+ const { runState } = await import('./commands/state')
77
+ return runState(commandArgs, opts)
78
+ }
79
+ if (command === 'reset') {
80
+ const { runReset } = await import('./commands/reset')
81
+ return runReset(commandArgs, opts)
82
+ }
83
+ const { runInspect } = await import('./commands/inspect')
84
+ await runInspect([command, ...commandArgs], { ...opts, verbose: parsed.verbose })
85
+ return 0
86
+ })
87
+ }
88
+
89
+ // the transport contract and the command's own name, re-exported so a host
90
+ // that only wants to register this entry and supply a bridge (a Box Durable
91
+ // Object, say) has one module to import.
92
+ export { rnxPublicBrand } from '../src/public-brand'
93
+ export type {
94
+ BridgeClaimResult,
95
+ BridgeSimInfo,
96
+ ParsedBridgeCliArgs,
97
+ WsBridge,
98
+ } from './ws-bridge'
package/cli/ws-bridge.ts CHANGED
@@ -403,6 +403,26 @@ export interface BridgeSimInfo {
403
403
  meta?: Record<string, unknown>
404
404
  }
405
405
 
406
+ // a lock owner is either a friendly cli label ("active user") or a raw cli
407
+ // identity key ("CLAUDE_CODE_SESSION_ID:<uuid>", "gppid-1234"). keep the list
408
+ // readable by collapsing a "<source>:<value>" identity to a short form that
409
+ // still says which agent holds it.
410
+ export function formatLockOwner(owner: string): string {
411
+ const colon = owner.indexOf(':')
412
+ if (colon <= 0) return owner.length > 24 ? `${owner.slice(0, 21)}…` : owner
413
+ const source = owner.slice(0, colon)
414
+ const value = owner.slice(colon + 1)
415
+ const short = value.length > 12 ? `${value.slice(0, 8)}…` : value
416
+ if (
417
+ source === 'TM_SESSION' ||
418
+ source === 'CLAUDE_CODE_SESSION_ID' ||
419
+ source === 'CODEX_THREAD_ID'
420
+ ) {
421
+ return `agent ${short}`
422
+ }
423
+ return `${source} ${short}`
424
+ }
425
+
406
426
  interface ParseBridgeCliArgsOptions {
407
427
  port?: number
408
428
  commandTimeoutMs?: number
@@ -769,6 +789,16 @@ export function createBridge(wsPort: number, opts: WsBridgeOptions = {}): WsBrid
769
789
  }
770
790
  }
771
791
 
792
+ /**
793
+ * how a command reaches a simulator. left out, it resolves the way the host
794
+ * CLI always has: the cloud box route when a box session is set, otherwise the
795
+ * local ws daemon. a box shell passes its own bridge so the same command runs
796
+ * in the calling process against the box's own simulator.
797
+ */
798
+ export interface BridgeTransportOption {
799
+ createBridge?: (parsed: ParsedBridgeCliArgs) => WsBridge
800
+ }
801
+
772
802
  export function createBridgeFromParsed(parsed: ParsedBridgeCliArgs): WsBridge {
773
803
  const cloudBridge = createCloudBridgeForParsed(parsed)
774
804
  if (cloudBridge) return cloudBridge
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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;
@@ -299,6 +299,16 @@ function assertGpuBrowserCommand(command, runtime = currentRuntime()) {
299
299
  `[reap-browser] Chrome process did not retain the required ${angle} GPU arguments`
300
300
  );
301
301
  }
302
+ for (const name of ["--enable-features=", "--disable-features="]) {
303
+ const lists = args.filter((arg) => arg.startsWith(name)).map((arg) => arg.slice(name.length).split(",").filter(Boolean));
304
+ const kept = new Set(lists.at(-1) ?? []);
305
+ const dropped = lists.slice(0, -1).flat().filter((feature) => !kept.has(feature));
306
+ if (dropped.length > 0) {
307
+ throw new Error(
308
+ `[reap-browser] Chrome keeps only its last ${name.slice(0, -1)} switch, which dropped ${dropped.join(",")}; add them to the merged list in scripts/lib/reap-browser.ts`
309
+ );
310
+ }
311
+ }
302
312
  if (runtime.platform === "darwin" && command.includes("/Applications/Google Chrome.app/")) {
303
313
  throw new Error(
304
314
  "[reap-browser] refused the user's installed Google Chrome; use Playwright channel chromium"
@@ -568,6 +578,46 @@ function gpuChromeArgs(platform = process.platform) {
568
578
  "--ignore-gpu-blocklist"
569
579
  ];
570
580
  }
581
+ var PLAYWRIGHT_DISABLED_FEATURES = [
582
+ "AvoidUnnecessaryBeforeUnloadCheckSync",
583
+ "BoundaryEventDispatchTracksNodeRemoval",
584
+ "DestroyProfileOnBrowserClose",
585
+ "DialMediaRouteProvider",
586
+ "GlobalMediaControls",
587
+ "HttpsUpgrades",
588
+ "LensOverlay",
589
+ "MediaRouter",
590
+ "PaintHolding",
591
+ "ThirdPartyStoragePartitioning",
592
+ "Translate",
593
+ "AutoDeElevate",
594
+ "RenderDocument",
595
+ "OptimizationHints",
596
+ "msForceBrowserSignIn",
597
+ "msEdgeUpdateLaunchServicesPreferredVersion"
598
+ ];
599
+ var PLAYWRIGHT_ENABLED_FEATURES = ["CDPScreenshotNewSurface"];
600
+ var DISABLED_FEATURES = ["NetworkTimeServiceQuerying"];
601
+ function mergeFeatureSwitches(args, enabled = []) {
602
+ const enable = /* @__PURE__ */ new Set([...PLAYWRIGHT_ENABLED_FEATURES, ...enabled]);
603
+ const disable = /* @__PURE__ */ new Set([...PLAYWRIGHT_DISABLED_FEATURES, ...DISABLED_FEATURES]);
604
+ const rest = [];
605
+ for (const arg of args) {
606
+ const match = /^--(enable|disable)-features=(.*)$/.exec(arg);
607
+ if (!match) {
608
+ rest.push(arg);
609
+ continue;
610
+ }
611
+ for (const feature of match[2].split(",")) {
612
+ if (feature) (match[1] === "enable" ? enable : disable).add(feature);
613
+ }
614
+ }
615
+ return [
616
+ ...rest,
617
+ `--enable-features=${[...enable].join(",")}`,
618
+ `--disable-features=${[...disable].join(",")}`
619
+ ];
620
+ }
571
621
  function gpuChromeLaunchOptions(opts = {}, runtime = currentRuntime()) {
572
622
  const callerArgs = Array.isArray(opts.args) ? opts.args : [];
573
623
  const unsafe = callerArgs.find(isSoftwareRendererArgument);
@@ -608,7 +658,10 @@ function gpuChromeLaunchOptions(opts = {}, runtime = currentRuntime()) {
608
658
  // com.google.chrome.for.testing, so automation cannot become the target of
609
659
  // Dock open/quit events intended for the user's com.google.Chrome browser.
610
660
  channel: "chromium",
611
- args: [...unmanagedCallerArgs, ...gpuChromeArgs(runtime.platform)],
661
+ args: mergeFeatureSwitches([
662
+ ...unmanagedCallerArgs,
663
+ ...gpuChromeArgs(runtime.platform)
664
+ ]),
612
665
  ignoreDefaultArgs: ignoredDefaults
613
666
  };
614
667
  }
@@ -656,21 +709,23 @@ function softwareChromeLaunchOptions(opts) {
656
709
  }
657
710
  const callerArgs = Array.isArray(opts.args) ? opts.args.map(String) : [];
658
711
  const unmanagedCallerArgs = callerArgs.filter((arg) => {
659
- return !arg.startsWith("--use-angle=") && arg !== "--enable-gpu" && arg !== "--enable-gpu-rasterization" && arg !== "--enable-zero-copy" && arg !== "--ignore-gpu-blocklist" && !/^--enable-unsafe-webgpu(?:=.*)?$/i.test(arg) && !/^--enable-features=(?:Vulkan|WebGPU)(?:,(?:Vulkan|WebGPU))*$/i.test(arg) && !/^--enable-unsafe-swiftshader(?:=.*)?$/i.test(arg);
712
+ return !arg.startsWith("--use-angle=") && arg !== "--enable-gpu" && arg !== "--enable-gpu-rasterization" && arg !== "--enable-zero-copy" && arg !== "--ignore-gpu-blocklist" && !/^--enable-unsafe-webgpu(?:=.*)?$/i.test(arg) && !/^--enable-unsafe-swiftshader(?:=.*)?$/i.test(arg);
660
713
  });
661
714
  const software = {
662
715
  ...opts,
663
- args: [
664
- ...unmanagedCallerArgs,
665
- "--use-angle=swiftshader",
666
- "--enable-unsafe-swiftshader",
667
- // playwright's bundled software chromium exposes no navigator.gpu without
668
- // these two, and the compositor's only backend is webgpu. emitted here
669
- // rather than per caller so a hosted-linux launch and a local gpu launch
670
- // agree on what a sim needs.
671
- "--enable-unsafe-webgpu",
672
- "--enable-features=Vulkan"
673
- ]
716
+ // playwright's bundled software chromium exposes no navigator.gpu without
717
+ // --enable-unsafe-webgpu plus the Vulkan feature, and the compositor's only
718
+ // backend is webgpu. emitted here rather than per caller so a hosted-linux
719
+ // launch and a local gpu launch agree on what a sim needs.
720
+ args: mergeFeatureSwitches(
721
+ [
722
+ ...unmanagedCallerArgs,
723
+ "--use-angle=swiftshader",
724
+ "--enable-unsafe-swiftshader",
725
+ "--enable-unsafe-webgpu"
726
+ ],
727
+ ["Vulkan"]
728
+ )
674
729
  };
675
730
  delete software.channel;
676
731
  delete software.executablePath;
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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;
@@ -65,6 +65,7 @@ __export(home_paths_exports, {
65
65
  profilesDir: () => profilesDir,
66
66
  readActiveRuntime: () => readActiveRuntime,
67
67
  readDaemonLockfile: () => readDaemonLockfile,
68
+ readDefaultBox: () => readDefaultBox,
68
69
  readDevBridgeLockfiles: () => readDevBridgeLockfiles,
69
70
  readLiveRuntimeVersions: () => readLiveRuntimeVersions,
70
71
  readOrCreateAnonymousId: () => readOrCreateAnonymousId,
@@ -80,6 +81,7 @@ __export(home_paths_exports, {
80
81
  shouldSkipPersistentDaemon: () => shouldSkipPersistentDaemon,
81
82
  writeActiveRuntime: () => writeActiveRuntime,
82
83
  writeDaemonLockfile: () => writeDaemonLockfile,
84
+ writeDefaultBox: () => writeDefaultBox,
83
85
  writeDevBridgeLockfile: () => writeDevBridgeLockfile,
84
86
  writeOnboardingPreferences: () => writeOnboardingPreferences,
85
87
  writePrivacyPreferences: () => writePrivacyPreferences,
@@ -242,6 +244,18 @@ function readOrCreateAnonymousId() {
242
244
  writeSharedConfig({ anonymousId: created });
243
245
  return created;
244
246
  }
247
+ function readDefaultBox() {
248
+ const stored = readSharedConfig().defaultBox;
249
+ if (typeof stored !== "object" || stored === null) return null;
250
+ if (!("boxId" in stored) || typeof stored.boxId !== "string" || !stored.boxId) {
251
+ return null;
252
+ }
253
+ const name = "name" in stored && typeof stored.name === "string" ? stored.name : null;
254
+ return { boxId: stored.boxId, name };
255
+ }
256
+ function writeDefaultBox(box) {
257
+ writeSharedConfig({ defaultBox: box });
258
+ }
245
259
  function runtimeUpgradeNoticePath() {
246
260
  return import_node_path.default.join(rnxHomeDir(), "runtime-upgraded.json");
247
261
  }
@@ -599,6 +613,7 @@ function removeDevBridgeLockfile(owner) {
599
613
  profilesDir,
600
614
  readActiveRuntime,
601
615
  readDaemonLockfile,
616
+ readDefaultBox,
602
617
  readDevBridgeLockfiles,
603
618
  readLiveRuntimeVersions,
604
619
  readOrCreateAnonymousId,
@@ -614,6 +629,7 @@ function removeDevBridgeLockfile(owner) {
614
629
  shouldSkipPersistentDaemon,
615
630
  writeActiveRuntime,
616
631
  writeDaemonLockfile,
632
+ writeDefaultBox,
617
633
  writeDevBridgeLockfile,
618
634
  writeOnboardingPreferences,
619
635
  writePrivacyPreferences,
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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;
@@ -3442,6 +3442,7 @@ function normalizeCloudOrigin(source) {
3442
3442
  function createCloudSession(input) {
3443
3443
  const session = {
3444
3444
  version: CLOUD_SESSION_VERSION,
3445
+ service: "sim",
3445
3446
  boxId: input.boxId.trim(),
3446
3447
  boxToken: input.boxToken,
3447
3448
  simId: input.simId.trim(),
@@ -3459,7 +3460,7 @@ var init_cloud_session = __esm({
3459
3460
  "cli/cloud-session.ts"() {
3460
3461
  "use strict";
3461
3462
  init_backend_origin();
3462
- CLOUD_SESSION_VERSION = 2;
3463
+ CLOUD_SESSION_VERSION = 3;
3463
3464
  MAX_ENCODED_SESSION_BYTES = 32 * 1024;
3464
3465
  RNX_SHELL_UPDATE_PREFIX = "__RNX_SHELL_UPDATE_V1__";
3465
3466
  RNX_SHELL_UPDATE_SET_PREFIX = `${RNX_SHELL_UPDATE_PREFIX}set:`;
@@ -3705,7 +3706,8 @@ function distinctByContent(directory, options) {
3705
3706
  return [...byContent.values()];
3706
3707
  }
3707
3708
  function placeMetroDescriptor(listing, descriptor) {
3708
- const perScale = descriptor.scales.map(
3709
+ const scales = [...new Set(descriptor.scales)];
3710
+ const perScale = scales.map(
3709
3711
  (scale) => distinctByContent(
3710
3712
  listing.directory,
3711
3713
  resolveMetroIosAssetDestFiles(listing.files, descriptor, scale)
@@ -3713,7 +3715,7 @@ function placeMetroDescriptor(listing, descriptor) {
3713
3715
  );
3714
3716
  const files = /* @__PURE__ */ new Map();
3715
3717
  const ambiguous = [];
3716
- descriptor.scales.forEach((scale, index) => {
3718
+ scales.forEach((scale, index) => {
3717
3719
  const options = perScale[index] ?? [];
3718
3720
  if (options.length === 1 && options[0]) files.set(scale, options[0]);
3719
3721
  else if (options.length > 1) ambiguous.push(...options);
@@ -3721,6 +3723,7 @@ function placeMetroDescriptor(listing, descriptor) {
3721
3723
  if (perScale.length === 0 || perScale.some((options) => options.length === 0)) {
3722
3724
  return { files, ambiguous, verified: false, mismatched: false };
3723
3725
  }
3726
+ const fileHashes = !descriptor.fileUris && descriptor.fileHashes?.length === descriptor.scales.length ? descriptor.fileHashes : null;
3724
3727
  for (const combination of placementCombinations(perScale)) {
3725
3728
  let bytes;
3726
3729
  try {
@@ -3730,14 +3733,23 @@ function placeMetroDescriptor(listing, descriptor) {
3730
3733
  } catch {
3731
3734
  continue;
3732
3735
  }
3733
- if (metroDescriptorHash(bytes) !== descriptor.hash) continue;
3736
+ const identical = fileHashes ? bytes.every((file, index) => {
3737
+ const digest = (0, import_node_crypto5.createHash)("md5").update(file).digest("hex");
3738
+ return descriptor.scales.some(
3739
+ (scale, declared) => scale === scales[index] && fileHashes[declared] === digest
3740
+ );
3741
+ }) : scales.length === descriptor.scales.length && metroDescriptorHash(bytes) === descriptor.hash;
3742
+ if (!identical) continue;
3734
3743
  const chosen = /* @__PURE__ */ new Map();
3735
- descriptor.scales.forEach((scale, index) => {
3744
+ scales.forEach((scale, index) => {
3736
3745
  const relative2 = combination[index];
3737
3746
  if (relative2) chosen.set(scale, relative2);
3738
3747
  });
3739
3748
  return { files: chosen, ambiguous: [], verified: true, mismatched: false };
3740
3749
  }
3750
+ if (!fileHashes && scales.length !== descriptor.scales.length) {
3751
+ return { files, ambiguous, verified: false, mismatched: false };
3752
+ }
3741
3753
  return { files, ambiguous, verified: false, mismatched: true };
3742
3754
  }
3743
3755
  function unverifiedFileKey(dest) {
@@ -3850,7 +3862,7 @@ async function inferCloudModuleIdentity(source) {
3850
3862
  );
3851
3863
  }
3852
3864
  }
3853
- async function produceCloudArtifact(bundlePath, assetsPath) {
3865
+ async function produceCloudArtifact(bundlePath, assetsPath, maxBytes = MAX_RNX_CLOUD_BUNDLE_BYTES) {
3854
3866
  const source = await loadBundleSource(bundlePath);
3855
3867
  const descriptors = extractAssetDescriptors(source);
3856
3868
  const search = assetsPath ? explicitMetroAssetDest((0, import_node_path15.resolve)(assetsPath), descriptors) : descriptors.length > 0 && !isRemoteBundleInput(bundlePath) ? searchMetroAssetDest(bundlePath, descriptors) : { dest: null, searched: [], truncated: false };
@@ -3907,9 +3919,9 @@ async function produceCloudArtifact(bundlePath, assetsPath) {
3907
3919
  });
3908
3920
  const bytes = Buffer.from(artifact.code, "utf8");
3909
3921
  const assets = artifact.receipt.assets;
3910
- if (bytes.length > MAX_RNX_CLOUD_BUNDLE_BYTES) {
3922
+ if (bytes.length > maxBytes) {
3911
3923
  throw new Error(
3912
- `${REMOTE_COMMAND} artifact is ${bytes.length} bytes and exceeds the ${MAX_RNX_CLOUD_BUNDLE_BYTES}-byte limit. Embedded assets weigh ${assets.bytes} bytes on disk, and base64 embedding costs about a third on top of that, so the practical asset budget is roughly 15 MB.${largestEmbeddedAssets(assets.sizes, 10)}`
3924
+ `${REMOTE_COMMAND} artifact is ${bytes.length} bytes and exceeds the ${maxBytes}-byte limit. Embedded assets weigh ${assets.bytes} bytes on disk, and base64 embedding costs about a third on top of that, so the practical asset budget is roughly ${Math.round(maxBytes * 0.75 / 1e6)} MB.${largestEmbeddedAssets(assets.sizes, 10)}`
3913
3925
  );
3914
3926
  }
3915
3927
  const warnings = [];
@@ -3918,9 +3930,9 @@ async function produceCloudArtifact(bundlePath, assetsPath) {
3918
3930
  `${REMOTE_COMMAND} embedded a placeholder image for ${substituted.length} asset(s) no scale of which is in ${search.searched.join(", ") || "any asset dest directory"}: ${substituted.join(", ")}. Build the bundle with --assets-dest, or pass --assets <dir>, to ship the real images.`
3919
3931
  );
3920
3932
  }
3921
- if (bytes.length >= WARN_ARTIFACT_BYTES) {
3933
+ if (bytes.length >= Math.floor(maxBytes * 0.8)) {
3922
3934
  warnings.push(
3923
- `${REMOTE_COMMAND} artifact is ${bytes.length} bytes, ${Math.round(bytes.length / MAX_RNX_CLOUD_BUNDLE_BYTES * 100)}% of the ${MAX_RNX_CLOUD_BUNDLE_BYTES}-byte limit.${largestEmbeddedAssets(assets.sizes, 5)}`
3935
+ `${REMOTE_COMMAND} artifact is ${bytes.length} bytes, ${Math.round(bytes.length / maxBytes * 100)}% of the ${maxBytes}-byte limit.${largestEmbeddedAssets(assets.sizes, 5)}`
3924
3936
  );
3925
3937
  }
3926
3938
  return {
@@ -4023,7 +4035,7 @@ async function createCloudBox(options) {
4023
4035
  warnings: artifact.warnings
4024
4036
  };
4025
4037
  }
4026
- var import_node_crypto5, import_node_fs14, import_node_path15, DEFAULT_RNX_CLOUD_ORIGIN, MAX_RNX_CLOUD_BUNDLE_BYTES, REMOTE_COMMAND, WARN_ARTIFACT_BYTES, MAX_ASSET_DEST_FILES, ACCOUNT_CHOICE_REFUSALS, PROJECT_ONLY_DIRECTORIES, MAX_PLACEMENT_COMBINATIONS;
4038
+ var import_node_crypto5, 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;
4027
4039
  var init_cloud_client = __esm({
4028
4040
  "cli/cloud-client.ts"() {
4029
4041
  "use strict";
@@ -4044,7 +4056,6 @@ var init_cloud_client = __esm({
4044
4056
  DEFAULT_RNX_CLOUD_ORIGIN = rnxPublicBrand.origin;
4045
4057
  MAX_RNX_CLOUD_BUNDLE_BYTES = RNX_CLOUD_MAX_ARTIFACT_BYTES;
4046
4058
  REMOTE_COMMAND = "rnx ios --remote";
4047
- WARN_ARTIFACT_BYTES = Math.floor(MAX_RNX_CLOUD_BUNDLE_BYTES * 0.8);
4048
4059
  MAX_ASSET_DEST_FILES = 25e3;
4049
4060
  ACCOUNT_CHOICE_REFUSALS = /* @__PURE__ */ new Set([
4050
4061
  "accountId is required",
@@ -1,4 +1,4 @@
1
- /*! rnx v0.1.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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.442 | (c) 2026 Tamagui LLC | Proprietary — see LICENSE */
1
+ /*! rnx v0.1.443 | (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;